aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-08-20 06:06:11 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-10-22 20:24:34 -0400
commit263d90cefc7d82a01c296c59532ff59d67c63509 (patch)
treedf289cc3bbb8681b3a42e3c0a25202b085fc9362 /fs
parent5e19a995f4ad8a8f20749a396bb01ebb6d4df96c (diff)
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 <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs')
-rw-r--r--fs/nilfs2/gcinode.c140
-rw-r--r--fs/nilfs2/inode.c22
-rw-r--r--fs/nilfs2/ioctl.c17
-rw-r--r--fs/nilfs2/nilfs.h9
-rw-r--r--fs/nilfs2/segment.c3
-rw-r--r--fs/nilfs2/the_nilfs.c8
-rw-r--r--fs/nilfs2/the_nilfs.h7
7 files changed, 64 insertions, 142 deletions
diff --git a/fs/nilfs2/gcinode.c b/fs/nilfs2/gcinode.c
index cd19a3709bda..34f8f84a22e3 100644
--- a/fs/nilfs2/gcinode.c
+++ b/fs/nilfs2/gcinode.c
@@ -28,13 +28,6 @@
28 * gcinodes), and this file provides lookup function of the dummy 28 * gcinodes), and this file provides lookup function of the dummy
29 * inodes and their buffer read function. 29 * inodes and their buffer read function.
30 * 30 *
31 * Since NILFS2 keeps up multiple checkpoints/snapshots across GC, it
32 * has to treat blocks that belong to a same file but have different
33 * checkpoint numbers. To avoid interference among generations, dummy
34 * inodes are managed separately from actual inodes, and their lookup
35 * function (nilfs_gc_iget) is designed to be specified with a
36 * checkpoint number argument as well as an inode number.
37 *
38 * Buffers and pages held by the dummy inodes will be released each 31 * Buffers and pages held by the dummy inodes will be released each
39 * time after they are copied to a new log. Dirty blocks made on the 32 * time after they are copied to a new log. Dirty blocks made on the
40 * current generation and the blocks to be moved by GC never overlap 33 * 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)
180 return 0; 173 return 0;
181} 174}
182 175
183/* 176int nilfs_init_gcinode(struct inode *inode)
184 * nilfs_init_gccache() - allocate and initialize gc_inode hash table
185 * @nilfs - the_nilfs
186 *
187 * Return Value: On success, 0.
188 * On error, a negative error code is returned.
189 */
190int nilfs_init_gccache(struct the_nilfs *nilfs)
191{
192 int loop;
193
194 BUG_ON(nilfs->ns_gc_inodes_h);
195
196 INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
197
198 nilfs->ns_gc_inodes_h =
199 kmalloc(sizeof(struct hlist_head) * NILFS_GCINODE_HASH_SIZE,
200 GFP_NOFS);
201 if (nilfs->ns_gc_inodes_h == NULL)
202 return -ENOMEM;
203
204 for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++)
205 INIT_HLIST_HEAD(&nilfs->ns_gc_inodes_h[loop]);
206 return 0;
207}
208
209/*
210 * nilfs_destroy_gccache() - free gc_inode hash table
211 * @nilfs - the nilfs
212 */
213void nilfs_destroy_gccache(struct the_nilfs *nilfs)
214{ 177{
215 if (nilfs->ns_gc_inodes_h) { 178 struct nilfs_inode_info *ii = NILFS_I(inode);
216 nilfs_remove_all_gcinode(nilfs); 179 struct the_nilfs *nilfs = NILFS_SB(inode->i_sb)->s_nilfs;
217 kfree(nilfs->ns_gc_inodes_h); 180 int ret;
218 nilfs->ns_gc_inodes_h = NULL;
219 }
220}
221
222static struct inode *alloc_gcinode(struct the_nilfs *nilfs, ino_t ino,
223 __u64 cno)
224{
225 struct inode *inode;
226 struct nilfs_inode_info *ii;
227
228 inode = nilfs_mdt_new_common(nilfs, NULL, ino);
229 if (!inode)
230 return NULL;
231
232 if (nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0) < 0) {
233 nilfs_destroy_inode(inode);
234 return NULL;
235 }
236 inode->i_op = NULL;
237 inode->i_fop = NULL;
238 inode->i_mapping->a_ops = &def_gcinode_aops;
239
240 ii = NILFS_I(inode);
241 ii->i_cno = cno;
242 ii->i_flags = 0;
243 ii->i_state = 1 << NILFS_I_GCINODE;
244 ii->i_bh = NULL;
245 nilfs_bmap_init_gc(ii->i_bmap);
246 181
247 return inode; 182 ret = nilfs_mdt_init(inode, nilfs, GFP_NOFS, 0);
248} 183 if (!ret) {
184 inode->i_mapping->a_ops = &def_gcinode_aops;
249 185
250static unsigned long ihash(ino_t ino, __u64 cno) 186 ii->i_flags = 0;
251{ 187 nilfs_bmap_init_gc(ii->i_bmap);
252 return hash_long((unsigned long)((ino << 2) + cno),
253 NILFS_GCINODE_HASH_BITS);
254}
255 188
256/* 189 /*
257 * nilfs_gc_iget() - find or create gc inode with specified (ino,cno) 190 * Add the inode to GC inode list. Garbage Collection
258 */ 191 * is serialized and no two processes manipulate the
259struct inode *nilfs_gc_iget(struct the_nilfs *nilfs, ino_t ino, __u64 cno) 192 * list simultaneously.
260{ 193 */
261 struct hlist_head *head = nilfs->ns_gc_inodes_h + ihash(ino, cno); 194 igrab(inode);
262 struct hlist_node *node;
263 struct inode *inode;
264
265 hlist_for_each_entry(inode, node, head, i_hash) {
266 if (inode->i_ino == ino && NILFS_I(inode)->i_cno == cno)
267 return inode;
268 }
269
270 inode = alloc_gcinode(nilfs, ino, cno);
271 if (likely(inode)) {
272 hlist_add_head(&inode->i_hash, head);
273 list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes); 195 list_add(&NILFS_I(inode)->i_dirty, &nilfs->ns_gc_inodes);
274 } 196 }
275 return inode; 197 return ret;
276}
277
278/*
279 * nilfs_clear_gcinode() - clear and free a gc inode
280 */
281void nilfs_clear_gcinode(struct inode *inode)
282{
283 nilfs_mdt_destroy(inode);
284} 198}
285 199
286/* 200/**
287 * nilfs_remove_all_gcinode() - remove all inodes from the_nilfs 201 * nilfs_remove_all_gcinodes() - remove all unprocessed gc inodes
288 */ 202 */
289void nilfs_remove_all_gcinode(struct the_nilfs *nilfs) 203void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs)
290{ 204{
291 struct hlist_head *head = nilfs->ns_gc_inodes_h; 205 struct list_head *head = &nilfs->ns_gc_inodes;
292 struct hlist_node *node, *n; 206 struct nilfs_inode_info *ii;
293 struct inode *inode;
294 int loop;
295 207
296 for (loop = 0; loop < NILFS_GCINODE_HASH_SIZE; loop++, head++) { 208 while (!list_empty(head)) {
297 hlist_for_each_entry_safe(inode, node, n, head, i_hash) { 209 ii = list_first_entry(head, struct nilfs_inode_info, i_dirty);
298 hlist_del_init(&inode->i_hash); 210 list_del_init(&ii->i_dirty);
299 list_del_init(&NILFS_I(inode)->i_dirty); 211 iput(&ii->vfs_inode);
300 nilfs_clear_gcinode(inode); /* might sleep */
301 }
302 } 212 }
303} 213}
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index 6e9df85b5824..82cfdbc43e1c 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)
527 return inode; 527 return inode;
528} 528}
529 529
530struct inode *nilfs_iget_for_gc(struct super_block *sb, unsigned long ino,
531 __u64 cno)
532{
533 struct nilfs_iget_args args = { .ino = ino, .cno = cno, .for_gc = 1 };
534 struct inode *inode;
535 int err;
536
537 inode = iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args);
538 if (unlikely(!inode))
539 return ERR_PTR(-ENOMEM);
540 if (!(inode->i_state & I_NEW))
541 return inode;
542
543 err = nilfs_init_gcinode(inode);
544 if (unlikely(err)) {
545 iget_failed(inode);
546 return ERR_PTR(err);
547 }
548 unlock_new_inode(inode);
549 return inode;
550}
551
530void nilfs_write_inode_common(struct inode *inode, 552void nilfs_write_inode_common(struct inode *inode,
531 struct nilfs_inode *raw_inode, int has_bmap) 553 struct nilfs_inode *raw_inode, int has_bmap)
532{ 554{
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index 0442ee3b394f..2ee6843c2e87 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,
333 return 0; 333 return 0;
334} 334}
335 335
336static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs, 336static int nilfs_ioctl_move_blocks(struct super_block *sb,
337 struct nilfs_argv *argv, void *buf) 337 struct nilfs_argv *argv, void *buf)
338{ 338{
339 size_t nmembs = argv->v_nmembs; 339 size_t nmembs = argv->v_nmembs;
@@ -348,7 +348,7 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
348 for (i = 0, vdesc = buf; i < nmembs; ) { 348 for (i = 0, vdesc = buf; i < nmembs; ) {
349 ino = vdesc->vd_ino; 349 ino = vdesc->vd_ino;
350 cno = vdesc->vd_cno; 350 cno = vdesc->vd_cno;
351 inode = nilfs_gc_iget(nilfs, ino, cno); 351 inode = nilfs_iget_for_gc(sb, ino, cno);
352 if (unlikely(inode == NULL)) { 352 if (unlikely(inode == NULL)) {
353 ret = -ENOMEM; 353 ret = -ENOMEM;
354 goto failed; 354 goto failed;
@@ -356,11 +356,15 @@ static int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
356 do { 356 do {
357 ret = nilfs_ioctl_move_inode_block(inode, vdesc, 357 ret = nilfs_ioctl_move_inode_block(inode, vdesc,
358 &buffers); 358 &buffers);
359 if (unlikely(ret < 0)) 359 if (unlikely(ret < 0)) {
360 iput(inode);
360 goto failed; 361 goto failed;
362 }
361 vdesc++; 363 vdesc++;
362 } while (++i < nmembs && 364 } while (++i < nmembs &&
363 vdesc->vd_ino == ino && vdesc->vd_cno == cno); 365 vdesc->vd_ino == ino && vdesc->vd_cno == cno);
366
367 iput(inode); /* The inode still remains in GC inode list */
364 } 368 }
365 369
366 list_for_each_entry_safe(bh, n, &buffers, b_assoc_buffers) { 370 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,
566 } 570 }
567 571
568 /* 572 /*
569 * nilfs_ioctl_move_blocks() will call nilfs_gc_iget(), 573 * nilfs_ioctl_move_blocks() will call nilfs_iget_for_gc(),
570 * which will operates an inode list without blocking. 574 * which will operates an inode list without blocking.
571 * To protect the list from concurrent operations, 575 * To protect the list from concurrent operations,
572 * nilfs_ioctl_move_blocks should be atomic operation. 576 * nilfs_ioctl_move_blocks should be atomic operation.
@@ -576,15 +580,14 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp,
576 goto out_free; 580 goto out_free;
577 } 581 }
578 582
579 ret = nilfs_ioctl_move_blocks(nilfs, &argv[0], kbufs[0]); 583 ret = nilfs_ioctl_move_blocks(inode->i_sb, &argv[0], kbufs[0]);
580 if (ret < 0) 584 if (ret < 0)
581 printk(KERN_ERR "NILFS: GC failed during preparation: " 585 printk(KERN_ERR "NILFS: GC failed during preparation: "
582 "cannot read source blocks: err=%d\n", ret); 586 "cannot read source blocks: err=%d\n", ret);
583 else 587 else
584 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); 588 ret = nilfs_clean_segments(inode->i_sb, argv, kbufs);
585 589
586 if (ret < 0) 590 nilfs_remove_all_gcinodes(nilfs);
587 nilfs_remove_all_gcinode(nilfs);
588 clear_nilfs_gc_running(nilfs); 591 clear_nilfs_gc_running(nilfs);
589 592
590out_free: 593out_free:
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h
index d3d54046e5f8..797cd437970e 100644
--- a/fs/nilfs2/nilfs.h
+++ b/fs/nilfs2/nilfs.h
@@ -248,6 +248,8 @@ extern void nilfs_set_inode_flags(struct inode *);
248extern int nilfs_read_inode_common(struct inode *, struct nilfs_inode *); 248extern int nilfs_read_inode_common(struct inode *, struct nilfs_inode *);
249extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int); 249extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int);
250extern struct inode *nilfs_iget(struct super_block *, unsigned long); 250extern struct inode *nilfs_iget(struct super_block *, unsigned long);
251extern struct inode *nilfs_iget_for_gc(struct super_block *sb,
252 unsigned long ino, __u64 cno);
251extern void nilfs_update_inode(struct inode *, struct buffer_head *); 253extern void nilfs_update_inode(struct inode *, struct buffer_head *);
252extern void nilfs_truncate(struct inode *); 254extern void nilfs_truncate(struct inode *);
253extern void nilfs_evict_inode(struct inode *); 255extern void nilfs_evict_inode(struct inode *);
@@ -292,11 +294,8 @@ int nilfs_gccache_submit_read_data(struct inode *, sector_t, sector_t, __u64,
292int nilfs_gccache_submit_read_node(struct inode *, sector_t, __u64, 294int nilfs_gccache_submit_read_node(struct inode *, sector_t, __u64,
293 struct buffer_head **); 295 struct buffer_head **);
294int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *); 296int nilfs_gccache_wait_and_mark_dirty(struct buffer_head *);
295int nilfs_init_gccache(struct the_nilfs *); 297int nilfs_init_gcinode(struct inode *inode);
296void nilfs_destroy_gccache(struct the_nilfs *); 298void nilfs_remove_all_gcinodes(struct the_nilfs *nilfs);
297void nilfs_clear_gcinode(struct inode *);
298struct inode *nilfs_gc_iget(struct the_nilfs *, ino_t, __u64);
299void nilfs_remove_all_gcinode(struct the_nilfs *);
300 299
301/* gcdat.c */ 300/* gcdat.c */
302int nilfs_init_gcdat_inode(struct the_nilfs *); 301int nilfs_init_gcdat_inode(struct the_nilfs *);
diff --git a/fs/nilfs2/segment.c b/fs/nilfs2/segment.c
index eee4b223c293..9cf71389f369 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)
2451 list_for_each_entry_safe(ii, n, head, i_dirty) { 2451 list_for_each_entry_safe(ii, n, head, i_dirty) {
2452 if (!test_bit(NILFS_I_UPDATED, &ii->i_state)) 2452 if (!test_bit(NILFS_I_UPDATED, &ii->i_state))
2453 continue; 2453 continue;
2454 hlist_del_init(&ii->vfs_inode.i_hash);
2455 list_del_init(&ii->i_dirty); 2454 list_del_init(&ii->i_dirty);
2456 nilfs_clear_gcinode(&ii->vfs_inode); 2455 iput(&ii->vfs_inode);
2457 } 2456 }
2458} 2457}
2459 2458
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 461b7211e14f..6a012b9e1b31 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)
87 init_rwsem(&nilfs->ns_writer_sem); 87 init_rwsem(&nilfs->ns_writer_sem);
88 INIT_LIST_HEAD(&nilfs->ns_list); 88 INIT_LIST_HEAD(&nilfs->ns_list);
89 INIT_LIST_HEAD(&nilfs->ns_supers); 89 INIT_LIST_HEAD(&nilfs->ns_supers);
90 INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
90 spin_lock_init(&nilfs->ns_last_segment_lock); 91 spin_lock_init(&nilfs->ns_last_segment_lock);
91 nilfs->ns_gc_inodes_h = NULL;
92 init_rwsem(&nilfs->ns_segctor_sem); 92 init_rwsem(&nilfs->ns_segctor_sem);
93 93
94 return nilfs; 94 return nilfs;
@@ -164,7 +164,6 @@ void put_nilfs(struct the_nilfs *nilfs)
164 nilfs_mdt_destroy(nilfs->ns_gc_dat); 164 nilfs_mdt_destroy(nilfs->ns_gc_dat);
165 } 165 }
166 if (nilfs_init(nilfs)) { 166 if (nilfs_init(nilfs)) {
167 nilfs_destroy_gccache(nilfs);
168 brelse(nilfs->ns_sbh[0]); 167 brelse(nilfs->ns_sbh[0]);
169 brelse(nilfs->ns_sbh[1]); 168 brelse(nilfs->ns_sbh[1]);
170 } 169 }
@@ -736,11 +735,6 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data)
736 if (err) 735 if (err)
737 goto failed_sbh; 736 goto failed_sbh;
738 737
739 /* Initialize gcinode cache */
740 err = nilfs_init_gccache(nilfs);
741 if (err)
742 goto failed_sbh;
743
744 set_nilfs_init(nilfs); 738 set_nilfs_init(nilfs);
745 err = 0; 739 err = 0;
746 out: 740 out:
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
index f785a7b0ab99..c7ecd0c623a3 100644
--- a/fs/nilfs2/the_nilfs.h
+++ b/fs/nilfs2/the_nilfs.h
@@ -81,7 +81,6 @@ enum {
81 * @ns_sufile: segusage file inode 81 * @ns_sufile: segusage file inode
82 * @ns_gc_dat: shadow inode of the DAT file inode for GC 82 * @ns_gc_dat: shadow inode of the DAT file inode for GC
83 * @ns_gc_inodes: dummy inodes to keep live blocks 83 * @ns_gc_inodes: dummy inodes to keep live blocks
84 * @ns_gc_inodes_h: hash list to keep dummy inode holding live blocks
85 * @ns_blocksize_bits: bit length of block size 84 * @ns_blocksize_bits: bit length of block size
86 * @ns_blocksize: block size 85 * @ns_blocksize: block size
87 * @ns_nsegments: number of segments in filesystem 86 * @ns_nsegments: number of segments in filesystem
@@ -165,9 +164,8 @@ struct the_nilfs {
165 struct inode *ns_sufile; 164 struct inode *ns_sufile;
166 struct inode *ns_gc_dat; 165 struct inode *ns_gc_dat;
167 166
168 /* GC inode list and hash table head */ 167 /* GC inode list */
169 struct list_head ns_gc_inodes; 168 struct list_head ns_gc_inodes;
170 struct hlist_head *ns_gc_inodes_h;
171 169
172 /* Disk layout information (static) */ 170 /* Disk layout information (static) */
173 unsigned int ns_blocksize_bits; 171 unsigned int ns_blocksize_bits;
@@ -182,9 +180,6 @@ struct the_nilfs {
182 u32 ns_crc_seed; 180 u32 ns_crc_seed;
183}; 181};
184 182
185#define NILFS_GCINODE_HASH_BITS 8
186#define NILFS_GCINODE_HASH_SIZE (1<<NILFS_GCINODE_HASH_BITS)
187
188#define THE_NILFS_FNS(bit, name) \ 183#define THE_NILFS_FNS(bit, name) \
189static inline void set_nilfs_##name(struct the_nilfs *nilfs) \ 184static inline void set_nilfs_##name(struct the_nilfs *nilfs) \
190{ \ 185{ \