From b91c9a97c9333c87fe2a0c94b3b22b24df1c5fc2 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 20 Aug 2010 23:46:06 +0900 Subject: nilfs2: allow nilfs_destroy_inode to destroy metadata file inodes The current nilfs_destroy_inode() doesn't handle metadata file inodes including gc inodes (dummy inodes used for garbage collection). This allows nilfs_destroy_inode() to destroy inodes of metadata files. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 9f4913f78408..51576b4dbf7a 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -167,6 +167,12 @@ struct inode *nilfs_alloc_inode(struct super_block *sb) void nilfs_destroy_inode(struct inode *inode) { + struct nilfs_mdt_info *mdi = NILFS_MDT(inode); + + if (mdi) { + kfree(mdi->mi_bgl); /* kfree(NULL) is safe */ + kfree(mdi); + } kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); } -- cgit v1.2.3 From 0e14a3595bddedfb27b51a6b0a29b5173aa2511a Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 20 Aug 2010 21:20:29 +0900 Subject: nilfs2: use iget5_locked to get inode This uses iget5_locked instead of iget_locked so that gc cache can look up inodes with an inode number and an optional checkpoint number. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 51576b4dbf7a..f3a00a3b2a03 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -155,6 +155,7 @@ struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) return NULL; ii->i_bh = NULL; ii->i_state = 0; + ii->i_cno = 0; ii->vfs_inode.i_version = 1; nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi); return &ii->vfs_inode; -- cgit v1.2.3 From 4d8d9293dce503eb0e083e17a02a328d397e7f00 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Wed, 25 Aug 2010 17:45:44 +0900 Subject: nilfs2: set pointer to root object in inodes This puts a pointer to nilfs_root object in the private part of on-memory inode, and makes nilfs_iget function pick up the inode with the same root object. Non-root inodes inherit its nilfs_root object from parent inode. That of the root inode is allocated through nilfs_attach_checkpoint() function. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index f3a00a3b2a03..a1c0e38a7706 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -391,18 +391,24 @@ static int nilfs_sync_fs(struct super_block *sb, int wait) return err; } -int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) +int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, + struct nilfs_root **rootp) { struct the_nilfs *nilfs = sbi->s_nilfs; + struct nilfs_root *root; struct nilfs_checkpoint *raw_cp; struct buffer_head *bh_cp; - int err; + int err = -ENOMEM; + + root = nilfs_find_or_create_root( + nilfs, curr_mnt ? NILFS_CPTREE_CURRENT_CNO : cno); + if (!root) + return err; down_write(&nilfs->ns_super_sem); list_add(&sbi->s_list, &nilfs->ns_supers); up_write(&nilfs->ns_super_sem); - err = -ENOMEM; sbi->s_ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size); if (!sbi->s_ifile) goto delist; @@ -428,6 +434,8 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) atomic_set(&sbi->s_blocks_count, le64_to_cpu(raw_cp->cp_blocks_count)); nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); + + *rootp = root; return 0; failed_bh: @@ -440,6 +448,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) down_write(&nilfs->ns_super_sem); list_del_init(&sbi->s_list); up_write(&nilfs->ns_super_sem); + nilfs_put_root(root); return err; } @@ -551,12 +560,20 @@ static struct inode * nilfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) { struct inode *inode; + struct nilfs_root *root; if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO && ino != NILFS_SKETCH_INO) return ERR_PTR(-ESTALE); - inode = nilfs_iget(sb, ino); + root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, + NILFS_CPTREE_CURRENT_CNO); + if (!root) + return ERR_PTR(-ESTALE); + + /* new file handle type is required to export snapshots */ + inode = nilfs_iget(sb, root, ino); + nilfs_put_root(root); if (IS_ERR(inode)) return ERR_CAST(inode); if (generation && inode->i_generation != generation) { @@ -815,9 +832,10 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, struct the_nilfs *nilfs) { struct nilfs_sb_info *sbi; + struct nilfs_root *fsroot; struct inode *root; __u64 cno; - int err; + int err, curr_mnt; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -859,6 +877,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, goto failed_sbi; cno = nilfs_last_cno(nilfs); + curr_mnt = true; if (sb->s_flags & MS_RDONLY) { if (nilfs_test_opt(sbi, SNAPSHOT)) { @@ -881,10 +900,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, goto failed_sbi; } cno = sbi->s_snapshot_cno; + curr_mnt = false; } } - err = nilfs_attach_checkpoint(sbi, cno); + err = nilfs_attach_checkpoint(sbi, cno, curr_mnt, &fsroot); if (err) { printk(KERN_ERR "NILFS: error loading a checkpoint" " (checkpoint number=%llu).\n", (unsigned long long)cno); @@ -897,7 +917,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, goto failed_checkpoint; } - root = nilfs_iget(sb, NILFS_ROOT_INO); + root = nilfs_iget(sb, fsroot, NILFS_ROOT_INO); if (IS_ERR(root)) { printk(KERN_ERR "NILFS: get root inode failed\n"); err = PTR_ERR(root); @@ -917,6 +937,8 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, goto failed_segctor; } + nilfs_put_root(fsroot); + if (!(sb->s_flags & MS_RDONLY)) { down_write(&nilfs->ns_sem); nilfs_setup_super(sbi); @@ -935,6 +957,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, failed_checkpoint: nilfs_detach_checkpoint(sbi); + nilfs_put_root(fsroot); failed_sbi: put_nilfs(nilfs); -- cgit v1.2.3 From 8e656fd518784b49453f60c5f78b78703bc85cb2 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 27 Aug 2010 00:23:02 +0900 Subject: nilfs2: make snapshots in checkpoint tree exportable The previous export operations cannot handle multiple versions of a filesystem if they belong to the same sb instance. This adds a new type of file handle and extends export operations so that they can get the inode specified by a checkpoint number as well as an inode number and a generation number. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 52 +--------------------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index a1c0e38a7706..adbf5826b837 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -48,10 +48,10 @@ #include #include #include -#include #include #include #include "nilfs.h" +#include "export.h" #include "mdt.h" #include "alloc.h" #include "btree.h" @@ -556,56 +556,6 @@ static const struct super_operations nilfs_sops = { .show_options = nilfs_show_options }; -static struct inode * -nilfs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) -{ - struct inode *inode; - struct nilfs_root *root; - - if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO && - ino != NILFS_SKETCH_INO) - return ERR_PTR(-ESTALE); - - root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, - NILFS_CPTREE_CURRENT_CNO); - if (!root) - return ERR_PTR(-ESTALE); - - /* new file handle type is required to export snapshots */ - inode = nilfs_iget(sb, root, ino); - nilfs_put_root(root); - if (IS_ERR(inode)) - return ERR_CAST(inode); - if (generation && inode->i_generation != generation) { - iput(inode); - return ERR_PTR(-ESTALE); - } - - return inode; -} - -static struct dentry * -nilfs_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, - int fh_type) -{ - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, - nilfs_nfs_get_inode); -} - -static struct dentry * -nilfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, - int fh_type) -{ - return generic_fh_to_parent(sb, fid, fh_len, fh_type, - nilfs_nfs_get_inode); -} - -static const struct export_operations nilfs_export_ops = { - .fh_to_dentry = nilfs_fh_to_dentry, - .fh_to_parent = nilfs_fh_to_parent, - .get_parent = nilfs_get_parent, -}; - enum { Opt_err_cont, Opt_err_panic, Opt_err_ro, Opt_barrier, Opt_nobarrier, Opt_snapshot, Opt_order, Opt_norecovery, -- cgit v1.2.3 From e912a5b66837ee89fb025e67b5efeaa11930c2ce Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 14 Aug 2010 13:07:15 +0900 Subject: nilfs2: use root object to get ifile This rewrites functions using ifile so that they get ifile from nilfs_root object, and will remove sbi->s_ifile. Some functions that don't know the root object are extended to receive it from caller. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 42 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 29 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index adbf5826b837..87c57810ae88 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -358,9 +358,9 @@ static void nilfs_put_super(struct super_block *sb) down_write(&nilfs->ns_super_sem); if (nilfs->ns_current == sbi) nilfs->ns_current = NULL; + list_del_init(&sbi->s_list); up_write(&nilfs->ns_super_sem); - nilfs_detach_checkpoint(sbi); put_nilfs(sbi->s_nilfs); sbi->s_super = NULL; sb->s_fs_info = NULL; @@ -405,13 +405,12 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, if (!root) return err; - down_write(&nilfs->ns_super_sem); - list_add(&sbi->s_list, &nilfs->ns_supers); - up_write(&nilfs->ns_super_sem); + if (root->ifile) + goto reuse; /* already attached checkpoint */ - sbi->s_ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size); - if (!sbi->s_ifile) - goto delist; + root->ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size); + if (!root->ifile) + goto failed; down_read(&nilfs->ns_segctor_sem); err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, @@ -427,7 +426,7 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, } goto failed; } - err = nilfs_read_inode_common(sbi->s_ifile, &raw_cp->cp_ifile_inode); + err = nilfs_read_inode_common(root->ifile, &raw_cp->cp_ifile_inode); if (unlikely(err)) goto failed_bh; atomic_set(&sbi->s_inodes_count, le64_to_cpu(raw_cp->cp_inodes_count)); @@ -435,35 +434,18 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); + reuse: *rootp = root; return 0; failed_bh: nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); failed: - nilfs_mdt_destroy(sbi->s_ifile); - sbi->s_ifile = NULL; - - delist: - down_write(&nilfs->ns_super_sem); - list_del_init(&sbi->s_list); - up_write(&nilfs->ns_super_sem); nilfs_put_root(root); return err; } -void nilfs_detach_checkpoint(struct nilfs_sb_info *sbi) -{ - struct the_nilfs *nilfs = sbi->s_nilfs; - - nilfs_mdt_destroy(sbi->s_ifile); - sbi->s_ifile = NULL; - down_write(&nilfs->ns_super_sem); - list_del_init(&sbi->s_list); - up_write(&nilfs->ns_super_sem); -} - static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; @@ -862,7 +844,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, } if (!(sb->s_flags & MS_RDONLY)) { - err = nilfs_attach_segment_constructor(sbi); + err = nilfs_attach_segment_constructor(sbi, fsroot); if (err) goto failed_checkpoint; } @@ -896,6 +878,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, } down_write(&nilfs->ns_super_sem); + list_add(&sbi->s_list, &nilfs->ns_supers); if (!nilfs_test_opt(sbi, SNAPSHOT)) nilfs->ns_current = sbi; up_write(&nilfs->ns_super_sem); @@ -906,7 +889,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, nilfs_detach_segment_constructor(sbi); failed_checkpoint: - nilfs_detach_checkpoint(sbi); nilfs_put_root(fsroot); failed_sbi: @@ -966,6 +948,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) up_write(&nilfs->ns_sem); } else { __u64 features; + struct nilfs_root *root; /* * Mounting a RDONLY partition read-write, so reread and @@ -987,7 +970,8 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) sb->s_flags &= ~MS_RDONLY; - err = nilfs_attach_segment_constructor(sbi); + root = NILFS_I(sb->s_root->d_inode)->i_root; + err = nilfs_attach_segment_constructor(sbi, root); if (err) goto restore_opts; -- cgit v1.2.3 From b7c0634204993d7c6678c852e4bd118426599111 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 14 Aug 2010 14:48:32 +0900 Subject: nilfs2: move inode count and block count into root object This moves sbi->s_inodes_count and sbi->s_blocks_count into nilfs_root object. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 87c57810ae88..acfa74e45f0b 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -429,8 +429,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, err = nilfs_read_inode_common(root->ifile, &raw_cp->cp_ifile_inode); if (unlikely(err)) goto failed_bh; - atomic_set(&sbi->s_inodes_count, le64_to_cpu(raw_cp->cp_inodes_count)); - atomic_set(&sbi->s_blocks_count, le64_to_cpu(raw_cp->cp_blocks_count)); + + atomic_set(&root->inodes_count, le64_to_cpu(raw_cp->cp_inodes_count)); + atomic_set(&root->blocks_count, le64_to_cpu(raw_cp->cp_blocks_count)); nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, cno, bh_cp); @@ -449,8 +450,8 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; - struct nilfs_sb_info *sbi = NILFS_SB(sb); - struct the_nilfs *nilfs = sbi->s_nilfs; + struct nilfs_root *root = NILFS_I(dentry->d_inode)->i_root; + struct the_nilfs *nilfs = root->nilfs; u64 id = huge_encode_dev(sb->s_bdev->bd_dev); unsigned long long blocks; unsigned long overhead; @@ -486,7 +487,7 @@ static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_bfree = nfreeblocks; buf->f_bavail = (buf->f_bfree >= nrsvblocks) ? (buf->f_bfree - nrsvblocks) : 0; - buf->f_files = atomic_read(&sbi->s_inodes_count); + buf->f_files = atomic_read(&root->inodes_count); buf->f_ffree = 0; /* nilfs_count_free_inodes(sb); */ buf->f_namelen = NILFS_NAME_LEN; buf->f_fsid.val[0] = (u32)id; -- cgit v1.2.3 From 367ea33486a68f935a01311a3be9b7e97d2e5ead Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Thu, 26 Aug 2010 01:52:51 +0900 Subject: nilfs2: split out nilfs_get_root_dentry This splits the code to allocate root dentry into a separate routine for convenience in successive changes. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 54 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 19 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index acfa74e45f0b..1e12930f8b94 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -750,6 +750,39 @@ int nilfs_check_feature_compatibility(struct super_block *sb, return 0; } +static int nilfs_get_root_dentry(struct super_block *sb, + struct nilfs_root *root, + struct dentry **root_dentry) +{ + struct inode *inode; + struct dentry *dentry; + int ret = 0; + + inode = nilfs_iget(sb, root, NILFS_ROOT_INO); + if (IS_ERR(inode)) { + printk(KERN_ERR "NILFS: get root inode failed\n"); + ret = PTR_ERR(inode); + goto out; + } + if (!S_ISDIR(inode->i_mode) || !inode->i_blocks || !inode->i_size) { + iput(inode); + printk(KERN_ERR "NILFS: corrupt root inode.\n"); + ret = -EINVAL; + goto out; + } + + dentry = d_alloc_root(inode); + if (!dentry) { + iput(inode); + printk(KERN_ERR "NILFS: get root dentry failed\n"); + ret = -ENOMEM; + goto out; + } + *root_dentry = dentry; + out: + return ret; +} + /** * nilfs_fill_super() - initialize a super block instance * @sb: super_block @@ -766,7 +799,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, { struct nilfs_sb_info *sbi; struct nilfs_root *fsroot; - struct inode *root; __u64 cno; int err, curr_mnt; @@ -850,25 +882,9 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, goto failed_checkpoint; } - root = nilfs_iget(sb, fsroot, NILFS_ROOT_INO); - if (IS_ERR(root)) { - printk(KERN_ERR "NILFS: get root inode failed\n"); - err = PTR_ERR(root); - goto failed_segctor; - } - if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { - iput(root); - printk(KERN_ERR "NILFS: corrupt root inode.\n"); - err = -EINVAL; - goto failed_segctor; - } - sb->s_root = d_alloc_root(root); - if (!sb->s_root) { - iput(root); - printk(KERN_ERR "NILFS: get root dentry failed\n"); - err = -ENOMEM; + err = nilfs_get_root_dentry(sb, fsroot, &sb->s_root); + if (err) goto failed_segctor; - } nilfs_put_root(fsroot); -- cgit v1.2.3 From ab4d8f7ebf33beff97e766d18db47f1ea9635769 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Thu, 26 Aug 2010 02:15:41 +0900 Subject: nilfs2: split out nilfs_attach_snapshot This splits the code to attach snapshots into a separate routine for convenience sake. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 73 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 45 insertions(+), 28 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1e12930f8b94..ebeb746c4845 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -783,6 +783,40 @@ static int nilfs_get_root_dentry(struct super_block *sb, return ret; } +static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, + struct dentry **root_dentry) +{ + struct the_nilfs *nilfs = NILFS_SB(s)->s_nilfs; + struct nilfs_root *root; + int ret; + + down_read(&nilfs->ns_segctor_sem); + ret = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, cno); + up_read(&nilfs->ns_segctor_sem); + if (ret < 0) { + ret = (ret == -ENOENT) ? -EINVAL : ret; + goto out; + } else if (!ret) { + printk(KERN_ERR "NILFS: The specified checkpoint is " + "not a snapshot (checkpoint number=%llu).\n", + (unsigned long long)cno); + ret = -EINVAL; + goto out; + } + + ret = nilfs_attach_checkpoint(NILFS_SB(s), cno, false, &root); + if (ret) { + printk(KERN_ERR "NILFS: error loading snapshot " + "(checkpoint number=%llu).\n", + (unsigned long long)cno); + goto out; + } + ret = nilfs_get_root_dentry(s, root, root_dentry); + nilfs_put_root(root); + out: + return ret; +} + /** * nilfs_fill_super() - initialize a super block instance * @sb: super_block @@ -800,7 +834,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, struct nilfs_sb_info *sbi; struct nilfs_root *fsroot; __u64 cno; - int err, curr_mnt; + int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -841,35 +875,17 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, if (err) goto failed_sbi; - cno = nilfs_last_cno(nilfs); - curr_mnt = true; - - if (sb->s_flags & MS_RDONLY) { - if (nilfs_test_opt(sbi, SNAPSHOT)) { - down_read(&nilfs->ns_segctor_sem); - err = nilfs_cpfile_is_snapshot(nilfs->ns_cpfile, - sbi->s_snapshot_cno); - up_read(&nilfs->ns_segctor_sem); - if (err < 0) { - if (err == -ENOENT) - err = -EINVAL; - goto failed_sbi; - } - if (!err) { - printk(KERN_ERR - "NILFS: The specified checkpoint is " - "not a snapshot " - "(checkpoint number=%llu).\n", - (unsigned long long)sbi->s_snapshot_cno); - err = -EINVAL; - goto failed_sbi; - } - cno = sbi->s_snapshot_cno; - curr_mnt = false; - } + if (nilfs_test_opt(sbi, SNAPSHOT)) { + err = nilfs_attach_snapshot(sb, sbi->s_snapshot_cno, + &sb->s_root); + if (err) + goto failed_sbi; + + goto add_to_supers; } - err = nilfs_attach_checkpoint(sbi, cno, curr_mnt, &fsroot); + cno = nilfs_last_cno(nilfs); + err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); if (err) { printk(KERN_ERR "NILFS: error loading a checkpoint" " (checkpoint number=%llu).\n", (unsigned long long)cno); @@ -894,6 +910,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, up_write(&nilfs->ns_sem); } + add_to_supers: down_write(&nilfs->ns_super_sem); list_add(&sbi->s_list, &nilfs->ns_supers); if (!nilfs_test_opt(sbi, SNAPSHOT)) -- cgit v1.2.3 From f11459ad7dab9e9eb5a05b8bd3bec338ea8f485d Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 16 Aug 2010 01:54:52 +0900 Subject: nilfs2: do not allocate multiple super block instances for a device This stops allocating multiple super block instances for a device. All snapshots and a current mode mount (i.e. latest tree) will be controlled with nilfs_root objects that are kept within an sb instance. nilfs_get_sb() is rewritten so that it always has a root object for the latest tree and snapshots make additional root objects. The root dentry of the latest tree is binded to sb->s_root even if it isn't attached on a directory. Root dentries of snapshots or the latest tree are binded to mnt->mnt_root on which they are mounted. With this patch, nilfs_find_sbinfo() function, nilfs->ns_supers list, and nilfs->ns_current back pointer, are deleted. In addition, init_nilfs() and load_nilfs() are simplified since they will be called once for a device, not repeatedly called for mount points. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 216 +++++++++++++++++++++++++----------------------------- 1 file changed, 100 insertions(+), 116 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index ebeb746c4845..2e58e7c629b5 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -355,16 +355,11 @@ static void nilfs_put_super(struct super_block *sb) nilfs_cleanup_super(sbi); up_write(&nilfs->ns_sem); } - down_write(&nilfs->ns_super_sem); - if (nilfs->ns_current == sbi) - nilfs->ns_current = NULL; - list_del_init(&sbi->s_list); - up_write(&nilfs->ns_super_sem); put_nilfs(sbi->s_nilfs); sbi->s_super = NULL; sb->s_fs_info = NULL; - nilfs_put_sbinfo(sbi); + kfree(sbi); } static int nilfs_sync_fs(struct super_block *sb, int wait) @@ -500,12 +495,12 @@ static int nilfs_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct super_block *sb = vfs->mnt_sb; struct nilfs_sb_info *sbi = NILFS_SB(sb); + struct nilfs_root *root = NILFS_I(vfs->mnt_root->d_inode)->i_root; if (!nilfs_test_opt(sbi, BARRIER)) seq_puts(seq, ",nobarrier"); - if (nilfs_test_opt(sbi, SNAPSHOT)) - seq_printf(seq, ",cp=%llu", - (unsigned long long int)sbi->s_snapshot_cno); + if (root->cno != NILFS_CPTREE_CURRENT_CNO) + seq_printf(seq, ",cp=%llu", (unsigned long long)root->cno); if (nilfs_test_opt(sbi, ERRORS_PANIC)) seq_puts(seq, ",errors=panic"); if (nilfs_test_opt(sbi, ERRORS_CONT)) @@ -605,27 +600,11 @@ static int parse_options(char *options, struct super_block *sb, int is_remount) if (match_int(&args[0], &option) || option <= 0) return 0; if (is_remount) { - if (!nilfs_test_opt(sbi, SNAPSHOT)) { - printk(KERN_ERR - "NILFS: cannot change regular " - "mount to snapshot.\n"); - return 0; - } else if (option != sbi->s_snapshot_cno) { - printk(KERN_ERR - "NILFS: cannot remount to a " - "different snapshot.\n"); - return 0; - } - break; - } - if (!(sb->s_flags & MS_RDONLY)) { - printk(KERN_ERR "NILFS: cannot mount snapshot " - "read/write. A read-only option is " - "required.\n"); + printk(KERN_ERR + "NILFS: \"%s\" option is invalid " + "for remount.\n", p); return 0; } - sbi->s_snapshot_cno = option; - nilfs_set_opt(sbi, SNAPSHOT); break; case Opt_norecovery: nilfs_set_opt(sbi, NORECOVERY); @@ -771,16 +750,32 @@ static int nilfs_get_root_dentry(struct super_block *sb, goto out; } - dentry = d_alloc_root(inode); - if (!dentry) { - iput(inode); - printk(KERN_ERR "NILFS: get root dentry failed\n"); - ret = -ENOMEM; - goto out; + if (root->cno == NILFS_CPTREE_CURRENT_CNO) { + dentry = d_find_alias(inode); + if (!dentry) { + dentry = d_alloc_root(inode); + if (!dentry) { + iput(inode); + ret = -ENOMEM; + goto failed_dentry; + } + } else { + iput(inode); + } + } else { + dentry = d_obtain_alias(inode); + if (IS_ERR(dentry)) { + ret = PTR_ERR(dentry); + goto failed_dentry; + } } *root_dentry = dentry; out: return ret; + + failed_dentry: + printk(KERN_ERR "NILFS: get root dentry failed\n"); + goto out; } static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, @@ -817,6 +812,25 @@ static int nilfs_attach_snapshot(struct super_block *s, __u64 cno, return ret; } +static int nilfs_tree_was_touched(struct dentry *root_dentry) +{ + return atomic_read(&root_dentry->d_count) > 1; +} + +/** + * nilfs_try_to_shrink_tree() - try to shrink dentries of a checkpoint + * @root_dentry: root dentry of the tree to be shrunk + * + * This function returns true if the tree was in-use. + */ +static int nilfs_try_to_shrink_tree(struct dentry *root_dentry) +{ + if (have_submounts(root_dentry)) + return true; + shrink_dcache_parent(root_dentry); + return nilfs_tree_was_touched(root_dentry); +} + /** * nilfs_fill_super() - initialize a super block instance * @sb: super_block @@ -845,7 +859,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, get_nilfs(nilfs); sbi->s_nilfs = nilfs; sbi->s_super = sb; - atomic_set(&sbi->s_count, 1); err = init_nilfs(nilfs, sbi, (char *)data); if (err) @@ -853,7 +866,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, spin_lock_init(&sbi->s_inode_lock); INIT_LIST_HEAD(&sbi->s_dirty_files); - INIT_LIST_HEAD(&sbi->s_list); /* * Following initialization is overlapped because @@ -875,20 +887,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, if (err) goto failed_sbi; - if (nilfs_test_opt(sbi, SNAPSHOT)) { - err = nilfs_attach_snapshot(sb, sbi->s_snapshot_cno, - &sb->s_root); - if (err) - goto failed_sbi; - - goto add_to_supers; - } - cno = nilfs_last_cno(nilfs); err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); if (err) { - printk(KERN_ERR "NILFS: error loading a checkpoint" - " (checkpoint number=%llu).\n", (unsigned long long)cno); + printk(KERN_ERR "NILFS: error loading last checkpoint " + "(checkpoint number=%llu).\n", (unsigned long long)cno); goto failed_sbi; } @@ -910,13 +913,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, up_write(&nilfs->ns_sem); } - add_to_supers: - down_write(&nilfs->ns_super_sem); - list_add(&sbi->s_list, &nilfs->ns_supers); - if (!nilfs_test_opt(sbi, SNAPSHOT)) - nilfs->ns_current = sbi; - up_write(&nilfs->ns_super_sem); - return 0; failed_segctor: @@ -928,7 +924,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, failed_sbi: put_nilfs(nilfs); sb->s_fs_info = NULL; - nilfs_put_sbinfo(sbi); + kfree(sbi); return err; } @@ -938,13 +934,10 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) struct the_nilfs *nilfs = sbi->s_nilfs; unsigned long old_sb_flags; struct nilfs_mount_options old_opts; - int was_snapshot, err; + int err; - down_write(&nilfs->ns_super_sem); old_sb_flags = sb->s_flags; old_opts.mount_opt = sbi->s_mount_opt; - old_opts.snapshot_cno = sbi->s_snapshot_cno; - was_snapshot = nilfs_test_opt(sbi, SNAPSHOT); if (!parse_options(data, sb, 1)) { err = -EINVAL; @@ -953,11 +946,6 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) sb->s_flags = (sb->s_flags & ~MS_POSIXACL); err = -EINVAL; - if (was_snapshot && !(*flags & MS_RDONLY)) { - printk(KERN_ERR "NILFS (device %s): cannot remount snapshot " - "read/write.\n", sb->s_id); - goto restore_opts; - } if (!nilfs_valid_fs(nilfs)) { printk(KERN_WARNING "NILFS (device %s): couldn't " @@ -1014,14 +1002,11 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) up_write(&nilfs->ns_sem); } out: - up_write(&nilfs->ns_super_sem); return 0; restore_opts: sb->s_flags = old_sb_flags; sbi->s_mount_opt = old_opts.mount_opt; - sbi->s_snapshot_cno = old_opts.snapshot_cno; - up_write(&nilfs->ns_super_sem); return err; } @@ -1075,18 +1060,14 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd) static int nilfs_set_bdev_super(struct super_block *s, void *data) { - struct nilfs_super_data *sd = data; - - s->s_bdev = sd->bdev; + s->s_bdev = data; s->s_dev = s->s_bdev->bd_dev; return 0; } static int nilfs_test_bdev_super(struct super_block *s, void *data) { - struct nilfs_super_data *sd = data; - - return sd->sbi && s->s_fs_info == (void *)sd->sbi; + return (void *)s->s_bdev == data; } static int @@ -1097,7 +1078,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, struct super_block *s; fmode_t mode = FMODE_READ; struct the_nilfs *nilfs; - int err, need_to_close = 1; + struct dentry *root_dentry; + int err, s_new = false; if (!(flags & MS_RDONLY)) mode |= FMODE_WRITE; @@ -1106,12 +1088,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, if (IS_ERR(sd.bdev)) return PTR_ERR(sd.bdev); - /* - * To get mount instance using sget() vfs-routine, NILFS needs - * much more information than normal filesystems to identify mount - * instance. For snapshot mounts, not only a mount type (ro-mount - * or rw-mount) but also a checkpoint number is required. - */ sd.cno = 0; sd.flags = flags; if (nilfs_identify((char *)data, &sd)) { @@ -1127,38 +1103,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, mutex_lock(&nilfs->ns_mount_mutex); - if (!sd.cno) { - /* - * Check if an exclusive mount exists or not. - * Snapshot mounts coexist with a current mount - * (i.e. rw-mount or ro-mount), whereas rw-mount and - * ro-mount are mutually exclusive. - */ - down_read(&nilfs->ns_super_sem); - if (nilfs->ns_current && - ((nilfs->ns_current->s_super->s_flags ^ flags) - & MS_RDONLY)) { - up_read(&nilfs->ns_super_sem); - err = -EBUSY; - goto failed_unlock; - } - up_read(&nilfs->ns_super_sem); - } - - /* - * Find existing nilfs_sb_info struct - */ - sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); - - /* - * Get super block instance holding the nilfs_sb_info struct. - * A new instance is allocated if no existing mount is present or - * existing instance has been unmounted. - */ - s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); - if (sd.sbi) - nilfs_put_sbinfo(sd.sbi); - + s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); if (IS_ERR(s)) { err = PTR_ERR(s); goto failed_unlock; @@ -1167,6 +1112,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, if (!s->s_root) { char b[BDEVNAME_SIZE]; + s_new = true; + /* New superblock instance created */ s->s_flags = flags; s->s_mode = mode; @@ -1179,16 +1126,53 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, goto cancel_new; s->s_flags |= MS_ACTIVE; - need_to_close = 0; + } else if (!sd.cno) { + int busy = false; + + if (nilfs_tree_was_touched(s->s_root)) { + busy = nilfs_try_to_shrink_tree(s->s_root); + if (busy && (flags ^ s->s_flags) & MS_RDONLY) { + printk(KERN_ERR "NILFS: the device already " + "has a %s mount.\n", + (s->s_flags & MS_RDONLY) ? + "read-only" : "read/write"); + err = -EBUSY; + goto failed_super; + } + } + if (!busy) { + /* + * Try remount to setup mount states if the current + * tree is not mounted and only snapshots use this sb. + */ + err = nilfs_remount(s, &flags, data); + if (err) + goto failed_super; + } + } + + if (sd.cno) { + err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); + if (err) { + if (s_new) + goto cancel_new; + goto failed_super; + } + } else { + root_dentry = dget(s->s_root); } mutex_unlock(&nilfs->ns_mount_mutex); put_nilfs(nilfs); - if (need_to_close) + if (!s_new) close_bdev_exclusive(sd.bdev, mode); - simple_set_mnt(mnt, s); + + mnt->mnt_sb = s; + mnt->mnt_root = root_dentry; return 0; + failed_super: + deactivate_locked_super(s); failed_unlock: mutex_unlock(&nilfs->ns_mount_mutex); put_nilfs(nilfs); @@ -1202,7 +1186,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, put_nilfs(nilfs); deactivate_locked_super(s); /* - * deactivate_locked_super() invokes close_bdev_exclusive(). + * This deactivate_locked_super() invokes close_bdev_exclusive(). * We must finish all post-cleaning before this call; * put_nilfs() needs the block device. */ -- cgit v1.2.3 From 348fe8da13621b3d14ab2d156e74551611997017 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Thu, 9 Sep 2010 02:07:56 +0900 Subject: nilfs2: simplify life cycle management of nilfs object This stops pre-allocating nilfs object in nilfs_get_sb routine, and stops managing its life cycle by reference counting. nilfs_find_or_create_nilfs() function, nilfs->ns_mount_mutex, nilfs_objects list, and the reference counter will be removed through the simplification. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 67 ++++++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 45 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 2e58e7c629b5..5893cb27c909 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -356,7 +356,7 @@ static void nilfs_put_super(struct super_block *sb) up_write(&nilfs->ns_sem); } - put_nilfs(sbi->s_nilfs); + destroy_nilfs(nilfs); sbi->s_super = NULL; sb->s_fs_info = NULL; kfree(sbi); @@ -836,15 +836,14 @@ static int nilfs_try_to_shrink_tree(struct dentry *root_dentry) * @sb: super_block * @data: mount options * @silent: silent mode flag - * @nilfs: the_nilfs struct * * This function is called exclusively by nilfs->ns_mount_mutex. * So, the recovery process is protected from other simultaneous mounts. */ static int -nilfs_fill_super(struct super_block *sb, void *data, int silent, - struct the_nilfs *nilfs) +nilfs_fill_super(struct super_block *sb, void *data, int silent) { + struct the_nilfs *nilfs; struct nilfs_sb_info *sbi; struct nilfs_root *fsroot; __u64 cno; @@ -855,14 +854,18 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, return -ENOMEM; sb->s_fs_info = sbi; + sbi->s_super = sb; - get_nilfs(nilfs); + nilfs = alloc_nilfs(sb->s_bdev); + if (!nilfs) { + err = -ENOMEM; + goto failed_sbi; + } sbi->s_nilfs = nilfs; - sbi->s_super = sb; err = init_nilfs(nilfs, sbi, (char *)data); if (err) - goto failed_sbi; + goto failed_nilfs; spin_lock_init(&sbi->s_inode_lock); INIT_LIST_HEAD(&sbi->s_dirty_files); @@ -885,14 +888,14 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, err = load_nilfs(nilfs, sbi); if (err) - goto failed_sbi; + goto failed_nilfs; cno = nilfs_last_cno(nilfs); err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); if (err) { printk(KERN_ERR "NILFS: error loading last checkpoint " "(checkpoint number=%llu).\n", (unsigned long long)cno); - goto failed_sbi; + goto failed_nilfs; } if (!(sb->s_flags & MS_RDONLY)) { @@ -921,8 +924,10 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, failed_checkpoint: nilfs_put_root(fsroot); + failed_nilfs: + destroy_nilfs(nilfs); + failed_sbi: - put_nilfs(nilfs); sb->s_fs_info = NULL; kfree(sbi); return err; @@ -1077,7 +1082,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, struct nilfs_super_data sd; struct super_block *s; fmode_t mode = FMODE_READ; - struct the_nilfs *nilfs; struct dentry *root_dentry; int err, s_new = false; @@ -1095,18 +1099,10 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, goto failed; } - nilfs = find_or_create_nilfs(sd.bdev); - if (!nilfs) { - err = -ENOMEM; - goto failed; - } - - mutex_lock(&nilfs->ns_mount_mutex); - s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); if (IS_ERR(s)) { err = PTR_ERR(s); - goto failed_unlock; + goto failed; } if (!s->s_root) { @@ -1120,10 +1116,9 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); sb_set_blocksize(s, block_size(sd.bdev)); - err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0, - nilfs); + err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (err) - goto cancel_new; + goto failed_super; s->s_flags |= MS_ACTIVE; } else if (!sd.cno) { @@ -1153,17 +1148,12 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, if (sd.cno) { err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); - if (err) { - if (s_new) - goto cancel_new; + if (err) goto failed_super; - } } else { root_dentry = dget(s->s_root); } - mutex_unlock(&nilfs->ns_mount_mutex); - put_nilfs(nilfs); if (!s_new) close_bdev_exclusive(sd.bdev, mode); @@ -1173,23 +1163,10 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, failed_super: deactivate_locked_super(s); - failed_unlock: - mutex_unlock(&nilfs->ns_mount_mutex); - put_nilfs(nilfs); - failed: - close_bdev_exclusive(sd.bdev, mode); - return err; - cancel_new: - /* Abandoning the newly allocated superblock */ - mutex_unlock(&nilfs->ns_mount_mutex); - put_nilfs(nilfs); - deactivate_locked_super(s); - /* - * This deactivate_locked_super() invokes close_bdev_exclusive(). - * We must finish all post-cleaning before this call; - * put_nilfs() needs the block device. - */ + failed: + if (!s_new) + close_bdev_exclusive(sd.bdev, mode); return err; } -- cgit v1.2.3 From f1e89c86fdd0f5e59f6768146c86437934202033 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 5 Sep 2010 12:20:59 +0900 Subject: nilfs2: use iget for all metadata files This makes use of iget5_locked to allocate or get inode for metadata files to stop using own inode allocator. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 5893cb27c909..39e7d7f8eda0 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -356,6 +356,10 @@ static void nilfs_put_super(struct super_block *sb) up_write(&nilfs->ns_sem); } + iput(nilfs->ns_sufile); + iput(nilfs->ns_cpfile); + iput(nilfs->ns_dat); + destroy_nilfs(nilfs); sbi->s_super = NULL; sb->s_fs_info = NULL; @@ -403,10 +407,6 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, if (root->ifile) goto reuse; /* already attached checkpoint */ - root->ifile = nilfs_ifile_new(sbi, nilfs->ns_inode_size); - if (!root->ifile) - goto failed; - down_read(&nilfs->ns_segctor_sem); err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp, &bh_cp); @@ -421,8 +421,10 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, } goto failed; } - err = nilfs_read_inode_common(root->ifile, &raw_cp->cp_ifile_inode); - if (unlikely(err)) + + err = nilfs_ifile_read(sbi->s_super, root, nilfs->ns_inode_size, + &raw_cp->cp_ifile_inode, &root->ifile); + if (err) goto failed_bh; atomic_set(&root->inodes_count, le64_to_cpu(raw_cp->cp_inodes_count)); @@ -895,7 +897,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent) if (err) { printk(KERN_ERR "NILFS: error loading last checkpoint " "(checkpoint number=%llu).\n", (unsigned long long)cno); - goto failed_nilfs; + goto failed_unload; } if (!(sb->s_flags & MS_RDONLY)) { @@ -924,6 +926,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent) failed_checkpoint: nilfs_put_root(fsroot); + failed_unload: + iput(nilfs->ns_sufile); + iput(nilfs->ns_cpfile); + iput(nilfs->ns_dat); + failed_nilfs: destroy_nilfs(nilfs); -- cgit v1.2.3 From 032dbb3b503a30fce732ec4c05525d0abed1f1d6 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 13 Sep 2010 11:16:34 +0900 Subject: 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 --- fs/nilfs2/super.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'fs/nilfs2/super.c') 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 -- cgit v1.2.3 From 2879ed66e4c6da1dfc6bb0bd04566b61824f9256 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 5 Sep 2010 13:35:53 +0900 Subject: nilfs2: remove own inode allocator and destructor for metadata files This finally removes own inode allocator and destructor functions for metadata files. Several routines, nilfs_mdt_new(), nilfs_mdt_new_common(), nilfs_mdt_clear(), nilfs_mdt_destroy(), and nilfs_alloc_inode_common() will be gone. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index ab96d26bf7e9..d92ebd5d60d9 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -146,7 +146,7 @@ void nilfs_warning(struct super_block *sb, const char *function, } -struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) +struct inode *nilfs_alloc_inode(struct super_block *sb) { struct nilfs_inode_info *ii; @@ -157,15 +157,10 @@ struct inode *nilfs_alloc_inode_common(struct the_nilfs *nilfs) ii->i_state = 0; ii->i_cno = 0; ii->vfs_inode.i_version = 1; - nilfs_btnode_cache_init(&ii->i_btnode_cache, nilfs->ns_bdi); + nilfs_btnode_cache_init(&ii->i_btnode_cache, sb->s_bdi); return &ii->vfs_inode; } -struct inode *nilfs_alloc_inode(struct super_block *sb) -{ - return nilfs_alloc_inode_common(NILFS_SB(sb)->s_nilfs); -} - void nilfs_destroy_inode(struct inode *inode) { struct nilfs_mdt_info *mdi = NILFS_MDT(inode); -- cgit v1.2.3 From c05dbfc2609993ccc067879579e2a7726e12b3f1 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Thu, 16 Sep 2010 00:36:24 +0900 Subject: nilfs2: accept 64-bit checkpoint numbers in cp mount option The current implementation doesn't mount snapshots with checkpoint numbers larger than INT_MAX since it uses match_int() for parsing "cp=" mount option. This uses simple_strtoull() for the conversion to resolve the issue. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index d92ebd5d60d9..a1cd444103ff 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -556,7 +556,6 @@ static int parse_options(char *options, struct super_block *sb, int is_remount) struct nilfs_sb_info *sbi = NILFS_SB(sb); char *p; substring_t args[MAX_OPT_ARGS]; - int option; if (!options) return 1; @@ -594,8 +593,6 @@ static int parse_options(char *options, struct super_block *sb, int is_remount) nilfs_write_opt(sbi, ERROR_MODE, ERRORS_CONT); break; case Opt_snapshot: - if (match_int(&args[0], &option) || option <= 0) - return 0; if (is_remount) { printk(KERN_ERR "NILFS: \"%s\" option is invalid " @@ -1065,7 +1062,7 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd) { char *p, *options = data; substring_t args[MAX_OPT_ARGS]; - int option, token; + int token; int ret = 0; do { @@ -1073,16 +1070,18 @@ static int nilfs_identify(char *data, struct nilfs_super_data *sd) if (p != NULL && *p) { token = match_token(p, tokens, args); if (token == Opt_snapshot) { - if (!(sd->flags & MS_RDONLY)) + if (!(sd->flags & MS_RDONLY)) { ret++; - else { - ret = match_int(&args[0], &option); - if (!ret) { - if (option > 0) - sd->cno = option; - else - ret++; - } + } else { + sd->cno = simple_strtoull(args[0].from, + NULL, 0); + /* + * No need to see the end pointer; + * match_token() has done syntax + * checking. + */ + if (sd->cno == 0) + ret++; } } if (ret) -- cgit v1.2.3 From 5beb6e0b2008386571fd342d0a4a14f5c8c0baf8 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 20 Sep 2010 18:19:06 +0900 Subject: nilfs2: add bdev freeze/thaw support Nilfs hasn't supported the freeze/thaw feature because it didn't work due to the peculiar design that multiple super block instances could be allocated for a device. This limitation was removed by the patch "nilfs2: do not allocate multiple super block instances for a device". So now this adds the freeze/thaw support to nilfs. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index a1cd444103ff..92e8c769584c 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -73,6 +73,7 @@ struct kmem_cache *nilfs_transaction_cachep; struct kmem_cache *nilfs_segbuf_cachep; struct kmem_cache *nilfs_btree_path_cache; +static int nilfs_setup_super(struct nilfs_sb_info *sbi, int is_mount); static int nilfs_remount(struct super_block *sb, int *flags, char *data); static void nilfs_set_error(struct nilfs_sb_info *sbi) @@ -439,6 +440,36 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, return err; } +static int nilfs_freeze(struct super_block *sb) +{ + struct nilfs_sb_info *sbi = NILFS_SB(sb); + struct the_nilfs *nilfs = sbi->s_nilfs; + int err; + + if (sb->s_flags & MS_RDONLY) + return 0; + + /* Mark super block clean */ + down_write(&nilfs->ns_sem); + err = nilfs_cleanup_super(sbi); + up_write(&nilfs->ns_sem); + return err; +} + +static int nilfs_unfreeze(struct super_block *sb) +{ + struct nilfs_sb_info *sbi = NILFS_SB(sb); + struct the_nilfs *nilfs = sbi->s_nilfs; + + if (sb->s_flags & MS_RDONLY) + return 0; + + down_write(&nilfs->ns_sem); + nilfs_setup_super(sbi, false); + up_write(&nilfs->ns_sem); + return 0; +} + static int nilfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct super_block *sb = dentry->d_sb; @@ -523,6 +554,8 @@ static const struct super_operations nilfs_sops = { .put_super = nilfs_put_super, /* .write_super = nilfs_write_super, */ .sync_fs = nilfs_sync_fs, + .freeze_fs = nilfs_freeze, + .unfreeze_fs = nilfs_unfreeze, /* .write_super_lockfs */ /* .unlockfs */ .statfs = nilfs_statfs, @@ -626,7 +659,7 @@ nilfs_set_default_options(struct nilfs_sb_info *sbi, NILFS_MOUNT_ERRORS_RO | NILFS_MOUNT_BARRIER; } -static int nilfs_setup_super(struct nilfs_sb_info *sbi) +static int nilfs_setup_super(struct nilfs_sb_info *sbi, int is_mount) { struct the_nilfs *nilfs = sbi->s_nilfs; struct nilfs_super_block **sbp; @@ -638,6 +671,9 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi) if (!sbp) return -EIO; + if (!is_mount) + goto skip_mount_setup; + max_mnt_count = le16_to_cpu(sbp[0]->s_max_mnt_count); mnt_count = le16_to_cpu(sbp[0]->s_mnt_count); @@ -654,9 +690,11 @@ static int nilfs_setup_super(struct nilfs_sb_info *sbi) sbp[0]->s_max_mnt_count = cpu_to_le16(NILFS_DFL_MAX_MNT_COUNT); sbp[0]->s_mnt_count = cpu_to_le16(mnt_count + 1); + sbp[0]->s_mtime = cpu_to_le64(get_seconds()); + +skip_mount_setup: sbp[0]->s_state = cpu_to_le16(le16_to_cpu(sbp[0]->s_state) & ~NILFS_VALID_FS); - sbp[0]->s_mtime = cpu_to_le64(get_seconds()); /* synchronize sbp[1] with sbp[0] */ memcpy(sbp[1], sbp[0], nilfs->ns_sbsize); return nilfs_commit_super(sbi, NILFS_SB_COMMIT_ALL); @@ -938,7 +976,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent) if (!(sb->s_flags & MS_RDONLY)) { down_write(&nilfs->ns_sem); - nilfs_setup_super(sbi); + nilfs_setup_super(sbi, true); up_write(&nilfs->ns_sem); } @@ -1034,7 +1072,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) goto restore_opts; down_write(&nilfs->ns_sem); - nilfs_setup_super(sbi); + nilfs_setup_super(sbi, true); up_write(&nilfs->ns_sem); } out: @@ -1132,7 +1170,19 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, goto failed; } + /* + * once the super is inserted into the list by sget, s_umount + * will protect the lockfs code from trying to start a snapshot + * while we are mounting + */ + mutex_lock(&sd.bdev->bd_fsfreeze_mutex); + if (sd.bdev->bd_fsfreeze_count > 0) { + mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); + err = -EBUSY; + goto failed; + } s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); + mutex_unlock(&sd.bdev->bd_fsfreeze_mutex); if (IS_ERR(s)) { err = PTR_ERR(s); goto failed; -- cgit v1.2.3 From 026a7d63d55ba8656ed8c8a0733265cc7d47bb8c Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Thu, 7 Oct 2010 14:19:48 +0900 Subject: nilfs2: get rid of bdi from nilfs object Nilfs now can use sb->s_bdi to get backing_dev_info, so we use it instead of ns_bdi on the nilfs object and remove ns_bdi. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 92e8c769584c..8e77016bafae 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -910,6 +910,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent) struct the_nilfs *nilfs; struct nilfs_sb_info *sbi; struct nilfs_root *fsroot; + struct backing_dev_info *bdi; __u64 cno; int err; @@ -948,7 +949,9 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_export_op = &nilfs_export_ops; sb->s_root = NULL; sb->s_time_gran = 1; - sb->s_bdi = nilfs->ns_bdi; + + bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; + sb->s_bdi = bdi ? : &default_backing_dev_info; err = load_nilfs(nilfs, sbi); if (err) -- cgit v1.2.3 From abc0b50b6b9a9de8ae210f059598265a5438f2c4 Mon Sep 17 00:00:00 2001 From: Jiro SEKIBA Date: Fri, 8 Oct 2010 22:37:27 +0900 Subject: nilfs2: eliminate sparse warnings - "symbol not declared" change nilfs_dat_commit_free and nilfs_inode_cachep static to fix following warnings fs/nilfs2/super.c:72:19: warning: symbol 'nilfs_inode_cachep' was not declared. Should it be static? fs/nilfs2/dat.c:106:6: warning: symbol 'nilfs_dat_commit_free' was not declared. Should it be static? Signed-off-by: Jiro SEKIBA Signed-off-by: Ryusuke Konishi --- fs/nilfs2/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nilfs2/super.c') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 8e77016bafae..ab629078f4e2 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -68,7 +68,7 @@ MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " "(NILFS)"); MODULE_LICENSE("GPL"); -struct kmem_cache *nilfs_inode_cachep; +static struct kmem_cache *nilfs_inode_cachep; struct kmem_cache *nilfs_transaction_cachep; struct kmem_cache *nilfs_segbuf_cachep; struct kmem_cache *nilfs_btree_path_cache; -- cgit v1.2.3