From 9566a7a851eb7201e3207eab53ee81efd0850fee Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Tue, 10 Aug 2010 00:58:41 +0900 Subject: nilfs2: accept future revisions Compatibility of nilfs partitions is now managed with three feature sets. This changes old compatibility check with revision number so that it can accept future revisions. Note that we can stop support of experimental versions of nilfs that doesn't know the feature sets by incrementing NILFS_CURRENT_REV. We don't have to do it soon, but it would be a possible option whenever the need arises. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/the_nilfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index ba7c10c..461b721 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -468,8 +468,8 @@ static unsigned long long nilfs_max_size(unsigned int blkbits) static int nilfs_store_disk_layout(struct the_nilfs *nilfs, struct nilfs_super_block *sbp) { - if (le32_to_cpu(sbp->s_rev_level) != NILFS_CURRENT_REV) { - printk(KERN_ERR "NILFS: revision mismatch " + if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) { + printk(KERN_ERR "NILFS: unsupported revision " "(superblock rev.=%d.%d, current rev.=%d.%d). " "Please check the version of mkfs.nilfs.\n", le32_to_cpu(sbp->s_rev_level), -- cgit v1.1 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/mdt.c | 2 -- fs/nilfs2/super.c | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index d01aff4..ee943a3 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -577,7 +577,5 @@ void nilfs_mdt_destroy(struct inode *inode) nilfs_palloc_destroy_cache(inode); nilfs_mdt_clear(inode); - kfree(mdi->mi_bgl); /* kfree(NULL) is safe */ - kfree(mdi); nilfs_destroy_inode(inode); } diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 9f4913f..51576b4 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.1 From 7d6cd92fe2de3c286b8e95f43223f09db9302635 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 21 Aug 2010 00:30:39 +0900 Subject: nilfs2: allow nilfs_dirty_inode to mark metadata file inodes dirty This allows sop->dirty_inode callback function (nilfs_dirty_inode) to handle metadata file inodes. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/inode.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index eccb2f2..f1750ca 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -808,6 +808,7 @@ int nilfs_mark_inode_dirty(struct inode *inode) void nilfs_dirty_inode(struct inode *inode) { struct nilfs_transaction_info ti; + struct nilfs_mdt_info *mdi = NILFS_MDT(inode); if (is_bad_inode(inode)) { nilfs_warning(inode->i_sb, __func__, @@ -815,6 +816,10 @@ void nilfs_dirty_inode(struct inode *inode) dump_stack(); return; } + if (mdi) { + nilfs_mdt_mark_dirty(inode); + return; + } nilfs_transaction_begin(inode->i_sb, &ti, 0); nilfs_mark_inode_dirty(inode); nilfs_transaction_commit(inode->i_sb); /* never fails */ -- cgit v1.1 From 6c43f41000312fefa482c3bfdd97e7f81d6be0ec Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 20 Aug 2010 20:10:38 +0900 Subject: nilfs2: keep zero value in i_cno except for gc-inodes On-memory inode structures of nilfs have a member "i_cno" which stores a checkpoint number related to the inode. For gc-inodes, this field indicates version of data each gc-inode caches for GC. Log writer temporarily uses "i_cno" to transfer the latest checkpoint number. This stops the latter use and lets only gc-inodes use it. The purpose of this patch is to allow the successive change use "i_cno" for inode lookup. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/segment.c | 29 ++++++++++++++--------------- fs/nilfs2/segment.h | 3 ++- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 9fd051a..eee4b22 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -366,8 +366,7 @@ static int nilfs_segctor_reset_segment_buffer(struct nilfs_sc_info *sci) if (nilfs_doing_gc()) flags = NILFS_SS_GC; - err = nilfs_segbuf_reset(segbuf, flags, sci->sc_seg_ctime, - sci->sc_sbi->s_nilfs->ns_cno); + err = nilfs_segbuf_reset(segbuf, flags, sci->sc_seg_ctime, sci->sc_cno); if (unlikely(err)) return err; @@ -440,17 +439,26 @@ static void nilfs_segctor_end_finfo(struct nilfs_sc_info *sci, struct nilfs_finfo *finfo; struct nilfs_inode_info *ii; struct nilfs_segment_buffer *segbuf; + __u64 cno; if (sci->sc_blk_cnt == 0) return; ii = NILFS_I(inode); + + if (test_bit(NILFS_I_GCINODE, &ii->i_state)) + cno = ii->i_cno; + else if (NILFS_ROOT_METADATA_FILE(inode->i_ino)) + cno = 0; + else + cno = sci->sc_cno; + finfo = nilfs_segctor_map_segsum_entry(sci, &sci->sc_finfo_ptr, sizeof(*finfo)); finfo->fi_ino = cpu_to_le64(inode->i_ino); finfo->fi_nblocks = cpu_to_le32(sci->sc_blk_cnt); finfo->fi_ndatablk = cpu_to_le32(sci->sc_datablk_cnt); - finfo->fi_cno = cpu_to_le64(ii->i_cno); + finfo->fi_cno = cpu_to_le64(cno); segbuf = sci->sc_curseg; segbuf->sb_sum.sumbytes = sci->sc_binfo_ptr.offset + @@ -1976,7 +1984,6 @@ static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci, struct nilfs_sb_info *sbi) { struct nilfs_inode_info *ii, *n; - __u64 cno = sbi->s_nilfs->ns_cno; spin_lock(&sbi->s_inode_lock); retry: @@ -2002,7 +2009,6 @@ static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci, brelse(ibh); goto retry; } - ii->i_cno = cno; clear_bit(NILFS_I_QUEUED, &ii->i_state); set_bit(NILFS_I_BUSY, &ii->i_state); @@ -2011,8 +2017,6 @@ static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci, } spin_unlock(&sbi->s_inode_lock); - NILFS_I(sbi->s_ifile)->i_cno = cno; - return 0; } @@ -2021,19 +2025,13 @@ static void nilfs_segctor_check_out_files(struct nilfs_sc_info *sci, { struct nilfs_transaction_info *ti = current->journal_info; struct nilfs_inode_info *ii, *n; - __u64 cno = sbi->s_nilfs->ns_cno; spin_lock(&sbi->s_inode_lock); list_for_each_entry_safe(ii, n, &sci->sc_dirty_files, i_dirty) { if (!test_and_clear_bit(NILFS_I_UPDATED, &ii->i_state) || - test_bit(NILFS_I_DIRTY, &ii->i_state)) { - /* The current checkpoint number (=nilfs->ns_cno) is - changed between check-in and check-out only if the - super root is written out. So, we can update i_cno - for the inodes that remain in the dirty list. */ - ii->i_cno = cno; + test_bit(NILFS_I_DIRTY, &ii->i_state)) continue; - } + clear_bit(NILFS_I_BUSY, &ii->i_state); brelse(ii->i_bh); ii->i_bh = NULL; @@ -2054,6 +2052,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) int err; sci->sc_stage.scnt = NILFS_ST_INIT; + sci->sc_cno = nilfs->ns_cno; err = nilfs_segctor_check_in_files(sci, sbi); if (unlikely(err)) diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index 17c487b..675d932 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h @@ -107,6 +107,7 @@ struct nilfs_segsum_pointer { * @sc_datablk_cnt: Data block count of a file * @sc_nblk_this_inc: Number of blocks included in the current logical segment * @sc_seg_ctime: Creation time + * @sc_cno: checkpoint number of current log * @sc_flags: Internal flags * @sc_state_lock: spinlock for sc_state and so on * @sc_state: Segctord state flags @@ -156,7 +157,7 @@ struct nilfs_sc_info { unsigned long sc_datablk_cnt; unsigned long sc_nblk_this_inc; time_t sc_seg_ctime; - + __u64 sc_cno; unsigned long sc_flags; spinlock_t sc_state_lock; -- cgit v1.1 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/inode.c | 37 ++++++++++++++++++++++++++++++++++--- fs/nilfs2/super.c | 1 + 2 files changed, 35 insertions(+), 3 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index f1750ca..6e9df85 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -34,6 +34,11 @@ #include "cpfile.h" #include "ifile.h" +struct nilfs_iget_args { + u64 ino; + __u64 cno; + int for_gc; +}; /** * nilfs_get_block() - get a file block on the filesystem (callback function) @@ -320,7 +325,6 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) /* ii->i_file_acl = 0; */ /* ii->i_dir_acl = 0; */ ii->i_dir_start_lookup = 0; - ii->i_cno = 0; nilfs_set_inode_flags(inode); spin_lock(&sbi->s_next_gen_lock); inode->i_generation = sbi->s_next_generation++; @@ -410,7 +414,6 @@ int nilfs_read_inode_common(struct inode *inode, 0 : le32_to_cpu(raw_inode->i_dir_acl); #endif ii->i_dir_start_lookup = 0; - ii->i_cno = 0; inode->i_generation = le32_to_cpu(raw_inode->i_generation); if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || @@ -476,12 +479,40 @@ static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, return err; } +static int nilfs_iget_test(struct inode *inode, void *opaque) +{ + struct nilfs_iget_args *args = opaque; + struct nilfs_inode_info *ii; + + if (args->ino != inode->i_ino) + return 0; + + ii = NILFS_I(inode); + if (!test_bit(NILFS_I_GCINODE, &ii->i_state)) + return !args->for_gc; + + return args->for_gc && args->cno == ii->i_cno; +} + +static int nilfs_iget_set(struct inode *inode, void *opaque) +{ + struct nilfs_iget_args *args = opaque; + + inode->i_ino = args->ino; + if (args->for_gc) { + NILFS_I(inode)->i_state = 1 << NILFS_I_GCINODE; + NILFS_I(inode)->i_cno = args->cno; + } + return 0; +} + struct inode *nilfs_iget(struct super_block *sb, unsigned long ino) { + struct nilfs_iget_args args = { .ino = ino, .cno = 0, .for_gc = 0 }; struct inode *inode; int err; - inode = iget_locked(sb, ino); + inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args); if (unlikely(!inode)) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 51576b4..f3a00a3 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.1 From 5e19a995f4ad8a8f20749a396bb01ebb6d4df96c Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 21 Aug 2010 22:01:51 +0900 Subject: nilfs2: separate initializer of metadata file inode This separates a part of initialization code of metadata file inode, and makes it available from the nilfs iget function that a later patch will add to. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/gcinode.c | 6 +++++- fs/nilfs2/mdt.c | 44 +++++++++++++++++++++++++++----------------- fs/nilfs2/mdt.h | 4 +++- 3 files changed, 35 insertions(+), 19 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index bed3a78..cd19a37 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c @@ -225,10 +225,14 @@ static struct inode *alloc_gcinode(struct the_nilfs *nilfs, ino_t ino, struct inode *inode; struct nilfs_inode_info *ii; - inode = nilfs_mdt_new_common(nilfs, NULL, ino, GFP_NOFS, 0); + inode = nilfs_mdt_new_common(nilfs, NULL, ino); if (!inode) return NULL; + if (nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0) < 0) { + nilfs_destroy_inode(inode); + return NULL; + } inode->i_op = NULL; inode->i_fop = NULL; inode->i_mapping->a_ops = &def_gcinode_aops; diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index ee943a3..73e5da3 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -439,6 +439,27 @@ static const struct address_space_operations def_mdt_aops = { static const struct inode_operations def_mdt_iops; static const struct file_operations def_mdt_fops; + +int nilfs_mdt_init(struct inode *inode, struct the_nilfs *nilfs, + gfp_t gfp_mask, size_t objsz) +{ + struct nilfs_mdt_info *mi; + + mi = kzalloc(max(sizeof(*mi), objsz), GFP_NOFS); + if (!mi) + return -ENOMEM; + + mi->mi_nilfs = nilfs; + init_rwsem(&mi->mi_sem); + inode->i_private = mi; + + inode->i_mode = S_IFREG; + mapping_set_gfp_mask(inode->i_mapping, gfp_mask); + inode->i_mapping->backing_dev_info = nilfs->ns_bdi; + + return 0; +} + /* * NILFS2 uses pseudo inodes for meta data files such as DAT, cpfile, sufile, * ifile, or gcinodes. This allows the B-tree code and segment constructor @@ -454,12 +475,10 @@ static const struct file_operations def_mdt_fops; * @nilfs: nilfs object * @sb: super block instance the metadata file belongs to * @ino: inode number - * @gfp_mask: gfp mask for data pages - * @objsz: size of the private object attached to inode->i_private */ struct inode * nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, - ino_t ino, gfp_t gfp_mask, size_t objsz) + ino_t ino) { struct inode *inode = nilfs_alloc_inode_common(nilfs); @@ -467,15 +486,6 @@ nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, return NULL; else { struct address_space * const mapping = &inode->i_data; - struct nilfs_mdt_info *mi; - - mi = kzalloc(max(sizeof(*mi), objsz), GFP_NOFS); - if (!mi) { - nilfs_destroy_inode(inode); - return NULL; - } - mi->mi_nilfs = nilfs; - init_rwsem(&mi->mi_sem); inode->i_sb = sb; /* sb may be NULL for some meta data files */ inode->i_blkbits = nilfs->ns_blocksize_bits; @@ -483,8 +493,6 @@ nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, atomic_set(&inode->i_count, 1); inode->i_nlink = 1; inode->i_ino = ino; - inode->i_mode = S_IFREG; - inode->i_private = mi; #ifdef INIT_UNUSED_INODE_FIELDS atomic_set(&inode->i_writecount, 0); @@ -515,9 +523,7 @@ nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, mapping->host = NULL; /* instead of inode */ mapping->flags = 0; - mapping_set_gfp_mask(mapping, gfp_mask); mapping->assoc_mapping = NULL; - mapping->backing_dev_info = nilfs->ns_bdi; inode->i_mapping = mapping; } @@ -530,10 +536,14 @@ struct inode *nilfs_mdt_new(struct the_nilfs *nilfs, struct super_block *sb, { struct inode *inode; - inode = nilfs_mdt_new_common(nilfs, sb, ino, NILFS_MDT_GFP, objsz); + inode = nilfs_mdt_new_common(nilfs, sb, ino); if (!inode) return NULL; + if (nilfs_mdt_init(inode, nilfs, NILFS_MDT_GFP, objsz) < 0) { + nilfs_destroy_inode(inode); + return NULL; + } inode->i_op = &def_mdt_iops; inode->i_fop = &def_mdt_fops; inode->i_mapping->a_ops = &def_mdt_aops; diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index 6c4bbb0..f445602 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -76,10 +76,12 @@ int nilfs_mdt_forget_block(struct inode *, unsigned long); int nilfs_mdt_mark_block_dirty(struct inode *, unsigned long); int nilfs_mdt_fetch_dirty(struct inode *); +int nilfs_mdt_init(struct inode *inode, struct the_nilfs *nilfs, + gfp_t gfp_mask, size_t objsz); struct inode *nilfs_mdt_new(struct the_nilfs *, struct super_block *, ino_t, size_t); struct inode *nilfs_mdt_new_common(struct the_nilfs *, struct super_block *, - ino_t, gfp_t, size_t); + ino_t); void nilfs_mdt_destroy(struct inode *); void nilfs_mdt_set_entry_size(struct inode *, unsigned, unsigned); void nilfs_mdt_set_shadow(struct inode *, struct inode *); -- cgit v1.1 From 263d90cefc7d82a01c296c59532ff59d67c63509 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 20 Aug 2010 19:06:11 +0900 Subject: nilfs2: remove own inode hash used for GC This uses inode hash function that vfs provides instead of the own hash table for caching gc inodes. This finally removes the own inode hash from nilfs. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/gcinode.c | 140 +++++++++----------------------------------------- fs/nilfs2/inode.c | 22 ++++++++ fs/nilfs2/ioctl.c | 17 +++--- fs/nilfs2/nilfs.h | 9 ++-- fs/nilfs2/segment.c | 3 +- fs/nilfs2/the_nilfs.c | 8 +-- fs/nilfs2/the_nilfs.h | 7 +-- 7 files changed, 64 insertions(+), 142 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index cd19a37..34f8f84 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c @@ -28,13 +28,6 @@ * gcinodes), and this file provides lookup function of the dummy * inodes and their buffer read function. * - * Since NILFS2 keeps up multiple checkpoints/snapshots across GC, it - * has to treat blocks that belong to a same file but have different - * checkpoint numbers. To avoid interference among generations, dummy - * inodes are managed separately from actual inodes, and their lookup - * function (nilfs_gc_iget) is designed to be specified with a - * checkpoint number argument as well as an inode number. - * * Buffers and pages held by the dummy inodes will be released each * time after they are copied to a new log. Dirty blocks made on the * current generation and the blocks to be moved by GC never overlap @@ -180,124 +173,41 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) return 0; } -/* - * nilfs_init_gccache() - allocate and initialize gc_inode hash table - * @nilfs - the_nilfs - * - * Return Value: On success, 0. - * On error, a negative error code is returned. - */ -int nilfs_init_gccache(struct the_nilfs *nilfs) -{ - int loop; - - BUG_ON(nilfs->ns_gc_inodes_h); - - INIT_LIST_HEAD(&nilfs->ns_gc_inodes); - - nilfs->ns_gc_inodes_h = - kmalloc(sizeof(struct hlist_head) * NILFS_GCINODE_HASH_SIZE, - GFP_NOFS); - if (nilfs->ns_gc_inodes_h == NULL) - return -ENOMEM; - - for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++) - INIT_HLIST_HEAD(&nilfs->ns_gc_inodes_h[loop]); - return 0; -} - -/* - * nilfs_destroy_gccache() - free gc_inode hash table - * @nilfs - the nilfs - */ -void nilfs_destroy_gccache(struct the_nilfs *nilfs) +int nilfs_init_gcinode(struct inode *inode) { - if (nilfs->ns_gc_inodes_h) { - nilfs_remove_all_gcinode(nilfs); - kfree(nilfs->ns_gc_inodes_h); - nilfs->ns_gc_inodes_h = NULL; - } -} - -static struct inode *alloc_gcinode(struct the_nilfs *nilfs, ino_t ino, - __u64 cno) -{ - struct inode *inode; - struct nilfs_inode_info *ii; - - inode = nilfs_mdt_new_common(nilfs, NULL, ino); - if (!inode) - return NULL; - - if (nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0) < 0) { - nilfs_destroy_inode(inode); - return NULL; - } - inode->i_op = NULL; - inode->i_fop = NULL; - inode->i_mapping->a_ops = &def_gcinode_aops; - - ii = NILFS_I(inode); - ii->i_cno = cno; - ii->i_flags = 0; - ii->i_state = 1 << NILFS_I_GCINODE; - ii->i_bh = NULL; - nilfs_bmap_init_gc(ii->i_bmap); + struct nilfs_inode_info *ii = NILFS_I(inode); + struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; + int ret; - return inode; -} + ret = nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0); + if (!ret) { + inode->i_mapping->a_ops = &def_gcinode_aops; -static unsigned long ihash(ino_t ino, __u64 cno) -{ - return hash_long((unsigned long)((ino << 2) + cno), - NILFS_GCINODE_HASH_BITS); -} + ii->i_flags = 0; + nilfs_bmap_init_gc(ii->i_bmap); -/* - * nilfs_gc_iget() - find or create gc inode with specified (ino,cno) - */ -struct inode *nilfs_gc_iget(struct the_nilfs *nilfs, ino_t ino, __u64 cno) -{ - struct hlist_head *head = nilfs->ns_gc_inodes_h + ihash(ino, cno); - struct hlist_node *node; - struct inode *inode; - - hlist_for_each_entry(inode, node, head, i_hash) { - if (inode->i_ino == ino && NILFS_I(inode)->i_cno == cno) - return inode; - } - - inode = alloc_gcinode(nilfs, ino, cno); - if (likely(inode)) { - hlist_add_head(&inode->i_hash, head); + /* + * Add the inode to GC inode list. Garbage Collection + * is serialized and no two processes manipulate the + * list simultaneously. + */ + igrab(inode); list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); } - return inode; -} - -/* - * nilfs_clear_gcinode() - clear and free a gc inode - */ -void nilfs_clear_gcinode(struct inode *inode) -{ - nilfs_mdt_destroy(inode); + return ret; } -/* - * nilfs_remove_all_gcinode() - remove all inodes from the_nilfs +/** + * nilfs_remove_all_gcinodes() - remove all unprocessed gc inodes */ -void nilfs_remove_all_gcinode(struct the_nilfs *nilfs) +void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs) { - struct hlist_head *head = nilfs->ns_gc_inodes_h; - struct hlist_node *node, *n; - struct inode *inode; - int loop; + struct list_head *head = &nilfs->ns_gc_inodes; + struct nilfs_inode_info *ii; - for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++, head++) { - hlist_for_each_entry_safe(inode, node, n, head, i_hash) { - hlist_del_init(&inode->i_hash); - list_del_init(&NILFS_I(inode)->i_dirty); - nilfs_clear_gcinode(inode); /* might sleep */ - } + while (!list_empty(head)) { + ii = list_first_entry(head, struct nilfs_inode_info, i_dirty); + list_del_init(&ii->i_dirty); + iput(&ii->vfs_inode); } } diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 6e9df85..82cfdbc 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -527,6 +527,28 @@ struct inode *nilfs_iget(struct super_block *sb, unsigned long ino) return inode; } +struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino, + __u64 cno) +{ + struct nilfs_iget_args args = { .ino = ino, .cno = cno, .for_gc = 1 }; + struct inode *inode; + int err; + + inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args); + if (unlikely(!inode)) + return ERR_PTR(-ENOMEM); + if (!(inode->i_state & I_NEW)) + return inode; + + err = nilfs_init_gcinode(inode); + if (unlikely(err)) { + iget_failed(inode); + return ERR_PTR(err); + } + unlock_new_inode(inode); + return inode; +} + void nilfs_write_inode_common(struct inode *inode, struct nilfs_inode *raw_inode, int has_bmap) { diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 0442ee3..2ee6843 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -333,7 +333,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode, return 0; } -static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, +static int nilfs_ioctl_move_blocks(struct super_block *sb, struct nilfs_argv *argv, void *buf) { size_t nmembs = argv->v_nmembs; @@ -348,7 +348,7 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, for (i = 0, vdesc = buf; i < nmembs; ) { ino = vdesc->vd_ino; cno = vdesc->vd_cno; - inode = nilfs_gc_iget(nilfs, ino, cno); + inode = nilfs_iget_for_gc(sb, ino, cno); if (unlikely(inode == NULL)) { ret = -ENOMEM; goto failed; @@ -356,11 +356,15 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, do { ret = nilfs_ioctl_move_inode_block(inode, vdesc, &buffers); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + iput(inode); goto failed; + } vdesc++; } while (++i < nmembs && vdesc->vd_ino == ino && vdesc->vd_cno == cno); + + iput(inode); /* The inode still remains in GC inode list */ } list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { @@ -566,7 +570,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, } /* - * nilfs_ioctl_move_blocks() will call nilfs_gc_iget(), + * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(), * which will operates an inode list without blocking. * To protect the list from concurrent operations, * nilfs_ioctl_move_blocks should be atomic operation. @@ -576,15 +580,14 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, goto out_free; } - ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]); + ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); if (ret < 0) printk(KERN_ERR "NILFS: GC failed during preparation: " "cannot read source blocks: err=%d\n", ret); else ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); - if (ret < 0) - nilfs_remove_all_gcinode(nilfs); + nilfs_remove_all_gcinodes(nilfs); clear_nilfs_gc_running(nilfs); out_free: diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index d3d5404..797cd43 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -248,6 +248,8 @@ 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); extern struct inode *nilfs_iget(struct super_block *, unsigned long); +extern struct inode *nilfs_iget_for_gc(struct super_block *sb, + unsigned long ino, __u64 cno); extern void nilfs_update_inode(struct inode *, struct buffer_head *); extern void nilfs_truncate(struct inode *); extern void nilfs_evict_inode(struct inode *); @@ -292,11 +294,8 @@ int nilfs_gccache_submit_read_data(struct inode *, sector_t, sector_t, __u64, int nilfs_gccache_submit_read_node(struct inode *, sector_t, __u64, struct buffer_head **); int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *); -int nilfs_init_gccache(struct the_nilfs *); -void nilfs_destroy_gccache(struct the_nilfs *); -void nilfs_clear_gcinode(struct inode *); -struct inode *nilfs_gc_iget(struct the_nilfs *, ino_t, __u64); -void nilfs_remove_all_gcinode(struct the_nilfs *); +int nilfs_init_gcinode(struct inode *inode); +void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs); /* gcdat.c */ int nilfs_init_gcdat_inode(struct the_nilfs *); diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index eee4b22..9cf7138 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2451,9 +2451,8 @@ nilfs_remove_written_gcinodes(struct the_nilfs *nilfs, struct list_head *head) list_for_each_entry_safe(ii, n, head, i_dirty) { if (!test_bit(NILFS_I_UPDATED, &ii->i_state)) continue; - hlist_del_init(&ii->vfs_inode.i_hash); list_del_init(&ii->i_dirty); - nilfs_clear_gcinode(&ii->vfs_inode); + iput(&ii->vfs_inode); } } diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 461b721..6a012b9 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -87,8 +87,8 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) init_rwsem(&nilfs->ns_writer_sem); INIT_LIST_HEAD(&nilfs->ns_list); INIT_LIST_HEAD(&nilfs->ns_supers); + INIT_LIST_HEAD(&nilfs->ns_gc_inodes); spin_lock_init(&nilfs->ns_last_segment_lock); - nilfs->ns_gc_inodes_h = NULL; init_rwsem(&nilfs->ns_segctor_sem); return nilfs; @@ -164,7 +164,6 @@ void put_nilfs(struct the_nilfs *nilfs) nilfs_mdt_destroy(nilfs->ns_gc_dat); } if (nilfs_init(nilfs)) { - nilfs_destroy_gccache(nilfs); brelse(nilfs->ns_sbh[0]); brelse(nilfs->ns_sbh[1]); } @@ -736,11 +735,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) if (err) goto failed_sbh; - /* Initialize gcinode cache */ - err = nilfs_init_gccache(nilfs); - if (err) - goto failed_sbh; - set_nilfs_init(nilfs); err = 0; out: diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index f785a7b..c7ecd0c 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -81,7 +81,6 @@ enum { * @ns_sufile: segusage file inode * @ns_gc_dat: shadow inode of the DAT file inode for GC * @ns_gc_inodes: dummy inodes to keep live blocks - * @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks * @ns_blocksize_bits: bit length of block size * @ns_blocksize: block size * @ns_nsegments: number of segments in filesystem @@ -165,9 +164,8 @@ struct the_nilfs { struct inode *ns_sufile; struct inode *ns_gc_dat; - /* GC inode list and hash table head */ + /* GC inode list */ struct list_head ns_gc_inodes; - struct hlist_head *ns_gc_inodes_h; /* Disk layout information (static) */ unsigned int ns_blocksize_bits; @@ -182,9 +180,6 @@ struct the_nilfs { u32 ns_crc_seed; }; -#define NILFS_GCINODE_HASH_BITS 8 -#define NILFS_GCINODE_HASH_SIZE (1< Date: Sat, 14 Aug 2010 12:59:15 +0900 Subject: nilfs2: add checkpoint tree to nilfs object To hold multiple versions of a filesystem in one sb instance, a new on-memory structure is necessary to handle one or more checkpoints. This adds a red-black tree of checkpoints to nilfs object, and adds lookup and create functions for them. Each checkpoint is represented by "nilfs_root" structure, and this structure has rb_node to configure the rb-tree. The nilfs_root object is identified with a checkpoint number. For each snapshot, a nilfs_root object is allocated and the checkpoint number of snapshot is assigned to it. For a regular mount (i.e. current mode mount), NILFS_CPTREE_CURRENT_CNO constant is assigned to the corresponding nilfs_root object. Each nilfs_root object has an ifile inode and some counters. These items will displace those of nilfs_sb_info structure in successive patches. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/the_nilfs.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nilfs2/the_nilfs.h | 42 +++++++++++++++++++++++ 2 files changed, 134 insertions(+) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 6a012b9..f1d5992 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -89,6 +89,8 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) INIT_LIST_HEAD(&nilfs->ns_supers); INIT_LIST_HEAD(&nilfs->ns_gc_inodes); spin_lock_init(&nilfs->ns_last_segment_lock); + nilfs->ns_cptree = RB_ROOT; + spin_lock_init(&nilfs->ns_cptree_lock); init_rwsem(&nilfs->ns_segctor_sem); return nilfs; @@ -809,6 +811,96 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs) return ncleansegs <= nilfs->ns_nrsvsegs + nincsegs; } +struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno) +{ + struct rb_node *n; + struct nilfs_root *root; + + spin_lock(&nilfs->ns_cptree_lock); + n = nilfs->ns_cptree.rb_node; + while (n) { + root = rb_entry(n, struct nilfs_root, rb_node); + + if (cno < root->cno) { + n = n->rb_left; + } else if (cno > root->cno) { + n = n->rb_right; + } else { + atomic_inc(&root->count); + spin_unlock(&nilfs->ns_cptree_lock); + return root; + } + } + spin_unlock(&nilfs->ns_cptree_lock); + + return NULL; +} + +struct nilfs_root * +nilfs_find_or_create_root(struct the_nilfs *nilfs, __u64 cno) +{ + struct rb_node **p, *parent; + struct nilfs_root *root, *new; + + root = nilfs_lookup_root(nilfs, cno); + if (root) + return root; + + new = kmalloc(sizeof(*root), GFP_KERNEL); + if (!new) + return NULL; + + spin_lock(&nilfs->ns_cptree_lock); + + p = &nilfs->ns_cptree.rb_node; + parent = NULL; + + while (*p) { + parent = *p; + root = rb_entry(parent, struct nilfs_root, rb_node); + + if (cno < root->cno) { + p = &(*p)->rb_left; + } else if (cno > root->cno) { + p = &(*p)->rb_right; + } else { + atomic_inc(&root->count); + spin_unlock(&nilfs->ns_cptree_lock); + kfree(new); + return root; + } + } + + new->cno = cno; + new->ifile = NULL; + new->nilfs = nilfs; + atomic_set(&new->count, 1); + atomic_set(&new->inodes_count, 0); + atomic_set(&new->blocks_count, 0); + + rb_link_node(&new->rb_node, parent, p); + rb_insert_color(&new->rb_node, &nilfs->ns_cptree); + + spin_unlock(&nilfs->ns_cptree_lock); + + return new; +} + +void nilfs_put_root(struct nilfs_root *root) +{ + if (atomic_dec_and_test(&root->count)) { + struct the_nilfs *nilfs = root->nilfs; + + spin_lock(&nilfs->ns_cptree_lock); + rb_erase(&root->rb_node, &nilfs->ns_cptree); + spin_unlock(&nilfs->ns_cptree_lock); + if (root->ifile) + nilfs_mdt_destroy(root->ifile); + + kfree(root); + } +} + /** * nilfs_find_sbinfo - find existing nilfs_sb_info structure * @nilfs: nilfs object diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index c7ecd0c..0afede6 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -80,6 +81,8 @@ enum { * @ns_cpfile: checkpoint file inode * @ns_sufile: segusage file inode * @ns_gc_dat: shadow inode of the DAT file inode for GC + * @ns_cptree: rb-tree of all mounted checkpoints (nilfs_root) + * @ns_cptree_lock: lock protecting @ns_cptree * @ns_gc_inodes: dummy inodes to keep live blocks * @ns_blocksize_bits: bit length of block size * @ns_blocksize: block size @@ -164,6 +167,10 @@ struct the_nilfs { struct inode *ns_sufile; struct inode *ns_gc_dat; + /* Checkpoint tree */ + struct rb_root ns_cptree; + spinlock_t ns_cptree_lock; + /* GC inode list */ struct list_head ns_gc_inodes; @@ -200,6 +207,32 @@ THE_NILFS_FNS(DISCONTINUED, discontinued) THE_NILFS_FNS(GC_RUNNING, gc_running) THE_NILFS_FNS(SB_DIRTY, sb_dirty) +/** + * struct nilfs_root - nilfs root object + * @cno: checkpoint number + * @rb_node: red-black tree node + * @count: refcount of this structure + * @nilfs: nilfs object + * @ifile: inode file + * @root: root inode + * @inodes_count: number of inodes + * @blocks_count: number of blocks (Reserved) + */ +struct nilfs_root { + __u64 cno; + struct rb_node rb_node; + + atomic_t count; + struct the_nilfs *nilfs; + struct inode *ifile; + + atomic_t inodes_count; + atomic_t blocks_count; +}; + +/* Special checkpoint number */ +#define NILFS_CPTREE_CURRENT_CNO 0 + /* Minimum interval of periodical update of superblocks (in seconds) */ #define NILFS_SB_FREQ 10 @@ -222,6 +255,10 @@ int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t); int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); +struct nilfs_root *nilfs_lookup_root(struct the_nilfs *nilfs, __u64 cno); +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 *); @@ -235,6 +272,11 @@ static inline void get_nilfs(struct the_nilfs *nilfs) atomic_inc(&nilfs->ns_count); } +static inline void nilfs_get_root(struct nilfs_root *root) +{ + atomic_inc(&root->count); +} + static inline void nilfs_attach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) { -- cgit v1.1 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/inode.c | 27 ++++++++++++++++++++++----- fs/nilfs2/namei.c | 5 +++-- fs/nilfs2/nilfs.h | 7 +++++-- fs/nilfs2/recovery.c | 12 ++++++++---- fs/nilfs2/super.c | 37 ++++++++++++++++++++++++++++++------- 5 files changed, 68 insertions(+), 20 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 82cfdbc..7306fc7 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -37,6 +37,7 @@ struct nilfs_iget_args { u64 ino; __u64 cno; + struct nilfs_root *root; int for_gc; }; @@ -284,6 +285,7 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) struct nilfs_sb_info *sbi = NILFS_SB(sb); struct inode *inode; struct nilfs_inode_info *ii; + struct nilfs_root *root; int err = -ENOMEM; ino_t ino; @@ -294,8 +296,10 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) mapping_set_gfp_mask(inode->i_mapping, mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); + root = NILFS_I(dir)->i_root; ii = NILFS_I(inode); ii->i_state = 1 << NILFS_I_NEW; + ii->i_root = root; err = nilfs_ifile_create_inode(sbi->s_ifile, &ino, &ii->i_bh); if (unlikely(err)) @@ -484,7 +488,7 @@ static int nilfs_iget_test(struct inode *inode, void *opaque) struct nilfs_iget_args *args = opaque; struct nilfs_inode_info *ii; - if (args->ino != inode->i_ino) + if (args->ino != inode->i_ino || args->root != NILFS_I(inode)->i_root) return 0; ii = NILFS_I(inode); @@ -502,13 +506,21 @@ static int nilfs_iget_set(struct inode *inode, void *opaque) if (args->for_gc) { NILFS_I(inode)->i_state = 1 << NILFS_I_GCINODE; NILFS_I(inode)->i_cno = args->cno; + NILFS_I(inode)->i_root = NULL; + } else { + if (args->root && args->ino == NILFS_ROOT_INO) + nilfs_get_root(args->root); + NILFS_I(inode)->i_root = args->root; } return 0; } -struct inode *nilfs_iget(struct super_block *sb, unsigned long ino) +struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root, + unsigned long ino) { - struct nilfs_iget_args args = { .ino = ino, .cno = 0, .for_gc = 0 }; + struct nilfs_iget_args args = { + .ino = ino, .root = root, .cno = 0, .for_gc = 0 + }; struct inode *inode; int err; @@ -530,7 +542,9 @@ struct inode *nilfs_iget(struct super_block *sb, unsigned long ino) struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino, __u64 cno) { - struct nilfs_iget_args args = { .ino = ino, .cno = cno, .for_gc = 1 }; + struct nilfs_iget_args args = { + .ino = ino, .root = NULL, .cno = cno, .for_gc = 1 + }; struct inode *inode; int err; @@ -682,6 +696,9 @@ static void nilfs_clear_inode(struct inode *inode) nilfs_bmap_clear(ii->i_bmap); nilfs_btnode_cache_clear(&ii->i_btnode_cache); + + if (ii->i_root && inode->i_ino == NILFS_ROOT_INO) + nilfs_put_root(ii->i_root); } void nilfs_evict_inode(struct inode *inode) @@ -690,7 +707,7 @@ void nilfs_evict_inode(struct inode *inode) struct super_block *sb = inode->i_sb; struct nilfs_inode_info *ii = NILFS_I(inode); - if (inode->i_nlink || unlikely(is_bad_inode(inode))) { + if (inode->i_nlink || !ii->i_root || unlikely(is_bad_inode(inode))) { if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); end_writeback(inode); diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index ad6ed2c..1110d56 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -70,7 +70,7 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) ino = nilfs_inode_by_name(dir, &dentry->d_name); inode = NULL; if (ino) { - inode = nilfs_iget(dir->i_sb, ino); + inode = nilfs_iget(dir->i_sb, NILFS_I(dir)->i_root, ino); if (IS_ERR(inode)) return ERR_CAST(inode); } @@ -87,7 +87,8 @@ struct dentry *nilfs_get_parent(struct dentry *child) if (!ino) return ERR_PTR(-ENOENT); - inode = nilfs_iget(child->d_inode->i_sb, ino); + inode = nilfs_iget(child->d_inode->i_sb, + NILFS_I(child->d_inode)->i_root, ino); if (IS_ERR(inode)) return ERR_CAST(inode); return d_obtain_alias(inode); diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 797cd43..21d90c4 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -59,6 +59,7 @@ struct nilfs_inode_info { #endif struct buffer_head *i_bh; /* i_bh contains a new or dirty disk inode */ + struct nilfs_root *i_root; struct inode vfs_inode; }; @@ -247,7 +248,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); -extern struct inode *nilfs_iget(struct super_block *, unsigned long); +struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root, + unsigned long ino); extern struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino, __u64 cno); extern void nilfs_update_inode(struct inode *, struct buffer_head *); @@ -285,7 +287,8 @@ extern struct nilfs_super_block **nilfs_prepare_super(struct nilfs_sb_info *, int flip); extern int nilfs_commit_super(struct nilfs_sb_info *, int); extern int nilfs_cleanup_super(struct nilfs_sb_info *); -extern int nilfs_attach_checkpoint(struct nilfs_sb_info *, __u64); +int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno, int curr_mnt, + struct nilfs_root **root); extern void nilfs_detach_checkpoint(struct nilfs_sb_info *); /* gcinode.c */ diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index d0c35ef..a9a5ba8 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -504,6 +504,7 @@ static int nilfs_recovery_copy_block(struct the_nilfs *nilfs, static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, + struct nilfs_root *root, struct list_head *head, unsigned long *nr_salvaged_blocks) { @@ -515,7 +516,7 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs, int err = 0, err2 = 0; list_for_each_entry_safe(rb, n, head, list) { - inode = nilfs_iget(sbi->s_super, rb->ino); + inode = nilfs_iget(sbi->s_super, root, rb->ino); if (IS_ERR(inode)) { err = PTR_ERR(inode); inode = NULL; @@ -578,6 +579,7 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs, */ static int nilfs_do_roll_forward(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, + struct nilfs_root *root, struct nilfs_recovery_info *ri) { struct buffer_head *bh_sum = NULL; @@ -649,7 +651,7 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs, goto failed; if (flags & NILFS_SS_LOGEND) { err = nilfs_recover_dsync_blocks( - nilfs, sbi, &dsync_blocks, + nilfs, sbi, root, &dsync_blocks, &nsalvaged_blocks); if (unlikely(err)) goto failed; @@ -746,19 +748,20 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, struct nilfs_recovery_info *ri) { + struct nilfs_root *root; int err; if (ri->ri_lsegs_start == 0 || ri->ri_lsegs_end == 0) return 0; - err = nilfs_attach_checkpoint(sbi, ri->ri_cno); + err = nilfs_attach_checkpoint(sbi, ri->ri_cno, true, &root); if (unlikely(err)) { printk(KERN_ERR "NILFS: error loading the latest checkpoint.\n"); return err; } - err = nilfs_do_roll_forward(nilfs, sbi, ri); + err = nilfs_do_roll_forward(nilfs, sbi, root, ri); if (unlikely(err)) goto failed; @@ -789,6 +792,7 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs, failed: nilfs_detach_checkpoint(sbi); + nilfs_put_root(root); return err; } diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index f3a00a3..a1c0e38 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.1 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/export.h | 17 +++++++ fs/nilfs2/namei.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++------- fs/nilfs2/nilfs.h | 3 -- fs/nilfs2/super.c | 52 +------------------- 4 files changed, 138 insertions(+), 71 deletions(-) create mode 100644 fs/nilfs2/export.h (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/export.h b/fs/nilfs2/export.h new file mode 100644 index 0000000..a71cc41 --- /dev/null +++ b/fs/nilfs2/export.h @@ -0,0 +1,17 @@ +#ifndef NILFS_EXPORT_H +#define NILFS_EXPORT_H + +#include + +extern const struct export_operations nilfs_export_ops; + +struct nilfs_fid { + u64 cno; + u64 ino; + u32 gen; + + u32 parent_gen; + u64 parent_ino; +} __attribute__ ((packed)); + +#endif diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 1110d56..a65f465 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -40,7 +40,11 @@ #include #include "nilfs.h" +#include "export.h" +#define NILFS_FID_SIZE_NON_CONNECTABLE \ + (offsetof(struct nilfs_fid, parent_gen) / 4) +#define NILFS_FID_SIZE_CONNECTABLE (sizeof(struct nilfs_fid) / 4) static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode) { @@ -77,23 +81,6 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) return d_splice_alias(inode, dentry); } -struct dentry *nilfs_get_parent(struct dentry *child) -{ - unsigned long ino; - struct inode *inode; - struct qstr dotdot = {.name = "..", .len = 2}; - - ino = nilfs_inode_by_name(child->d_inode, &dotdot); - if (!ino) - return ERR_PTR(-ENOENT); - - inode = nilfs_iget(child->d_inode->i_sb, - NILFS_I(child->d_inode)->i_root, ino); - if (IS_ERR(inode)) - return ERR_CAST(inode); - return d_obtain_alias(inode); -} - /* * By the time this is called, we already have created * the directory cache entry for the new file, but it @@ -469,6 +456,115 @@ out: return err; } +/* + * Export operations + */ +static struct dentry *nilfs_get_parent(struct dentry *child) +{ + unsigned long ino; + struct inode *inode; + struct qstr dotdot = {.name = "..", .len = 2}; + struct nilfs_root *root; + + ino = nilfs_inode_by_name(child->d_inode, &dotdot); + if (!ino) + return ERR_PTR(-ENOENT); + + root = NILFS_I(child->d_inode)->i_root; + + inode = nilfs_iget(child->d_inode->i_sb, root, ino); + if (IS_ERR(inode)) + return ERR_CAST(inode); + + return d_obtain_alias(inode); +} + +static struct dentry *nilfs_get_dentry(struct super_block *sb, u64 cno, + u64 ino, u32 gen) +{ + struct nilfs_root *root; + struct inode *inode; + + if (ino < NILFS_FIRST_INO(sb) && ino != NILFS_ROOT_INO) + return ERR_PTR(-ESTALE); + + root = nilfs_lookup_root(NILFS_SB(sb)->s_nilfs, cno); + if (!root) + return ERR_PTR(-ESTALE); + + inode = nilfs_iget(sb, root, ino); + nilfs_put_root(root); + + if (IS_ERR(inode)) + return ERR_CAST(inode); + if (gen && inode->i_generation != gen) { + iput(inode); + return ERR_PTR(-ESTALE); + } + return d_obtain_alias(inode); +} + +static struct dentry *nilfs_fh_to_dentry(struct super_block *sb, struct fid *fh, + int fh_len, int fh_type) +{ + struct nilfs_fid *fid = (struct nilfs_fid *)fh; + + if ((fh_len != NILFS_FID_SIZE_NON_CONNECTABLE && + fh_len != NILFS_FID_SIZE_CONNECTABLE) || + (fh_type != FILEID_NILFS_WITH_PARENT && + fh_type != FILEID_NILFS_WITHOUT_PARENT)) + return NULL; + + return nilfs_get_dentry(sb, fid->cno, fid->ino, fid->gen); +} + +static struct dentry *nilfs_fh_to_parent(struct super_block *sb, struct fid *fh, + int fh_len, int fh_type) +{ + struct nilfs_fid *fid = (struct nilfs_fid *)fh; + + if (fh_len != NILFS_FID_SIZE_CONNECTABLE || + fh_type != FILEID_NILFS_WITH_PARENT) + return NULL; + + return nilfs_get_dentry(sb, fid->cno, fid->parent_ino, fid->parent_gen); +} + +static int nilfs_encode_fh(struct dentry *dentry, __u32 *fh, int *lenp, + int connectable) +{ + struct nilfs_fid *fid = (struct nilfs_fid *)fh; + struct inode *inode = dentry->d_inode; + struct nilfs_root *root = NILFS_I(inode)->i_root; + int type; + + if (*lenp < NILFS_FID_SIZE_NON_CONNECTABLE || + (connectable && *lenp < NILFS_FID_SIZE_CONNECTABLE)) + return 255; + + fid->cno = root->cno; + fid->ino = inode->i_ino; + fid->gen = inode->i_generation; + + if (connectable && !S_ISDIR(inode->i_mode)) { + struct inode *parent; + + spin_lock(&dentry->d_lock); + parent = dentry->d_parent->d_inode; + fid->parent_ino = parent->i_ino; + fid->parent_gen = parent->i_generation; + spin_unlock(&dentry->d_lock); + + type = FILEID_NILFS_WITH_PARENT; + *lenp = NILFS_FID_SIZE_CONNECTABLE; + } else { + type = FILEID_NILFS_WITHOUT_PARENT; + *lenp = NILFS_FID_SIZE_NON_CONNECTABLE; + } + + return type; +} + const struct inode_operations nilfs_dir_inode_operations = { .create = nilfs_create, .lookup = nilfs_lookup, @@ -493,3 +589,10 @@ const struct inode_operations nilfs_symlink_inode_operations = { .follow_link = page_follow_link_light, .put_link = page_put_link, }; + +const struct export_operations nilfs_export_ops = { + .encode_fh = nilfs_encode_fh, + .fh_to_dentry = nilfs_fh_to_dentry, + .fh_to_parent = nilfs_fh_to_parent, + .get_parent = nilfs_get_parent, +}; diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 21d90c4..aa7940f 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -264,9 +264,6 @@ extern int nilfs_set_file_dirty(struct nilfs_sb_info *, struct inode *, extern int nilfs_mark_inode_dirty(struct inode *); extern void nilfs_dirty_inode(struct inode *); -/* namei.c */ -extern struct dentry *nilfs_get_parent(struct dentry *); - /* super.c */ extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); extern struct inode *nilfs_alloc_inode(struct super_block *); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index a1c0e38..adbf582 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.1 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/inode.c | 48 +++++++++++++++++++++--------------------------- fs/nilfs2/nilfs.h | 1 - fs/nilfs2/recovery.c | 3 +-- fs/nilfs2/sb.h | 3 --- fs/nilfs2/segment.c | 43 ++++++++++++++++++++++++++----------------- fs/nilfs2/segment.h | 7 ++++++- fs/nilfs2/super.c | 42 +++++++++++++----------------------------- 7 files changed, 67 insertions(+), 80 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 7306fc7..7e883d5 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -301,7 +301,7 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) ii->i_state = 1 << NILFS_I_NEW; ii->i_root = root; - err = nilfs_ifile_create_inode(sbi->s_ifile, &ino, &ii->i_bh); + err = nilfs_ifile_create_inode(root->ifile, &ino, &ii->i_bh); if (unlikely(err)) goto failed_ifile_create_inode; /* reference count of i_bh inherits from nilfs_mdt_read_block() */ @@ -358,16 +358,6 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) return ERR_PTR(err); } -void nilfs_free_inode(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - struct nilfs_sb_info *sbi = NILFS_SB(sb); - - /* XXX: check error code? Is there any thing I can do? */ - (void) nilfs_ifile_delete_inode(sbi->s_ifile, inode->i_ino); - atomic_dec(&sbi->s_inodes_count); -} - void nilfs_set_inode_flags(struct inode *inode) { unsigned int flags = NILFS_I(inode)->i_flags; @@ -431,7 +421,8 @@ int nilfs_read_inode_common(struct inode *inode, return 0; } -static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, +static int __nilfs_read_inode(struct super_block *sb, + struct nilfs_root *root, unsigned long ino, struct inode *inode) { struct nilfs_sb_info *sbi = NILFS_SB(sb); @@ -441,11 +432,11 @@ static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, int err; down_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ - err = nilfs_ifile_get_inode_block(sbi->s_ifile, ino, &bh); + err = nilfs_ifile_get_inode_block(root->ifile, ino, &bh); if (unlikely(err)) goto bad_inode; - raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, bh); + raw_inode = nilfs_ifile_map_inode(root->ifile, ino, bh); err = nilfs_read_inode_common(inode, raw_inode); if (err) @@ -468,14 +459,14 @@ static int __nilfs_read_inode(struct super_block *sb, unsigned long ino, inode, inode->i_mode, huge_decode_dev(le64_to_cpu(raw_inode->i_device_code))); } - nilfs_ifile_unmap_inode(sbi->s_ifile, ino, bh); + nilfs_ifile_unmap_inode(root->ifile, ino, bh); brelse(bh); up_read(&NILFS_MDT(dat)->mi_sem); /* XXX */ nilfs_set_inode_flags(inode); return 0; failed_unmap: - nilfs_ifile_unmap_inode(sbi->s_ifile, ino, bh); + nilfs_ifile_unmap_inode(root->ifile, ino, bh); brelse(bh); bad_inode: @@ -530,7 +521,7 @@ struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root, if (!(inode->i_state & I_NEW)) return inode; - err = __nilfs_read_inode(sb, ino, inode); + err = __nilfs_read_inode(sb, root, ino, inode); if (unlikely(err)) { iget_failed(inode); return ERR_PTR(err); @@ -595,21 +586,20 @@ void nilfs_update_inode(struct inode *inode, struct buffer_head *ibh) { ino_t ino = inode->i_ino; struct nilfs_inode_info *ii = NILFS_I(inode); - struct super_block *sb = inode->i_sb; - struct nilfs_sb_info *sbi = NILFS_SB(sb); + struct inode *ifile = ii->i_root->ifile; struct nilfs_inode *raw_inode; - raw_inode = nilfs_ifile_map_inode(sbi->s_ifile, ino, ibh); + raw_inode = nilfs_ifile_map_inode(ifile, ino, ibh); if (test_and_clear_bit(NILFS_I_NEW, &ii->i_state)) - memset(raw_inode, 0, NILFS_MDT(sbi->s_ifile)->mi_entry_size); + memset(raw_inode, 0, NILFS_MDT(ifile)->mi_entry_size); set_bit(NILFS_I_INODE_DIRTY, &ii->i_state); nilfs_write_inode_common(inode, raw_inode, 0); /* XXX: call with has_bmap = 0 is a workaround to avoid deadlock of bmap. This delays update of i_bmap to just before writing */ - nilfs_ifile_unmap_inode(sbi->s_ifile, ino, ibh); + nilfs_ifile_unmap_inode(ifile, ino, ibh); } #define NILFS_MAX_TRUNCATE_BLOCKS 16384 /* 64MB for 4KB block */ @@ -719,12 +709,16 @@ void nilfs_evict_inode(struct inode *inode) if (inode->i_data.nrpages) truncate_inode_pages(&inode->i_data, 0); + /* TODO: some of the following operations may fail. */ nilfs_truncate_bmap(ii, 0); nilfs_mark_inode_dirty(inode); end_writeback(inode); + + nilfs_ifile_delete_inode(ii->i_root->ifile, inode->i_ino); + atomic_dec(&NILFS_SB(sb)->s_inodes_count); + nilfs_clear_inode(inode); - nilfs_free_inode(inode); - /* nilfs_free_inode() marks inode buffer dirty */ + if (IS_SYNC(inode)) nilfs_set_transaction_flag(NILFS_TI_SYNC); nilfs_transaction_commit(sb); @@ -779,8 +773,8 @@ int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, spin_lock(&sbi->s_inode_lock); if (ii->i_bh == NULL) { spin_unlock(&sbi->s_inode_lock); - err = nilfs_ifile_get_inode_block(sbi->s_ifile, inode->i_ino, - pbh); + err = nilfs_ifile_get_inode_block(ii->i_root->ifile, + inode->i_ino, pbh); if (unlikely(err)) return err; spin_lock(&sbi->s_inode_lock); @@ -860,7 +854,7 @@ int nilfs_mark_inode_dirty(struct inode *inode) } nilfs_update_inode(inode, ibh); nilfs_mdt_mark_buffer_dirty(ibh); - nilfs_mdt_mark_dirty(sbi->s_ifile); + nilfs_mdt_mark_dirty(NILFS_I(inode)->i_root->ifile); brelse(ibh); return 0; } diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index aa7940f..3870c10 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -286,7 +286,6 @@ 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); -extern void nilfs_detach_checkpoint(struct nilfs_sb_info *); /* gcinode.c */ int nilfs_gccache_submit_read_data(struct inode *, sector_t, sector_t, __u64, diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index a9a5ba8..dcb5a98 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -773,7 +773,7 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs, goto failed; } - err = nilfs_attach_segment_constructor(sbi); + err = nilfs_attach_segment_constructor(sbi, root); if (unlikely(err)) goto failed; @@ -791,7 +791,6 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs, } failed: - nilfs_detach_checkpoint(sbi); nilfs_put_root(root); return err; } diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h index 0776ccc..50c418e 100644 --- a/fs/nilfs2/sb.h +++ b/fs/nilfs2/sb.h @@ -68,9 +68,6 @@ struct nilfs_sb_info { spinlock_t s_inode_lock; /* Lock for the nilfs inode. It covers s_dirty_files list */ - /* Metadata files */ - struct inode *s_ifile; /* index file inode */ - /* Inode allocator */ spinlock_t s_next_gen_lock; u32 s_next_generation; diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 9cf7138..2a6b74e 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -763,12 +763,12 @@ static void nilfs_dispose_list(struct nilfs_sb_info *sbi, } } -static int nilfs_test_metadata_dirty(struct nilfs_sb_info *sbi) +static int nilfs_test_metadata_dirty(struct the_nilfs *nilfs, + struct nilfs_root *root) { - struct the_nilfs *nilfs = sbi->s_nilfs; int ret = 0; - if (nilfs_mdt_fetch_dirty(sbi->s_ifile)) + if (nilfs_mdt_fetch_dirty(root->ifile)) ret++; if (nilfs_mdt_fetch_dirty(nilfs->ns_cpfile)) ret++; @@ -793,7 +793,7 @@ static int nilfs_segctor_confirm(struct nilfs_sc_info *sci) struct nilfs_sb_info *sbi = sci->sc_sbi; int ret = 0; - if (nilfs_test_metadata_dirty(sbi)) + if (nilfs_test_metadata_dirty(sbi->s_nilfs, sci->sc_root)) set_bit(NILFS_SC_DIRTY, &sci->sc_flags); spin_lock(&sbi->s_inode_lock); @@ -809,7 +809,7 @@ static void nilfs_segctor_clear_metadata_dirty(struct nilfs_sc_info *sci) struct nilfs_sb_info *sbi = sci->sc_sbi; struct the_nilfs *nilfs = sbi->s_nilfs; - nilfs_mdt_clear_dirty(sbi->s_ifile); + nilfs_mdt_clear_dirty(sci->sc_root->ifile); nilfs_mdt_clear_dirty(nilfs->ns_cpfile); nilfs_mdt_clear_dirty(nilfs->ns_sufile); nilfs_mdt_clear_dirty(nilfs_dat_inode(nilfs)); @@ -869,7 +869,8 @@ static int nilfs_segctor_fill_in_checkpoint(struct nilfs_sc_info *sci) else nilfs_checkpoint_set_minor(raw_cp); - nilfs_write_inode_common(sbi->s_ifile, &raw_cp->cp_ifile_inode, 1); + nilfs_write_inode_common(sci->sc_root->ifile, + &raw_cp->cp_ifile_inode, 1); nilfs_cpfile_put_checkpoint(nilfs->ns_cpfile, nilfs->ns_cno, bh_cp); return 0; @@ -894,13 +895,12 @@ static void nilfs_fill_in_file_bmap(struct inode *ifile, } } -static void nilfs_segctor_fill_in_file_bmap(struct nilfs_sc_info *sci, - struct inode *ifile) +static void nilfs_segctor_fill_in_file_bmap(struct nilfs_sc_info *sci) { struct nilfs_inode_info *ii; list_for_each_entry(ii, &sci->sc_dirty_files, i_dirty) { - nilfs_fill_in_file_bmap(ifile, ii); + nilfs_fill_in_file_bmap(sci->sc_root->ifile, ii); set_bit(NILFS_I_COLLECTED, &ii->i_state); } } @@ -1143,7 +1143,7 @@ static int nilfs_segctor_collect_blocks(struct nilfs_sc_info *sci, int mode) sci->sc_stage.flags |= NILFS_CF_IFILE_STARTED; /* Fall through */ case NILFS_ST_IFILE: - err = nilfs_segctor_scan_file(sci, sbi->s_ifile, + err = nilfs_segctor_scan_file(sci, sci->sc_root->ifile, &nilfs_sc_file_ops); if (unlikely(err)) break; @@ -1984,6 +1984,7 @@ static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci, struct nilfs_sb_info *sbi) { struct nilfs_inode_info *ii, *n; + struct inode *ifile = sci->sc_root->ifile; spin_lock(&sbi->s_inode_lock); retry: @@ -1994,14 +1995,14 @@ static int nilfs_segctor_check_in_files(struct nilfs_sc_info *sci, spin_unlock(&sbi->s_inode_lock); err = nilfs_ifile_get_inode_block( - sbi->s_ifile, ii->vfs_inode.i_ino, &ibh); + ifile, ii->vfs_inode.i_ino, &ibh); if (unlikely(err)) { nilfs_warning(sbi->s_super, __func__, "failed to get inode block.\n"); return err; } nilfs_mdt_mark_buffer_dirty(ibh); - nilfs_mdt_mark_dirty(sbi->s_ifile); + nilfs_mdt_mark_dirty(ifile); spin_lock(&sbi->s_inode_lock); if (likely(!ii->i_bh)) ii->i_bh = ibh; @@ -2058,7 +2059,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) if (unlikely(err)) goto out; - if (nilfs_test_metadata_dirty(sbi)) + if (nilfs_test_metadata_dirty(nilfs, sci->sc_root)) set_bit(NILFS_SC_DIRTY, &sci->sc_flags); if (nilfs_segctor_clean(sci)) @@ -2090,7 +2091,7 @@ static int nilfs_segctor_do_construct(struct nilfs_sc_info *sci, int mode) goto failed; if (sci->sc_stage.flags & NILFS_CF_IFILE_STARTED) - nilfs_segctor_fill_in_file_bmap(sci, sbi->s_ifile); + nilfs_segctor_fill_in_file_bmap(sci); if (mode == SC_LSEG_SR && sci->sc_stage.scnt >= NILFS_ST_CPFILE) { @@ -2684,7 +2685,8 @@ static void nilfs_segctor_kill_thread(struct nilfs_sc_info *sci) /* * Setup & clean-up functions */ -static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi) +static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi, + struct nilfs_root *root) { struct nilfs_sc_info *sci; @@ -2695,6 +2697,9 @@ static struct nilfs_sc_info *nilfs_segctor_new(struct nilfs_sb_info *sbi) sci->sc_sbi = sbi; sci->sc_super = sbi->s_super; + nilfs_get_root(root); + sci->sc_root = root; + init_waitqueue_head(&sci->sc_wait_request); init_waitqueue_head(&sci->sc_wait_daemon); init_waitqueue_head(&sci->sc_wait_task); @@ -2769,6 +2774,8 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) WARN_ON(!list_empty(&sci->sc_segbufs)); WARN_ON(!list_empty(&sci->sc_write_logs)); + nilfs_put_root(sci->sc_root); + down_write(&sbi->s_nilfs->ns_segctor_sem); del_timer_sync(&sci->sc_timer); @@ -2778,6 +2785,7 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) /** * nilfs_attach_segment_constructor - attach a segment constructor * @sbi: nilfs_sb_info + * @root: root object of the current filesystem tree * * nilfs_attach_segment_constructor() allocates a struct nilfs_sc_info, * initializes it, and starts the segment constructor. @@ -2787,7 +2795,8 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) * * %-ENOMEM - Insufficient memory available. */ -int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi) +int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi, + struct nilfs_root *root) { struct the_nilfs *nilfs = sbi->s_nilfs; int err; @@ -2801,7 +2810,7 @@ int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi) nilfs_detach_segment_constructor(sbi); } - sbi->s_sc_info = nilfs_segctor_new(sbi); + sbi->s_sc_info = nilfs_segctor_new(sbi, root); if (!sbi->s_sc_info) return -ENOMEM; diff --git a/fs/nilfs2/segment.h b/fs/nilfs2/segment.h index 675d932..cd8056e 100644 --- a/fs/nilfs2/segment.h +++ b/fs/nilfs2/segment.h @@ -29,6 +29,8 @@ #include #include "sb.h" +struct nilfs_root; + /** * struct nilfs_recovery_info - Recovery information * @ri_need_recovery: Recovery status @@ -87,6 +89,7 @@ struct nilfs_segsum_pointer { * struct nilfs_sc_info - Segment constructor information * @sc_super: Back pointer to super_block struct * @sc_sbi: Back pointer to nilfs_sb_info struct + * @sc_root: root object of the current filesystem tree * @sc_nblk_inc: Block count of current generation * @sc_dirty_files: List of files to be written * @sc_gc_inodes: List of GC inodes having blocks to be written @@ -129,6 +132,7 @@ struct nilfs_segsum_pointer { struct nilfs_sc_info { struct super_block *sc_super; struct nilfs_sb_info *sc_sbi; + struct nilfs_root *sc_root; unsigned long sc_nblk_inc; @@ -231,7 +235,8 @@ extern void nilfs_flush_segment(struct super_block *, ino_t); extern int nilfs_clean_segments(struct super_block *, struct nilfs_argv *, void **); -extern int nilfs_attach_segment_constructor(struct nilfs_sb_info *); +int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi, + struct nilfs_root *root); extern void nilfs_detach_segment_constructor(struct nilfs_sb_info *); /* recovery.c */ diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index adbf582..87c5781 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.1 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/inode.c | 4 ++-- fs/nilfs2/sb.h | 2 -- fs/nilfs2/segment.c | 4 ++-- fs/nilfs2/super.c | 11 ++++++----- 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 7e883d5..ca09e43 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -306,7 +306,7 @@ struct inode *nilfs_new_inode(struct inode *dir, int mode) goto failed_ifile_create_inode; /* reference count of i_bh inherits from nilfs_mdt_read_block() */ - atomic_inc(&sbi->s_inodes_count); + atomic_inc(&root->inodes_count); inode_init_owner(inode, dir, mode); inode->i_ino = ino; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; @@ -715,7 +715,7 @@ void nilfs_evict_inode(struct inode *inode) end_writeback(inode); nilfs_ifile_delete_inode(ii->i_root->ifile, inode->i_ino); - atomic_dec(&NILFS_SB(sb)->s_inodes_count); + atomic_dec(&ii->i_root->inodes_count); nilfs_clear_inode(inode); diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h index 50c418e..3cc3675 100644 --- a/fs/nilfs2/sb.h +++ b/fs/nilfs2/sb.h @@ -44,8 +44,6 @@ struct nilfs_sc_info; struct nilfs_sb_info { /* Snapshot status */ __u64 s_snapshot_cno; /* Checkpoint number */ - atomic_t s_inodes_count; - atomic_t s_blocks_count; /* Reserved (might be deleted) */ /* Mount options */ unsigned long s_mount_opt; diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 2a6b74e..b75306d 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -856,9 +856,9 @@ static int nilfs_segctor_fill_in_checkpoint(struct nilfs_sc_info *sci) raw_cp->cp_snapshot_list.ssl_next = 0; raw_cp->cp_snapshot_list.ssl_prev = 0; raw_cp->cp_inodes_count = - cpu_to_le64(atomic_read(&sbi->s_inodes_count)); + cpu_to_le64(atomic_read(&sci->sc_root->inodes_count)); raw_cp->cp_blocks_count = - cpu_to_le64(atomic_read(&sbi->s_blocks_count)); + cpu_to_le64(atomic_read(&sci->sc_root->blocks_count)); raw_cp->cp_nblk_inc = cpu_to_le64(sci->sc_nblk_inc + sci->sc_nblk_this_inc); raw_cp->cp_create = cpu_to_le64(sci->sc_seg_ctime); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 87c5781..acfa74e 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.1 From fd52202930b7e8db48bee5a6fc6b1f438e822a23 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sat, 14 Aug 2010 21:44:51 +0900 Subject: nilfs2: use checkpoint tree for mount check of snapshots This rewrites nilfs_checkpoint_is_mounted() function so that it decides whether a checkpoint is mounted by whether the corresponding root object is found in checkpoint tree. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/the_nilfs.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index f1d5992..89c7856 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -954,26 +954,20 @@ struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, int snapshot_mount) { - struct nilfs_sb_info *sbi; - int ret = 0; + struct nilfs_root *root; + int ret; - down_read(&nilfs->ns_super_sem); - if (cno == 0 || cno > nilfs->ns_cno) - goto out_unlock; + if (cno < 0 || cno > nilfs->ns_cno) + return false; - list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { - if (sbi->s_snapshot_cno == cno && - (!snapshot_mount || nilfs_test_opt(sbi, SNAPSHOT))) { - /* exclude read-only mounts */ - ret++; - break; - } - } - /* for protecting recent checkpoints */ if (cno >= nilfs_last_cno(nilfs)) - ret++; + return true; /* protect recent checkpoints */ - out_unlock: - up_read(&nilfs->ns_super_sem); + ret = false; + root = nilfs_lookup_root(nilfs, cno); + if (root) { + ret = true; + nilfs_put_root(root); + } return ret; } -- cgit v1.1 From dc3d3b810a644dfa329efaa230cd514226f8981d Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 15 Aug 2010 23:33:57 +0900 Subject: nilfs2: deny write access to inodes in snapshots Snapshots of nilfs are read-only. After super block instances (sb) will be unified, nilfs will need to check write access by a way other than implicit test with IS_RDONLY(inode). This is because IS_RDONLY() refers to MS_RDONLY bit of inode->i_sb->s_flags and it will become inaccurate after the unification of sb. To prepare for the issue, this uses i_op->permission to deny write access to inodes in snapshots. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/inode.c | 11 +++++++++++ fs/nilfs2/namei.c | 1 + fs/nilfs2/nilfs.h | 4 +--- 3 files changed, 13 insertions(+), 3 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index ca09e43..3efef0e 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -764,6 +764,17 @@ out_err: return err; } +int nilfs_permission(struct inode *inode, int mask) +{ + struct nilfs_root *root = NILFS_I(inode)->i_root; + + if ((mask & MAY_WRITE) && root && + root->cno != NILFS_CPTREE_CURRENT_CNO) + return -EROFS; /* snapshot is not writable */ + + return generic_permission(inode, mask, NULL); +} + int nilfs_load_inode_block(struct nilfs_sb_info *sbi, struct inode *inode, struct buffer_head **pbh) { diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index a65f465..185d160 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -588,6 +588,7 @@ const struct inode_operations nilfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, + .permission = nilfs_permission, }; const struct export_operations nilfs_export_ops = { diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 3870c10..cf5507a 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -201,12 +201,9 @@ static inline struct inode *nilfs_dat_inode(const struct the_nilfs *nilfs) */ #ifdef CONFIG_NILFS_POSIX_ACL #error "NILFS: not yet supported POSIX ACL" -extern int nilfs_permission(struct inode *, int, struct nameidata *); extern int nilfs_acl_chmod(struct inode *); extern int nilfs_init_acl(struct inode *, struct inode *); #else -#define nilfs_permission NULL - static inline int nilfs_acl_chmod(struct inode *inode) { return 0; @@ -256,6 +253,7 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *); extern void nilfs_truncate(struct inode *); extern void nilfs_evict_inode(struct inode *); extern int nilfs_setattr(struct dentry *, struct iattr *); +int nilfs_permission(struct inode *inode, int mask); extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *, struct buffer_head **); extern int nilfs_inode_dirty(struct inode *); -- cgit v1.1 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') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index acfa74e..1e12930 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.1 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') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 1e12930..ebeb746 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.1 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/sb.h | 5 -- fs/nilfs2/super.c | 216 +++++++++++++++++++++++--------------------------- fs/nilfs2/the_nilfs.c | 89 +-------------------- fs/nilfs2/the_nilfs.h | 16 ---- 4 files changed, 101 insertions(+), 225 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h index 3cc3675..35a0715 100644 --- a/fs/nilfs2/sb.h +++ b/fs/nilfs2/sb.h @@ -42,9 +42,6 @@ struct nilfs_sc_info; * NILFS super-block data in memory */ struct nilfs_sb_info { - /* Snapshot status */ - __u64 s_snapshot_cno; /* Checkpoint number */ - /* Mount options */ unsigned long s_mount_opt; uid_t s_resuid; @@ -57,8 +54,6 @@ struct nilfs_sb_info { /* Fundamental members */ struct super_block *s_super; /* reverse pointer to super_block */ struct the_nilfs *s_nilfs; - struct list_head s_list; /* list head for nilfs->ns_supers */ - atomic_t s_count; /* reference count */ /* Segment constructor */ struct list_head s_dirty_files; /* dirty files list */ diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index ebeb746..2e58e7c 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. */ diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 89c7856..960c287 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -82,11 +82,9 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) atomic_set(&nilfs->ns_count, 1); atomic_set(&nilfs->ns_ndirtyblks, 0); init_rwsem(&nilfs->ns_sem); - init_rwsem(&nilfs->ns_super_sem); mutex_init(&nilfs->ns_mount_mutex); init_rwsem(&nilfs->ns_writer_sem); INIT_LIST_HEAD(&nilfs->ns_list); - INIT_LIST_HEAD(&nilfs->ns_supers); INIT_LIST_HEAD(&nilfs->ns_gc_inodes); spin_lock_init(&nilfs->ns_last_segment_lock); nilfs->ns_cptree = RB_ROOT; @@ -307,15 +305,6 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) int valid_fs = nilfs_valid_fs(nilfs); int err; - if (nilfs_loaded(nilfs)) { - if (valid_fs || - ((s_flags & MS_RDONLY) && nilfs_test_opt(sbi, NORECOVERY))) - return 0; - printk(KERN_ERR "NILFS: the filesystem is in an incomplete " - "recovery state.\n"); - return -EINVAL; - } - if (!valid_fs) { printk(KERN_WARNING "NILFS warning: mounting unchecked fs\n"); if (s_flags & MS_RDONLY) { @@ -632,12 +621,7 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, * * init_nilfs() performs common initialization per block device (e.g. * reading the super block, getting disk layout information, initializing - * shared fields in the_nilfs). It takes on some portion of the jobs - * typically done by a fill_super() routine. This division arises from - * the nature that multiple NILFS instances may be simultaneously - * mounted on a device. - * For multiple mounts on the same device, only the first mount - * invokes these tasks. + * shared fields in the_nilfs). * * Return Value: On success, 0 is returned. On error, a negative error * code is returned. @@ -651,27 +635,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) int err; down_write(&nilfs->ns_sem); - if (nilfs_init(nilfs)) { - /* Load values from existing the_nilfs */ - sbp = nilfs->ns_sbp[0]; - err = nilfs_store_magic_and_option(sb, sbp, data); - if (err) - goto out; - - err = nilfs_check_feature_compatibility(sb, sbp); - if (err) - goto out; - - blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); - if (sb->s_blocksize != blocksize && - !sb_set_blocksize(sb, blocksize)) { - printk(KERN_ERR "NILFS: blocksize %d unfit to device\n", - blocksize); - err = -EINVAL; - } - sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits); - goto out; - } blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); if (!blocksize) { @@ -901,56 +864,6 @@ void nilfs_put_root(struct nilfs_root *root) } } -/** - * nilfs_find_sbinfo - find existing nilfs_sb_info structure - * @nilfs: nilfs object - * @rw_mount: mount type (non-zero value for read/write mount) - * @cno: checkpoint number (zero for read-only mount) - * - * nilfs_find_sbinfo() returns the nilfs_sb_info structure which - * @rw_mount and @cno (in case of snapshots) matched. If no instance - * was found, NULL is returned. Although the super block instance can - * be unmounted after this function returns, the nilfs_sb_info struct - * is kept on memory until nilfs_put_sbinfo() is called. - */ -struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, - int rw_mount, __u64 cno) -{ - struct nilfs_sb_info *sbi; - - down_read(&nilfs->ns_super_sem); - /* - * The SNAPSHOT flag and sb->s_flags are supposed to be - * protected with nilfs->ns_super_sem. - */ - sbi = nilfs->ns_current; - if (rw_mount) { - if (sbi && !(sbi->s_super->s_flags & MS_RDONLY)) - goto found; /* read/write mount */ - else - goto out; - } else if (cno == 0) { - if (sbi && (sbi->s_super->s_flags & MS_RDONLY)) - goto found; /* read-only mount */ - else - goto out; - } - - list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { - if (nilfs_test_opt(sbi, SNAPSHOT) && - sbi->s_snapshot_cno == cno) - goto found; /* snapshot mount */ - } - out: - up_read(&nilfs->ns_super_sem); - return NULL; - - found: - atomic_inc(&sbi->s_count); - up_read(&nilfs->ns_super_sem); - return sbi; -} - int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, int snapshot_mount) { diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 0afede6..7b43693 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -52,16 +52,13 @@ enum { * @ns_bdi: backing dev info * @ns_writer: back pointer to writable nilfs_sb_info * @ns_sem: semaphore for shared states - * @ns_super_sem: semaphore for global operations across super block instances * @ns_mount_mutex: mutex protecting mount process of nilfs * @ns_writer_sem: semaphore protecting ns_writer attach/detach - * @ns_current: back pointer to current mount * @ns_sbh: buffer heads of on-disk super blocks * @ns_sbp: pointers to super block data * @ns_sbwtime: previous write time of super block * @ns_sbwcount: write count of super block * @ns_sbsize: size of valid data in super block - * @ns_supers: list of nilfs super block structs * @ns_seg_seq: segment sequence counter * @ns_segnum: index number of the latest full segment. * @ns_nextnum: index number of the full segment index to be used next @@ -104,17 +101,10 @@ struct the_nilfs { struct backing_dev_info *ns_bdi; struct nilfs_sb_info *ns_writer; struct rw_semaphore ns_sem; - struct rw_semaphore ns_super_sem; struct mutex ns_mount_mutex; struct rw_semaphore ns_writer_sem; /* - * components protected by ns_super_sem - */ - struct nilfs_sb_info *ns_current; - struct list_head ns_supers; - - /* * used for * - loading the latest checkpoint exclusively. * - allocating a new full segment. @@ -294,12 +284,6 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) up_write(&nilfs->ns_writer_sem); } -static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) -{ - if (atomic_dec_and_test(&sbi->s_count)) - kfree(sbi); -} - static inline int nilfs_valid_fs(struct the_nilfs *nilfs) { unsigned valid_fs; -- cgit v1.1 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/ioctl.c | 4 +-- fs/nilfs2/super.c | 67 +++++++++++++++------------------------------ fs/nilfs2/the_nilfs.c | 75 ++++----------------------------------------------- fs/nilfs2/the_nilfs.h | 16 ++--------- 4 files changed, 31 insertions(+), 131 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 2ee6843..338858f 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -117,7 +117,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, if (copy_from_user(&cpmode, argp, sizeof(cpmode))) goto out; - mutex_lock(&nilfs->ns_mount_mutex); + down_read(&inode->i_sb->s_umount); nilfs_transaction_begin(inode->i_sb, &ti, 0); ret = nilfs_cpfile_change_cpmode( @@ -127,7 +127,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp, else nilfs_transaction_commit(inode->i_sb); /* never fails */ - mutex_unlock(&nilfs->ns_mount_mutex); + up_read(&inode->i_sb->s_umount); out: mnt_drop_write(filp->f_path.mnt); return ret; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 2e58e7c..5893cb2 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; } diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 960c287..6eeb4f0 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -35,9 +35,6 @@ #include "segbuf.h" -static LIST_HEAD(nilfs_objects); -static DEFINE_SPINLOCK(nilfs_lock); - static int nilfs_valid_sb(struct nilfs_super_block *sbp); void nilfs_set_last_segment(struct the_nilfs *nilfs, @@ -61,16 +58,13 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, } /** - * alloc_nilfs - allocate the_nilfs structure + * alloc_nilfs - allocate a nilfs object * @bdev: block device to which the_nilfs is related * - * alloc_nilfs() allocates memory for the_nilfs and - * initializes its reference count and locks. - * * Return Value: On success, pointer to the_nilfs is returned. * On error, NULL is returned. */ -static struct the_nilfs *alloc_nilfs(struct block_device *bdev) +struct the_nilfs *alloc_nilfs(struct block_device *bdev) { struct the_nilfs *nilfs; @@ -79,12 +73,9 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) return NULL; nilfs->ns_bdev = bdev; - atomic_set(&nilfs->ns_count, 1); atomic_set(&nilfs->ns_ndirtyblks, 0); init_rwsem(&nilfs->ns_sem); - mutex_init(&nilfs->ns_mount_mutex); init_rwsem(&nilfs->ns_writer_sem); - INIT_LIST_HEAD(&nilfs->ns_list); INIT_LIST_HEAD(&nilfs->ns_gc_inodes); spin_lock_init(&nilfs->ns_last_segment_lock); nilfs->ns_cptree = RB_ROOT; @@ -95,67 +86,11 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev) } /** - * find_or_create_nilfs - find or create nilfs object - * @bdev: block device to which the_nilfs is related - * - * find_nilfs() looks up an existent nilfs object created on the - * device and gets the reference count of the object. If no nilfs object - * is found on the device, a new nilfs object is allocated. - * - * Return Value: On success, pointer to the nilfs object is returned. - * On error, NULL is returned. - */ -struct the_nilfs *find_or_create_nilfs(struct block_device *bdev) -{ - struct the_nilfs *nilfs, *new = NULL; - - retry: - spin_lock(&nilfs_lock); - list_for_each_entry(nilfs, &nilfs_objects, ns_list) { - if (nilfs->ns_bdev == bdev) { - get_nilfs(nilfs); - spin_unlock(&nilfs_lock); - if (new) - put_nilfs(new); - return nilfs; /* existing object */ - } - } - if (new) { - list_add_tail(&new->ns_list, &nilfs_objects); - spin_unlock(&nilfs_lock); - return new; /* new object */ - } - spin_unlock(&nilfs_lock); - - new = alloc_nilfs(bdev); - if (new) - goto retry; - return NULL; /* insufficient memory */ -} - -/** - * put_nilfs - release a reference to the_nilfs - * @nilfs: the_nilfs structure to be released - * - * put_nilfs() decrements a reference counter of the_nilfs. - * If the reference count reaches zero, the_nilfs is freed. + * destroy_nilfs - destroy nilfs object + * @nilfs: nilfs object to be released */ -void put_nilfs(struct the_nilfs *nilfs) +void destroy_nilfs(struct the_nilfs *nilfs) { - spin_lock(&nilfs_lock); - if (!atomic_dec_and_test(&nilfs->ns_count)) { - spin_unlock(&nilfs_lock); - return; - } - list_del_init(&nilfs->ns_list); - spin_unlock(&nilfs_lock); - - /* - * Increment of ns_count never occurs below because the caller - * of get_nilfs() holds at least one reference to the_nilfs. - * Thus its exclusion control is not required here. - */ - might_sleep(); if (nilfs_loaded(nilfs)) { nilfs_mdt_destroy(nilfs->ns_sufile); diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 7b43693..1908dc7 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -46,13 +46,10 @@ enum { /** * struct the_nilfs - struct to supervise multiple nilfs mount points * @ns_flags: flags - * @ns_count: reference count - * @ns_list: list head for nilfs_list * @ns_bdev: block device * @ns_bdi: backing dev info * @ns_writer: back pointer to writable nilfs_sb_info * @ns_sem: semaphore for shared states - * @ns_mount_mutex: mutex protecting mount process of nilfs * @ns_writer_sem: semaphore protecting ns_writer attach/detach * @ns_sbh: buffer heads of on-disk super blocks * @ns_sbp: pointers to super block data @@ -94,14 +91,11 @@ enum { */ struct the_nilfs { unsigned long ns_flags; - atomic_t ns_count; - struct list_head ns_list; struct block_device *ns_bdev; struct backing_dev_info *ns_bdi; struct nilfs_sb_info *ns_writer; struct rw_semaphore ns_sem; - struct mutex ns_mount_mutex; struct rw_semaphore ns_writer_sem; /* @@ -239,8 +233,8 @@ static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs) } void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); -struct the_nilfs *find_or_create_nilfs(struct block_device *); -void put_nilfs(struct the_nilfs *); +struct the_nilfs *alloc_nilfs(struct block_device *bdev); +void destroy_nilfs(struct the_nilfs *nilfs); int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t); @@ -256,12 +250,6 @@ void nilfs_fall_back_super_block(struct the_nilfs *); void nilfs_swap_super_block(struct the_nilfs *); -static inline void get_nilfs(struct the_nilfs *nilfs) -{ - /* Caller must have at least one reference of the_nilfs. */ - atomic_inc(&nilfs->ns_count); -} - static inline void nilfs_get_root(struct nilfs_root *root) { atomic_inc(&root->count); -- cgit v1.1 From 518d1a6a1d6610a014875a2fe3252e89b6260d2f Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Fri, 20 Aug 2010 23:40:54 +0900 Subject: nilfs2: allow nilfs_clear_inode to clear metadata file inodes Allows clear inode function (nilfs_clear_inode) to handle metadata files that uses bitmap-based object alloctor. DAT and ifile correspond to this. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/inode.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 3efef0e..5485dd1 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -674,6 +674,7 @@ void nilfs_truncate(struct inode *inode) static void nilfs_clear_inode(struct inode *inode) { struct nilfs_inode_info *ii = NILFS_I(inode); + struct nilfs_mdt_info *mdi = NILFS_MDT(inode); /* * Free resources allocated in nilfs_read_inode(), here. @@ -682,6 +683,9 @@ static void nilfs_clear_inode(struct inode *inode) brelse(ii->i_bh); ii->i_bh = NULL; + if (mdi && mdi->mi_palloc_cache) + nilfs_palloc_destroy_cache(inode); + if (test_bit(NILFS_I_BMAP, &ii->i_state)) nilfs_bmap_clear(ii->i_bmap); -- cgit v1.1 From adbb39b5485b72dca963a2bc9b1b22bfc19d4967 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 5 Sep 2010 10:14:43 +0900 Subject: nilfs2: do not allocate nilfs_mdt_info structure to gc-inodes GC-inode now doesn't need the nilfs_mdt_info structure and there is no reason that it is a sort of metadata files. This stops the allocation and makes them not dependent on metadata file routines. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/gcinode.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c index 34f8f84..33ad25d 100644 --- a/fs/nilfs2/gcinode.c +++ b/fs/nilfs2/gcinode.c @@ -168,7 +168,7 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *bh) } nilfs_btnode_mark_dirty(bh); } else { - nilfs_mdt_mark_buffer_dirty(bh); + nilfs_mark_buffer_dirty(bh); } return 0; } @@ -177,24 +177,24 @@ int nilfs_init_gcinode(struct inode *inode) { struct nilfs_inode_info *ii = NILFS_I(inode); struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs; - int ret; - ret = nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0); - if (!ret) { - inode->i_mapping->a_ops = &def_gcinode_aops; + inode->i_mode = S_IFREG; + mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS); + inode->i_mapping->a_ops = &def_gcinode_aops; + inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; - ii->i_flags = 0; - nilfs_bmap_init_gc(ii->i_bmap); + ii->i_flags = 0; + nilfs_bmap_init_gc(ii->i_bmap); - /* - * Add the inode to GC inode list. Garbage Collection - * is serialized and no two processes manipulate the - * list simultaneously. - */ - igrab(inode); - list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); - } - return ret; + /* + * Add the inode to GC inode list. Garbage Collection + * is serialized and no two processes manipulate the + * list simultaneously. + */ + igrab(inode); + list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); + + return 0; } /** -- cgit v1.1 From a8070dd365dd995f6139a2fc3aeee10159bdcc45 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 30 Aug 2010 23:42:18 +0900 Subject: nilfs2: add routines to save and restore bmap state This adds routines to save and restore the state of bmap structure. The bmap state is stored in a given nilfs_bmap_store object. These routines will be used to roll back the state of dat inode without using gcdat inode. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/bmap.c | 18 ++++++++++++++++++ fs/nilfs2/bmap.h | 8 ++++++++ 2 files changed, 26 insertions(+) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 3dbdc1d..0024440 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -548,3 +548,21 @@ void nilfs_bmap_commit_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap) lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; } + +void nilfs_bmap_save(const struct nilfs_bmap *bmap, + struct nilfs_bmap_store *store) +{ + memcpy(store->data, bmap->b_u.u_data, sizeof(store->data)); + store->last_allocated_key = bmap->b_last_allocated_key; + store->last_allocated_ptr = bmap->b_last_allocated_ptr; + store->state = bmap->b_state; +} + +void nilfs_bmap_restore(struct nilfs_bmap *bmap, + const struct nilfs_bmap_store *store) +{ + memcpy(bmap->b_u.u_data, store->data, sizeof(store->data)); + bmap->b_last_allocated_key = store->last_allocated_key; + bmap->b_last_allocated_ptr = store->last_allocated_ptr; + bmap->b_state = store->state; +} diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index a20569b..5f3339e 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -135,6 +135,12 @@ struct nilfs_bmap { /* state */ #define NILFS_BMAP_DIRTY 0x00000001 +struct nilfs_bmap_store { + __le64 data[NILFS_BMAP_SIZE / sizeof(__le64)]; + __u64 last_allocated_key; + __u64 last_allocated_ptr; + int state; +}; int nilfs_bmap_test_and_clear_dirty(struct nilfs_bmap *); int nilfs_bmap_read(struct nilfs_bmap *, struct nilfs_inode *); @@ -156,6 +162,8 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *); void nilfs_bmap_init_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); +void nilfs_bmap_save(const struct nilfs_bmap *, struct nilfs_bmap_store *); +void nilfs_bmap_restore(struct nilfs_bmap *, const struct nilfs_bmap_store *); static inline int nilfs_bmap_lookup(struct nilfs_bmap *bmap, __u64 key, __u64 *ptr) -- cgit v1.1 From ebdfed4dc59d177cf26013a0c9b8ee9652e9a140 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Mon, 6 Sep 2010 12:05:43 +0900 Subject: nilfs2: add routines to roll back state of DAT file This adds optional function to metadata files which makes a copy of bmap, page caches, and b-tree node cache, and rolls back to the copy as needed. This enhancement is intended to displace gcdat inode that provides a similar function in a different way. In this patch, nilfs_shadow_map structure is added to store a copy of the foregoing states. nilfs_mdt_setup_shadow_map relates this structure to a metadata file. And, nilfs_mdt_save_to_shadow_map() and nilfs_mdt_restore_from_shadow_map() provides save and restore functions respectively. Finally, nilfs_mdt_clear_shadow_map() clears states of nilfs_shadow_map. The copy of b-tree node cache and page cache is made by duplicating only dirty pages into corresponding caches in nilfs_shadow_map. Their restoration is done by clearing dirty pages from original caches and by copying dirty pages back from nilfs_shadow_map. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/btnode.c | 17 ++------- fs/nilfs2/mdt.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++--- fs/nilfs2/mdt.h | 14 ++++++++ fs/nilfs2/page.c | 25 +++++++++++++ fs/nilfs2/page.h | 4 +++ 5 files changed, 145 insertions(+), 19 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/btnode.c b/fs/nilfs2/btnode.c index f78ab10..5115814c 100644 --- a/fs/nilfs2/btnode.c +++ b/fs/nilfs2/btnode.c @@ -37,15 +37,7 @@ void nilfs_btnode_cache_init_once(struct address_space *btnc) { - memset(btnc, 0, sizeof(*btnc)); - INIT_RADIX_TREE(&btnc->page_tree, GFP_ATOMIC); - spin_lock_init(&btnc->tree_lock); - INIT_LIST_HEAD(&btnc->private_list); - spin_lock_init(&btnc->private_lock); - - spin_lock_init(&btnc->i_mmap_lock); - INIT_RAW_PRIO_TREE_ROOT(&btnc->i_mmap); - INIT_LIST_HEAD(&btnc->i_mmap_nonlinear); + nilfs_mapping_init_once(btnc); } static const struct address_space_operations def_btnode_aops = { @@ -55,12 +47,7 @@ static const struct address_space_operations def_btnode_aops = { void nilfs_btnode_cache_init(struct address_space *btnc, struct backing_dev_info *bdi) { - btnc->host = NULL; /* can safely set to host inode ? */ - btnc->flags = 0; - mapping_set_gfp_mask(btnc, GFP_NOFS); - btnc->assoc_mapping = NULL; - btnc->backing_dev_info = bdi; - btnc->a_ops = &def_btnode_aops; + nilfs_mapping_init(btnc, bdi, &def_btnode_aops); } void nilfs_btnode_cache_clear(struct address_space *btnc) diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 73e5da3..00664686 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -398,16 +398,22 @@ int nilfs_mdt_fetch_dirty(struct inode *inode) static int nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) { - struct inode *inode = container_of(page->mapping, - struct inode, i_data); - struct super_block *sb = inode->i_sb; - struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs; + struct inode *inode; + struct super_block *sb; + struct the_nilfs *nilfs; struct nilfs_sb_info *writer = NULL; int err = 0; redirty_page_for_writepage(wbc, page); unlock_page(page); + inode = page->mapping->host; + if (!inode) + return 0; + + sb = inode->i_sb; + nilfs = NILFS_MDT(inode)->mi_nilfs; + if (page->mapping->assoc_mapping) return 0; /* Do not request flush for shadow page cache */ if (!sb) { @@ -567,6 +573,96 @@ void nilfs_mdt_set_shadow(struct inode *orig, struct inode *shadow) &NILFS_I(orig)->i_btnode_cache; } +static const struct address_space_operations shadow_map_aops = { + .sync_page = block_sync_page, +}; + +/** + * nilfs_mdt_setup_shadow_map - setup shadow map and bind it to metadata file + * @inode: inode of the metadata file + * @shadow: shadow mapping + */ +int nilfs_mdt_setup_shadow_map(struct inode *inode, + struct nilfs_shadow_map *shadow) +{ + struct nilfs_mdt_info *mi = NILFS_MDT(inode); + struct backing_dev_info *bdi = NILFS_I_NILFS(inode)->ns_bdi; + + INIT_LIST_HEAD(&shadow->frozen_buffers); + nilfs_mapping_init_once(&shadow->frozen_data); + nilfs_mapping_init(&shadow->frozen_data, bdi, &shadow_map_aops); + nilfs_mapping_init_once(&shadow->frozen_btnodes); + nilfs_mapping_init(&shadow->frozen_btnodes, bdi, &shadow_map_aops); + mi->mi_shadow = shadow; + return 0; +} + +/** + * nilfs_mdt_save_to_shadow_map - copy bmap and dirty pages to shadow map + * @inode: inode of the metadata file + */ +int nilfs_mdt_save_to_shadow_map(struct inode *inode) +{ + struct nilfs_mdt_info *mi = NILFS_MDT(inode); + struct nilfs_inode_info *ii = NILFS_I(inode); + struct nilfs_shadow_map *shadow = mi->mi_shadow; + int ret; + + ret = nilfs_copy_dirty_pages(&shadow->frozen_data, inode->i_mapping); + if (ret) + goto out; + + ret = nilfs_copy_dirty_pages(&shadow->frozen_btnodes, + &ii->i_btnode_cache); + if (ret) + goto out; + + nilfs_bmap_save(ii->i_bmap, &shadow->bmap_store); + out: + return ret; +} + +/** + * nilfs_mdt_restore_from_shadow_map - restore dirty pages and bmap state + * @inode: inode of the metadata file + */ +void nilfs_mdt_restore_from_shadow_map(struct inode *inode) +{ + struct nilfs_mdt_info *mi = NILFS_MDT(inode); + struct nilfs_inode_info *ii = NILFS_I(inode); + struct nilfs_shadow_map *shadow = mi->mi_shadow; + + down_write(&mi->mi_sem); + + if (mi->mi_palloc_cache) + nilfs_palloc_clear_cache(inode); + + nilfs_clear_dirty_pages(inode->i_mapping); + nilfs_copy_back_pages(inode->i_mapping, &shadow->frozen_data); + + nilfs_clear_dirty_pages(&ii->i_btnode_cache); + nilfs_copy_back_pages(&ii->i_btnode_cache, &shadow->frozen_btnodes); + + nilfs_bmap_restore(ii->i_bmap, &shadow->bmap_store); + + up_write(&mi->mi_sem); +} + +/** + * nilfs_mdt_clear_shadow_map - truncate pages in shadow map caches + * @inode: inode of the metadata file + */ +void nilfs_mdt_clear_shadow_map(struct inode *inode) +{ + struct nilfs_mdt_info *mi = NILFS_MDT(inode); + struct nilfs_shadow_map *shadow = mi->mi_shadow; + + down_write(&mi->mi_sem); + truncate_inode_pages(&shadow->frozen_data, 0); + truncate_inode_pages(&shadow->frozen_btnodes, 0); + up_write(&mi->mi_sem); +} + static void nilfs_mdt_clear(struct inode *inode) { struct nilfs_inode_info *ii = NILFS_I(inode); diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index f445602..e7f0d15 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -28,6 +28,13 @@ #include "nilfs.h" #include "page.h" +struct nilfs_shadow_map { + struct nilfs_bmap_store bmap_store; + struct address_space frozen_data; + struct address_space frozen_btnodes; + struct list_head frozen_buffers; +}; + /** * struct nilfs_mdt_info - on-memory private data of meta data files * @mi_nilfs: back pointer to the_nilfs struct @@ -37,6 +44,7 @@ * @mi_first_entry_offset: offset to the first entry * @mi_entries_per_block: number of entries in a block * @mi_palloc_cache: persistent object allocator cache + * @mi_shadow: shadow of bmap and page caches * @mi_blocks_per_group: number of blocks in a group * @mi_blocks_per_desc_block: number of blocks per descriptor block */ @@ -48,6 +56,7 @@ struct nilfs_mdt_info { unsigned mi_first_entry_offset; unsigned long mi_entries_per_block; struct nilfs_palloc_cache *mi_palloc_cache; + struct nilfs_shadow_map *mi_shadow; unsigned long mi_blocks_per_group; unsigned long mi_blocks_per_desc_block; }; @@ -86,6 +95,11 @@ void nilfs_mdt_destroy(struct inode *); void nilfs_mdt_set_entry_size(struct inode *, unsigned, unsigned); void nilfs_mdt_set_shadow(struct inode *, struct inode *); +int nilfs_mdt_setup_shadow_map(struct inode *inode, + struct nilfs_shadow_map *shadow); +int nilfs_mdt_save_to_shadow_map(struct inode *inode); +void nilfs_mdt_restore_from_shadow_map(struct inode *inode); +void nilfs_mdt_clear_shadow_map(struct inode *inode); #define nilfs_mdt_mark_buffer_dirty(bh) nilfs_mark_buffer_dirty(bh) diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index aab11db..6384ac1 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -513,6 +513,31 @@ unsigned nilfs_page_count_clean_buffers(struct page *page, } return nc; } + +void nilfs_mapping_init_once(struct address_space *mapping) +{ + memset(mapping, 0, sizeof(*mapping)); + INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC); + spin_lock_init(&mapping->tree_lock); + INIT_LIST_HEAD(&mapping->private_list); + spin_lock_init(&mapping->private_lock); + + spin_lock_init(&mapping->i_mmap_lock); + INIT_RAW_PRIO_TREE_ROOT(&mapping->i_mmap); + INIT_LIST_HEAD(&mapping->i_mmap_nonlinear); +} + +void nilfs_mapping_init(struct address_space *mapping, + struct backing_dev_info *bdi, + const struct address_space_operations *aops) +{ + mapping->host = NULL; + mapping->flags = 0; + mapping_set_gfp_mask(mapping, GFP_NOFS); + mapping->assoc_mapping = NULL; + mapping->backing_dev_info = bdi; + mapping->a_ops = aops; +} /* * NILFS2 needs clear_page_dirty() in the following two cases: diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h index f53d8da..6ec4f49 100644 --- a/fs/nilfs2/page.h +++ b/fs/nilfs2/page.h @@ -59,6 +59,10 @@ void nilfs_free_private_page(struct page *); int nilfs_copy_dirty_pages(struct address_space *, struct address_space *); void nilfs_copy_back_pages(struct address_space *, struct address_space *); void nilfs_clear_dirty_pages(struct address_space *); +void nilfs_mapping_init_once(struct address_space *mapping); +void nilfs_mapping_init(struct address_space *mapping, + struct backing_dev_info *bdi, + const struct address_space_operations *aops); unsigned nilfs_page_count_clean_buffers(struct page *, unsigned, unsigned); #define NILFS_PAGE_BUG(page, m, a...) \ -- cgit v1.1 From b1f6a4f294088b3fcf9ae67915ca550a1ded2819 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Tue, 31 Aug 2010 11:40:34 +0900 Subject: nilfs2: add routines to redirect access to buffers of DAT file During garbage collection (GC), DAT file, which converts virtual block number to real block number, may return disk block number that is not yet written to the device. To avoid access to unwritten blocks, the current implementation stores changes to the caches of GCDAT during GC and atomically commit the changes into the DAT file after they are written to the device. This patch, instead, adds a function that makes a copy of specified buffer and stores it in nilfs_shadow_map, and a function to get the backup copy as needed (nilfs_mdt_freeze_buffer and nilfs_mdt_get_frozen_buffer respectively). Before DAT changes block number in an entry block, it makes a copy and redirect access to the buffer so that address conversion function (i.e. nilfs_dat_translate) refers to the old address saved in the copy. This patch gives requisites for such redirection. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/mdt.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/nilfs2/mdt.h | 3 +++ fs/nilfs2/page.c | 2 ++ fs/nilfs2/page.h | 2 ++ fs/nilfs2/segment.c | 1 + 5 files changed, 75 insertions(+) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 00664686..532f85a 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -622,6 +622,72 @@ int nilfs_mdt_save_to_shadow_map(struct inode *inode) return ret; } +int nilfs_mdt_freeze_buffer(struct inode *inode, struct buffer_head *bh) +{ + struct nilfs_shadow_map *shadow = NILFS_MDT(inode)->mi_shadow; + struct buffer_head *bh_frozen; + struct page *page; + int blkbits = inode->i_blkbits; + int ret = -ENOMEM; + + page = grab_cache_page(&shadow->frozen_data, bh->b_page->index); + if (!page) + return ret; + + if (!page_has_buffers(page)) + create_empty_buffers(page, 1 << blkbits, 0); + + bh_frozen = nilfs_page_get_nth_block(page, bh_offset(bh) >> blkbits); + if (bh_frozen) { + if (!buffer_uptodate(bh_frozen)) + nilfs_copy_buffer(bh_frozen, bh); + if (list_empty(&bh_frozen->b_assoc_buffers)) { + list_add_tail(&bh_frozen->b_assoc_buffers, + &shadow->frozen_buffers); + set_buffer_nilfs_redirected(bh); + } else { + brelse(bh_frozen); /* already frozen */ + } + ret = 0; + } + unlock_page(page); + page_cache_release(page); + return ret; +} + +struct buffer_head * +nilfs_mdt_get_frozen_buffer(struct inode *inode, struct buffer_head *bh) +{ + struct nilfs_shadow_map *shadow = NILFS_MDT(inode)->mi_shadow; + struct buffer_head *bh_frozen = NULL; + struct page *page; + int n; + + page = find_lock_page(&shadow->frozen_data, bh->b_page->index); + if (page) { + if (page_has_buffers(page)) { + n = bh_offset(bh) >> inode->i_blkbits; + bh_frozen = nilfs_page_get_nth_block(page, n); + } + unlock_page(page); + page_cache_release(page); + } + return bh_frozen; +} + +static void nilfs_release_frozen_buffers(struct nilfs_shadow_map *shadow) +{ + struct list_head *head = &shadow->frozen_buffers; + struct buffer_head *bh; + + while (!list_empty(head)) { + bh = list_first_entry(head, struct buffer_head, + b_assoc_buffers); + list_del_init(&bh->b_assoc_buffers); + brelse(bh); /* drop ref-count to make it releasable */ + } +} + /** * nilfs_mdt_restore_from_shadow_map - restore dirty pages and bmap state * @inode: inode of the metadata file @@ -658,6 +724,7 @@ void nilfs_mdt_clear_shadow_map(struct inode *inode) struct nilfs_shadow_map *shadow = mi->mi_shadow; down_write(&mi->mi_sem); + nilfs_release_frozen_buffers(shadow); truncate_inode_pages(&shadow->frozen_data, 0); truncate_inode_pages(&shadow->frozen_btnodes, 0); up_write(&mi->mi_sem); diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index e7f0d15..e60bbfe 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -100,6 +100,9 @@ int nilfs_mdt_setup_shadow_map(struct inode *inode, int nilfs_mdt_save_to_shadow_map(struct inode *inode); void nilfs_mdt_restore_from_shadow_map(struct inode *inode); void nilfs_mdt_clear_shadow_map(struct inode *inode); +int nilfs_mdt_freeze_buffer(struct inode *inode, struct buffer_head *bh); +struct buffer_head *nilfs_mdt_get_frozen_buffer(struct inode *inode, + struct buffer_head *bh); #define nilfs_mdt_mark_buffer_dirty(bh) nilfs_mark_buffer_dirty(bh) diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 6384ac1..7083344 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -131,6 +131,7 @@ void nilfs_forget_buffer(struct buffer_head *bh) lock_buffer(bh); clear_buffer_nilfs_volatile(bh); clear_buffer_nilfs_checked(bh); + clear_buffer_nilfs_redirected(bh); clear_buffer_dirty(bh); if (nilfs_page_buffers_clean(page)) __nilfs_clear_page_dirty(page); @@ -483,6 +484,7 @@ void nilfs_clear_dirty_pages(struct address_space *mapping) clear_buffer_dirty(bh); clear_buffer_nilfs_volatile(bh); clear_buffer_nilfs_checked(bh); + clear_buffer_nilfs_redirected(bh); clear_buffer_uptodate(bh); clear_buffer_mapped(bh); unlock_buffer(bh); diff --git a/fs/nilfs2/page.h b/fs/nilfs2/page.h index 6ec4f49..fb9e8a8 100644 --- a/fs/nilfs2/page.h +++ b/fs/nilfs2/page.h @@ -35,12 +35,14 @@ enum { BH_NILFS_Node, BH_NILFS_Volatile, BH_NILFS_Checked, + BH_NILFS_Redirected, }; BUFFER_FNS(NILFS_Allocated, nilfs_allocated) /* nilfs private buffers */ BUFFER_FNS(NILFS_Node, nilfs_node) /* nilfs node buffers */ BUFFER_FNS(NILFS_Volatile, nilfs_volatile) BUFFER_FNS(NILFS_Checked, nilfs_checked) /* buffer is verified */ +BUFFER_FNS(NILFS_Redirected, nilfs_redirected) /* redirected to a copy */ void nilfs_mark_buffer_dirty(struct buffer_head *bh); diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index b75306d..91dc066 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -1908,6 +1908,7 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) set_buffer_uptodate(bh); clear_buffer_dirty(bh); clear_buffer_nilfs_volatile(bh); + clear_buffer_nilfs_redirected(bh); if (bh == segbuf->sb_super_root) { if (bh->b_page != bd_page) { end_page_writeback(bd_page); -- cgit v1.1 From c1c1d7092072093ad960db2f6c08f06705c57fa4 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 29 Aug 2010 12:44:56 +0900 Subject: nilfs2: get rid of GCDAT inode This applies prepared rollback function and redirect function of metadata file to DAT file, and eliminates GCDAT inode. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/Makefile | 2 +- fs/nilfs2/bmap.c | 16 ---------- fs/nilfs2/bmap.h | 2 -- fs/nilfs2/dat.c | 30 +++++++++++++++++- fs/nilfs2/gcdat.c | 87 --------------------------------------------------- fs/nilfs2/mdt.c | 9 ------ fs/nilfs2/mdt.h | 1 - fs/nilfs2/nilfs.h | 8 +---- fs/nilfs2/page.c | 28 ++--------------- fs/nilfs2/segment.c | 14 ++++----- fs/nilfs2/the_nilfs.c | 13 +------- fs/nilfs2/the_nilfs.h | 2 -- 12 files changed, 41 insertions(+), 171 deletions(-) delete mode 100644 fs/nilfs2/gcdat.c (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/Makefile b/fs/nilfs2/Makefile index df3e62c..85c9873 100644 --- a/fs/nilfs2/Makefile +++ b/fs/nilfs2/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_NILFS2_FS) += nilfs2.o nilfs2-y := inode.o file.o dir.o super.o namei.o page.o mdt.o \ btnode.o bmap.o btree.o direct.o dat.o recovery.o \ the_nilfs.o segbuf.o segment.o cpfile.o sufile.o \ - ifile.o alloc.o gcinode.o ioctl.o gcdat.o + ifile.o alloc.o gcinode.o ioctl.o diff --git a/fs/nilfs2/bmap.c b/fs/nilfs2/bmap.c index 0024440..8b782b0 100644 --- a/fs/nilfs2/bmap.c +++ b/fs/nilfs2/bmap.c @@ -533,22 +533,6 @@ void nilfs_bmap_init_gc(struct nilfs_bmap *bmap) nilfs_btree_init_gc(bmap); } -void nilfs_bmap_init_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap) -{ - memcpy(gcbmap, bmap, sizeof(*bmap)); - init_rwsem(&gcbmap->b_sem); - lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); - gcbmap->b_inode = &NILFS_BMAP_I(gcbmap)->vfs_inode; -} - -void nilfs_bmap_commit_gcdat(struct nilfs_bmap *gcbmap, struct nilfs_bmap *bmap) -{ - memcpy(bmap, gcbmap, sizeof(*bmap)); - init_rwsem(&bmap->b_sem); - lockdep_set_class(&bmap->b_sem, &nilfs_bmap_dat_lock_key); - bmap->b_inode = &NILFS_BMAP_I(bmap)->vfs_inode; -} - void nilfs_bmap_save(const struct nilfs_bmap *bmap, struct nilfs_bmap_store *store) { diff --git a/fs/nilfs2/bmap.h b/fs/nilfs2/bmap.h index 5f3339e..bde1c0aa2 100644 --- a/fs/nilfs2/bmap.h +++ b/fs/nilfs2/bmap.h @@ -159,8 +159,6 @@ int nilfs_bmap_lookup_at_level(struct nilfs_bmap *, __u64, int, __u64 *); int nilfs_bmap_mark(struct nilfs_bmap *, __u64, int); void nilfs_bmap_init_gc(struct nilfs_bmap *); -void nilfs_bmap_init_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); -void nilfs_bmap_commit_gcdat(struct nilfs_bmap *, struct nilfs_bmap *); void nilfs_bmap_save(const struct nilfs_bmap *, struct nilfs_bmap_store *); void nilfs_bmap_restore(struct nilfs_bmap *, const struct nilfs_bmap_store *); diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 0131467..7091c4e 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -36,6 +36,7 @@ struct nilfs_dat_info { struct nilfs_mdt_info mi; struct nilfs_palloc_cache palloc_cache; + struct nilfs_shadow_map shadow; }; static inline struct nilfs_dat_info *NILFS_DAT_I(struct inode *dat) @@ -327,6 +328,23 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) ret = nilfs_palloc_get_entry_block(dat, vblocknr, 0, &entry_bh); if (ret < 0) return ret; + + /* + * The given disk block number (blocknr) is not yet written to + * the device at this point. + * + * To prevent nilfs_dat_translate() from returning the + * uncommited block number, this makes a copy of the entry + * buffer and redirects nilfs_dat_translate() to the copy. + */ + if (!buffer_nilfs_redirected(entry_bh)) { + ret = nilfs_mdt_freeze_buffer(dat, entry_bh); + if (ret) { + brelse(entry_bh); + return ret; + } + } + kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); if (unlikely(entry->de_blocknr == cpu_to_le64(0))) { @@ -371,7 +389,7 @@ int nilfs_dat_move(struct inode *dat, __u64 vblocknr, sector_t blocknr) */ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) { - struct buffer_head *entry_bh; + struct buffer_head *entry_bh, *bh; struct nilfs_dat_entry *entry; sector_t blocknr; void *kaddr; @@ -381,6 +399,15 @@ int nilfs_dat_translate(struct inode *dat, __u64 vblocknr, sector_t *blocknrp) if (ret < 0) return ret; + if (!nilfs_doing_gc() && buffer_nilfs_redirected(entry_bh)) { + bh = nilfs_mdt_get_frozen_buffer(dat, entry_bh); + if (bh) { + WARN_ON(!buffer_uptodate(bh)); + brelse(entry_bh); + entry_bh = bh; + } + } + kaddr = kmap_atomic(entry_bh->b_page, KM_USER0); entry = nilfs_palloc_block_get_entry(dat, vblocknr, entry_bh, kaddr); blocknr = le64_to_cpu(entry->de_blocknr); @@ -468,6 +495,7 @@ struct inode *nilfs_dat_new(struct the_nilfs *nilfs, size_t entry_size) di = NILFS_DAT_I(dat); lockdep_set_class(&di->mi.mi_sem, &dat_lock_key); nilfs_palloc_setup_cache(dat, &di->palloc_cache); + nilfs_mdt_setup_shadow_map(dat, &di->shadow); } return dat; } diff --git a/fs/nilfs2/gcdat.c b/fs/nilfs2/gcdat.c deleted file mode 100644 index 84a45d1..0000000 --- a/fs/nilfs2/gcdat.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * gcdat.c - NILFS shadow DAT inode for GC - * - * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * Written by Seiji Kihara , Amagai Yoshiji , - * and Ryusuke Konishi . - * - */ - -#include -#include "nilfs.h" -#include "page.h" -#include "mdt.h" - -int nilfs_init_gcdat_inode(struct the_nilfs *nilfs) -{ - struct inode *dat = nilfs->ns_dat, *gcdat = nilfs->ns_gc_dat; - struct nilfs_inode_info *dii = NILFS_I(dat), *gii = NILFS_I(gcdat); - int err; - - gcdat->i_state = 0; - gcdat->i_blocks = dat->i_blocks; - gii->i_flags = dii->i_flags; - gii->i_state = dii->i_state | (1 << NILFS_I_GCDAT); - gii->i_cno = 0; - nilfs_bmap_init_gcdat(gii->i_bmap, dii->i_bmap); - err = nilfs_copy_dirty_pages(gcdat->i_mapping, dat->i_mapping); - if (unlikely(err)) - return err; - - return nilfs_copy_dirty_pages(&gii->i_btnode_cache, - &dii->i_btnode_cache); -} - -void nilfs_commit_gcdat_inode(struct the_nilfs *nilfs) -{ - struct inode *dat = nilfs->ns_dat, *gcdat = nilfs->ns_gc_dat; - struct nilfs_inode_info *dii = NILFS_I(dat), *gii = NILFS_I(gcdat); - struct address_space *mapping = dat->i_mapping; - struct address_space *gmapping = gcdat->i_mapping; - - down_write(&NILFS_MDT(dat)->mi_sem); - dat->i_blocks = gcdat->i_blocks; - dii->i_flags = gii->i_flags; - dii->i_state = gii->i_state & ~(1 << NILFS_I_GCDAT); - - nilfs_bmap_commit_gcdat(gii->i_bmap, dii->i_bmap); - - nilfs_palloc_clear_cache(dat); - nilfs_palloc_clear_cache(gcdat); - nilfs_clear_dirty_pages(mapping); - nilfs_copy_back_pages(mapping, gmapping); - /* note: mdt dirty flags should be cleared by segctor. */ - - nilfs_clear_dirty_pages(&dii->i_btnode_cache); - nilfs_copy_back_pages(&dii->i_btnode_cache, &gii->i_btnode_cache); - - up_write(&NILFS_MDT(dat)->mi_sem); -} - -void nilfs_clear_gcdat_inode(struct the_nilfs *nilfs) -{ - struct inode *gcdat = nilfs->ns_gc_dat; - struct nilfs_inode_info *gii = NILFS_I(gcdat); - - gcdat->i_state = I_FREEING | I_CLEAR; - gii->i_flags = 0; - - nilfs_palloc_clear_cache(gcdat); - truncate_inode_pages(gcdat->i_mapping, 0); - truncate_inode_pages(&gii->i_btnode_cache, 0); -} diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 532f85a..3bbd340 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -414,8 +414,6 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) sb = inode->i_sb; nilfs = NILFS_MDT(inode)->mi_nilfs; - if (page->mapping->assoc_mapping) - return 0; /* Do not request flush for shadow page cache */ if (!sb) { down_read(&nilfs->ns_writer_sem); writer = nilfs->ns_writer; @@ -566,13 +564,6 @@ void nilfs_mdt_set_entry_size(struct inode *inode, unsigned entry_size, mi->mi_first_entry_offset = DIV_ROUND_UP(header_size, entry_size); } -void nilfs_mdt_set_shadow(struct inode *orig, struct inode *shadow) -{ - shadow->i_mapping->assoc_mapping = orig->i_mapping; - NILFS_I(shadow)->i_btnode_cache.assoc_mapping = - &NILFS_I(orig)->i_btnode_cache; -} - static const struct address_space_operations shadow_map_aops = { .sync_page = block_sync_page, }; diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index e60bbfe..1e0901c 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -93,7 +93,6 @@ struct inode *nilfs_mdt_new_common(struct the_nilfs *, struct super_block *, ino_t); void nilfs_mdt_destroy(struct inode *); void nilfs_mdt_set_entry_size(struct inode *, unsigned, unsigned); -void nilfs_mdt_set_shadow(struct inode *, struct inode *); int nilfs_mdt_setup_shadow_map(struct inode *inode, struct nilfs_shadow_map *shadow); diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index cf5507a..e9f4579 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -101,7 +101,6 @@ enum { NILFS_I_INODE_DIRTY, /* write_inode is requested */ NILFS_I_BMAP, /* has bmap and btnode_cache */ NILFS_I_GCINODE, /* inode for GC, on memory only */ - NILFS_I_GCDAT, /* shadow DAT, on memory only */ }; /* @@ -193,7 +192,7 @@ static inline int nilfs_doing_construction(void) static inline struct inode *nilfs_dat_inode(const struct the_nilfs *nilfs) { - return nilfs_doing_gc() ? nilfs->ns_gc_dat : nilfs->ns_dat; + return nilfs->ns_dat; } /* @@ -294,11 +293,6 @@ int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *); int nilfs_init_gcinode(struct inode *inode); void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs); -/* gcdat.c */ -int nilfs_init_gcdat_inode(struct the_nilfs *); -void nilfs_commit_gcdat_inode(struct the_nilfs *); -void nilfs_clear_gcdat_inode(struct the_nilfs *); - /* * Inodes and files operations */ diff --git a/fs/nilfs2/page.c b/fs/nilfs2/page.c index 7083344..a6c3c2e8 100644 --- a/fs/nilfs2/page.c +++ b/fs/nilfs2/page.c @@ -79,8 +79,8 @@ struct buffer_head *nilfs_grab_buffer(struct inode *inode, { int blkbits = inode->i_blkbits; pgoff_t index = blkoff >> (PAGE_CACHE_SHIFT - blkbits); - struct page *page, *opage; - struct buffer_head *bh, *obh; + struct page *page; + struct buffer_head *bh; page = grab_cache_page(mapping, index); if (unlikely(!page)) @@ -92,30 +92,6 @@ struct buffer_head *nilfs_grab_buffer(struct inode *inode, page_cache_release(page); return NULL; } - if (!buffer_uptodate(bh) && mapping->assoc_mapping != NULL) { - /* - * Shadow page cache uses assoc_mapping to point its original - * page cache. The following code tries the original cache - * if the given cache is a shadow and it didn't hit. - */ - opage = find_lock_page(mapping->assoc_mapping, index); - if (!opage) - return bh; - - obh = __nilfs_get_page_block(opage, blkoff, index, blkbits, - b_state); - if (buffer_uptodate(obh)) { - nilfs_copy_buffer(bh, obh); - if (buffer_dirty(obh)) { - nilfs_mark_buffer_dirty(bh); - if (!buffer_nilfs_node(bh) && NILFS_MDT(inode)) - nilfs_mdt_mark_dirty(inode); - } - } - brelse(obh); - unlock_page(opage); - page_cache_release(opage); - } return bh; } diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 91dc066..b0c5e08 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -1945,11 +1945,9 @@ static void nilfs_segctor_complete_write(struct nilfs_sc_info *sci) nilfs_drop_collected_inodes(&sci->sc_dirty_files); - if (nilfs_doing_gc()) { + if (nilfs_doing_gc()) nilfs_drop_collected_inodes(&sci->sc_gc_inodes); - if (update_sr) - nilfs_commit_gcdat_inode(nilfs); - } else + else nilfs->ns_nongc_ctime = sci->sc_seg_ctime; sci->sc_nblk_inc += sci->sc_nblk_this_inc; @@ -2472,13 +2470,15 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, nilfs_transaction_lock(sbi, &ti, 1); - err = nilfs_init_gcdat_inode(nilfs); + err = nilfs_mdt_save_to_shadow_map(nilfs->ns_dat); if (unlikely(err)) goto out_unlock; err = nilfs_ioctl_prepare_clean_segments(nilfs, argv, kbufs); - if (unlikely(err)) + if (unlikely(err)) { + nilfs_mdt_restore_from_shadow_map(nilfs->ns_dat); goto out_unlock; + } sci->sc_freesegs = kbufs[4]; sci->sc_nfreesegs = argv[4].v_nmembs; @@ -2510,7 +2510,7 @@ int nilfs_clean_segments(struct super_block *sb, struct nilfs_argv *argv, out_unlock: sci->sc_freesegs = NULL; sci->sc_nfreesegs = 0; - nilfs_clear_gcdat_inode(nilfs); + nilfs_mdt_clear_shadow_map(nilfs->ns_dat); nilfs_transaction_unlock(sbi); return err; } diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 6eeb4f0..b7666bc 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -96,7 +96,6 @@ void destroy_nilfs(struct the_nilfs *nilfs) nilfs_mdt_destroy(nilfs->ns_sufile); nilfs_mdt_destroy(nilfs->ns_cpfile); nilfs_mdt_destroy(nilfs->ns_dat); - nilfs_mdt_destroy(nilfs->ns_gc_dat); } if (nilfs_init(nilfs)) { brelse(nilfs->ns_sbh[0]); @@ -131,20 +130,14 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) if (unlikely(!nilfs->ns_dat)) goto failed; - nilfs->ns_gc_dat = nilfs_dat_new(nilfs, dat_entry_size); - if (unlikely(!nilfs->ns_gc_dat)) - goto failed_dat; - nilfs->ns_cpfile = nilfs_cpfile_new(nilfs, checkpoint_size); if (unlikely(!nilfs->ns_cpfile)) - goto failed_gc_dat; + goto failed_dat; nilfs->ns_sufile = nilfs_sufile_new(nilfs, segment_usage_size); if (unlikely(!nilfs->ns_sufile)) goto failed_cpfile; - nilfs_mdt_set_shadow(nilfs->ns_dat, nilfs->ns_gc_dat); - err = nilfs_dat_read(nilfs->ns_dat, (void *)bh_sr->b_data + NILFS_SR_DAT_OFFSET(inode_size)); if (unlikely(err)) @@ -173,9 +166,6 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) failed_cpfile: nilfs_mdt_destroy(nilfs->ns_cpfile); - failed_gc_dat: - nilfs_mdt_destroy(nilfs->ns_gc_dat); - failed_dat: nilfs_mdt_destroy(nilfs->ns_dat); goto failed; @@ -371,7 +361,6 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) nilfs_mdt_destroy(nilfs->ns_cpfile); nilfs_mdt_destroy(nilfs->ns_sufile); nilfs_mdt_destroy(nilfs->ns_dat); - nilfs_mdt_destroy(nilfs->ns_gc_dat); failed: nilfs_clear_recovery_info(&ri); diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 1908dc7..a5178dc 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -74,7 +74,6 @@ enum { * @ns_dat: DAT file inode * @ns_cpfile: checkpoint file inode * @ns_sufile: segusage file inode - * @ns_gc_dat: shadow inode of the DAT file inode for GC * @ns_cptree: rb-tree of all mounted checkpoints (nilfs_root) * @ns_cptree_lock: lock protecting @ns_cptree * @ns_gc_inodes: dummy inodes to keep live blocks @@ -149,7 +148,6 @@ struct the_nilfs { struct inode *ns_dat; struct inode *ns_cpfile; struct inode *ns_sufile; - struct inode *ns_gc_dat; /* Checkpoint tree */ struct rb_root ns_cptree; -- cgit v1.1 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/cpfile.c | 49 +++++++++++++++++++++------------- fs/nilfs2/cpfile.h | 4 +-- fs/nilfs2/dat.c | 61 ++++++++++++++++++++++++------------------ fs/nilfs2/dat.h | 4 +-- fs/nilfs2/ifile.c | 51 ++++++++++++++++++++++++----------- fs/nilfs2/ifile.h | 4 ++- fs/nilfs2/inode.c | 13 ++++++--- fs/nilfs2/mdt.c | 16 +++++------ fs/nilfs2/mdt.h | 3 +-- fs/nilfs2/nilfs.h | 2 ++ fs/nilfs2/sufile.c | 73 +++++++++++++++++++++++++++++---------------------- fs/nilfs2/sufile.h | 4 +-- fs/nilfs2/super.c | 21 ++++++++++----- fs/nilfs2/the_nilfs.c | 58 ++++++++++++++-------------------------- 14 files changed, 207 insertions(+), 156 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 1873781..03de1da 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c @@ -933,27 +933,40 @@ int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat) } /** - * nilfs_cpfile_read - read cpfile inode - * @cpfile: cpfile inode - * @raw_inode: on-disk cpfile inode - */ -int nilfs_cpfile_read(struct inode *cpfile, struct nilfs_inode *raw_inode) -{ - return nilfs_read_inode_common(cpfile, raw_inode); -} - -/** - * nilfs_cpfile_new - create cpfile - * @nilfs: nilfs object + * nilfs_cpfile_read - read or get cpfile inode + * @sb: super block instance * @cpsize: size of a checkpoint entry + * @raw_inode: on-disk cpfile inode + * @inodep: buffer to store the inode */ -struct inode *nilfs_cpfile_new(struct the_nilfs *nilfs, size_t cpsize) +int nilfs_cpfile_read(struct super_block *sb, size_t cpsize, + struct nilfs_inode *raw_inode, struct inode **inodep) { struct inode *cpfile; + int err; - cpfile = nilfs_mdt_new(nilfs, NULL, NILFS_CPFILE_INO, 0); - if (cpfile) - nilfs_mdt_set_entry_size(cpfile, cpsize, - sizeof(struct nilfs_cpfile_header)); - return cpfile; + cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO); + if (unlikely(!cpfile)) + return -ENOMEM; + if (!(cpfile->i_state & I_NEW)) + goto out; + + err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0); + if (err) + goto failed; + + nilfs_mdt_set_entry_size(cpfile, cpsize, + sizeof(struct nilfs_cpfile_header)); + + err = nilfs_read_inode_common(cpfile, raw_inode); + if (err) + goto failed; + + unlock_new_inode(cpfile); + out: + *inodep = cpfile; + return 0; + failed: + iget_failed(cpfile); + return err; } diff --git a/fs/nilfs2/cpfile.h b/fs/nilfs2/cpfile.h index bc0809e..a242b9a 100644 --- a/fs/nilfs2/cpfile.h +++ b/fs/nilfs2/cpfile.h @@ -40,7 +40,7 @@ int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int, void *, unsigned, size_t); -int nilfs_cpfile_read(struct inode *cpfile, struct nilfs_inode *raw_inode); -struct inode *nilfs_cpfile_new(struct the_nilfs *nilfs, size_t cpsize); +int nilfs_cpfile_read(struct super_block *sb, size_t cpsize, + struct nilfs_inode *raw_inode, struct inode **inodep); #endif /* _NILFS_CPFILE_H */ diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index 7091c4e..ab04a68 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -463,39 +463,48 @@ ssize_t nilfs_dat_get_vinfo(struct inode *dat, void *buf, unsigned visz, } /** - * nilfs_dat_read - read dat inode - * @dat: dat inode - * @raw_inode: on-disk dat inode - */ -int nilfs_dat_read(struct inode *dat, struct nilfs_inode *raw_inode) -{ - return nilfs_read_inode_common(dat, raw_inode); -} - -/** - * nilfs_dat_new - create dat file - * @nilfs: nilfs object + * nilfs_dat_read - read or get dat inode + * @sb: super block instance * @entry_size: size of a dat entry + * @raw_inode: on-disk dat inode + * @inodep: buffer to store the inode */ -struct inode *nilfs_dat_new(struct the_nilfs *nilfs, size_t entry_size) +int nilfs_dat_read(struct super_block *sb, size_t entry_size, + struct nilfs_inode *raw_inode, struct inode **inodep) { static struct lock_class_key dat_lock_key; struct inode *dat; struct nilfs_dat_info *di; int err; - dat = nilfs_mdt_new(nilfs, NULL, NILFS_DAT_INO, sizeof(*di)); - if (dat) { - err = nilfs_palloc_init_blockgroup(dat, entry_size); - if (unlikely(err)) { - nilfs_mdt_destroy(dat); - return NULL; - } + dat = nilfs_iget_locked(sb, NULL, NILFS_DAT_INO); + if (unlikely(!dat)) + return -ENOMEM; + if (!(dat->i_state & I_NEW)) + goto out; - di = NILFS_DAT_I(dat); - lockdep_set_class(&di->mi.mi_sem, &dat_lock_key); - nilfs_palloc_setup_cache(dat, &di->palloc_cache); - nilfs_mdt_setup_shadow_map(dat, &di->shadow); - } - return dat; + err = nilfs_mdt_init(dat, NILFS_MDT_GFP, sizeof(*di)); + if (err) + goto failed; + + err = nilfs_palloc_init_blockgroup(dat, entry_size); + if (err) + goto failed; + + di = NILFS_DAT_I(dat); + lockdep_set_class(&di->mi.mi_sem, &dat_lock_key); + nilfs_palloc_setup_cache(dat, &di->palloc_cache); + nilfs_mdt_setup_shadow_map(dat, &di->shadow); + + err = nilfs_read_inode_common(dat, raw_inode); + if (err) + goto failed; + + unlock_new_inode(dat); + out: + *inodep = dat; + return 0; + failed: + iget_failed(dat); + return err; } diff --git a/fs/nilfs2/dat.h b/fs/nilfs2/dat.h index d31c3aa..cbd8e97 100644 --- a/fs/nilfs2/dat.h +++ b/fs/nilfs2/dat.h @@ -53,7 +53,7 @@ int nilfs_dat_freev(struct inode *, __u64 *, size_t); int nilfs_dat_move(struct inode *, __u64, sector_t); ssize_t nilfs_dat_get_vinfo(struct inode *, void *, unsigned, size_t); -int nilfs_dat_read(struct inode *dat, struct nilfs_inode *raw_inode); -struct inode *nilfs_dat_new(struct the_nilfs *nilfs, size_t entry_size); +int nilfs_dat_read(struct super_block *sb, size_t entry_size, + struct nilfs_inode *raw_inode, struct inode **inodep); #endif /* _NILFS_DAT_H */ diff --git a/fs/nilfs2/ifile.c b/fs/nilfs2/ifile.c index 922d9dd..9f8a2da 100644 --- a/fs/nilfs2/ifile.c +++ b/fs/nilfs2/ifile.c @@ -161,25 +161,46 @@ int nilfs_ifile_get_inode_block(struct inode *ifile, ino_t ino, } /** - * nilfs_ifile_new - create inode file - * @sbi: nilfs_sb_info struct + * nilfs_ifile_read - read or get ifile inode + * @sb: super block instance + * @root: root object * @inode_size: size of an inode + * @raw_inode: on-disk ifile inode + * @inodep: buffer to store the inode */ -struct inode *nilfs_ifile_new(struct nilfs_sb_info *sbi, size_t inode_size) +int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root, + size_t inode_size, struct nilfs_inode *raw_inode, + struct inode **inodep) { struct inode *ifile; int err; - ifile = nilfs_mdt_new(sbi->s_nilfs, sbi->s_super, NILFS_IFILE_INO, - sizeof(struct nilfs_ifile_info)); - if (ifile) { - err = nilfs_palloc_init_blockgroup(ifile, inode_size); - if (unlikely(err)) { - nilfs_mdt_destroy(ifile); - return NULL; - } - nilfs_palloc_setup_cache(ifile, - &NILFS_IFILE_I(ifile)->palloc_cache); - } - return ifile; + ifile = nilfs_iget_locked(sb, root, NILFS_IFILE_INO); + if (unlikely(!ifile)) + return -ENOMEM; + if (!(ifile->i_state & I_NEW)) + goto out; + + err = nilfs_mdt_init(ifile, NILFS_MDT_GFP, + sizeof(struct nilfs_ifile_info)); + if (err) + goto failed; + + err = nilfs_palloc_init_blockgroup(ifile, inode_size); + if (err) + goto failed; + + nilfs_palloc_setup_cache(ifile, &NILFS_IFILE_I(ifile)->palloc_cache); + + err = nilfs_read_inode_common(ifile, raw_inode); + if (err) + goto failed; + + unlock_new_inode(ifile); + out: + *inodep = ifile; + return 0; + failed: + iget_failed(ifile); + return err; } diff --git a/fs/nilfs2/ifile.h b/fs/nilfs2/ifile.h index cbca32e..59b6f2b 100644 --- a/fs/nilfs2/ifile.h +++ b/fs/nilfs2/ifile.h @@ -49,6 +49,8 @@ int nilfs_ifile_create_inode(struct inode *, ino_t *, struct buffer_head **); int nilfs_ifile_delete_inode(struct inode *, ino_t); int nilfs_ifile_get_inode_block(struct inode *, ino_t, struct buffer_head **); -struct inode *nilfs_ifile_new(struct nilfs_sb_info *sbi, size_t inode_size); +int nilfs_ifile_read(struct super_block *sb, struct nilfs_root *root, + size_t inode_size, struct nilfs_inode *raw_inode, + struct inode **inodep); #endif /* _NILFS_IFILE_H */ diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 5485dd1..5b3d43f 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -506,16 +506,23 @@ static int nilfs_iget_set(struct inode *inode, void *opaque) return 0; } -struct inode *nilfs_iget(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 nilfs_iget_args args = { .ino = ino, .root = root, .cno = 0, .for_gc = 0 }; + + return iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args); +} + +struct inode *nilfs_iget(struct super_block *sb, struct nilfs_root *root, + unsigned long ino) +{ struct inode *inode; int err; - inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args); + inode = nilfs_iget_locked(sb, root, ino); if (unlikely(!inode)) return ERR_PTR(-ENOMEM); if (!(inode->i_state & I_NEW)) diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 3bbd340..44326cf 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -444,8 +444,7 @@ static const struct inode_operations def_mdt_iops; static const struct file_operations def_mdt_fops; -int nilfs_mdt_init(struct inode *inode, struct the_nilfs *nilfs, - gfp_t gfp_mask, size_t objsz) +int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz) { struct nilfs_mdt_info *mi; @@ -453,13 +452,17 @@ int nilfs_mdt_init(struct inode *inode, struct the_nilfs *nilfs, if (!mi) return -ENOMEM; - mi->mi_nilfs = nilfs; + mi->mi_nilfs = NILFS_I_NILFS(inode); init_rwsem(&mi->mi_sem); inode->i_private = mi; inode->i_mode = S_IFREG; mapping_set_gfp_mask(inode->i_mapping, gfp_mask); - inode->i_mapping->backing_dev_info = nilfs->ns_bdi; + inode->i_mapping->backing_dev_info = inode->i_sb->s_bdi; + + inode->i_op = &def_mdt_iops; + inode->i_fop = &def_mdt_fops; + inode->i_mapping->a_ops = &def_mdt_aops; return 0; } @@ -544,13 +547,10 @@ struct inode *nilfs_mdt_new(struct the_nilfs *nilfs, struct super_block *sb, if (!inode) return NULL; - if (nilfs_mdt_init(inode, nilfs, NILFS_MDT_GFP, objsz) < 0) { + if (nilfs_mdt_init(inode, NILFS_MDT_GFP, objsz) < 0) { nilfs_destroy_inode(inode); return NULL; } - inode->i_op = &def_mdt_iops; - inode->i_fop = &def_mdt_fops; - inode->i_mapping->a_ops = &def_mdt_aops; return inode; } diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index 1e0901c..73ff7c0 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -85,8 +85,7 @@ int nilfs_mdt_forget_block(struct inode *, unsigned long); int nilfs_mdt_mark_block_dirty(struct inode *, unsigned long); int nilfs_mdt_fetch_dirty(struct inode *); -int nilfs_mdt_init(struct inode *inode, struct the_nilfs *nilfs, - gfp_t gfp_mask, size_t objsz); +int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz); struct inode *nilfs_mdt_new(struct the_nilfs *, struct super_block *, ino_t, size_t); struct inode *nilfs_mdt_new_common(struct the_nilfs *, struct super_block *, diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index e9f4579..2ca2ca5 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_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, unsigned long ino); extern struct inode *nilfs_iget_for_gc(struct super_block *sb, diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 3c6cc60..599d9c2 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c @@ -635,46 +635,55 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, } /** - * nilfs_sufile_read - read sufile inode - * @sufile: sufile inode + * nilfs_sufile_read - read or get sufile inode + * @sb: super block instance + * @susize: size of a segment usage entry * @raw_inode: on-disk sufile inode + * @inodep: buffer to store the inode */ -int nilfs_sufile_read(struct inode *sufile, struct nilfs_inode *raw_inode) +int nilfs_sufile_read(struct super_block *sb, size_t susize, + struct nilfs_inode *raw_inode, struct inode **inodep) { - struct nilfs_sufile_info *sui = NILFS_SUI(sufile); + struct inode *sufile; + struct nilfs_sufile_info *sui; struct buffer_head *header_bh; struct nilfs_sufile_header *header; void *kaddr; - int ret; + int err; - ret = nilfs_read_inode_common(sufile, raw_inode); - if (ret < 0) - return ret; + sufile = nilfs_iget_locked(sb, NULL, NILFS_SUFILE_INO); + if (unlikely(!sufile)) + return -ENOMEM; + if (!(sufile->i_state & I_NEW)) + goto out; - ret = nilfs_sufile_get_header_block(sufile, &header_bh); - if (!ret) { - kaddr = kmap_atomic(header_bh->b_page, KM_USER0); - header = kaddr + bh_offset(header_bh); - sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs); - kunmap_atomic(kaddr, KM_USER0); - brelse(header_bh); - } - return ret; -} + err = nilfs_mdt_init(sufile, NILFS_MDT_GFP, sizeof(*sui)); + if (err) + goto failed; -/** - * nilfs_sufile_new - create sufile - * @nilfs: nilfs object - * @susize: size of a segment usage entry - */ -struct inode *nilfs_sufile_new(struct the_nilfs *nilfs, size_t susize) -{ - struct inode *sufile; + nilfs_mdt_set_entry_size(sufile, susize, + sizeof(struct nilfs_sufile_header)); + + err = nilfs_read_inode_common(sufile, raw_inode); + if (err) + goto failed; + + err = nilfs_sufile_get_header_block(sufile, &header_bh); + if (err) + goto failed; - sufile = nilfs_mdt_new(nilfs, NULL, NILFS_SUFILE_INO, - sizeof(struct nilfs_sufile_info)); - if (sufile) - nilfs_mdt_set_entry_size(sufile, susize, - sizeof(struct nilfs_sufile_header)); - return sufile; + sui = NILFS_SUI(sufile); + kaddr = kmap_atomic(header_bh->b_page, KM_USER0); + header = kaddr + bh_offset(header_bh); + sui->ncleansegs = le64_to_cpu(header->sh_ncleansegs); + kunmap_atomic(kaddr, KM_USER0); + brelse(header_bh); + + unlock_new_inode(sufile); + out: + *inodep = sufile; + return 0; + failed: + iget_failed(sufile); + return err; } diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index 15163b8..203f610 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h @@ -61,8 +61,8 @@ void nilfs_sufile_do_cancel_free(struct inode *, __u64, struct buffer_head *, void nilfs_sufile_do_set_error(struct inode *, __u64, struct buffer_head *, struct buffer_head *); -int nilfs_sufile_read(struct inode *sufile, struct nilfs_inode *raw_inode); -struct inode *nilfs_sufile_new(struct the_nilfs *nilfs, size_t susize); +int nilfs_sufile_read(struct super_block *sb, size_t susize, + struct nilfs_inode *raw_inode, struct inode **inodep); /** * nilfs_sufile_scrap - make a segment garbage diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 5893cb2..39e7d7f 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); diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index b7666bc..4d6763e 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -92,11 +92,6 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) void destroy_nilfs(struct the_nilfs *nilfs) { might_sleep(); - if (nilfs_loaded(nilfs)) { - nilfs_mdt_destroy(nilfs->ns_sufile); - nilfs_mdt_destroy(nilfs->ns_cpfile); - nilfs_mdt_destroy(nilfs->ns_dat); - } if (nilfs_init(nilfs)) { brelse(nilfs->ns_sbh[0]); brelse(nilfs->ns_sbh[1]); @@ -104,11 +99,13 @@ void destroy_nilfs(struct the_nilfs *nilfs) kfree(nilfs); } -static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) +static int nilfs_load_super_root(struct the_nilfs *nilfs, + struct super_block *sb, sector_t sr_block) { struct buffer_head *bh_sr; struct nilfs_super_root *raw_sr; struct nilfs_super_block **sbp = nilfs->ns_sbp; + struct nilfs_inode *rawi; unsigned dat_entry_size, segment_usage_size, checkpoint_size; unsigned inode_size; int err; @@ -125,34 +122,22 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) inode_size = nilfs->ns_inode_size; - err = -ENOMEM; - nilfs->ns_dat = nilfs_dat_new(nilfs, dat_entry_size); - if (unlikely(!nilfs->ns_dat)) + rawi = (void *)bh_sr->b_data + NILFS_SR_DAT_OFFSET(inode_size); + err = nilfs_dat_read(sb, dat_entry_size, rawi, &nilfs->ns_dat); + if (err) goto failed; - nilfs->ns_cpfile = nilfs_cpfile_new(nilfs, checkpoint_size); - if (unlikely(!nilfs->ns_cpfile)) + rawi = (void *)bh_sr->b_data + NILFS_SR_CPFILE_OFFSET(inode_size); + err = nilfs_cpfile_read(sb, checkpoint_size, rawi, &nilfs->ns_cpfile); + if (err) goto failed_dat; - nilfs->ns_sufile = nilfs_sufile_new(nilfs, segment_usage_size); - if (unlikely(!nilfs->ns_sufile)) + rawi = (void *)bh_sr->b_data + NILFS_SR_SUFILE_OFFSET(inode_size); + err = nilfs_sufile_read(sb, segment_usage_size, rawi, + &nilfs->ns_sufile); + if (err) goto failed_cpfile; - err = nilfs_dat_read(nilfs->ns_dat, (void *)bh_sr->b_data + - NILFS_SR_DAT_OFFSET(inode_size)); - if (unlikely(err)) - goto failed_sufile; - - err = nilfs_cpfile_read(nilfs->ns_cpfile, (void *)bh_sr->b_data + - NILFS_SR_CPFILE_OFFSET(inode_size)); - if (unlikely(err)) - goto failed_sufile; - - err = nilfs_sufile_read(nilfs->ns_sufile, (void *)bh_sr->b_data + - NILFS_SR_SUFILE_OFFSET(inode_size)); - if (unlikely(err)) - goto failed_sufile; - raw_sr = (struct nilfs_super_root *)bh_sr->b_data; nilfs->ns_nongc_ctime = le64_to_cpu(raw_sr->sr_nongc_ctime); @@ -160,14 +145,11 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) brelse(bh_sr); return err; - failed_sufile: - nilfs_mdt_destroy(nilfs->ns_sufile); - failed_cpfile: - nilfs_mdt_destroy(nilfs->ns_cpfile); + iput(nilfs->ns_cpfile); failed_dat: - nilfs_mdt_destroy(nilfs->ns_dat); + iput(nilfs->ns_dat); goto failed; } @@ -290,7 +272,7 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) goto scan_error; } - err = nilfs_load_super_root(nilfs, ri.ri_super_root); + err = nilfs_load_super_root(nilfs, sbi->s_super, ri.ri_super_root); if (unlikely(err)) { printk(KERN_ERR "NILFS: error loading super root.\n"); goto failed; @@ -358,9 +340,9 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) goto failed; failed_unload: - nilfs_mdt_destroy(nilfs->ns_cpfile); - nilfs_mdt_destroy(nilfs->ns_sufile); - nilfs_mdt_destroy(nilfs->ns_dat); + iput(nilfs->ns_cpfile); + iput(nilfs->ns_sufile); + iput(nilfs->ns_dat); failed: nilfs_clear_recovery_info(&ri); @@ -782,7 +764,7 @@ void nilfs_put_root(struct nilfs_root *root) rb_erase(&root->rb_node, &nilfs->ns_cptree); spin_unlock(&nilfs->ns_cptree_lock); if (root->ifile) - nilfs_mdt_destroy(root->ifile); + iput(root->ifile); kfree(root); } -- cgit v1.1 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/cpfile.c | 23 ++++++++--------------- fs/nilfs2/inode.c | 10 ++++++++++ fs/nilfs2/nilfs.h | 3 +++ fs/nilfs2/super.c | 32 ++++++++++++++++++++++++++++++++ fs/nilfs2/the_nilfs.c | 21 --------------------- fs/nilfs2/the_nilfs.h | 1 - 6 files changed, 53 insertions(+), 37 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 03de1da..5ff15a8 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 5b3d43f..71d4bc8 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 2ca2ca5..f6e276ea 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 39e7d7f..ab96d26 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 4d6763e..4cc705a 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 a5178dc..cae56f3 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 *); -- cgit v1.1 From c6e071884aca360a14c21757d760e76ec34b4894 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 5 Sep 2010 00:23:50 +0900 Subject: nilfs2: get rid of mi_nilfs back pointer to nilfs object This removes a back pointer to nilfs object from nilfs_mdt_info structure that is attached to metadata files. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/mdt.c | 9 +++------ fs/nilfs2/mdt.h | 8 ++------ fs/nilfs2/sufile.c | 4 ++-- fs/nilfs2/sufile.h | 2 +- 4 files changed, 8 insertions(+), 15 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 44326cf..32695f3 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -78,7 +78,7 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, struct buffer_head *, void *)) { - struct the_nilfs *nilfs = NILFS_MDT(inode)->mi_nilfs; + struct the_nilfs *nilfs = NILFS_I_NILFS(inode); struct super_block *sb = inode->i_sb; struct nilfs_transaction_info ti; struct buffer_head *bh; @@ -167,9 +167,7 @@ nilfs_mdt_submit_block(struct inode *inode, unsigned long blkoff, unlock_buffer(bh); goto failed_bh; } - bh->b_bdev = NILFS_MDT(inode)->mi_nilfs->ns_bdev; - bh->b_blocknr = (sector_t)blknum; - set_buffer_mapped(bh); + map_bh(bh, inode->i_sb, (sector_t)blknum); bh->b_end_io = end_buffer_read_sync; get_bh(bh); @@ -412,7 +410,7 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) return 0; sb = inode->i_sb; - nilfs = NILFS_MDT(inode)->mi_nilfs; + nilfs = NILFS_SB(sb)->s_nilfs; if (!sb) { down_read(&nilfs->ns_writer_sem); @@ -452,7 +450,6 @@ int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz) if (!mi) return -ENOMEM; - mi->mi_nilfs = NILFS_I_NILFS(inode); init_rwsem(&mi->mi_sem); inode->i_private = mi; diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index 73ff7c0..76356d2 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -37,7 +37,6 @@ struct nilfs_shadow_map { /** * struct nilfs_mdt_info - on-memory private data of meta data files - * @mi_nilfs: back pointer to the_nilfs struct * @mi_sem: reader/writer semaphore for meta data operations * @mi_bgl: per-blockgroup locking * @mi_entry_size: size of an entry @@ -49,7 +48,6 @@ struct nilfs_shadow_map { * @mi_blocks_per_desc_block: number of blocks per descriptor block */ struct nilfs_mdt_info { - struct the_nilfs *mi_nilfs; struct rw_semaphore mi_sem; struct blockgroup_lock *mi_bgl; unsigned mi_entry_size; @@ -68,9 +66,7 @@ static inline struct nilfs_mdt_info *NILFS_MDT(const struct inode *inode) static inline struct the_nilfs *NILFS_I_NILFS(struct inode *inode) { - struct super_block *sb = inode->i_sb; - - return sb ? NILFS_SB(sb)->s_nilfs : NILFS_MDT(inode)->mi_nilfs; + return NILFS_SB(inode->i_sb)->s_nilfs; } /* Default GFP flags using highmem */ @@ -117,7 +113,7 @@ static inline void nilfs_mdt_clear_dirty(struct inode *inode) static inline __u64 nilfs_mdt_cno(struct inode *inode) { - return NILFS_MDT(inode)->mi_nilfs->ns_cno; + return NILFS_I_NILFS(inode)->ns_cno; } #define nilfs_mdt_bgl_lock(inode, bg) \ diff --git a/fs/nilfs2/sufile.c b/fs/nilfs2/sufile.c index 599d9c2..1d6f488 100644 --- a/fs/nilfs2/sufile.c +++ b/fs/nilfs2/sufile.c @@ -505,7 +505,7 @@ int nilfs_sufile_get_stat(struct inode *sufile, struct nilfs_sustat *sustat) { struct buffer_head *header_bh; struct nilfs_sufile_header *header; - struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; + struct the_nilfs *nilfs = NILFS_I_NILFS(sufile); void *kaddr; int ret; @@ -583,7 +583,7 @@ ssize_t nilfs_sufile_get_suinfo(struct inode *sufile, __u64 segnum, void *buf, struct nilfs_segment_usage *su; struct nilfs_suinfo *si = buf; size_t susz = NILFS_MDT(sufile)->mi_entry_size; - struct the_nilfs *nilfs = NILFS_MDT(sufile)->mi_nilfs; + struct the_nilfs *nilfs = NILFS_I_NILFS(sufile); void *kaddr; unsigned long nsegs, segusages_per_block; ssize_t n; diff --git a/fs/nilfs2/sufile.h b/fs/nilfs2/sufile.h index 203f610..a943fba 100644 --- a/fs/nilfs2/sufile.h +++ b/fs/nilfs2/sufile.h @@ -31,7 +31,7 @@ static inline unsigned long nilfs_sufile_get_nsegments(struct inode *sufile) { - return NILFS_MDT(sufile)->mi_nilfs->ns_nsegments; + return NILFS_I_NILFS(sufile)->ns_nsegments; } unsigned long nilfs_sufile_get_ncleansegs(struct inode *sufile); -- cgit v1.1 From 090fd5b10165033d7c30afde0a7e59141d820602 Mon Sep 17 00:00:00 2001 From: Ryusuke Konishi Date: Sun, 5 Sep 2010 16:17:35 +0900 Subject: nilfs2: get rid of back pointer to writable sb instance Nilfs object holds a back pointer to a writable super block instance in nilfs->ns_writer, and this became eliminable since sb is now made per device and all inodes have a valid pointer to it. This deletes the ns_writer pointer and a reader/writer semaphore protecting it. Signed-off-by: Ryusuke Konishi --- fs/nilfs2/mdt.c | 33 ++------------------------------- fs/nilfs2/recovery.c | 4 ---- fs/nilfs2/segment.c | 4 ---- fs/nilfs2/the_nilfs.c | 1 - fs/nilfs2/the_nilfs.h | 21 --------------------- 5 files changed, 2 insertions(+), 61 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 32695f3..0a2ccfc 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -78,25 +78,11 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, struct buffer_head *, void *)) { - struct the_nilfs *nilfs = NILFS_I_NILFS(inode); struct super_block *sb = inode->i_sb; struct nilfs_transaction_info ti; struct buffer_head *bh; int err; - if (!sb) { - /* - * Make sure this function is not called from any - * read-only context. - */ - if (!nilfs->ns_writer) { - WARN_ON(1); - err = -EROFS; - goto out; - } - sb = nilfs->ns_writer->s_super; - } - nilfs_transaction_begin(sb, &ti, 0); err = -ENOMEM; @@ -112,7 +98,7 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, if (buffer_uptodate(bh)) goto failed_bh; - bh->b_bdev = nilfs->ns_bdev; + bh->b_bdev = sb->s_bdev; err = nilfs_mdt_insert_new_block(inode, block, bh, init_block); if (likely(!err)) { get_bh(bh); @@ -129,7 +115,7 @@ static int nilfs_mdt_create_block(struct inode *inode, unsigned long block, err = nilfs_transaction_commit(sb); else nilfs_transaction_abort(sb); - out: + return err; } @@ -398,8 +384,6 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) { struct inode *inode; struct super_block *sb; - struct the_nilfs *nilfs; - struct nilfs_sb_info *writer = NULL; int err = 0; redirty_page_for_writepage(wbc, page); @@ -410,25 +394,12 @@ nilfs_mdt_write_page(struct page *page, struct writeback_control *wbc) return 0; sb = inode->i_sb; - nilfs = NILFS_SB(sb)->s_nilfs; - - if (!sb) { - down_read(&nilfs->ns_writer_sem); - writer = nilfs->ns_writer; - if (!writer) { - up_read(&nilfs->ns_writer_sem); - return -EROFS; - } - sb = writer->s_super; - } if (wbc->sync_mode == WB_SYNC_ALL) err = nilfs_construct_segment(sb); else if (wbc->for_reclaim) nilfs_flush_segment(sb, inode->i_ino); - if (writer) - up_read(&nilfs->ns_writer_sem); return err; } diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index dcb5a98..5d2711c2 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c @@ -440,7 +440,6 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, segnum[2] = ri->ri_segnum; segnum[3] = ri->ri_nextnum; - nilfs_attach_writer(nilfs, sbi); /* * Releasing the next segment of the latest super root. * The next segment is invalidated by this recovery. @@ -480,7 +479,6 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs, failed: /* No need to recover sufile because it will be destroyed on error */ - nilfs_detach_writer(nilfs, sbi); return err; } @@ -599,7 +597,6 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs, }; int state = RF_INIT_ST; - nilfs_attach_writer(nilfs, sbi); pseg_start = ri->ri_lsegs_start; seg_seq = ri->ri_lsegs_start_seq; segnum = nilfs_get_segnum_of_block(nilfs, pseg_start); @@ -690,7 +687,6 @@ static int nilfs_do_roll_forward(struct the_nilfs *nilfs, out: brelse(bh_sum); dispose_recovery_list(&dsync_blocks); - nilfs_detach_writer(nilfs, sbi); return err; confused: diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index b0c5e08..56350bf 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2799,7 +2799,6 @@ static void nilfs_segctor_destroy(struct nilfs_sc_info *sci) int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi, struct nilfs_root *root) { - struct the_nilfs *nilfs = sbi->s_nilfs; int err; if (NILFS_SC(sbi)) { @@ -2815,10 +2814,8 @@ int nilfs_attach_segment_constructor(struct nilfs_sb_info *sbi, if (!sbi->s_sc_info) return -ENOMEM; - nilfs_attach_writer(nilfs, sbi); err = nilfs_segctor_start_thread(NILFS_SC(sbi)); if (err) { - nilfs_detach_writer(nilfs, sbi); kfree(sbi->s_sc_info); sbi->s_sc_info = NULL; } @@ -2855,5 +2852,4 @@ void nilfs_detach_segment_constructor(struct nilfs_sb_info *sbi) up_write(&nilfs->ns_segctor_sem); nilfs_dispose_list(sbi, &garbage_list, 1); - nilfs_detach_writer(nilfs, sbi); } diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 4cc705a..a94aa57 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -75,7 +75,6 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) nilfs->ns_bdev = bdev; atomic_set(&nilfs->ns_ndirtyblks, 0); init_rwsem(&nilfs->ns_sem); - init_rwsem(&nilfs->ns_writer_sem); INIT_LIST_HEAD(&nilfs->ns_gc_inodes); spin_lock_init(&nilfs->ns_last_segment_lock); nilfs->ns_cptree = RB_ROOT; diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index cae56f3..bbbc1c7 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -48,9 +48,7 @@ enum { * @ns_flags: flags * @ns_bdev: block device * @ns_bdi: backing dev info - * @ns_writer: back pointer to writable nilfs_sb_info * @ns_sem: semaphore for shared states - * @ns_writer_sem: semaphore protecting ns_writer attach/detach * @ns_sbh: buffer heads of on-disk super blocks * @ns_sbp: pointers to super block data * @ns_sbwtime: previous write time of super block @@ -93,9 +91,7 @@ struct the_nilfs { struct block_device *ns_bdev; struct backing_dev_info *ns_bdi; - struct nilfs_sb_info *ns_writer; struct rw_semaphore ns_sem; - struct rw_semaphore ns_writer_sem; /* * used for @@ -252,23 +248,6 @@ static inline void nilfs_get_root(struct nilfs_root *root) atomic_inc(&root->count); } -static inline void -nilfs_attach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) -{ - down_write(&nilfs->ns_writer_sem); - nilfs->ns_writer = sbi; - up_write(&nilfs->ns_writer_sem); -} - -static inline void -nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) -{ - down_write(&nilfs->ns_writer_sem); - if (sbi == nilfs->ns_writer) - nilfs->ns_writer = NULL; - up_write(&nilfs->ns_writer_sem); -} - static inline int nilfs_valid_fs(struct the_nilfs *nilfs) { unsigned valid_fs; -- cgit v1.1 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/mdt.c | 111 ------------------------------------------------------ fs/nilfs2/mdt.h | 5 --- fs/nilfs2/nilfs.h | 1 - fs/nilfs2/super.c | 9 +---- 4 files changed, 2 insertions(+), 124 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index 0a2ccfc..d60fdb0 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -36,7 +36,6 @@ #define NILFS_MDT_MAX_RA_BLOCKS (16 - 1) -#define INIT_UNUSED_INODE_FIELDS static int nilfs_mdt_insert_new_block(struct inode *inode, unsigned long block, @@ -435,93 +434,6 @@ int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz) return 0; } -/* - * NILFS2 uses pseudo inodes for meta data files such as DAT, cpfile, sufile, - * ifile, or gcinodes. This allows the B-tree code and segment constructor - * to treat them like regular files, and this helps to simplify the - * implementation. - * On the other hand, some of the pseudo inodes have an irregular point: - * They don't have valid inode->i_sb pointer because their lifetimes are - * longer than those of the super block structs; they may continue for - * several consecutive mounts/umounts. This would need discussions. - */ -/** - * nilfs_mdt_new_common - allocate a pseudo inode for metadata file - * @nilfs: nilfs object - * @sb: super block instance the metadata file belongs to - * @ino: inode number - */ -struct inode * -nilfs_mdt_new_common(struct the_nilfs *nilfs, struct super_block *sb, - ino_t ino) -{ - struct inode *inode = nilfs_alloc_inode_common(nilfs); - - if (!inode) - return NULL; - else { - struct address_space * const mapping = &inode->i_data; - - inode->i_sb = sb; /* sb may be NULL for some meta data files */ - inode->i_blkbits = nilfs->ns_blocksize_bits; - inode->i_flags = 0; - atomic_set(&inode->i_count, 1); - inode->i_nlink = 1; - inode->i_ino = ino; - -#ifdef INIT_UNUSED_INODE_FIELDS - atomic_set(&inode->i_writecount, 0); - inode->i_size = 0; - inode->i_blocks = 0; - inode->i_bytes = 0; - inode->i_generation = 0; -#ifdef CONFIG_QUOTA - memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); -#endif - inode->i_pipe = NULL; - inode->i_bdev = NULL; - inode->i_cdev = NULL; - inode->i_rdev = 0; -#ifdef CONFIG_SECURITY - inode->i_security = NULL; -#endif - inode->dirtied_when = 0; - - INIT_LIST_HEAD(&inode->i_list); - INIT_LIST_HEAD(&inode->i_sb_list); - inode->i_state = 0; -#endif - - spin_lock_init(&inode->i_lock); - mutex_init(&inode->i_mutex); - init_rwsem(&inode->i_alloc_sem); - - mapping->host = NULL; /* instead of inode */ - mapping->flags = 0; - mapping->assoc_mapping = NULL; - - inode->i_mapping = mapping; - } - - return inode; -} - -struct inode *nilfs_mdt_new(struct the_nilfs *nilfs, struct super_block *sb, - ino_t ino, size_t objsz) -{ - struct inode *inode; - - inode = nilfs_mdt_new_common(nilfs, sb, ino); - if (!inode) - return NULL; - - if (nilfs_mdt_init(inode, NILFS_MDT_GFP, objsz) < 0) { - nilfs_destroy_inode(inode); - return NULL; - } - return inode; -} - void nilfs_mdt_set_entry_size(struct inode *inode, unsigned entry_size, unsigned header_size) { @@ -688,26 +600,3 @@ void nilfs_mdt_clear_shadow_map(struct inode *inode) truncate_inode_pages(&shadow->frozen_btnodes, 0); up_write(&mi->mi_sem); } - -static void nilfs_mdt_clear(struct inode *inode) -{ - struct nilfs_inode_info *ii = NILFS_I(inode); - - invalidate_mapping_pages(inode->i_mapping, 0, -1); - truncate_inode_pages(inode->i_mapping, 0); - - if (test_bit(NILFS_I_BMAP, &ii->i_state)) - nilfs_bmap_clear(ii->i_bmap); - nilfs_btnode_cache_clear(&ii->i_btnode_cache); -} - -void nilfs_mdt_destroy(struct inode *inode) -{ - struct nilfs_mdt_info *mdi = NILFS_MDT(inode); - - if (mdi->mi_palloc_cache) - nilfs_palloc_destroy_cache(inode); - nilfs_mdt_clear(inode); - - nilfs_destroy_inode(inode); -} diff --git a/fs/nilfs2/mdt.h b/fs/nilfs2/mdt.h index 76356d2..b13734b 100644 --- a/fs/nilfs2/mdt.h +++ b/fs/nilfs2/mdt.h @@ -82,11 +82,6 @@ int nilfs_mdt_mark_block_dirty(struct inode *, unsigned long); int nilfs_mdt_fetch_dirty(struct inode *); int nilfs_mdt_init(struct inode *inode, gfp_t gfp_mask, size_t objsz); -struct inode *nilfs_mdt_new(struct the_nilfs *, struct super_block *, ino_t, - size_t); -struct inode *nilfs_mdt_new_common(struct the_nilfs *, struct super_block *, - ino_t); -void nilfs_mdt_destroy(struct inode *); void nilfs_mdt_set_entry_size(struct inode *, unsigned, unsigned); int nilfs_mdt_setup_shadow_map(struct inode *inode, diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index f6e276ea..f7560da 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h @@ -266,7 +266,6 @@ extern int nilfs_mark_inode_dirty(struct inode *); extern void nilfs_dirty_inode(struct inode *); /* super.c */ -extern struct inode *nilfs_alloc_inode_common(struct the_nilfs *); extern struct inode *nilfs_alloc_inode(struct super_block *); extern void nilfs_destroy_inode(struct inode *); extern void nilfs_error(struct super_block *, const char *, const char *, ...) diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index ab96d26..d92ebd5 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.1 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') diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index d92ebd5..a1cd444 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.1 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/ioctl.c | 2 ++ fs/nilfs2/segment.c | 2 ++ fs/nilfs2/super.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 58 insertions(+), 4 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 338858f..3e90f86 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c @@ -580,6 +580,8 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, goto out_free; } + vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); + ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]); if (ret < 0) printk(KERN_ERR "NILFS: GC failed during preparation: " diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 56350bf..172ad42 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -191,6 +191,8 @@ int nilfs_transaction_begin(struct super_block *sb, if (ret > 0) return 0; + vfs_check_frozen(sb, SB_FREEZE_WRITE); + sbi = NILFS_SB(sb); nilfs = sbi->s_nilfs; down_read(&nilfs->ns_segctor_sem); diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index a1cd444..92e8c76 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.1 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/mdt.c | 2 +- fs/nilfs2/segbuf.c | 3 ++- fs/nilfs2/super.c | 5 ++++- fs/nilfs2/the_nilfs.c | 4 ---- fs/nilfs2/the_nilfs.h | 2 -- 5 files changed, 7 insertions(+), 9 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/mdt.c b/fs/nilfs2/mdt.c index d60fdb0..39a5b84 100644 --- a/fs/nilfs2/mdt.c +++ b/fs/nilfs2/mdt.c @@ -457,7 +457,7 @@ int nilfs_mdt_setup_shadow_map(struct inode *inode, struct nilfs_shadow_map *shadow) { struct nilfs_mdt_info *mi = NILFS_MDT(inode); - struct backing_dev_info *bdi = NILFS_I_NILFS(inode)->ns_bdi; + struct backing_dev_info *bdi = inode->i_sb->s_bdi; INIT_LIST_HEAD(&shadow->frozen_buffers); nilfs_mapping_init_once(&shadow->frozen_data); diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 4588fb9..0f83e93 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -371,7 +371,8 @@ static int nilfs_segbuf_submit_bio(struct nilfs_segment_buffer *segbuf, struct bio *bio = wi->bio; int err; - if (segbuf->sb_nbio > 0 && bdi_write_congested(wi->nilfs->ns_bdi)) { + if (segbuf->sb_nbio > 0 && + bdi_write_congested(segbuf->sb_super->s_bdi)) { wait_for_completion(&segbuf->sb_bio_event); segbuf->sb_nbio--; if (unlikely(atomic_read(&segbuf->sb_err))) { diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 92e8c76..8e77016 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) diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index a94aa57..bd02b61 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c @@ -535,7 +535,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) { struct super_block *sb = sbi->s_super; struct nilfs_super_block *sbp; - struct backing_dev_info *bdi; int blocksize; int err; @@ -598,9 +597,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); - bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; - nilfs->ns_bdi = bdi ? : &default_backing_dev_info; - err = nilfs_store_log_cursor(nilfs, sbp); if (err) goto failed_sbh; diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index bbbc1c7..69226e1 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h @@ -47,7 +47,6 @@ enum { * struct the_nilfs - struct to supervise multiple nilfs mount points * @ns_flags: flags * @ns_bdev: block device - * @ns_bdi: backing dev info * @ns_sem: semaphore for shared states * @ns_sbh: buffer heads of on-disk super blocks * @ns_sbp: pointers to super block data @@ -90,7 +89,6 @@ struct the_nilfs { unsigned long ns_flags; struct block_device *ns_bdev; - struct backing_dev_info *ns_bdi; struct rw_semaphore ns_sem; /* -- cgit v1.1 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/dat.c | 3 ++- fs/nilfs2/super.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/dat.c b/fs/nilfs2/dat.c index ab04a68..49c844d 100644 --- a/fs/nilfs2/dat.c +++ b/fs/nilfs2/dat.c @@ -103,7 +103,8 @@ void nilfs_dat_abort_alloc(struct inode *dat, struct nilfs_palloc_req *req) nilfs_palloc_abort_alloc_entry(dat, req); } -void nilfs_dat_commit_free(struct inode *dat, struct nilfs_palloc_req *req) +static void nilfs_dat_commit_free(struct inode *dat, + struct nilfs_palloc_req *req) { struct nilfs_dat_entry *entry; void *kaddr; diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 8e77016..ab62907 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.1 From 6b81e14e645016597c81e71cd27ee5c57c3a3c36 Mon Sep 17 00:00:00 2001 From: Jiro SEKIBA Date: Thu, 14 Oct 2010 13:52:00 +0900 Subject: nilfs2: eliminate sparse warning - "context imbalance" insert sparse annotations to fix following sparse warning. fs/nilfs2/segment.c:2681:3: warning: context imbalance in 'nilfs_segctor_kill_thread' - unexpected unlock nilfs_segctor_kill_thread is only called inside sc_state_lock lock. sparse doesn't detect the context and warn "unexpected unlock". __acquires/__releases pretend to lock/unlock the sc_state_lock for sparse. Signed-off-by: Jiro SEKIBA Signed-off-by: Ryusuke Konishi --- fs/nilfs2/segment.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs/nilfs2') diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c index 172ad42..d926af6 100644 --- a/fs/nilfs2/segment.c +++ b/fs/nilfs2/segment.c @@ -2674,6 +2674,8 @@ static int nilfs_segctor_start_thread(struct nilfs_sc_info *sci) } static void nilfs_segctor_kill_thread(struct nilfs_sc_info *sci) + __acquires(&sci->sc_state_lock) + __releases(&sci->sc_state_lock) { sci->sc_state |= NILFS_SEGCTOR_QUIT; -- cgit v1.1