aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-09-12 22:16:34 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-10-22 20:24:38 -0400
commit032dbb3b503a30fce732ec4c05525d0abed1f1d6 (patch)
tree462696abcf0783d50efe97a3ca2641beecc91a3e /fs
parentf1e89c86fdd0f5e59f6768146c86437934202033 (diff)
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>
Diffstat (limited to 'fs')
-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)
863 */ 863 */
864int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) 864int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
865{ 865{
866 struct the_nilfs *nilfs;
867 int ret; 866 int ret;
868 867
869 nilfs = NILFS_MDT(cpfile)->mi_nilfs;
870
871 switch (mode) { 868 switch (mode) {
872 case NILFS_CHECKPOINT: 869 case NILFS_CHECKPOINT:
873 /* 870 if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno))
874 * Check for protecting existing snapshot mounts: 871 /*
875 * ns_mount_mutex is used to make this operation atomic and 872 * Current implementation does not have to protect
876 * exclusive with a new mount job. Though it doesn't cover 873 * plain read-only mounts since they are exclusive
877 * umount, it's enough for the purpose. 874 * with a read/write mount and are protected from the
878 */ 875 * cleaner.
879 if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { 876 */
880 /* Current implementation does not have to protect
881 plain read-only mounts since they are exclusive
882 with a read/write mount and are protected from the
883 cleaner. */
884 ret = -EBUSY; 877 ret = -EBUSY;
885 } else 878 else
886 ret = nilfs_cpfile_clear_snapshot(cpfile, cno); 879 ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
887 return ret; 880 return ret;
888 case NILFS_SNAPSHOT: 881 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)
506 return 0; 506 return 0;
507} 507}
508 508
509struct inode *nilfs_ilookup(struct super_block *sb, struct nilfs_root *root,
510 unsigned long ino)
511{
512 struct nilfs_iget_args args = {
513 .ino = ino, .root = root, .cno = 0, .for_gc = 0
514 };
515
516 return ilookup5(sb, ino, nilfs_iget_test, &args);
517}
518
509struct inode *nilfs_iget_locked(struct super_block *sb, struct nilfs_root *root, 519struct inode *nilfs_iget_locked(struct super_block *sb, struct nilfs_root *root,
510 unsigned long ino) 520 unsigned long ino)
511{ 521{
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);
244extern void nilfs_set_inode_flags(struct inode *); 244extern void nilfs_set_inode_flags(struct inode *);
245extern int nilfs_read_inode_common(struct inode *, struct nilfs_inode *); 245extern int nilfs_read_inode_common(struct inode *, struct nilfs_inode *);
246extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int); 246extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int);
247struct inode *nilfs_ilookup(struct super_block *sb, struct nilfs_root *root,
248 unsigned long ino);
247struct inode *nilfs_iget_locked(struct super_block *sb, struct nilfs_root *root, 249struct inode *nilfs_iget_locked(struct super_block *sb, struct nilfs_root *root,
248 unsigned long ino); 250 unsigned long ino);
249struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root, 251struct 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);
285extern int nilfs_cleanup_super(struct nilfs_sb_info *); 287extern int nilfs_cleanup_super(struct nilfs_sb_info *);
286int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, 288int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt,
287 struct nilfs_root **root); 289 struct nilfs_root **root);
290int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno);
288 291
289/* gcinode.c */ 292/* gcinode.c */
290int nilfs_gccache_submit_read_data(struct inode *, sector_t, sector_t, __u64, 293int 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)
833 return nilfs_tree_was_touched(root_dentry); 833 return nilfs_tree_was_touched(root_dentry);
834} 834}
835 835
836int nilfs_checkpoint_is_mounted(struct super_block *sb, __u64 cno)
837{
838 struct the_nilfs *nilfs = NILFS_SB(sb)->s_nilfs;
839 struct nilfs_root *root;
840 struct inode *inode;
841 struct dentry *dentry;
842 int ret;
843
844 if (cno < 0 || cno > nilfs->ns_cno)
845 return false;
846
847 if (cno >= nilfs_last_cno(nilfs))
848 return true; /* protect recent checkpoints */
849
850 ret = false;
851 root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno);
852 if (root) {
853 inode = nilfs_ilookup(sb, root, NILFS_ROOT_INO);
854 if (inode) {
855 dentry = d_find_alias(inode);
856 if (dentry) {
857 if (nilfs_tree_was_touched(dentry))
858 ret = nilfs_try_to_shrink_tree(dentry);
859 dput(dentry);
860 }
861 iput(inode);
862 }
863 nilfs_put_root(root);
864 }
865 return ret;
866}
867
836/** 868/**
837 * nilfs_fill_super() - initialize a super block instance 869 * nilfs_fill_super() - initialize a super block instance
838 * @sb: super_block 870 * @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)
769 kfree(root); 769 kfree(root);
770 } 770 }
771} 771}
772
773int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno,
774 int snapshot_mount)
775{
776 struct nilfs_root *root;
777 int ret;
778
779 if (cno < 0 || cno > nilfs->ns_cno)
780 return false;
781
782 if (cno >= nilfs_last_cno(nilfs))
783 return true; /* protect recent checkpoints */
784
785 ret = false;
786 root = nilfs_lookup_root(nilfs, cno);
787 if (root) {
788 ret = true;
789 nilfs_put_root(root);
790 }
791 return ret;
792}
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,
242 __u64 cno); 242 __u64 cno);
243void nilfs_put_root(struct nilfs_root *root); 243void nilfs_put_root(struct nilfs_root *root);
244struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64); 244struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64);
245int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int);
246int nilfs_near_disk_full(struct the_nilfs *); 245int nilfs_near_disk_full(struct the_nilfs *);
247void nilfs_fall_back_super_block(struct the_nilfs *); 246void nilfs_fall_back_super_block(struct the_nilfs *);
248void nilfs_swap_super_block(struct the_nilfs *); 247void nilfs_swap_super_block(struct the_nilfs *);