aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2/cpfile.c
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2009-04-06 22:01:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-07 11:31:18 -0400
commit76068c4ff1cc03d9d24d17fd9e6a1475bc2f6730 (patch)
treeb2f56fbca8e7680135da5c610bd13283d8377a7f /fs/nilfs2/cpfile.c
parent8acfbf0939e98cc77dab94c24899c9930ddd1e13 (diff)
nilfs2: fix buggy behavior seen in enumerating checkpoints
This will fix the weird behavior of lscp command in listing continuously created checkpoints; the output of lscp is rewinded regularly for the recent nilfs. As a result of debugging, a defect was found in nilfs_cpfile_do_get_cpinfo() function. Though the function can be repeatedly called to enumerate checkpoints and it can skip invalid checkpoint entries, the index value was not carried between successive calls. The bug has long been present, and came to surface after applying a bugfix nilfs2-fix-problems-of-memory-allocation-in-ioctl.patch, which increased frequency of calling the function. The similar bugfix was already applied for ``snapshots'' by nilfs2-fix-gc-failure-on-volumes-keeping-numerous-snapshots.patch. This fixes the problem by making the index argument bidirectional on the function. 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/nilfs2/cpfile.c')
-rw-r--r--fs/nilfs2/cpfile.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c
index 50dff147744f..218b34418508 100644
--- a/fs/nilfs2/cpfile.c
+++ b/fs/nilfs2/cpfile.c
@@ -382,13 +382,13 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
382 ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); 382 ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
383} 383}
384 384
385static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno, 385static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
386 struct nilfs_cpinfo *ci, size_t nci) 386 struct nilfs_cpinfo *ci, size_t nci)
387{ 387{
388 struct nilfs_checkpoint *cp; 388 struct nilfs_checkpoint *cp;
389 struct buffer_head *bh; 389 struct buffer_head *bh;
390 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; 390 size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
391 __u64 cur_cno = nilfs_mdt_cno(cpfile); 391 __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
392 void *kaddr; 392 void *kaddr;
393 int n, ret; 393 int n, ret;
394 int ncps, i; 394 int ncps, i;
@@ -416,6 +416,8 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno,
416 } 416 }
417 417
418 ret = n; 418 ret = n;
419 if (n > 0)
420 *cnop = ci[n - 1].ci_cno + 1;
419 421
420 out: 422 out:
421 up_read(&NILFS_MDT(cpfile)->mi_sem); 423 up_read(&NILFS_MDT(cpfile)->mi_sem);
@@ -510,7 +512,7 @@ ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
510{ 512{
511 switch (mode) { 513 switch (mode) {
512 case NILFS_CHECKPOINT: 514 case NILFS_CHECKPOINT:
513 return nilfs_cpfile_do_get_cpinfo(cpfile, *cnop, ci, nci); 515 return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci);
514 case NILFS_SNAPSHOT: 516 case NILFS_SNAPSHOT:
515 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); 517 return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci);
516 default: 518 default:
@@ -526,13 +528,14 @@ ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
526int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) 528int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
527{ 529{
528 struct nilfs_cpinfo ci; 530 struct nilfs_cpinfo ci;
531 __u64 tcno = cno;
529 ssize_t nci; 532 ssize_t nci;
530 int ret; 533 int ret;
531 534
532 /* checkpoint number 0 is invalid */ 535 /* checkpoint number 0 is invalid */
533 if (cno == 0) 536 if (cno == 0)
534 return -ENOENT; 537 return -ENOENT;
535 nci = nilfs_cpfile_do_get_cpinfo(cpfile, cno, &ci, 1); 538 nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1);
536 if (nci < 0) 539 if (nci < 0)
537 return nci; 540 return nci;
538 else if (nci == 0 || ci.ci_cno != cno) 541 else if (nci == 0 || ci.ci_cno != cno)