aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsandeen@sandeen.net <sandeen@sandeen.net>2008-11-25 21:20:12 -0600
committerLachlan McIlroy <lachlan@redback.melbourne.sgi.com>2008-12-02 17:16:03 +1100
commit65fbaf2489c667bf79ae1f20403f30c66568d445 (patch)
tree9694dd8017f997730755dec5e58a2324361cf577
parent2ee4fa5cb716eba104a4ef8efe159e1007a2aef6 (diff)
downloadkernel_samsung_smdk4412-65fbaf2489c667bf79ae1f20403f30c66568d445.zip
kernel_samsung_smdk4412-65fbaf2489c667bf79ae1f20403f30c66568d445.tar.gz
kernel_samsung_smdk4412-65fbaf2489c667bf79ae1f20403f30c66568d445.tar.bz2
[XFS] Fix xfs_bulkstat_one size checks & error handling
The 32-bit xfs_blkstat_one handler was failing because a size check checked whether the remaining (32-bit) user buffer was less than the (64-bit) bulkstat buffer, and failed with ENOMEM if so. Move this check into the respective handlers so that they check the correct sizes. Also, the formatters were returning negative errors or positive bytes copied; this was odd in the positive error value world of xfs, and handled wrong by at least some of the callers, which treated the bytes returned as an error value. Move the bytes-used assignment into the formatters. Signed-off-by: Eric Sandeen <sandeen@sandeen.net> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com>
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c44
-rw-r--r--fs/xfs/xfs_itable.c21
-rw-r--r--fs/xfs/xfs_itable.h2
3 files changed, 39 insertions, 28 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index a97022f..2d33606 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -192,35 +192,43 @@ xfs_bstime_store_compat(
return 0;
}
+/* Return 0 on success or positive error (to xfs_bulkstat()) */
STATIC int
xfs_bulkstat_one_fmt_compat(
void __user *ubuffer,
+ int ubsize,
+ int *ubused,
const xfs_bstat_t *buffer)
{
compat_xfs_bstat_t __user *p32 = ubuffer;
- if (put_user(buffer->bs_ino, &p32->bs_ino) ||
- put_user(buffer->bs_mode, &p32->bs_mode) ||
- put_user(buffer->bs_nlink, &p32->bs_nlink) ||
- put_user(buffer->bs_uid, &p32->bs_uid) ||
- put_user(buffer->bs_gid, &p32->bs_gid) ||
- put_user(buffer->bs_rdev, &p32->bs_rdev) ||
- put_user(buffer->bs_blksize, &p32->bs_blksize) ||
- put_user(buffer->bs_size, &p32->bs_size) ||
+ if (ubsize < sizeof(*p32))
+ return XFS_ERROR(ENOMEM);
+
+ if (put_user(buffer->bs_ino, &p32->bs_ino) ||
+ put_user(buffer->bs_mode, &p32->bs_mode) ||
+ put_user(buffer->bs_nlink, &p32->bs_nlink) ||
+ put_user(buffer->bs_uid, &p32->bs_uid) ||
+ put_user(buffer->bs_gid, &p32->bs_gid) ||
+ put_user(buffer->bs_rdev, &p32->bs_rdev) ||
+ put_user(buffer->bs_blksize, &p32->bs_blksize) ||
+ put_user(buffer->bs_size, &p32->bs_size) ||
xfs_bstime_store_compat(&p32->bs_atime, &buffer->bs_atime) ||
xfs_bstime_store_compat(&p32->bs_mtime, &buffer->bs_mtime) ||
xfs_bstime_store_compat(&p32->bs_ctime, &buffer->bs_ctime) ||
- put_user(buffer->bs_blocks, &p32->bs_blocks) ||
- put_user(buffer->bs_xflags, &p32->bs_xflags) ||
- put_user(buffer->bs_extsize, &p32->bs_extsize) ||
- put_user(buffer->bs_extents, &p32->bs_extents) ||
- put_user(buffer->bs_gen, &p32->bs_gen) ||
- put_user(buffer->bs_projid, &p32->bs_projid) ||
- put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) ||
- put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
+ put_user(buffer->bs_blocks, &p32->bs_blocks) ||
+ put_user(buffer->bs_xflags, &p32->bs_xflags) ||
+ put_user(buffer->bs_extsize, &p32->bs_extsize) ||
+ put_user(buffer->bs_extents, &p32->bs_extents) ||
+ put_user(buffer->bs_gen, &p32->bs_gen) ||
+ put_user(buffer->bs_projid, &p32->bs_projid) ||
+ put_user(buffer->bs_dmevmask, &p32->bs_dmevmask) ||
+ put_user(buffer->bs_dmstate, &p32->bs_dmstate) ||
put_user(buffer->bs_aextents, &p32->bs_aextents))
- return -XFS_ERROR(EFAULT);
- return sizeof(*p32);
+ return XFS_ERROR(EFAULT);
+ if (ubused)
+ *ubused = sizeof(*p32);
+ return 0;
}
STATIC int
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 7bd49b8..e19d0a8 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -188,14 +188,21 @@ xfs_bulkstat_one_dinode(
}
}
+/* Return 0 on success or positive error */
STATIC int
xfs_bulkstat_one_fmt(
void __user *ubuffer,
+ int ubsize,
+ int *ubused,
const xfs_bstat_t *buffer)
{
+ if (ubsize < sizeof(*buffer))
+ return XFS_ERROR(ENOMEM);
if (copy_to_user(ubuffer, buffer, sizeof(*buffer)))
- return -EFAULT;
- return sizeof(*buffer);
+ return XFS_ERROR(EFAULT);
+ if (ubused)
+ *ubused = sizeof(*buffer);
+ return 0;
}
/*
@@ -223,8 +230,6 @@ xfs_bulkstat_one_int(
if (!buffer || xfs_internal_inum(mp, ino))
return XFS_ERROR(EINVAL);
- if (ubsize < sizeof(*buf))
- return XFS_ERROR(ENOMEM);
buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
@@ -239,15 +244,11 @@ xfs_bulkstat_one_int(
xfs_bulkstat_one_dinode(mp, ino, dip, buf);
}
- error = formatter(buffer, buf);
- if (error < 0) {
- error = EFAULT;
+ error = formatter(buffer, ubsize, ubused, buf);
+ if (error)
goto out_free;
- }
*stat = BULKSTAT_RV_DIDONE;
- if (ubused)
- *ubused = error;
out_free:
kmem_free(buf);
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index e210a4c..1fb04e7 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -71,6 +71,8 @@ xfs_bulkstat_single(
typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */
void __user *ubuffer, /* buffer to write to */
+ int ubsize, /* remaining user buffer sz */
+ int *ubused, /* bytes used by formatter */
const xfs_bstat_t *buffer); /* buffer to read from */
int