Commit 76068c4f authored by Ryusuke Konishi's avatar Ryusuke Konishi Committed by Linus Torvalds

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: default avatarRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8acfbf09
...@@ -382,13 +382,13 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, ...@@ -382,13 +382,13 @@ static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
} }
static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno, static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
struct nilfs_cpinfo *ci, size_t nci) struct nilfs_cpinfo *ci, size_t nci)
{ {
struct nilfs_checkpoint *cp; struct nilfs_checkpoint *cp;
struct buffer_head *bh; struct buffer_head *bh;
size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
__u64 cur_cno = nilfs_mdt_cno(cpfile); __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
void *kaddr; void *kaddr;
int n, ret; int n, ret;
int ncps, i; int ncps, i;
...@@ -416,6 +416,8 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno, ...@@ -416,6 +416,8 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 cno,
} }
ret = n; ret = n;
if (n > 0)
*cnop = ci[n - 1].ci_cno + 1;
out: out:
up_read(&NILFS_MDT(cpfile)->mi_sem); 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,7 +512,7 @@ ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
{ {
switch (mode) { switch (mode) {
case NILFS_CHECKPOINT: case NILFS_CHECKPOINT:
return nilfs_cpfile_do_get_cpinfo(cpfile, *cnop, ci, nci); return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, ci, nci);
case NILFS_SNAPSHOT: case NILFS_SNAPSHOT:
return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci); return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci);
default: default:
...@@ -526,13 +528,14 @@ ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, ...@@ -526,13 +528,14 @@ ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
{ {
struct nilfs_cpinfo ci; struct nilfs_cpinfo ci;
__u64 tcno = cno;
ssize_t nci; ssize_t nci;
int ret; int ret;
/* checkpoint number 0 is invalid */ /* checkpoint number 0 is invalid */
if (cno == 0) if (cno == 0)
return -ENOENT; return -ENOENT;
nci = nilfs_cpfile_do_get_cpinfo(cpfile, cno, &ci, 1); nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, 1);
if (nci < 0) if (nci < 0)
return nci; return nci;
else if (nci == 0 || ci.ci_cno != cno) else if (nci == 0 || ci.ci_cno != cno)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment