nilfs2: localize highmem mapping for checkpoint finalization within cpfile
authorRyusuke Konishi <konishi.ryusuke@gmail.com>
Mon, 22 Jan 2024 14:01:59 +0000 (23:01 +0900)
committerAndrew Morton <akpm@linux-foundation.org>
Thu, 22 Feb 2024 23:38:53 +0000 (15:38 -0800)
Move the checkpoint finalization routine to the cpfile side, and make the
page mapping local and temporary.  And use kmap_local instead of kmap to
access the checkpoint entry page when finalizing a checkpoint.

In this conversion, some of the information on the checkpoint entry being
rewritten is passed through the arguments of the newly added method
nilfs_cpfile_finalize_checkpoint().

Link: https://lkml.kernel.org/r/20240122140202.6950-13-konishi.ryusuke@gmail.com
Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
fs/nilfs2/cpfile.c
fs/nilfs2/cpfile.h
fs/nilfs2/segment.c

index f62da80e530a739db455ecf2fcc16351c0df9bd7..3af77252e08141b03584ddec364560b9e38798c3 100644 (file)
@@ -363,6 +363,80 @@ void nilfs_cpfile_put_checkpoint(struct inode *cpfile, __u64 cno,
        brelse(bh);
 }
 
+/**
+ * nilfs_cpfile_finalize_checkpoint - fill in a checkpoint entry in cpfile
+ * @cpfile: checkpoint file inode
+ * @cno:    checkpoint number
+ * @root:   nilfs root object
+ * @blkinc: number of blocks added by this checkpoint
+ * @ctime:  checkpoint creation time
+ * @minor:  minor checkpoint flag
+ *
+ * This function completes the checkpoint entry numbered by @cno in the
+ * cpfile with the data given by the arguments @root, @blkinc, @ctime, and
+ * @minor.
+ *
+ * Return: 0 on success, or the following negative error code on failure.
+ * * %-ENOMEM  - Insufficient memory available.
+ * * %-EIO     - I/O error (including metadata corruption).
+ */
+int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno,
+                                    struct nilfs_root *root, __u64 blkinc,
+                                    time64_t ctime, bool minor)
+{
+       struct buffer_head *cp_bh;
+       struct nilfs_checkpoint *cp;
+       void *kaddr;
+       int ret;
+
+       if (WARN_ON_ONCE(cno < 1))
+               return -EIO;
+
+       down_write(&NILFS_MDT(cpfile)->mi_sem);
+       ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
+       if (unlikely(ret < 0)) {
+               if (ret == -ENOENT)
+                       goto error;
+               goto out_sem;
+       }
+
+       kaddr = kmap_local_page(cp_bh->b_page);
+       cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
+       if (unlikely(nilfs_checkpoint_invalid(cp))) {
+               kunmap_local(kaddr);
+               brelse(cp_bh);
+               goto error;
+       }
+
+       cp->cp_snapshot_list.ssl_next = 0;
+       cp->cp_snapshot_list.ssl_prev = 0;
+       cp->cp_inodes_count = cpu_to_le64(atomic64_read(&root->inodes_count));
+       cp->cp_blocks_count = cpu_to_le64(atomic64_read(&root->blocks_count));
+       cp->cp_nblk_inc = cpu_to_le64(blkinc);
+       cp->cp_create = cpu_to_le64(ctime);
+       cp->cp_cno = cpu_to_le64(cno);
+
+       if (minor)
+               nilfs_checkpoint_set_minor(cp);
+       else
+               nilfs_checkpoint_clear_minor(cp);
+
+       nilfs_write_inode_common(root->ifile, &cp->cp_ifile_inode);
+       nilfs_bmap_write(NILFS_I(root->ifile)->i_bmap, &cp->cp_ifile_inode);
+
+       kunmap_local(kaddr);
+       brelse(cp_bh);
+out_sem:
+       up_write(&NILFS_MDT(cpfile)->mi_sem);
+       return ret;
+
+error:
+       nilfs_error(cpfile->i_sb,
+                   "checkpoint finalization failed due to metadata corruption.");
+       ret = -EIO;
+       goto out_sem;
+}
+
 /**
  * nilfs_cpfile_delete_checkpoints - delete checkpoints
  * @cpfile: inode of checkpoint file
index fcb1a94097b3f96e93b020c796979c9094be1808..aa1408a3af010ea0ec442e5e6f278c7b0556b887 100644 (file)
@@ -21,6 +21,9 @@ int nilfs_cpfile_get_checkpoint(struct inode *, __u64, int,
                                struct buffer_head **);
 int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno);
 void nilfs_cpfile_put_checkpoint(struct inode *, __u64, struct buffer_head *);
+int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno,
+                                    struct nilfs_root *root, __u64 blkinc,
+                                    time64_t ctime, bool minor);
 int nilfs_cpfile_delete_checkpoints(struct inode *, __u64, __u64);
 int nilfs_cpfile_delete_checkpoint(struct inode *, __u64);
 int nilfs_cpfile_change_cpmode(struct inode *, __u64, int);
index f38e56aa5aad02ffab0322e627e7c8c4b82fc9cf..aa5290cb7467cf2d756ec042b41b57e30c4336ae 100644 (file)
@@ -880,51 +880,6 @@ static void nilfs_segctor_clear_metadata_dirty(struct nilfs_sc_info *sci)
        nilfs_mdt_clear_dirty(nilfs->ns_dat);
 }
 
-static int nilfs_segctor_fill_in_checkpoint(struct nilfs_sc_info *sci)
-{
-       struct the_nilfs *nilfs = sci->sc_super->s_fs_info;
-       struct buffer_head *bh_cp;
-       struct nilfs_checkpoint *raw_cp;
-       struct inode *ifile;
-       int err;
-
-       err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, nilfs->ns_cno, 0,
-                                         &raw_cp, &bh_cp);
-       if (unlikely(err)) {
-               if (err == -EINVAL || err == -ENOENT) {
-                       nilfs_error(sci->sc_super,
-                                   "checkpoint finalization failed due to metadata corruption.");
-                       err = -EIO;
-               }
-               goto failed_ibh;
-       }
-       raw_cp->cp_snapshot_list.ssl_next = 0;
-       raw_cp->cp_snapshot_list.ssl_prev = 0;
-       raw_cp->cp_inodes_count =
-               cpu_to_le64(atomic64_read(&sci->sc_root->inodes_count));
-       raw_cp->cp_blocks_count =
-               cpu_to_le64(atomic64_read(&sci->sc_root->blocks_count));
-       raw_cp->cp_nblk_inc =
-               cpu_to_le64(sci->sc_nblk_inc + sci->sc_nblk_this_inc);
-       raw_cp->cp_create = cpu_to_le64(sci->sc_seg_ctime);
-       raw_cp->cp_cno = cpu_to_le64(nilfs->ns_cno);
-
-       if (test_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags))
-               nilfs_checkpoint_clear_minor(raw_cp);
-       else
-               nilfs_checkpoint_set_minor(raw_cp);
-
-       ifile = sci->sc_root->ifile;
-       nilfs_write_inode_common(ifile, &raw_cp->cp_ifile_inode);
-       nilfs_bmap_write(NILFS_I(ifile)->i_bmap, &raw_cp->cp_ifile_inode);
-
-       nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, nilfs->ns_cno, bh_cp);
-       return 0;
-
- failed_ibh:
-       return err;
-}
-
 static void nilfs_fill_in_file_bmap(struct inode *ifile,
                                    struct nilfs_inode_info *ii)
 
@@ -2105,7 +2060,11 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode)
 
                if (mode == SC_LSEG_SR &&
                    nilfs_sc_cstage_get(sci) >= NILFS_ST_CPFILE) {
-                       err = nilfs_segctor_fill_in_checkpoint(sci);
+                       err = nilfs_cpfile_finalize_checkpoint(
+                               nilfs->ns_cpfile, nilfs->ns_cno, sci->sc_root,
+                               sci->sc_nblk_inc + sci->sc_nblk_this_inc,
+                               sci->sc_seg_ctime,
+                               !test_bit(NILFS_SC_HAVE_DELTA, &sci->sc_flags));
                        if (unlikely(err))
                                goto failed_to_write;