summaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/cpfile.c
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@gmail.com>2024-01-22 23:01:58 +0900
committerAndrew Morton <akpm@linux-foundation.org>2024-02-22 15:38:53 -0800
commitd37db936c5436400ad5992e2e0d18af9d17d2941 (patch)
treeed4ad336066c183bc18fde9fcfa02b47a1ece34c /fs/nilfs2/cpfile.c
parent7282f2ae8105878a0cc9a2b042f2d6550bf76fc4 (diff)
downloadlinux-d37db936c5436400ad5992e2e0d18af9d17d2941.tar.gz
linux-d37db936c5436400ad5992e2e0d18af9d17d2941.tar.bz2
linux-d37db936c5436400ad5992e2e0d18af9d17d2941.zip
nilfs2: localize highmem mapping for checkpoint creation within cpfile
In order to convert kmap() used in cpfile to kmap_local, first move the checkpoint creation routine, which is one of the places where kmap is used, 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 (and header block page) when generating a checkpoint. Link: https://lkml.kernel.org/r/20240122140202.6950-12-konishi.ryusuke@gmail.com Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Diffstat (limited to 'fs/nilfs2/cpfile.c')
-rw-r--r--fs/nilfs2/cpfile.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c
index 39136637f715..f62da80e530a 100644
--- a/fs/nilfs2/cpfile.c
+++ b/fs/nilfs2/cpfile.c
@@ -273,6 +273,80 @@ int nilfs_cpfile_get_checkpoint(struct inode *cpfile,
}
/**
+ * nilfs_cpfile_create_checkpoint - create a checkpoint entry on cpfile
+ * @cpfile: checkpoint file inode
+ * @cno: number of checkpoint to set up
+ *
+ * This function creates a checkpoint with the number specified by @cno on
+ * cpfile. If the specified checkpoint entry already exists due to a past
+ * failure, it will be reused without returning an error.
+ * In either case, the buffer of the block containing the checkpoint entry
+ * and the cpfile inode are made dirty for inclusion in the write log.
+ *
+ * Return: 0 on success, or the following negative error code on failure.
+ * * %-ENOMEM - Insufficient memory available.
+ * * %-EIO - I/O error (including metadata corruption).
+ * * %-EROFS - Read only filesystem
+ */
+int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno)
+{
+ struct buffer_head *header_bh, *cp_bh;
+ struct nilfs_cpfile_header *header;
+ 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_header_block(cpfile, &header_bh);
+ if (unlikely(ret < 0)) {
+ if (ret == -ENOENT) {
+ nilfs_error(cpfile->i_sb,
+ "checkpoint creation failed due to metadata corruption.");
+ ret = -EIO;
+ }
+ goto out_sem;
+ }
+ ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 1, &cp_bh);
+ if (unlikely(ret < 0))
+ goto out_header;
+
+ kaddr = kmap_local_page(cp_bh->b_page);
+ cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
+ if (nilfs_checkpoint_invalid(cp)) {
+ /* a newly-created checkpoint */
+ nilfs_checkpoint_clear_invalid(cp);
+ if (!nilfs_cpfile_is_in_first(cpfile, cno))
+ nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
+ kaddr, 1);
+ kunmap_local(kaddr);
+
+ kaddr = kmap_local_page(header_bh->b_page);
+ header = nilfs_cpfile_block_get_header(cpfile, header_bh,
+ kaddr);
+ le64_add_cpu(&header->ch_ncheckpoints, 1);
+ kunmap_local(kaddr);
+ mark_buffer_dirty(header_bh);
+ } else {
+ kunmap_local(kaddr);
+ }
+
+ /* Force the buffer and the inode to become dirty */
+ mark_buffer_dirty(cp_bh);
+ brelse(cp_bh);
+ nilfs_mdt_mark_dirty(cpfile);
+
+out_header:
+ brelse(header_bh);
+
+out_sem:
+ up_write(&NILFS_MDT(cpfile)->mi_sem);
+ return ret;
+}
+
+/**
* nilfs_cpfile_put_checkpoint - put a checkpoint
* @cpfile: inode of checkpoint file
* @cno: checkpoint number