summaryrefslogtreecommitdiff
path: root/fs/nilfs2/ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nilfs2/ioctl.c')
-rw-r--r--fs/nilfs2/ioctl.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index e0a606643e87..01a04080ef70 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -69,7 +69,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
if (argv->v_index > ~(__u64)0 - argv->v_nmembs)
return -EINVAL;
- buf = (void *)get_zeroed_page(GFP_NOFS);
+ buf = kzalloc(PAGE_SIZE, GFP_NOFS);
if (unlikely(!buf))
return -ENOMEM;
maxmembs = PAGE_SIZE / argv->v_size;
@@ -107,7 +107,7 @@ static int nilfs_ioctl_wrap_copy(struct the_nilfs *nilfs,
}
argv->v_nmembs = total;
- free_pages((unsigned long)buf, 0);
+ kfree(buf);
return ret;
}
@@ -527,6 +527,7 @@ static int nilfs_ioctl_get_bdescs(struct inode *inode, struct file *filp,
* Return: 0 on success, or one of the following negative error codes on
* failure:
* * %-EEXIST - Block conflict detected.
+ * * %-EINVAL - Invalid virtual block descriptor.
* * %-EIO - I/O error.
* * %-ENOENT - Requested block doesn't exist.
* * %-ENOMEM - Insufficient memory available.
@@ -536,15 +537,30 @@ static int nilfs_ioctl_move_inode_block(struct inode *inode,
struct list_head *buffers)
{
struct buffer_head *bh;
+ __u64 limit_blkidx = (__u64)inode->i_sb->s_maxbytes >> inode->i_blkbits;
int ret;
- if (vdesc->vd_flags == 0)
+ /*
+ * vblocknr 0 is reserved as an invalid pointer. Also, limit_blkidx
+ * ensures that the page index converted from vd_vblocknr never
+ * overflows the page cache limit and respects the architecture's bmap
+ * key width.
+ */
+ if (unlikely(vdesc->vd_vblocknr == 0 ||
+ vdesc->vd_vblocknr >= limit_blkidx))
+ return -EINVAL;
+
+ if (vdesc->vd_flags == 0) {
+ if (unlikely(vdesc->vd_offset >= limit_blkidx))
+ return -EINVAL;
+
ret = nilfs_gccache_submit_read_data(
inode, vdesc->vd_offset, vdesc->vd_blocknr,
vdesc->vd_vblocknr, &bh);
- else
+ } else {
ret = nilfs_gccache_submit_read_node(
inode, vdesc->vd_blocknr, vdesc->vd_vblocknr, &bh);
+ }
if (unlikely(ret < 0)) {
if (ret == -ENOENT)
@@ -596,7 +612,7 @@ static int nilfs_ioctl_move_blocks(struct super_block *sb,
struct nilfs_vdesc *vdesc;
struct buffer_head *bh, *n;
LIST_HEAD(buffers);
- ino_t ino;
+ u64 ino;
__u64 cno;
int i, ret;