summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-09-13 11:16:34 +0900
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-10-23 09:24:38 +0900
commit032dbb3b503a30fce732ec4c05525d0abed1f1d6 (patch)
tree462696abcf0783d50efe97a3ca2641beecc91a3e
parentf1e89c86fdd0f5e59f6768146c86437934202033 (diff)
downloadlinux-stable-032dbb3b503a30fce732ec4c05525d0abed1f1d6.tar.gz
nilfs2: see state of root dentry for mount check of snapshots
After applied the patch that unified sb instances, root dentry of snapshots can be left in dcache even after their trees are unmounted. The orphan root dentry/inode keeps a root object, and this causes false positive of nilfs_checkpoint_is_mounted function. This resolves the issue by having nilfs_checkpoint_is_mounted test whether the root dentry is busy or not. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
-rw-r--r--fs/nilfs2/cpfile.c23
-rw-r--r--fs/nilfs2/inode.c10
-rw-r--r--fs/nilfs2/nilfs.h3
-rw-r--r--fs/nilfs2/super.c32
-rw-r--r--fs/nilfs2/the_nilfs.c21
-rw-r--r--fs/nilfs2/the_nilfs.h1
6 files changed, 53 insertions, 37 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c
index 03de1da8795b..5ff15a8a1024 100644
--- a/fs/nilfs2/cpfile.c
+++ b/fs/nilfs2/cpfile.c
@@ -863,26 +863,19 @@ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)
*/
int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
{
- struct the_nilfs *nilfs;
int ret;
- nilfs = NILFS_MDT(cpfile)->mi_nilfs;
-
switch (mode) {
case NILFS_CHECKPOINT:
- /*
- * Check for protecting existing snapshot mounts:
- * ns_mount_mutex is used to make this operation atomic and
- * exclusive with a new mount job. Though it doesn't cover
- * umount, it's enough for the purpose.
- */
- if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) {
- /* Current implementation does not have to protect
- plain read-only mounts since they are exclusive
- with a read/write mount and are protected from the
- cleaner. */
+ if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno))
+ /*
+ * Current implementation does not have to protect
+ * plain read-only mounts since they are exclusive
+ * with a read/write mount and are protected from the
+ * cleaner.
+ */
ret = -EBUSY;
- } else
+ else
ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
return ret;
case NILFS_SNAPSHOT:
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 5b3d43fb4e12..71d4bc8464e0 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -506,6 +506,16 @@ static int nilfs_iget_set(struct inode *inode, void *opaque)
return 0;
}
+struct inode *nilfs_ilookup(struct super_block *sb, struct nilfs_root *root,
+ unsigned long ino)
+{
+ struct nilfs_iget_args args = {
+ .ino = ino, .root = root, .cno = 0, .for_gc = 0
+ };
+
+ return ilookup5(sb, ino, nilfs_iget_test, &args);
+}
+
struct inode *nilfs_iget_locked(struct super_block *sb, struct nilfs_root *root,
unsigned long ino)
{
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
index 2ca2ca5ca848..f6e276eaaf6f 100644
--- a/fs/nilfs2/nilfs.h
+++ b/fs/nilfs2/nilfs.h
@@ -244,6 +244,8 @@ extern int nilfs_get_block(struct inode *, sector_t, struct buffer_head *, int);
extern void nilfs_set_inode_flags(struct inode *);
extern int nilfs_read_inode_common(struct inode *, struct nilfs_inode *);
extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int);
+struct inode *nilfs_ilookup(struct super_block *sb, struct nilfs_root *root,
+ unsigned long ino);
struct inode *nilfs_iget_locked(struct super_block *sb, struct nilfs_root *root,
unsigned long ino);
struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root,
@@ -285,6 +287,7 @@ extern int nilfs_commit_super(struct nilfs_sb_info *, int);
extern int nilfs_cleanup_super(struct nilfs_sb_info *);
int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt,
struct nilfs_root **root);
+int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno);
/* gcinode.c */
int nilfs_gccache_submit_read_data(struct inode *, sector_t, sector_t, __u64,
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 39e7d7f8eda0..ab96d26bf7e9 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -833,6 +833,38 @@ static int nilfs_try_to_shrink_tree(struct dentry *root_dentry)
return nilfs_tree_was_touched(root_dentry);
}
+int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno)
+{
+ struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
+ struct nilfs_root *root;
+ struct inode *inode;
+ struct dentry *dentry;
+ int ret;
+
+ if (cno < 0 || cno > nilfs->ns_cno)
+ return false;
+
+ if (cno >= nilfs_last_cno(nilfs))
+ return true; /* protect recent checkpoints */
+
+ ret = false;
+ root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno);
+ if (root) {
+ inode = nilfs_ilookup(sb, root, NILFS_ROOT_INO);
+ if (inode) {
+ dentry = d_find_alias(inode);
+ if (dentry) {
+ if (nilfs_tree_was_touched(dentry))
+ ret = nilfs_try_to_shrink_tree(dentry);
+ dput(dentry);
+ }
+ iput(inode);
+ }
+ nilfs_put_root(root);
+ }
+ return ret;
+}
+
/**
* nilfs_fill_super() - initialize a super block instance
* @sb: super_block
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 4d6763e28eb5..4cc705a1d135 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -769,24 +769,3 @@ void nilfs_put_root(struct nilfs_root *root)
kfree(root);
}
}
-
-int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno,
- int snapshot_mount)
-{
- struct nilfs_root *root;
- int ret;
-
- if (cno < 0 || cno > nilfs->ns_cno)
- return false;
-
- if (cno >= nilfs_last_cno(nilfs))
- return true; /* protect recent checkpoints */
-
- ret = false;
- root = nilfs_lookup_root(nilfs, cno);
- if (root) {
- ret = true;
- nilfs_put_root(root);
- }
- return ret;
-}
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
index a5178dc43dfd..cae56f338b64 100644
--- a/fs/nilfs2/the_nilfs.h
+++ b/fs/nilfs2/the_nilfs.h
@@ -242,7 +242,6 @@ struct nilfs_root *nilfs_find_or_create_root(struct the_nilfs *nilfs,
__u64 cno);
void nilfs_put_root(struct nilfs_root *root);
struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
-int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
int nilfs_near_disk_full(struct the_nilfs *);
void nilfs_fall_back_super_block(struct the_nilfs *);
void nilfs_swap_super_block(struct the_nilfs *);