mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
nilfs2: localize highmem mapping for checkpoint reading within cpfile
Move the code for reading from a checkpoint entry that is performed in nilfs_attach_checkpoint() 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. In order to load the ifile inode information included in the checkpoint entry within the inode lock section of nilfs_ifile_read(), the newly added checkpoint reading method nilfs_cpfile_read_checkpoint() is called indirectly via nilfs_ifile_read() instead of from nilfs_attach_checkpoint(). Link: https://lkml.kernel.org/r/20240122140202.6950-14-konishi.ryusuke@gmail.com Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
cce259b4c3
commit
1244a6d7a2
5 changed files with 87 additions and 34 deletions
|
@ -186,6 +186,74 @@ static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
|
||||||
nilfs_cpfile_get_blkoff(cpfile, cno));
|
nilfs_cpfile_get_blkoff(cpfile, cno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nilfs_cpfile_read_checkpoint - read a checkpoint entry in cpfile
|
||||||
|
* @cpfile: checkpoint file inode
|
||||||
|
* @cno: number of checkpoint entry to read
|
||||||
|
* @root: nilfs root object
|
||||||
|
* @ifile: ifile's inode to read and attach to @root
|
||||||
|
*
|
||||||
|
* This function imports checkpoint information from the checkpoint file and
|
||||||
|
* stores it to the inode file given by @ifile and the nilfs root object
|
||||||
|
* given by @root.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, or the following negative error code on failure.
|
||||||
|
* * %-EINVAL - Invalid checkpoint.
|
||||||
|
* * %-ENOMEM - Insufficient memory available.
|
||||||
|
* * %-EIO - I/O error (including metadata corruption).
|
||||||
|
*/
|
||||||
|
int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno,
|
||||||
|
struct nilfs_root *root, struct inode *ifile)
|
||||||
|
{
|
||||||
|
struct buffer_head *cp_bh;
|
||||||
|
struct nilfs_checkpoint *cp;
|
||||||
|
void *kaddr;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (cno < 1 || cno > nilfs_mdt_cno(cpfile))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
down_read(&NILFS_MDT(cpfile)->mi_sem);
|
||||||
|
ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
|
||||||
|
if (unlikely(ret < 0)) {
|
||||||
|
if (ret == -ENOENT)
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto out_sem;
|
||||||
|
}
|
||||||
|
|
||||||
|
kaddr = kmap_local_page(cp_bh->b_page);
|
||||||
|
cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);
|
||||||
|
if (nilfs_checkpoint_invalid(cp)) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto put_cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = nilfs_read_inode_common(ifile, &cp->cp_ifile_inode);
|
||||||
|
if (unlikely(ret)) {
|
||||||
|
/*
|
||||||
|
* Since this inode is on a checkpoint entry, treat errors
|
||||||
|
* as metadata corruption.
|
||||||
|
*/
|
||||||
|
nilfs_err(cpfile->i_sb,
|
||||||
|
"ifile inode (checkpoint number=%llu) corrupted",
|
||||||
|
(unsigned long long)cno);
|
||||||
|
ret = -EIO;
|
||||||
|
goto put_cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Configure the nilfs root object */
|
||||||
|
atomic64_set(&root->inodes_count, le64_to_cpu(cp->cp_inodes_count));
|
||||||
|
atomic64_set(&root->blocks_count, le64_to_cpu(cp->cp_blocks_count));
|
||||||
|
root->ifile = ifile;
|
||||||
|
|
||||||
|
put_cp:
|
||||||
|
kunmap_local(kaddr);
|
||||||
|
brelse(cp_bh);
|
||||||
|
out_sem:
|
||||||
|
up_read(&NILFS_MDT(cpfile)->mi_sem);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nilfs_cpfile_get_checkpoint - get a checkpoint
|
* nilfs_cpfile_get_checkpoint - get a checkpoint
|
||||||
* @cpfile: inode of checkpoint file
|
* @cpfile: inode of checkpoint file
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
int nilfs_cpfile_get_checkpoint(struct inode *, __u64, int,
|
int nilfs_cpfile_get_checkpoint(struct inode *, __u64, int,
|
||||||
struct nilfs_checkpoint **,
|
struct nilfs_checkpoint **,
|
||||||
struct buffer_head **);
|
struct buffer_head **);
|
||||||
|
int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno,
|
||||||
|
struct nilfs_root *root, struct inode *ifile);
|
||||||
int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno);
|
int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno);
|
||||||
void nilfs_cpfile_put_checkpoint(struct inode *, __u64, struct buffer_head *);
|
void nilfs_cpfile_put_checkpoint(struct inode *, __u64, struct buffer_head *);
|
||||||
int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno,
|
int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "mdt.h"
|
#include "mdt.h"
|
||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
|
#include "cpfile.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct nilfs_ifile_info - on-memory private data of ifile
|
* struct nilfs_ifile_info - on-memory private data of ifile
|
||||||
|
@ -173,14 +174,18 @@ int nilfs_ifile_count_free_inodes(struct inode *ifile,
|
||||||
* nilfs_ifile_read - read or get ifile inode
|
* nilfs_ifile_read - read or get ifile inode
|
||||||
* @sb: super block instance
|
* @sb: super block instance
|
||||||
* @root: root object
|
* @root: root object
|
||||||
|
* @cno: number of checkpoint entry to read
|
||||||
* @inode_size: size of an inode
|
* @inode_size: size of an inode
|
||||||
* @raw_inode: on-disk ifile inode
|
*
|
||||||
* @inodep: buffer to store the inode
|
* Return: 0 on success, or the following negative error code on failure.
|
||||||
|
* * %-EINVAL - Invalid checkpoint.
|
||||||
|
* * %-ENOMEM - Insufficient memory available.
|
||||||
|
* * %-EIO - I/O error (including metadata corruption).
|
||||||
*/
|
*/
|
||||||
int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
|
int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
|
||||||
size_t inode_size, struct nilfs_inode *raw_inode,
|
__u64 cno, size_t inode_size)
|
||||||
struct inode **inodep)
|
|
||||||
{
|
{
|
||||||
|
struct the_nilfs *nilfs;
|
||||||
struct inode *ifile;
|
struct inode *ifile;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
@ -201,13 +206,13 @@ int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
|
||||||
|
|
||||||
nilfs_palloc_setup_cache(ifile, &NILFS_IFILE_I(ifile)->palloc_cache);
|
nilfs_palloc_setup_cache(ifile, &NILFS_IFILE_I(ifile)->palloc_cache);
|
||||||
|
|
||||||
err = nilfs_read_inode_common(ifile, raw_inode);
|
nilfs = sb->s_fs_info;
|
||||||
|
err = nilfs_cpfile_read_checkpoint(nilfs->ns_cpfile, cno, root, ifile);
|
||||||
if (err)
|
if (err)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
unlock_new_inode(ifile);
|
unlock_new_inode(ifile);
|
||||||
out:
|
out:
|
||||||
*inodep = ifile;
|
|
||||||
return 0;
|
return 0;
|
||||||
failed:
|
failed:
|
||||||
iget_failed(ifile);
|
iget_failed(ifile);
|
||||||
|
|
|
@ -38,7 +38,6 @@ int nilfs_ifile_get_inode_block(struct inode *, ino_t, struct buffer_head **);
|
||||||
int nilfs_ifile_count_free_inodes(struct inode *, u64 *, u64 *);
|
int nilfs_ifile_count_free_inodes(struct inode *, u64 *, u64 *);
|
||||||
|
|
||||||
int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
|
int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root,
|
||||||
size_t inode_size, struct nilfs_inode *raw_inode,
|
__u64 cno, size_t inode_size);
|
||||||
struct inode **inodep);
|
|
||||||
|
|
||||||
#endif /* _NILFS_IFILE_H */
|
#endif /* _NILFS_IFILE_H */
|
||||||
|
|
|
@ -544,8 +544,6 @@ int nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt,
|
||||||
{
|
{
|
||||||
struct the_nilfs *nilfs = sb->s_fs_info;
|
struct the_nilfs *nilfs = sb->s_fs_info;
|
||||||
struct nilfs_root *root;
|
struct nilfs_root *root;
|
||||||
struct nilfs_checkpoint *raw_cp;
|
|
||||||
struct buffer_head *bh_cp;
|
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
|
|
||||||
root = nilfs_find_or_create_root(
|
root = nilfs_find_or_create_root(
|
||||||
|
@ -557,38 +555,19 @@ int nilfs_attach_checkpoint(struct super_block *sb, __u64 cno, int curr_mnt,
|
||||||
goto reuse; /* already attached checkpoint */
|
goto reuse; /* already attached checkpoint */
|
||||||
|
|
||||||
down_read(&nilfs->ns_segctor_sem);
|
down_read(&nilfs->ns_segctor_sem);
|
||||||
err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp,
|
err = nilfs_ifile_read(sb, root, cno, nilfs->ns_inode_size);
|
||||||
&bh_cp);
|
|
||||||
up_read(&nilfs->ns_segctor_sem);
|
up_read(&nilfs->ns_segctor_sem);
|
||||||
if (unlikely(err)) {
|
if (unlikely(err))
|
||||||
if (err == -ENOENT || err == -EINVAL) {
|
|
||||||
nilfs_err(sb,
|
|
||||||
"Invalid checkpoint (checkpoint number=%llu)",
|
|
||||||
(unsigned long long)cno);
|
|
||||||
err = -EINVAL;
|
|
||||||
}
|
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
|
||||||
|
|
||||||
err = nilfs_ifile_read(sb, root, nilfs->ns_inode_size,
|
|
||||||
&raw_cp->cp_ifile_inode, &root->ifile);
|
|
||||||
if (err)
|
|
||||||
goto failed_bh;
|
|
||||||
|
|
||||||
atomic64_set(&root->inodes_count,
|
|
||||||
le64_to_cpu(raw_cp->cp_inodes_count));
|
|
||||||
atomic64_set(&root->blocks_count,
|
|
||||||
le64_to_cpu(raw_cp->cp_blocks_count));
|
|
||||||
|
|
||||||
nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp);
|
|
||||||
|
|
||||||
reuse:
|
reuse:
|
||||||
*rootp = root;
|
*rootp = root;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
failed_bh:
|
|
||||||
nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp);
|
|
||||||
failed:
|
failed:
|
||||||
|
if (err == -EINVAL)
|
||||||
|
nilfs_err(sb, "Invalid checkpoint (checkpoint number=%llu)",
|
||||||
|
(unsigned long long)cno);
|
||||||
nilfs_put_root(root);
|
nilfs_put_root(root);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
Loading…
Add table
Reference in a new issue