aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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{ \