aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-04-06 22:01:47 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-07 11:31:17 -0400
commitb028fcfc4cd198a6aa1ffcfb872073ccc1db3459 (patch)
treed6a89ba7cf253ab1738d5295f557b77e77ac4311 /fs
parent85ef9cea02882baedd1e65336cf3dd292841dde3 (diff)
nilfs2: fix gc failure on volumes keeping numerous snapshots
This resolves the following failure of nilfs2 cleaner daemon: nilfs_cleanerd[20670]: cannot clean segments: No such file or directory nilfs_cleanerd[20670]: shutdown When creating thousands of snapshots, the cleaner daemon had rarely died as above due to an error returned from the kernel code. After applying the recent patch which fixed memory allocation problems in ioctl (Message-Id: <20081215.155840.105124170.ryusuke@osrg.net>), the problem gets more frequent. It turned out to be a bug of nilfs_ioctl_wrap_copy function and one of its callback routines to read out information of snapshots; if the nilfs_ioctl_wrap_copy function divided a large read request into multiple requests, the second and later requests have failed since a restart position on snapshot meta data was not properly set forward. It's a deficiency of the callback interface that cannot pass the restart position among multiple requests. This patch fixes the issue by allowing nilfs_ioctl_wrap_copy and snapshot read functions to exchange a position argument. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/nilfs2/cpfile.c24
-rw-r--r--fs/nilfs2/cpfile.h2
-rw-r--r--fs/nilfs2/ioctl.c38
3 files changed, 38 insertions, 26 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c
index 82462acd06ee..a4c9550fd774 100644
--- a/fs/nilfs2/cpfile.c
+++ b/fs/nilfs2/cpfile.c
@@ -422,20 +422,20 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno,
422 return ret; 422 return ret;
423} 423}
424 424
425static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno, 425static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
426 struct nilfs_cpinfo *ci, size_t nci) 426 struct nilfs_cpinfo *ci, size_t nci)
427{ 427{
428 struct buffer_head *bh; 428 struct buffer_head *bh;
429 struct nilfs_cpfile_header *header; 429 struct nilfs_cpfile_header *header;
430 struct nilfs_checkpoint *cp; 430 struct nilfs_checkpoint *cp;
431 __u64 curr, next; 431 __u64 curr = *cnop, next;
432 unsigned long curr_blkoff, next_blkoff; 432 unsigned long curr_blkoff, next_blkoff;
433 void *kaddr; 433 void *kaddr;
434 int n, ret; 434 int n, ret;
435 435
436 down_read(&NILFS_MDT(cpfile)->mi_sem); 436 down_read(&NILFS_MDT(cpfile)->mi_sem);
437 437
438 if (cno == 0) { 438 if (curr == 0) {
439 ret = nilfs_cpfile_get_header_block(cpfile, &bh); 439 ret = nilfs_cpfile_get_header_block(cpfile, &bh);
440 if (ret < 0) 440 if (ret < 0)
441 goto out; 441 goto out;
@@ -448,8 +448,11 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno,
448 ret = 0; 448 ret = 0;
449 goto out; 449 goto out;
450 } 450 }
451 } else 451 } else if (unlikely(curr == ~(__u64)0)) {
452 curr = cno; 452 ret = 0;
453 goto out;
454 }
455
453 curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr); 456 curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
454 ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh); 457 ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
455 if (ret < 0) 458 if (ret < 0)
@@ -461,7 +464,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno,
461 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n]); 464 nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n]);
462 next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); 465 next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
463 if (next == 0) { 466 if (next == 0) {
464 curr = next; 467 curr = ~(__u64)0; /* Terminator */
465 n++; 468 n++;
466 break; 469 break;
467 } 470 }
@@ -480,6 +483,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno,
480 } 483 }
481 kunmap_atomic(kaddr, KM_USER0); 484 kunmap_atomic(kaddr, KM_USER0);
482 brelse(bh); 485 brelse(bh);
486 *cnop = curr;
483 ret = n; 487 ret = n;
484 488
485 out: 489 out:
@@ -494,15 +498,15 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno,
494 * @ci: 498 * @ci:
495 * @nci: 499 * @nci:
496 */ 500 */
497ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, 501
498 __u64 cno, int mode, 502ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
499 struct nilfs_cpinfo *ci, size_t nci) 503 struct nilfs_cpinfo *ci, size_t nci)
500{ 504{
501 switch (mode) { 505 switch (mode) {
502 case NILFS_CHECKPOINT: 506 case NILFS_CHECKPOINT:
503 return nilfs_cpfile_do_get_cpinfo(cpfile, cno, ci, nci); 507 return nilfs_cpfile_do_get_cpinfo(cpfile, *cnop, ci, nci);
504 case NILFS_SNAPSHOT: 508 case NILFS_SNAPSHOT:
505 return nilfs_cpfile_do_get_ssinfo(cpfile, cno, ci, nci); 509 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci);
506 default: 510 default:
507 return -EINVAL; 511 return -EINVAL;
508 } 512 }
diff --git a/fs/nilfs2/cpfile.h b/fs/nilfs2/cpfile.h
index f097e90fcb20..1a8a1008c342 100644
--- a/fs/nilfs2/cpfile.h
+++ b/fs/nilfs2/cpfile.h
@@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64);
39int nilfs_cpfile_change_cpmode(struct inode *, __u64, int); 39int nilfs_cpfile_change_cpmode(struct inode *, __u64, int);
40int nilfs_cpfile_is_snapshot(struct inode *, __u64); 40int nilfs_cpfile_is_snapshot(struct inode *, __u64);
41int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *); 41int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *);
42ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64, int, 42ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int,
43 struct nilfs_cpinfo *, size_t); 43 struct nilfs_cpinfo *, size_t);
44 44
45#endif /* _NILFS_CPFILE_H */ 45#endif /* _NILFS_CPFILE_H */
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index 5ce06a01c7ec..d9e3990f9589 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -37,13 +37,14 @@
37static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs, 37static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
38 struct nilfs_argv *argv, int dir, 38 struct nilfs_argv *argv, int dir,
39 ssize_t (*dofunc)(struct the_nilfs *, 39 ssize_t (*dofunc)(struct the_nilfs *,
40 int, int, 40 __u64 *, int,
41 void *, size_t, size_t)) 41 void *, size_t, size_t))
42{ 42{
43 void *buf; 43 void *buf;
44 size_t maxmembs, total, n; 44 size_t maxmembs, total, n;
45 ssize_t nr; 45 ssize_t nr;
46 int ret, i; 46 int ret, i;
47 __u64 pos, ppos;
47 48
48 if (argv->v_nmembs == 0) 49 if (argv->v_nmembs == 0)
49 return 0; 50 return 0;
@@ -58,6 +59,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
58 59
59 ret = 0; 60 ret = 0;
60 total = 0; 61 total = 0;
62 pos = argv->v_index;
61 for (i = 0; i < argv->v_nmembs; i += n) { 63 for (i = 0; i < argv->v_nmembs; i += n) {
62 n = (argv->v_nmembs - i < maxmembs) ? 64 n = (argv->v_nmembs - i < maxmembs) ?
63 argv->v_nmembs - i : maxmembs; 65 argv->v_nmembs - i : maxmembs;
@@ -68,8 +70,9 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
68 ret = -EFAULT; 70 ret = -EFAULT;
69 break; 71 break;
70 } 72 }
71 nr = (*dofunc)(nilfs, argv->v_index + i, argv->v_flags, buf, 73 ppos = pos;
72 argv->v_size, n); 74 nr = (*dofunc)(nilfs, &pos, argv->v_flags, buf, argv->v_size,
75 n);
73 if (nr < 0) { 76 if (nr < 0) {
74 ret = nr; 77 ret = nr;
75 break; 78 break;
@@ -82,6 +85,10 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
82 break; 85 break;
83 } 86 }
84 total += nr; 87 total += nr;
88 if ((size_t)nr < n)
89 break;
90 if (pos == ppos)
91 pos += n;
85 } 92 }
86 argv->v_nmembs = total; 93 argv->v_nmembs = total;
87 94
@@ -138,10 +145,10 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct file *filp,
138} 145}
139 146
140static ssize_t 147static ssize_t
141nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, int index, int flags, 148nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
142 void *buf, size_t size, size_t nmembs) 149 void *buf, size_t size, size_t nmembs)
143{ 150{
144 return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, index, flags, buf, 151 return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
145 nmembs); 152 nmembs);
146} 153}
147 154
@@ -186,10 +193,10 @@ static int nilfs_ioctl_get_cpstat(struct inode *inode, struct file *filp,
186} 193}
187 194
188static ssize_t 195static ssize_t
189nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, int index, int flags, 196nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
190 void *buf, size_t size, size_t nmembs) 197 void *buf, size_t size, size_t nmembs)
191{ 198{
192 return nilfs_sufile_get_suinfo(nilfs->ns_sufile, index, buf, nmembs); 199 return nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs);
193} 200}
194 201
195static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp, 202static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp,
@@ -233,7 +240,7 @@ static int nilfs_ioctl_get_sustat(struct inode *inode, struct file *filp,
233} 240}
234 241
235static ssize_t 242static ssize_t
236nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, int index, int flags, 243nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
237 void *buf, size_t size, size_t nmembs) 244 void *buf, size_t size, size_t nmembs)
238{ 245{
239 return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs); 246 return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs);
@@ -262,7 +269,7 @@ static int nilfs_ioctl_get_vinfo(struct inode *inode, struct file *filp,
262} 269}
263 270
264static ssize_t 271static ssize_t
265nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, int index, int flags, 272nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
266 void *buf, size_t size, size_t nmembs) 273 void *buf, size_t size, size_t nmembs)
267{ 274{
268 struct inode *dat = nilfs_dat_inode(nilfs); 275 struct inode *dat = nilfs_dat_inode(nilfs);
@@ -341,7 +348,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
341} 348}
342 349
343static ssize_t 350static ssize_t
344nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, int index, int flags, 351nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags,
345 void *buf, size_t size, size_t nmembs) 352 void *buf, size_t size, size_t nmembs)
346{ 353{
347 struct inode *inode; 354 struct inode *inode;
@@ -413,7 +420,7 @@ static inline int nilfs_ioctl_move_blocks(struct the_nilfs *nilfs,
413} 420}
414 421
415static ssize_t 422static ssize_t
416nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, int index, 423nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp,
417 int flags, void *buf, size_t size, 424 int flags, void *buf, size_t size,
418 size_t nmembs) 425 size_t nmembs)
419{ 426{
@@ -439,7 +446,7 @@ static inline int nilfs_ioctl_delete_checkpoints(struct the_nilfs *nilfs,
439} 446}
440 447
441static ssize_t 448static ssize_t
442nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, int index, int flags, 449nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, __u64 *posp, int flags,
443 void *buf, size_t size, size_t nmembs) 450 void *buf, size_t size, size_t nmembs)
444{ 451{
445 int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs); 452 int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);
@@ -456,8 +463,9 @@ static inline int nilfs_ioctl_free_vblocknrs(struct the_nilfs *nilfs,
456} 463}
457 464
458static ssize_t 465static ssize_t
459nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, int index, int flags, 466nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp,
460 void *buf, size_t size, size_t nmembs) 467 int flags, void *buf, size_t size,
468 size_t nmembs)
461{ 469{
462 struct inode *dat = nilfs_dat_inode(nilfs); 470 struct inode *dat = nilfs_dat_inode(nilfs);
463 struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap; 471 struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
@@ -506,7 +514,7 @@ static inline int nilfs_ioctl_mark_blocks_dirty(struct the_nilfs *nilfs,
506} 514}
507 515
508static ssize_t 516static ssize_t
509nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, int index, int flags, 517nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags,
510 void *buf, size_t size, size_t nmembs) 518 void *buf, size_t size, size_t nmembs)
511{ 519{
512 struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs); 520 struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs);