Hi,
On Wed, 17 Dec 2008 06:48:59 +1300, John Huttley wrote:
> Ryusuke Konishi wrote:
> > I've found a bug of nilfs2 kernel module (in ioctl code) that may
> > cause this error.
> >
> > If the bug was the cause, it should occur for volumes having numerous
> > snapshots, or on the machine whose amount of memory is low.
> >
> > I would like to fix this early.
>
> The machine is has 1Gb ram 5110 processor in 64 bit mode
> nilfs is in a 4Gb partition. It is my IMAP spool.
> The only time snapshots are taken is for backup, this is daily.
>
> Traffic is low on the fs and the snapshot is deleted after the backup.
All right. This seems like another problem.
Anyhow, I made a patch to fix the other "no such file or directory"
problem of the cleaner daemon. It's against nilfs-2.0.5.
Try the attached patch when in the mood.
I'll include it in the next nilfs release.
Thanks,
Ryusuke
---
diff --git a/fs/cpfile.c b/fs/cpfile.c
index 480dd31..1e9ce4c 100644
--- a/fs/cpfile.c
+++ b/fs/cpfile.c
@@ -422,20 +422,20 @@ static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode
*cpfile, __u64 cno,
return ret;
}
-static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 cno,
+static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
struct nilfs_cpinfo *ci, size_t nci)
{
struct buffer_head *bh;
struct nilfs_cpfile_header *header;
struct nilfs_checkpoint *cp;
- __u64 curr, next;
+ __u64 curr = *cnop, next;
unsigned long curr_blkoff, next_blkoff;
void *kaddr;
int n, ret;
down_read(&NILFS_MDT(cpfile)->mi_sem);
- if (cno == 0) {
+ if (curr == 0) {
ret = nilfs_cpfile_get_header_block(cpfile, &bh);
if (ret < 0)
goto out;
@@ -448,8 +448,11 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode
*cpfile, __u64 cno,
ret = 0;
goto out;
}
- } else
- curr = cno;
+ } else if (unlikely(curr == ~(__u64)0)) {
+ ret = 0;
+ goto out;
+ }
+
curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
if (ret < 0)
@@ -461,7 +464,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode
*cpfile, __u64 cno,
nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, &ci[n]);
next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
if (next == 0) {
- curr = next;
+ curr = ~(__u64)0; /* Terminator */
n++;
break;
}
@@ -480,6 +483,7 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode
*cpfile, __u64 cno,
}
kunmap_atomic(kaddr, KM_USER0);
brelse(bh);
+ *cnop = curr;
ret = n;
out:
@@ -494,15 +498,15 @@ static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode
*cpfile, __u64 cno,
* @ci:
* @nci:
*/
-ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile,
- __u64 cno, int mode,
+
+ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
struct nilfs_cpinfo *ci, size_t nci)
{
switch (mode) {
case NILFS_CHECKPOINT:
- return nilfs_cpfile_do_get_cpinfo(cpfile, cno, ci, nci);
+ return nilfs_cpfile_do_get_cpinfo(cpfile, *cnop, ci, nci);
case NILFS_SNAPSHOT:
- return nilfs_cpfile_do_get_ssinfo(cpfile, cno, ci, nci);
+ return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, ci, nci);
default:
return -EINVAL;
}
diff --git a/fs/cpfile.h b/fs/cpfile.h
index 8bebcf1..02917e4 100644
--- a/fs/cpfile.h
+++ b/fs/cpfile.h
@@ -39,7 +39,7 @@ int nilfs_cpfile_delete_checkpoint(struct inode *, __u64);
int nilfs_cpfile_change_cpmode(struct inode *, __u64, int);
int nilfs_cpfile_is_snapshot(struct inode *, __u64);
int nilfs_cpfile_get_stat(struct inode *, struct nilfs_cpstat *);
-ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64, int,
+ssize_t nilfs_cpfile_get_cpinfo(struct inode *, __u64 *, int,
struct nilfs_cpinfo *, size_t);
#endif /* _NILFS_CPFILE_H */
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 5832e3b..9c55ee5 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -34,41 +34,32 @@
#include "dat.h"
-#define KMALLOC_SIZE_MIN 4096 /* 4KB */
-#define KMALLOC_SIZE_MAX 131072 /* 128 KB */
-
static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
struct nilfs_argv *argv, int dir,
ssize_t (*dofunc)(struct the_nilfs *,
- int, int,
+ __u64 *, int,
void *, size_t, size_t))
{
void *buf;
- size_t ksize, maxmembs, total, n;
+ size_t maxmembs, total, n;
ssize_t nr;
int ret, i;
+ __u64 pos, ppos;
if (argv->v_nmembs == 0)
return 0;
- ksize = min_t(unsigned long, argv->v_nmembs * argv->v_size,
- KMALLOC_SIZE_MAX);
- while (ksize >= KMALLOC_SIZE_MIN) {
- buf = kmalloc(ksize, GFP_NOWAIT | __GFP_NOWARN);
- if (buf)
- goto allocated;
- ksize >>= 1;
- }
- ksize = max_t(size_t, ksize, argv->v_size);
- buf = kmalloc(ksize, GFP_NOFS);
+ if (argv->v_size > PAGE_SIZE)
+ return -EINVAL;
+
+ buf = (void *)__get_free_pages(GFP_NOFS, 0);
if (unlikely(!buf))
return -ENOMEM;
-
- allocated:
- maxmembs = ksize / argv->v_size;
+ maxmembs = PAGE_SIZE / argv->v_size;
ret = 0;
total = 0;
+ pos = argv->v_index;
for (i = 0; i < argv->v_nmembs; i += n) {
n = (argv->v_nmembs - i < maxmembs) ?
argv->v_nmembs - i : maxmembs;
@@ -79,8 +70,9 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
ret = -EFAULT;
break;
}
- nr = (*dofunc)(nilfs, argv->v_index + i, argv->v_flags, buf,
- argv->v_size, n);
+ ppos = pos;
+ nr = (*dofunc)(nilfs, &pos, argv->v_flags, buf, argv->v_size,
+ n);
if (nr < 0) {
ret = nr;
break;
@@ -93,10 +85,14 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
break;
}
total += nr;
+ if ((size_t)nr < n)
+ break;
+ if (pos == ppos)
+ pos += n;
}
argv->v_nmembs = total;
- kfree(buf);
+ free_pages((unsigned long)buf, 0);
return ret;
}
@@ -141,10 +137,10 @@ nilfs_ioctl_delete_checkpoint(struct inode *inode, struct
file *filp,
}
static ssize_t
-nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_cpinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
- return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, index, flags, buf,
+ return nilfs_cpfile_get_cpinfo(nilfs->ns_cpfile, posp, flags, buf,
nmembs);
}
@@ -189,10 +185,10 @@ static int nilfs_ioctl_get_cpstat(struct inode *inode,
struct file *filp,
}
static ssize_t
-nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_suinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
- return nilfs_sufile_get_suinfo(nilfs->ns_sufile, index, buf, nmembs);
+ return nilfs_sufile_get_suinfo(nilfs->ns_sufile, *posp, buf, nmembs);
}
static int nilfs_ioctl_get_suinfo(struct inode *inode, struct file *filp,
@@ -236,7 +232,7 @@ static int nilfs_ioctl_get_sustat(struct inode *inode,
struct file *filp,
}
static ssize_t
-nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_vinfo(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
return nilfs_dat_get_vinfo(nilfs_dat_inode(nilfs), buf, nmembs);
@@ -264,7 +260,7 @@ static int nilfs_ioctl_get_vinfo(struct inode *inode,
struct file *filp,
}
static ssize_t
-nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_get_bdescs(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
struct inode *dat = nilfs_dat_inode(nilfs);
@@ -342,7 +338,7 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
}
static ssize_t
-nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_move_blocks(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
struct inode *inode;
@@ -414,7 +410,7 @@ static inline int nilfs_ioctl_move_blocks(struct the_nilfs
*nilfs,
}
static ssize_t
-nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, int index,
+nilfs_ioctl_do_delete_checkpoints(struct the_nilfs *nilfs, __u64 *posp,
int flags, void *buf, size_t size,
size_t nmembs)
{
@@ -440,7 +436,7 @@ static inline int nilfs_ioctl_delete_checkpoints(struct
the_nilfs *nilfs,
}
static ssize_t
-nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_free_vblocknrs(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
int ret = nilfs_dat_freev(nilfs_dat_inode(nilfs), buf, nmembs);
@@ -457,8 +453,9 @@ static inline int nilfs_ioctl_free_vblocknrs(struct
the_nilfs *nilfs,
}
static ssize_t
-nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, int index, int flags,
- void *buf, size_t size, size_t nmembs)
+nilfs_ioctl_do_mark_blocks_dirty(struct the_nilfs *nilfs, __u64 *posp,
+ int flags, void *buf, size_t size,
+ size_t nmembs)
{
struct inode *dat = nilfs_dat_inode(nilfs);
struct nilfs_bmap *bmap = NILFS_I(dat)->i_bmap;
@@ -507,7 +504,7 @@ static inline int nilfs_ioctl_mark_blocks_dirty(struct
the_nilfs *nilfs,
}
static ssize_t
-nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, int index, int flags,
+nilfs_ioctl_do_free_segments(struct the_nilfs *nilfs, __u64 *posp, int flags,
void *buf, size_t size, size_t nmembs)
{
struct nilfs_sb_info *sbi = nilfs_get_writer(nilfs);
_______________________________________________
users mailing list
[email protected]
https://www.nilfs.org/mailman/listinfo/users