LKML Archive on lore.kernel.org help / color / mirror / Atom feed
* [patch 0/3] Fix for XFS compat ioctls (try2) @ 2007-06-19 13:25 mmarek 2007-06-19 13:25 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode mmarek ` (2 more replies) 0 siblings, 3 replies; 12+ messages in thread From: mmarek @ 2007-06-19 13:25 UTC (permalink / raw) To: xfs; +Cc: linux-kernel Hi, here is my second attempt at fixing (some of) the XFS ioctls in compat mode. The main difference from the first version is the bulkstat patch, which I modified to do less copies (no unnecessary copy_in_user() anymore). -- have a nice day, Michal Marek ^ permalink raw reply [flat|nested] 12+ messages in thread
* [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode 2007-06-19 13:25 [patch 0/3] Fix for XFS compat ioctls (try2) mmarek @ 2007-06-19 13:25 ` mmarek 2007-06-28 3:06 ` David Chinner 2007-06-19 13:25 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " mmarek 2007-06-19 13:25 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " mmarek 2 siblings, 1 reply; 12+ messages in thread From: mmarek @ 2007-06-19 13:25 UTC (permalink / raw) To: xfs; +Cc: linux-kernel [-- Attachment #1: xfs-compat-ioctl-fsgeometry.patch --] [-- Type: text/plain, Size: 2733 bytes --] i386 struct xfs_fsop_geom_v1 has no padding after the last member, so the size is different. Signed-off-by: Michal Marek <mmarek@suse.cz> --- fs/xfs/linux-2.6/xfs_ioctl32.c | 42 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl32.c +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -75,6 +75,42 @@ xfs_ioctl32_flock( return (unsigned long)p; } +typedef struct compat_xfs_fsop_geom_v1 { + __u32 blocksize; /* filesystem (data) block size */ + __u32 rtextsize; /* realtime extent size */ + __u32 agblocks; /* fsblocks in an AG */ + __u32 agcount; /* number of allocation groups */ + __u32 logblocks; /* fsblocks in the log */ + __u32 sectsize; /* (data) sector size, bytes */ + __u32 inodesize; /* inode size in bytes */ + __u32 imaxpct; /* max allowed inode space(%) */ + __u64 datablocks; /* fsblocks in data subvolume */ + __u64 rtblocks; /* fsblocks in realtime subvol */ + __u64 rtextents; /* rt extents in realtime subvol*/ + __u64 logstart; /* starting fsblock of the log */ + unsigned char uuid[16]; /* unique id of the filesystem */ + __u32 sunit; /* stripe unit, fsblocks */ + __u32 swidth; /* stripe width, fsblocks */ + __s32 version; /* structure version */ + __u32 flags; /* superblock version flags */ + __u32 logsectsize; /* log sector size, bytes */ + __u32 rtsectsize; /* realtime sector size, bytes */ + __u32 dirblocksize; /* directory block size, bytes */ +} __attribute__((packed)) compat_xfs_fsop_geom_v1_t; + +#define XFS_IOC_FSGEOMETRY_V1_32 \ + _IOR ('X', 100, struct compat_xfs_fsop_geom_v1) + +STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg) +{ + compat_xfs_fsop_geom_v1_t __user *p32 = (void __user *)arg; + xfs_fsop_geom_v1_t __user *p = compat_alloc_user_space(sizeof(*p)); + + if (copy_in_user(p, p32, sizeof(*p32))) + return -EFAULT; + return (unsigned long)p; +} + #else typedef struct xfs_fsop_bulkreq32 { @@ -118,7 +154,6 @@ xfs_compat_ioctl( switch (cmd) { case XFS_IOC_DIOINFO: - case XFS_IOC_FSGEOMETRY_V1: case XFS_IOC_FSGEOMETRY: case XFS_IOC_GETVERSION: case XFS_IOC_GETXFLAGS: @@ -166,6 +201,10 @@ xfs_compat_ioctl( arg = xfs_ioctl32_flock(arg); cmd = _NATIVE_IOC(cmd, struct xfs_flock64); break; + case XFS_IOC_FSGEOMETRY_V1_32: + arg = xfs_ioctl32_geom_v1(arg); + cmd = _NATIVE_IOC(cmd, struct xfs_fsop_geom_v1); + break; #else /* These are handled fine if no alignment issues */ case XFS_IOC_ALLOCSP: @@ -176,6 +215,7 @@ xfs_compat_ioctl( case XFS_IOC_FREESP64: case XFS_IOC_RESVSP64: case XFS_IOC_UNRESVSP64: + case XFS_IOC_FSGEOMETRY_V1: break; /* xfs_bstat_t still has wrong u32 vs u64 alignment */ -- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode 2007-06-19 13:25 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode mmarek @ 2007-06-28 3:06 ` David Chinner 0 siblings, 0 replies; 12+ messages in thread From: David Chinner @ 2007-06-28 3:06 UTC (permalink / raw) To: mmarek; +Cc: xfs, linux-kernel On Tue, Jun 19, 2007 at 03:25:50PM +0200, mmarek@suse.cz wrote: > i386 struct xfs_fsop_geom_v1 has no padding after the last member, so > the size is different. Looks good. Added to my qa tree... Cheers, Dave. -- Dave Chinner Principal Engineer SGI Australian Software Group ^ permalink raw reply [flat|nested] 12+ messages in thread
* [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE in compat mode 2007-06-19 13:25 [patch 0/3] Fix for XFS compat ioctls (try2) mmarek 2007-06-19 13:25 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode mmarek @ 2007-06-19 13:25 ` mmarek 2007-06-28 3:07 ` David Chinner 2007-06-19 13:25 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " mmarek 2 siblings, 1 reply; 12+ messages in thread From: mmarek @ 2007-06-19 13:25 UTC (permalink / raw) To: xfs; +Cc: linux-kernel [-- Attachment #1: xfs-compat-ioctl-fshandle.patch --] [-- Type: text/plain, Size: 2979 bytes --] 32bit struct xfs_fsop_handlereq has different size and offsets (due to pointers). TODO: case XFS_IOC_{FSSETDM,ATTRLIST,ATTRMULTI}_BY_HANDLE still not handled. Signed-off-by: Michal Marek <mmarek@suse.cz> --- fs/xfs/linux-2.6/xfs_ioctl32.c | 57 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 5 deletions(-) --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl32.c +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -141,6 +141,50 @@ xfs_ioctl32_bulkstat( } #endif +typedef struct compat_xfs_fsop_handlereq { + __u32 fd; /* fd for FD_TO_HANDLE */ + compat_uptr_t path; /* user pathname */ + __u32 oflags; /* open flags */ + compat_uptr_t ihandle; /* user supplied handle */ + __u32 ihandlen; /* user supplied length */ + compat_uptr_t ohandle; /* user buffer for handle */ + compat_uptr_t ohandlen; /* user buffer length */ +} compat_xfs_fsop_handlereq_t; + +#define XFS_IOC_PATH_TO_FSHANDLE_32 \ + _IOWR('X', 104, struct compat_xfs_fsop_handlereq) +#define XFS_IOC_PATH_TO_HANDLE_32 \ + _IOWR('X', 105, struct compat_xfs_fsop_handlereq) +#define XFS_IOC_FD_TO_HANDLE_32 \ + _IOWR('X', 106, struct compat_xfs_fsop_handlereq) +#define XFS_IOC_OPEN_BY_HANDLE_32 \ + _IOWR('X', 107, struct compat_xfs_fsop_handlereq) +#define XFS_IOC_READLINK_BY_HANDLE_32 \ + _IOWR('X', 108, struct compat_xfs_fsop_handlereq) + +STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg) +{ + compat_xfs_fsop_handlereq_t __user *p32 = (void __user *)arg; + xfs_fsop_handlereq_t __user *p = compat_alloc_user_space(sizeof(*p)); + u32 addr; + + if (copy_in_user(&p->fd, &p32->fd, sizeof(__u32)) || + get_user(addr, &p32->path) || + put_user(compat_ptr(addr), &p->path) || + copy_in_user(&p->oflags, &p32->oflags, sizeof(__u32)) || + get_user(addr, &p32->ihandle) || + put_user(compat_ptr(addr), &p->ihandle) || + copy_in_user(&p->ihandlen, &p32->ihandlen, sizeof(__u32)) || + get_user(addr, &p32->ohandle) || + put_user(compat_ptr(addr), &p->ohandle) || + get_user(addr, &p32->ohandlen) || + put_user(compat_ptr(addr), &p->ohandlen)) + return -EFAULT; + + return (unsigned long)p; +} + + STATIC long xfs_compat_ioctl( int mode, @@ -166,12 +210,7 @@ xfs_compat_ioctl( case XFS_IOC_GETBMAPA: case XFS_IOC_GETBMAPX: /* not handled - case XFS_IOC_FD_TO_HANDLE: - case XFS_IOC_PATH_TO_HANDLE: - case XFS_IOC_PATH_TO_FSHANDLE: - case XFS_IOC_OPEN_BY_HANDLE: case XFS_IOC_FSSETDM_BY_HANDLE: - case XFS_IOC_READLINK_BY_HANDLE: case XFS_IOC_ATTRLIST_BY_HANDLE: case XFS_IOC_ATTRMULTI_BY_HANDLE: */ @@ -228,6 +267,14 @@ xfs_compat_ioctl( arg = xfs_ioctl32_bulkstat(arg); break; #endif + case XFS_IOC_FD_TO_HANDLE_32: + case XFS_IOC_PATH_TO_HANDLE_32: + case XFS_IOC_PATH_TO_FSHANDLE_32: + case XFS_IOC_OPEN_BY_HANDLE_32: + case XFS_IOC_READLINK_BY_HANDLE_32: + arg = xfs_ioctl32_fshandle(arg); + cmd = _NATIVE_IOC(cmd, struct xfs_fsop_handlereq); + break; default: return -ENOIOCTLCMD; } -- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE in compat mode 2007-06-19 13:25 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " mmarek @ 2007-06-28 3:07 ` David Chinner 0 siblings, 0 replies; 12+ messages in thread From: David Chinner @ 2007-06-28 3:07 UTC (permalink / raw) To: mmarek; +Cc: xfs, linux-kernel On Tue, Jun 19, 2007 at 03:25:51PM +0200, mmarek@suse.cz wrote: > 32bit struct xfs_fsop_handlereq has different size and offsets (due to > pointers). TODO: case XFS_IOC_{FSSETDM,ATTRLIST,ATTRMULTI}_BY_HANDLE > still not handled. Looks good. Added to my qa tree... Cheers, Dave. -- Dave Chinner Principal Engineer SGI Australian Software Group ^ permalink raw reply [flat|nested] 12+ messages in thread
* [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode 2007-06-19 13:25 [patch 0/3] Fix for XFS compat ioctls (try2) mmarek 2007-06-19 13:25 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode mmarek 2007-06-19 13:25 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " mmarek @ 2007-06-19 13:25 ` mmarek 2007-06-28 3:49 ` David Chinner 2007-06-28 18:15 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode Andrew Morton 2 siblings, 2 replies; 12+ messages in thread From: mmarek @ 2007-06-19 13:25 UTC (permalink / raw) To: xfs; +Cc: linux-kernel [-- Attachment #1: xfs-compat-ioctl-bulkstat.patch --] [-- Type: text/plain, Size: 14254 bytes --] * 32bit struct xfs_fsop_bulkreq has different size and layout of members, no matter the alignment. Move the code out of the #else branch (why was it there in the first place?). Define _32 variants of the ioctl constants. * 32bit struct xfs_bstat is different because of time_t and on i386 becaus of different padding. Create a new formatter xfs_bulkstat_one_compat() that takes care of this. To do this, we need to make xfs_bulkstat_one_iget() and xfs_bulkstat_one_dinode() non-static. * i386 struct xfs_inogrp has different padding. Introduce a similar "formatter" mechanism for xfs_inumbers: the native formatter is just a copy_to_user, the compat formatter takes care of the different layout Signed-off-by: Michal Marek <mmarek@suse.cz> --- fs/xfs/linux-2.6/xfs_ioctl.c | 2 fs/xfs/linux-2.6/xfs_ioctl32.c | 259 +++++++++++++++++++++++++++++++++++++---- fs/xfs/xfs_itable.c | 30 +++- fs/xfs/xfs_itable.h | 31 ++++ 4 files changed, 290 insertions(+), 32 deletions(-) --- linux-2.6.21.orig/fs/xfs/linux-2.6/xfs_ioctl32.c +++ linux-2.6.21/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -28,12 +28,27 @@ #include "xfs_vfs.h" #include "xfs_vnode.h" #include "xfs_dfrag.h" +#include "xfs_sb.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_inum.h" +#include "xfs_bmap_btree.h" +#include "xfs_dir2.h" +#include "xfs_dir2_sf.h" +#include "xfs_attr_sf.h" +#include "xfs_dinode.h" +#include "xfs_itable.h" +#include "xfs_error.h" +#include "xfs_inode.h" #define _NATIVE_IOC(cmd, type) \ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) #define BROKEN_X86_ALIGNMENT +#define _PACKED __attribute__((packed)) /* on ia32 l_start is on a 32-bit boundary */ typedef struct xfs_flock64_32 { __s16 l_type; @@ -111,35 +126,234 @@ STATIC unsigned long xfs_ioctl32_geom_v1 return (unsigned long)p; } +typedef struct compat_xfs_inogrp { + __u64 xi_startino; /* starting inode number */ + __s32 xi_alloccount; /* # bits set in allocmask */ + __u64 xi_allocmask; /* mask of allocated inodes */ +} __attribute__((packed)) compat_xfs_inogrp_t; + +STATIC int xfs_inumbers_fmt_compat( + void __user *ubuffer, + const xfs_inogrp_t *buffer, + long count, + long *written) +{ + compat_xfs_inogrp_t *p32 = ubuffer; + long i; + + for (i = 0; i < count; i++) { + if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) || + put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) || + put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask)) + return -EFAULT; + } + *written = count * sizeof(*p32); + return 0; +} + #else -typedef struct xfs_fsop_bulkreq32 { +#define xfs_inumbers_fmt_compat(a, b, c, d) xfs_inumbers_fmt(a, b, c, d) +#define _PACKED + +#endif + +/* XFS_IOC_FSBULKSTAT and friends */ + +typedef struct compat_xfs_bstime { + __s32 tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} compat_xfs_bstime_t; + +static int xfs_bstime_store_compat( + compat_xfs_bstime_t __user *p32, + xfs_bstime_t *p) +{ + __s32 sec32; + + sec32 = p->tv_sec; + if (put_user(sec32, &p32->tv_sec) || + put_user(p->tv_nsec, &p32->tv_nsec)) + return -EFAULT; + return 0; +} + +typedef struct compat_xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + compat_xfs_bstime_t bs_atime; /* access time */ + compat_xfs_bstime_t bs_mtime; /* modify time */ + compat_xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid; /* project id */ + unsigned char bs_pad[14]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} _PACKED compat_xfs_bstat_t; + +static int xfs_bulkstat_one_compat( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t ino, /* inode number to get data for */ + void __user *buffer, /* buffer to place output in */ + int ubsize, /* size of buffer */ + void *private_data, /* my private data */ + xfs_daddr_t bno, /* starting bno of inode cluster */ + int *ubused, /* bytes used by me */ + void *dibuff, /* on-disk inode buffer */ + int *stat) /* BULKSTAT_RV_... */ +{ + xfs_bstat_t *buf; /* return buffer */ + int error = 0; /* error value */ + xfs_dinode_t *dip; /* dinode inode pointer */ + compat_xfs_bstat_t __user *p32 = buffer; + + dip = (xfs_dinode_t *)dibuff; + *stat = BULKSTAT_RV_NOTHING; + + 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); + + if (dip == NULL) { + /* We're not being passed a pointer to a dinode. This happens + * if BULKSTAT_FG_IGET is selected. Do the iget. + */ + error = xfs_bulkstat_one_iget(mp, ino, bno, buf, stat); + if (error) + goto out_free; + } else { + xfs_bulkstat_one_dinode(mp, ino, dip, buf); + } + + if (put_user(buf->bs_ino, &p32->bs_ino) || + put_user(buf->bs_mode, &p32->bs_mode) || + put_user(buf->bs_nlink, &p32->bs_nlink) || + put_user(buf->bs_uid, &p32->bs_uid) || + put_user(buf->bs_gid, &p32->bs_gid) || + put_user(buf->bs_rdev, &p32->bs_rdev) || + put_user(buf->bs_blksize, &p32->bs_blksize) || + put_user(buf->bs_size, &p32->bs_size) || + xfs_bstime_store_compat(&p32->bs_atime, &buf->bs_atime) || + xfs_bstime_store_compat(&p32->bs_mtime, &buf->bs_mtime) || + xfs_bstime_store_compat(&p32->bs_ctime, &buf->bs_ctime) || + put_user(buf->bs_blocks, &p32->bs_blocks) || + put_user(buf->bs_xflags, &p32->bs_xflags) || + put_user(buf->bs_extsize, &p32->bs_extsize) || + put_user(buf->bs_extents, &p32->bs_extents) || + put_user(buf->bs_gen, &p32->bs_gen) || + put_user(buf->bs_projid, &p32->bs_projid) || + put_user(buf->bs_dmevmask, &p32->bs_dmevmask) || + put_user(buf->bs_dmstate, &p32->bs_dmstate) || + put_user(buf->bs_aextents, &p32->bs_aextents)) { + error = EFAULT; + goto out_free; + } + + *stat = BULKSTAT_RV_DIDONE; + if (ubused) + *ubused = sizeof(compat_xfs_bstat_t); + + out_free: + kmem_free(buf, sizeof(*buf)); + return error; +} + + + +typedef struct compat_xfs_fsop_bulkreq { compat_uptr_t lastip; /* last inode # pointer */ __s32 icount; /* count of entries in buffer */ compat_uptr_t ubuffer; /* user buffer for inode desc. */ - __s32 ocount; /* output count pointer */ -} xfs_fsop_bulkreq32_t; + compat_uptr_t ocount; /* output count pointer */ +} compat_xfs_fsop_bulkreq_t; -STATIC unsigned long -xfs_ioctl32_bulkstat( - unsigned long arg) +#define XFS_IOC_FSBULKSTAT_32 \ + _IOWR('X', 101, struct compat_xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE_32 \ + _IOWR('X', 102, struct compat_xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS_32 \ + _IOWR('X', 103, struct compat_xfs_fsop_bulkreq) + +/* copied from xfs_ioctl.c */ +STATIC int +xfs_ioc_bulkstat_compat( + xfs_mount_t *mp, + unsigned int cmd, + void __user *arg) { - xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg; - xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p)); + compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg; u32 addr; + xfs_fsop_bulkreq_t bulkreq; + int count; /* # of records returned */ + xfs_ino_t inlast; /* last inode number */ + int done; + int error; + + /* done = 1 if there are more stats to get and if bulkstat */ + /* should be called again (unused here, but used in dmapi) */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (XFS_FORCED_SHUTDOWN(mp)) + return -XFS_ERROR(EIO); - if (get_user(addr, &p32->lastip) || - put_user(compat_ptr(addr), &p->lastip) || - copy_in_user(&p->icount, &p32->icount, sizeof(s32)) || - get_user(addr, &p32->ubuffer) || - put_user(compat_ptr(addr), &p->ubuffer) || - get_user(addr, &p32->ocount) || - put_user(compat_ptr(addr), &p->ocount)) + if (get_user(addr, &p32->lastip)) + return -EFAULT; + bulkreq.lastip = compat_ptr(addr); + if (get_user(bulkreq.icount, &p32->icount) || + get_user(addr, &p32->ubuffer)) + return -EFAULT; + bulkreq.ubuffer = compat_ptr(addr); + if (get_user(addr, &p32->ocount)) return -EFAULT; + bulkreq.ocount = compat_ptr(addr); - return (unsigned long)p; + if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) + return -XFS_ERROR(EFAULT); + + if ((count = bulkreq.icount) <= 0) + return -XFS_ERROR(EINVAL); + + if (cmd == XFS_IOC_FSINUMBERS) + error = xfs_inumbers(mp, &inlast, &count, + bulkreq.ubuffer, xfs_inumbers_fmt_compat); + else + error = xfs_bulkstat(mp, &inlast, &count, + xfs_bulkstat_one_compat, NULL, + sizeof(compat_xfs_bstat_t), bulkreq.ubuffer, + BULKSTAT_FG_QUICK, &done); + + if (error) + return -error; + + if (bulkreq.ocount != NULL) { + if (copy_to_user(bulkreq.lastip, &inlast, + sizeof(xfs_ino_t))) + return -XFS_ERROR(EFAULT); + + if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) + return -XFS_ERROR(EFAULT); + } + + return 0; } -#endif + + typedef struct compat_xfs_fsop_handlereq { __u32 fd; /* fd for FD_TO_HANDLE */ @@ -261,12 +475,13 @@ xfs_compat_ioctl( case XFS_IOC_SWAPEXT: break; - case XFS_IOC_FSBULKSTAT_SINGLE: - case XFS_IOC_FSBULKSTAT: - case XFS_IOC_FSINUMBERS: - arg = xfs_ioctl32_bulkstat(arg); - break; #endif + case XFS_IOC_FSBULKSTAT_32: + case XFS_IOC_FSBULKSTAT_SINGLE_32: + case XFS_IOC_FSINUMBERS_32: + cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq); + return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount, + cmd, (void*)arg); case XFS_IOC_FD_TO_HANDLE_32: case XFS_IOC_PATH_TO_HANDLE_32: case XFS_IOC_PATH_TO_FSHANDLE_32: --- linux-2.6.21.orig/fs/xfs/xfs_itable.h +++ linux-2.6.21/fs/xfs/xfs_itable.h @@ -70,6 +70,21 @@ xfs_bulkstat_single( int *done); int +xfs_bulkstat_one_iget( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t ino, /* inode number to get data for */ + xfs_daddr_t bno, /* starting bno of inode cluster */ + xfs_bstat_t *buf, /* return buffer */ + int *stat); /* BULKSTAT_RV_... */ + +int +xfs_bulkstat_one_dinode( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t ino, /* inode number to get data for */ + xfs_dinode_t *dip, /* dinode inode pointer */ + xfs_bstat_t *buf); /* return buffer */ + +int xfs_bulkstat_one( xfs_mount_t *mp, xfs_ino_t ino, @@ -86,11 +101,25 @@ xfs_internal_inum( xfs_mount_t *mp, xfs_ino_t ino); +typedef int (*inumbers_fmt_pf)( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written); /* # of bytes written */ + +int +xfs_inumbers_fmt( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written); /* # of bytes written */ + int /* error status */ xfs_inumbers( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *last, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_inogrp_t __user *buffer);/* buffer with inode info */ + void __user *buffer, /* buffer with inode info */ + inumbers_fmt_pf formatter); #endif /* __XFS_ITABLE_H__ */ --- linux-2.6.21.orig/fs/xfs/xfs_itable.c +++ linux-2.6.21/fs/xfs/xfs_itable.c @@ -49,7 +49,7 @@ xfs_internal_inum( (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))); } -STATIC int +int xfs_bulkstat_one_iget( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ @@ -129,7 +129,7 @@ xfs_bulkstat_one_iget( return error; } -STATIC int +int xfs_bulkstat_one_dinode( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ @@ -748,6 +748,19 @@ xfs_bulkstat_single( return 0; } +int +xfs_inumbers_fmt( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written) /* # of bytes written */ +{ + if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer))) + return -EFAULT; + *written = count * sizeof(*buffer); + return 0; +} + /* * Return inode number table for the filesystem. */ @@ -756,7 +769,8 @@ xfs_inumbers( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *lastino, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_inogrp_t __user *ubuffer)/* buffer with inode descriptions */ + void __user *ubuffer,/* buffer with inode descriptions */ + inumbers_fmt_pf formatter) { xfs_buf_t *agbp; xfs_agino_t agino; @@ -835,12 +849,12 @@ xfs_inumbers( bufidx++; left--; if (bufidx == bcount) { - if (copy_to_user(ubuffer, buffer, - bufidx * sizeof(*buffer))) { + long written; + if (formatter(ubuffer, buffer, bufidx, &written)) { error = XFS_ERROR(EFAULT); break; } - ubuffer += bufidx; + ubuffer += written; *count += bufidx; bufidx = 0; } @@ -862,8 +876,8 @@ xfs_inumbers( } if (!error) { if (bufidx) { - if (copy_to_user(ubuffer, buffer, - bufidx * sizeof(*buffer))) + long written; + if (formatter(ubuffer, buffer, bufidx, &written)) error = XFS_ERROR(EFAULT); else *count += bufidx; --- linux-2.6.21.orig/fs/xfs/linux-2.6/xfs_ioctl.c +++ linux-2.6.21/fs/xfs/linux-2.6/xfs_ioctl.c @@ -1019,7 +1019,7 @@ xfs_ioc_bulkstat( if (cmd == XFS_IOC_FSINUMBERS) error = xfs_inumbers(mp, &inlast, &count, - bulkreq.ubuffer); + bulkreq.ubuffer, xfs_inumbers_fmt); else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) error = xfs_bulkstat_single(mp, &inlast, bulkreq.ubuffer, &done); -- ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode 2007-06-19 13:25 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " mmarek @ 2007-06-28 3:49 ` David Chinner 2007-07-02 9:40 ` Michal Marek 2007-06-28 18:15 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode Andrew Morton 1 sibling, 1 reply; 12+ messages in thread From: David Chinner @ 2007-06-28 3:49 UTC (permalink / raw) To: mmarek; +Cc: xfs, linux-kernel On Tue, Jun 19, 2007 at 03:25:52PM +0200, mmarek@suse.cz wrote: > * 32bit struct xfs_fsop_bulkreq has different size and layout of > members, no matter the alignment. Move the code out of the #else > branch (why was it there in the first place?). Define _32 variants of > the ioctl constants. > * 32bit struct xfs_bstat is different because of time_t and on > i386 becaus of different padding. Create a new formatter > xfs_bulkstat_one_compat() that takes care of this. To do this, we need > to make xfs_bulkstat_one_iget() and xfs_bulkstat_one_dinode() > non-static. > * i386 struct xfs_inogrp has different padding. Introduce a similar > "formatter" mechanism for xfs_inumbers: the native formatter is just a > copy_to_user, the compat formatter takes care of the different layout Oh, wow, that is so much nicer than the first version, Michal. ;) Still, I think there's possibly one further revision: > +static int xfs_bulkstat_one_compat( > + xfs_mount_t *mp, /* mount point for filesystem */ > + xfs_ino_t ino, /* inode number to get data for */ > + void __user *buffer, /* buffer to place output in */ > + int ubsize, /* size of buffer */ > + void *private_data, /* my private data */ > + xfs_daddr_t bno, /* starting bno of inode cluster */ > + int *ubused, /* bytes used by me */ > + void *dibuff, /* on-disk inode buffer */ > + int *stat) /* BULKSTAT_RV_... */ Hmmm - this is almost all duplicated code. It's pretty much what I described, but maybe not /quite/ what I had in mind here. It's a *big* improvement on the first version, but it seems now that the only real difference xfs_bulkstat_one() and xfs_bulkstat_one_compat() is copy_to_user() vs the discrete put_user calls. I think we can remove xfs_bulkstat_one_compat() completely by using the same method you used with the xfs_inumber_fmt functions. That would mean the only duplicated code is the initial ioctl handling (which we can't really avoid). It would also mean that there is no need to make xfs_bulkstat_one_iget() and xfs_bulkstat_one_dinode() non-static. Your thoughts? Other than that possible improvement, this looks really good. Cheers, Dave. -- Dave Chinner Principal Engineer SGI Australian Software Group ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode 2007-06-28 3:49 ` David Chinner @ 2007-07-02 9:40 ` Michal Marek 2007-07-02 15:05 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode (try3) Michal Marek 0 siblings, 1 reply; 12+ messages in thread From: Michal Marek @ 2007-07-02 9:40 UTC (permalink / raw) To: David Chinner; +Cc: xfs, linux-kernel David Chinner wrote: > On Tue, Jun 19, 2007 at 03:25:52PM +0200, mmarek@suse.cz wrote: >> +static int xfs_bulkstat_one_compat( >> + xfs_mount_t *mp, /* mount point for filesystem */ >> + xfs_ino_t ino, /* inode number to get data for */ >> + void __user *buffer, /* buffer to place output in */ >> + int ubsize, /* size of buffer */ >> + void *private_data, /* my private data */ >> + xfs_daddr_t bno, /* starting bno of inode cluster */ >> + int *ubused, /* bytes used by me */ >> + void *dibuff, /* on-disk inode buffer */ >> + int *stat) /* BULKSTAT_RV_... */ > > Hmmm - this is almost all duplicated code. It's pretty much what I > described, but maybe not /quite/ what I had in mind here. It's a > *big* improvement on the first version, but it seems now that the > only real difference xfs_bulkstat_one() and > xfs_bulkstat_one_compat() is copy_to_user() vs the discrete put_user > calls. > > I think we can remove xfs_bulkstat_one_compat() completely by using > the same method you used with the xfs_inumber_fmt functions. You mean xfs_ioc_bulkstat_compat() -> native xfs_bulkstat() -> native xfs_bulkstat_one() -> a compat output formatter, so a pointer-to-function passed to pointer-to-function? ;) I could (ab)use the void *private_data arg which xfs_bulkstat passes unmodified to the formatter; xfs_bulkstat_one() doesn't make use of it atm. I'll try it and post the result in a while. Michal ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode (try3) 2007-07-02 9:40 ` Michal Marek @ 2007-07-02 15:05 ` Michal Marek 2007-07-03 1:03 ` David Chinner 0 siblings, 1 reply; 12+ messages in thread From: Michal Marek @ 2007-07-02 15:05 UTC (permalink / raw) To: David Chinner; +Cc: xfs, linux-kernel On Mon, Jul 02, 2007 at 11:40:34AM +0200, Michal Marek wrote: > David Chinner wrote: > > I think we can remove xfs_bulkstat_one_compat() completely by using > > the same method you used with the xfs_inumber_fmt functions. > > You mean xfs_ioc_bulkstat_compat() -> native xfs_bulkstat() -> native > xfs_bulkstat_one() -> a compat output formatter, so a > pointer-to-function passed to pointer-to-function? ;) I could (ab)use > the void *private_data arg which xfs_bulkstat passes unmodified to the > formatter; xfs_bulkstat_one() doesn't make use of it atm. I'll try it > and post the result in a while. Hi David, what about this one? It about 30 lines shorter now :) Subject: Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode * 32bit struct xfs_fsop_bulkreq has different size and layout of members, no matter the alignment. Move the code out of the #else branch (why was it there in the first place?). Define _32 variants of the ioctl constants. * 32bit struct xfs_bstat is different because of time_t and on i386 because of different padding. Make xfs_bulkstat_one() accept a custom "output formater" in the private_data argument which takes care of the xfs_bulkstat_one_compat() that takes care of the different layout in the compat case. * i386 struct xfs_inogrp has different padding. Add a similar "output formater" mecanism to xfs_inumbers(). Signed-off-by: Michal Marek <mmarek@suse.cz> --- fs/xfs/linux-2.6/xfs_ioctl.c | 2 fs/xfs/linux-2.6/xfs_ioctl32.c | 221 ++++++++++++++++++++++++++++++++++++----- fs/xfs/xfs_itable.c | 41 ++++++- fs/xfs/xfs_itable.h | 20 +++ 4 files changed, 252 insertions(+), 32 deletions(-) --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl32.c +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -28,12 +28,27 @@ #include "xfs_vfs.h" #include "xfs_vnode.h" #include "xfs_dfrag.h" +#include "xfs_sb.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_inum.h" +#include "xfs_bmap_btree.h" +#include "xfs_dir2.h" +#include "xfs_dir2_sf.h" +#include "xfs_attr_sf.h" +#include "xfs_dinode.h" +#include "xfs_itable.h" +#include "xfs_error.h" +#include "xfs_inode.h" #define _NATIVE_IOC(cmd, type) \ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) #define BROKEN_X86_ALIGNMENT +#define _PACKED __attribute__((packed)) /* on ia32 l_start is on a 32-bit boundary */ typedef struct xfs_flock64_32 { __s16 l_type; @@ -111,35 +126,196 @@ STATIC unsigned long xfs_ioctl32_geom_v1 return (unsigned long)p; } +typedef struct compat_xfs_inogrp { + __u64 xi_startino; /* starting inode number */ + __s32 xi_alloccount; /* # bits set in allocmask */ + __u64 xi_allocmask; /* mask of allocated inodes */ +} __attribute__((packed)) compat_xfs_inogrp_t; + +STATIC int xfs_inumbers_fmt_compat( + void __user *ubuffer, + const xfs_inogrp_t *buffer, + long count, + long *written) +{ + compat_xfs_inogrp_t *p32 = ubuffer; + long i; + + for (i = 0; i < count; i++) { + if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) || + put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) || + put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask)) + return -EFAULT; + } + *written = count * sizeof(*p32); + return 0; +} + #else -typedef struct xfs_fsop_bulkreq32 { +#define xfs_inumbers_fmt_compat xfs_inumbers_fmt +#define _PACKED + +#endif + +/* XFS_IOC_FSBULKSTAT and friends */ + +typedef struct compat_xfs_bstime { + __s32 tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} compat_xfs_bstime_t; + +STATIC int xfs_bstime_store_compat( + compat_xfs_bstime_t __user *p32, + const xfs_bstime_t *p) +{ + __s32 sec32; + + sec32 = p->tv_sec; + if (put_user(sec32, &p32->tv_sec) || + put_user(p->tv_nsec, &p32->tv_nsec)) + return -EFAULT; + return 0; +} + +typedef struct compat_xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + compat_xfs_bstime_t bs_atime; /* access time */ + compat_xfs_bstime_t bs_mtime; /* modify time */ + compat_xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid; /* project id */ + unsigned char bs_pad[14]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} _PACKED compat_xfs_bstat_t; + +STATIC int xfs_bulkstat_one_fmt_compat( + void __user *ubuffer, + 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) || + 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_aextents, &p32->bs_aextents)) + return -EFAULT; + return sizeof(*p32); +} + + + +typedef struct compat_xfs_fsop_bulkreq { compat_uptr_t lastip; /* last inode # pointer */ __s32 icount; /* count of entries in buffer */ compat_uptr_t ubuffer; /* user buffer for inode desc. */ - __s32 ocount; /* output count pointer */ -} xfs_fsop_bulkreq32_t; + compat_uptr_t ocount; /* output count pointer */ +} compat_xfs_fsop_bulkreq_t; -STATIC unsigned long -xfs_ioctl32_bulkstat( - unsigned long arg) +#define XFS_IOC_FSBULKSTAT_32 \ + _IOWR('X', 101, struct compat_xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE_32 \ + _IOWR('X', 102, struct compat_xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS_32 \ + _IOWR('X', 103, struct compat_xfs_fsop_bulkreq) + +/* copied from xfs_ioctl.c */ +STATIC int +xfs_ioc_bulkstat_compat( + xfs_mount_t *mp, + unsigned int cmd, + void __user *arg) { - xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg; - xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p)); + compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg; u32 addr; + xfs_fsop_bulkreq_t bulkreq; + int count; /* # of records returned */ + xfs_ino_t inlast; /* last inode number */ + int done; + int error; + + /* done = 1 if there are more stats to get and if bulkstat */ + /* should be called again (unused here, but used in dmapi) */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (XFS_FORCED_SHUTDOWN(mp)) + return -XFS_ERROR(EIO); - if (get_user(addr, &p32->lastip) || - put_user(compat_ptr(addr), &p->lastip) || - copy_in_user(&p->icount, &p32->icount, sizeof(s32)) || - get_user(addr, &p32->ubuffer) || - put_user(compat_ptr(addr), &p->ubuffer) || - get_user(addr, &p32->ocount) || - put_user(compat_ptr(addr), &p->ocount)) + if (get_user(addr, &p32->lastip)) return -EFAULT; + bulkreq.lastip = compat_ptr(addr); + if (get_user(bulkreq.icount, &p32->icount) || + get_user(addr, &p32->ubuffer)) + return -EFAULT; + bulkreq.ubuffer = compat_ptr(addr); + if (get_user(addr, &p32->ocount)) + return -EFAULT; + bulkreq.ocount = compat_ptr(addr); - return (unsigned long)p; + if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) + return -XFS_ERROR(EFAULT); + + if ((count = bulkreq.icount) <= 0) + return -XFS_ERROR(EINVAL); + + if (cmd == XFS_IOC_FSINUMBERS) + error = xfs_inumbers(mp, &inlast, &count, + bulkreq.ubuffer, xfs_inumbers_fmt_compat); + else { + /* declare a var to get a warning in case the type changes */ + bulkstat_one_fmt_pf formatter = xfs_bulkstat_one_fmt_compat; + error = xfs_bulkstat(mp, &inlast, &count, + xfs_bulkstat_one, formatter, + sizeof(compat_xfs_bstat_t), bulkreq.ubuffer, + BULKSTAT_FG_QUICK, &done); + } + if (error) + return -error; + + if (bulkreq.ocount != NULL) { + if (copy_to_user(bulkreq.lastip, &inlast, + sizeof(xfs_ino_t))) + return -XFS_ERROR(EFAULT); + + if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) + return -XFS_ERROR(EFAULT); + } + + return 0; } -#endif + + typedef struct compat_xfs_fsop_handlereq { __u32 fd; /* fd for FD_TO_HANDLE */ @@ -261,12 +437,13 @@ xfs_compat_ioctl( case XFS_IOC_SWAPEXT: break; - case XFS_IOC_FSBULKSTAT_SINGLE: - case XFS_IOC_FSBULKSTAT: - case XFS_IOC_FSINUMBERS: - arg = xfs_ioctl32_bulkstat(arg); - break; #endif + case XFS_IOC_FSBULKSTAT_32: + case XFS_IOC_FSBULKSTAT_SINGLE_32: + case XFS_IOC_FSINUMBERS_32: + cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq); + return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount, + cmd, (void*)arg); case XFS_IOC_FD_TO_HANDLE_32: case XFS_IOC_PATH_TO_HANDLE_32: case XFS_IOC_PATH_TO_FSHANDLE_32: --- linux-2.6.orig/fs/xfs/xfs_itable.h +++ linux-2.6/fs/xfs/xfs_itable.h @@ -69,6 +69,10 @@ xfs_bulkstat_single( char __user *buffer, int *done); +typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */ + void __user *ubuffer, /* buffer to write to */ + const xfs_bstat_t *buffer); /* buffer to read from */ + int xfs_bulkstat_one( xfs_mount_t *mp, @@ -86,11 +90,25 @@ xfs_internal_inum( xfs_mount_t *mp, xfs_ino_t ino); +typedef int (*inumbers_fmt_pf)( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written); /* # of bytes written */ + +int +xfs_inumbers_fmt( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written); /* # of bytes written */ + int /* error status */ xfs_inumbers( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *last, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_inogrp_t __user *buffer);/* buffer with inode info */ + void __user *buffer, /* buffer with inode info */ + inumbers_fmt_pf formatter); #endif /* __XFS_ITABLE_H__ */ --- linux-2.6.orig/fs/xfs/xfs_itable.c +++ linux-2.6/fs/xfs/xfs_itable.c @@ -202,6 +202,16 @@ xfs_bulkstat_one_dinode( return 0; } +STATIC int +xfs_bulkstat_one_fmt( + void __user *ubuffer, + const xfs_bstat_t *buffer) +{ + if (copy_to_user(ubuffer, buffer, sizeof(*buffer))) + return -EFAULT; + return sizeof(*buffer); +} + /* * Return stat information for one inode. * Return 0 if ok, else errno. @@ -221,6 +231,7 @@ xfs_bulkstat_one( xfs_bstat_t *buf; /* return buffer */ int error = 0; /* error value */ xfs_dinode_t *dip; /* dinode inode pointer */ + bulkstat_one_fmt_pf formatter = private_data ? : xfs_bulkstat_one_fmt; dip = (xfs_dinode_t *)dibuff; *stat = BULKSTAT_RV_NOTHING; @@ -243,14 +254,14 @@ xfs_bulkstat_one( xfs_bulkstat_one_dinode(mp, ino, dip, buf); } - if (copy_to_user(buffer, buf, sizeof(*buf))) { + if ((error = formatter(buffer, buf)) < 0) { error = EFAULT; goto out_free; } *stat = BULKSTAT_RV_DIDONE; if (ubused) - *ubused = sizeof(*buf); + *ubused = error; out_free: kmem_free(buf, sizeof(*buf)); @@ -748,6 +759,19 @@ xfs_bulkstat_single( return 0; } +int +xfs_inumbers_fmt( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written) /* # of bytes written */ +{ + if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer))) + return -EFAULT; + *written = count * sizeof(*buffer); + return 0; +} + /* * Return inode number table for the filesystem. */ @@ -756,7 +780,8 @@ xfs_inumbers( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *lastino, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_inogrp_t __user *ubuffer)/* buffer with inode descriptions */ + void __user *ubuffer,/* buffer with inode descriptions */ + inumbers_fmt_pf formatter) { xfs_buf_t *agbp; xfs_agino_t agino; @@ -835,12 +860,12 @@ xfs_inumbers( bufidx++; left--; if (bufidx == bcount) { - if (copy_to_user(ubuffer, buffer, - bufidx * sizeof(*buffer))) { + long written; + if (formatter(ubuffer, buffer, bufidx, &written)) { error = XFS_ERROR(EFAULT); break; } - ubuffer += bufidx; + ubuffer += written; *count += bufidx; bufidx = 0; } @@ -862,8 +887,8 @@ xfs_inumbers( } if (!error) { if (bufidx) { - if (copy_to_user(ubuffer, buffer, - bufidx * sizeof(*buffer))) + long written; + if (formatter(ubuffer, buffer, bufidx, &written)) error = XFS_ERROR(EFAULT); else *count += bufidx; --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl.c +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl.c @@ -1019,7 +1019,7 @@ xfs_ioc_bulkstat( if (cmd == XFS_IOC_FSINUMBERS) error = xfs_inumbers(mp, &inlast, &count, - bulkreq.ubuffer); + bulkreq.ubuffer, xfs_inumbers_fmt); else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) error = xfs_bulkstat_single(mp, &inlast, bulkreq.ubuffer, &done); ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode (try3) 2007-07-02 15:05 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode (try3) Michal Marek @ 2007-07-03 1:03 ` David Chinner 0 siblings, 0 replies; 12+ messages in thread From: David Chinner @ 2007-07-03 1:03 UTC (permalink / raw) To: Michal Marek; +Cc: David Chinner, xfs, linux-kernel On Mon, Jul 02, 2007 at 05:05:09PM +0200, Michal Marek wrote: > On Mon, Jul 02, 2007 at 11:40:34AM +0200, Michal Marek wrote: > > David Chinner wrote: > > > I think we can remove xfs_bulkstat_one_compat() completely by using > > > the same method you used with the xfs_inumber_fmt functions. > > > > You mean xfs_ioc_bulkstat_compat() -> native xfs_bulkstat() -> native > > xfs_bulkstat_one() -> a compat output formatter, so a > > pointer-to-function passed to pointer-to-function? ;) I could (ab)use > > the void *private_data arg which xfs_bulkstat passes unmodified to the > > formatter; xfs_bulkstat_one() doesn't make use of it atm. I'll try it > > and post the result in a while. > > Hi David, what about this one? It about 30 lines shorter now :) Great. Added to my tree. I'll run some tests and then get it pushed out to the git trees. FWIW, I reordered the includes to match the order in most other XFS files so that it didn't break when I added other patches to the tree.... Cheers, Dave. -- Dave Chinner Principal Engineer SGI Australian Software Group ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode 2007-06-19 13:25 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " mmarek 2007-06-28 3:49 ` David Chinner @ 2007-06-28 18:15 ` Andrew Morton 2007-06-29 11:02 ` Michal Marek 1 sibling, 1 reply; 12+ messages in thread From: Andrew Morton @ 2007-06-28 18:15 UTC (permalink / raw) To: mmarek; +Cc: xfs, linux-kernel On Tue, 19 Jun 2007 15:25:52 +0200 mmarek@suse.cz wrote: > * 32bit struct xfs_fsop_bulkreq has different size and layout of > members, no matter the alignment. Move the code out of the #else > branch (why was it there in the first place?). Define _32 variants of > the ioctl constants. > * 32bit struct xfs_bstat is different because of time_t and on > i386 becaus of different padding. Create a new formatter > xfs_bulkstat_one_compat() that takes care of this. To do this, we need > to make xfs_bulkstat_one_iget() and xfs_bulkstat_one_dinode() > non-static. > * i386 struct xfs_inogrp has different padding. Introduce a similar > "formatter" mechanism for xfs_inumbers: the native formatter is just a > copy_to_user, the compat formatter takes care of the different layout test.kernel.org build failed: CC fs/xfs/linux-2.6/xfs_ioctl32.o fs/xfs/linux-2.6/xfs_ioctl32.c: In function ‘xfs_ioc_bulkstat_compat’: fs/xfs/linux-2.6/xfs_ioctl32.c:334: error: ‘xfs_inumbers_fmt_compat’ undeclared (first use in this function) fs/xfs/linux-2.6/xfs_ioctl32.c:334: error: (Each undeclared identifier is reported only once fs/xfs/linux-2.6/xfs_ioctl32.c:334: error: for each function it appears in.) http://test.kernel.org/abat/96972/debug/test.log.0 http://test.kernel.org/abat/96972/build/dotconfig ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode 2007-06-28 18:15 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode Andrew Morton @ 2007-06-29 11:02 ` Michal Marek 0 siblings, 0 replies; 12+ messages in thread From: Michal Marek @ 2007-06-29 11:02 UTC (permalink / raw) To: Andrew Morton; +Cc: xfs, linux-kernel On Thu, Jun 28, 2007 at 11:15:30AM -0700, Andrew Morton wrote: > CC fs/xfs/linux-2.6/xfs_ioctl32.o > fs/xfs/linux-2.6/xfs_ioctl32.c: In function ‘xfs_ioc_bulkstat_compat’: > fs/xfs/linux-2.6/xfs_ioctl32.c:334: error: ‘xfs_inumbers_fmt_compat’ undeclared (first use in this function) > fs/xfs/linux-2.6/xfs_ioctl32.c:334: error: (Each undeclared identifier is reported only once > fs/xfs/linux-2.6/xfs_ioctl32.c:334: error: for each function it appears in.) Sorry, the #define was wrong. This one should work better (at least build-tested on ppc64 this time): * 32bit struct xfs_fsop_bulkreq has different size and layout of members, no matter the alignment. Move the code out of the #else branch (why was it there in the first place?). Define _32 variants of the ioctl constants. * 32bit struct xfs_bstat is different because of time_t and on i386 becaus of different padding. Create a new formatter xfs_bulkstat_one_compat() that takes care of this. To do this, we need to make xfs_bulkstat_one_iget() and xfs_bulkstat_one_dinode() non-static. * i386 struct xfs_inogrp has different padding. Introduce a similar "formatter" mechanism for xfs_inumbers: the native formatter is just a copy_to_user, the compat formatter takes care of the different layout Signed-off-by: Michal Marek <mmarek@suse.cz> --- fs/xfs/linux-2.6/xfs_ioctl.c | 2 fs/xfs/linux-2.6/xfs_ioctl32.c | 259 +++++++++++++++++++++++++++++++++++++---- fs/xfs/xfs_itable.c | 30 +++- fs/xfs/xfs_itable.h | 31 ++++ 4 files changed, 290 insertions(+), 32 deletions(-) --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl32.c +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl32.c @@ -28,12 +28,27 @@ #include "xfs_vfs.h" #include "xfs_vnode.h" #include "xfs_dfrag.h" +#include "xfs_sb.h" +#include "xfs_log.h" +#include "xfs_trans.h" +#include "xfs_dmapi.h" +#include "xfs_mount.h" +#include "xfs_inum.h" +#include "xfs_bmap_btree.h" +#include "xfs_dir2.h" +#include "xfs_dir2_sf.h" +#include "xfs_attr_sf.h" +#include "xfs_dinode.h" +#include "xfs_itable.h" +#include "xfs_error.h" +#include "xfs_inode.h" #define _NATIVE_IOC(cmd, type) \ _IOC(_IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd), sizeof(type)) #if defined(CONFIG_IA64) || defined(CONFIG_X86_64) #define BROKEN_X86_ALIGNMENT +#define _PACKED __attribute__((packed)) /* on ia32 l_start is on a 32-bit boundary */ typedef struct xfs_flock64_32 { __s16 l_type; @@ -111,35 +126,234 @@ STATIC unsigned long xfs_ioctl32_geom_v1 return (unsigned long)p; } +typedef struct compat_xfs_inogrp { + __u64 xi_startino; /* starting inode number */ + __s32 xi_alloccount; /* # bits set in allocmask */ + __u64 xi_allocmask; /* mask of allocated inodes */ +} __attribute__((packed)) compat_xfs_inogrp_t; + +STATIC int xfs_inumbers_fmt_compat( + void __user *ubuffer, + const xfs_inogrp_t *buffer, + long count, + long *written) +{ + compat_xfs_inogrp_t *p32 = ubuffer; + long i; + + for (i = 0; i < count; i++) { + if (put_user(buffer[i].xi_startino, &p32[i].xi_startino) || + put_user(buffer[i].xi_alloccount, &p32[i].xi_alloccount) || + put_user(buffer[i].xi_allocmask, &p32[i].xi_allocmask)) + return -EFAULT; + } + *written = count * sizeof(*p32); + return 0; +} + #else -typedef struct xfs_fsop_bulkreq32 { +#define xfs_inumbers_fmt_compat xfs_inumbers_fmt +#define _PACKED + +#endif + +/* XFS_IOC_FSBULKSTAT and friends */ + +typedef struct compat_xfs_bstime { + __s32 tv_sec; /* seconds */ + __s32 tv_nsec; /* and nanoseconds */ +} compat_xfs_bstime_t; + +static int xfs_bstime_store_compat( + compat_xfs_bstime_t __user *p32, + xfs_bstime_t *p) +{ + __s32 sec32; + + sec32 = p->tv_sec; + if (put_user(sec32, &p32->tv_sec) || + put_user(p->tv_nsec, &p32->tv_nsec)) + return -EFAULT; + return 0; +} + +typedef struct compat_xfs_bstat { + __u64 bs_ino; /* inode number */ + __u16 bs_mode; /* type and mode */ + __u16 bs_nlink; /* number of links */ + __u32 bs_uid; /* user id */ + __u32 bs_gid; /* group id */ + __u32 bs_rdev; /* device value */ + __s32 bs_blksize; /* block size */ + __s64 bs_size; /* file size */ + compat_xfs_bstime_t bs_atime; /* access time */ + compat_xfs_bstime_t bs_mtime; /* modify time */ + compat_xfs_bstime_t bs_ctime; /* inode change time */ + int64_t bs_blocks; /* number of blocks */ + __u32 bs_xflags; /* extended flags */ + __s32 bs_extsize; /* extent size */ + __s32 bs_extents; /* number of extents */ + __u32 bs_gen; /* generation count */ + __u16 bs_projid; /* project id */ + unsigned char bs_pad[14]; /* pad space, unused */ + __u32 bs_dmevmask; /* DMIG event mask */ + __u16 bs_dmstate; /* DMIG state info */ + __u16 bs_aextents; /* attribute number of extents */ +} _PACKED compat_xfs_bstat_t; + +static int xfs_bulkstat_one_compat( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t ino, /* inode number to get data for */ + void __user *buffer, /* buffer to place output in */ + int ubsize, /* size of buffer */ + void *private_data, /* my private data */ + xfs_daddr_t bno, /* starting bno of inode cluster */ + int *ubused, /* bytes used by me */ + void *dibuff, /* on-disk inode buffer */ + int *stat) /* BULKSTAT_RV_... */ +{ + xfs_bstat_t *buf; /* return buffer */ + int error = 0; /* error value */ + xfs_dinode_t *dip; /* dinode inode pointer */ + compat_xfs_bstat_t __user *p32 = buffer; + + dip = (xfs_dinode_t *)dibuff; + *stat = BULKSTAT_RV_NOTHING; + + 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); + + if (dip == NULL) { + /* We're not being passed a pointer to a dinode. This happens + * if BULKSTAT_FG_IGET is selected. Do the iget. + */ + error = xfs_bulkstat_one_iget(mp, ino, bno, buf, stat); + if (error) + goto out_free; + } else { + xfs_bulkstat_one_dinode(mp, ino, dip, buf); + } + + if (put_user(buf->bs_ino, &p32->bs_ino) || + put_user(buf->bs_mode, &p32->bs_mode) || + put_user(buf->bs_nlink, &p32->bs_nlink) || + put_user(buf->bs_uid, &p32->bs_uid) || + put_user(buf->bs_gid, &p32->bs_gid) || + put_user(buf->bs_rdev, &p32->bs_rdev) || + put_user(buf->bs_blksize, &p32->bs_blksize) || + put_user(buf->bs_size, &p32->bs_size) || + xfs_bstime_store_compat(&p32->bs_atime, &buf->bs_atime) || + xfs_bstime_store_compat(&p32->bs_mtime, &buf->bs_mtime) || + xfs_bstime_store_compat(&p32->bs_ctime, &buf->bs_ctime) || + put_user(buf->bs_blocks, &p32->bs_blocks) || + put_user(buf->bs_xflags, &p32->bs_xflags) || + put_user(buf->bs_extsize, &p32->bs_extsize) || + put_user(buf->bs_extents, &p32->bs_extents) || + put_user(buf->bs_gen, &p32->bs_gen) || + put_user(buf->bs_projid, &p32->bs_projid) || + put_user(buf->bs_dmevmask, &p32->bs_dmevmask) || + put_user(buf->bs_dmstate, &p32->bs_dmstate) || + put_user(buf->bs_aextents, &p32->bs_aextents)) { + error = EFAULT; + goto out_free; + } + + *stat = BULKSTAT_RV_DIDONE; + if (ubused) + *ubused = sizeof(compat_xfs_bstat_t); + + out_free: + kmem_free(buf, sizeof(*buf)); + return error; +} + + + +typedef struct compat_xfs_fsop_bulkreq { compat_uptr_t lastip; /* last inode # pointer */ __s32 icount; /* count of entries in buffer */ compat_uptr_t ubuffer; /* user buffer for inode desc. */ - __s32 ocount; /* output count pointer */ -} xfs_fsop_bulkreq32_t; + compat_uptr_t ocount; /* output count pointer */ +} compat_xfs_fsop_bulkreq_t; -STATIC unsigned long -xfs_ioctl32_bulkstat( - unsigned long arg) +#define XFS_IOC_FSBULKSTAT_32 \ + _IOWR('X', 101, struct compat_xfs_fsop_bulkreq) +#define XFS_IOC_FSBULKSTAT_SINGLE_32 \ + _IOWR('X', 102, struct compat_xfs_fsop_bulkreq) +#define XFS_IOC_FSINUMBERS_32 \ + _IOWR('X', 103, struct compat_xfs_fsop_bulkreq) + +/* copied from xfs_ioctl.c */ +STATIC int +xfs_ioc_bulkstat_compat( + xfs_mount_t *mp, + unsigned int cmd, + void __user *arg) { - xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg; - xfs_fsop_bulkreq_t __user *p = compat_alloc_user_space(sizeof(*p)); + compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg; u32 addr; + xfs_fsop_bulkreq_t bulkreq; + int count; /* # of records returned */ + xfs_ino_t inlast; /* last inode number */ + int done; + int error; + + /* done = 1 if there are more stats to get and if bulkstat */ + /* should be called again (unused here, but used in dmapi) */ + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (XFS_FORCED_SHUTDOWN(mp)) + return -XFS_ERROR(EIO); - if (get_user(addr, &p32->lastip) || - put_user(compat_ptr(addr), &p->lastip) || - copy_in_user(&p->icount, &p32->icount, sizeof(s32)) || - get_user(addr, &p32->ubuffer) || - put_user(compat_ptr(addr), &p->ubuffer) || - get_user(addr, &p32->ocount) || - put_user(compat_ptr(addr), &p->ocount)) + if (get_user(addr, &p32->lastip)) + return -EFAULT; + bulkreq.lastip = compat_ptr(addr); + if (get_user(bulkreq.icount, &p32->icount) || + get_user(addr, &p32->ubuffer)) + return -EFAULT; + bulkreq.ubuffer = compat_ptr(addr); + if (get_user(addr, &p32->ocount)) return -EFAULT; + bulkreq.ocount = compat_ptr(addr); - return (unsigned long)p; + if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) + return -XFS_ERROR(EFAULT); + + if ((count = bulkreq.icount) <= 0) + return -XFS_ERROR(EINVAL); + + if (cmd == XFS_IOC_FSINUMBERS) + error = xfs_inumbers(mp, &inlast, &count, + bulkreq.ubuffer, xfs_inumbers_fmt_compat); + else + error = xfs_bulkstat(mp, &inlast, &count, + xfs_bulkstat_one_compat, NULL, + sizeof(compat_xfs_bstat_t), bulkreq.ubuffer, + BULKSTAT_FG_QUICK, &done); + + if (error) + return -error; + + if (bulkreq.ocount != NULL) { + if (copy_to_user(bulkreq.lastip, &inlast, + sizeof(xfs_ino_t))) + return -XFS_ERROR(EFAULT); + + if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) + return -XFS_ERROR(EFAULT); + } + + return 0; } -#endif + + typedef struct compat_xfs_fsop_handlereq { __u32 fd; /* fd for FD_TO_HANDLE */ @@ -261,12 +475,13 @@ xfs_compat_ioctl( case XFS_IOC_SWAPEXT: break; - case XFS_IOC_FSBULKSTAT_SINGLE: - case XFS_IOC_FSBULKSTAT: - case XFS_IOC_FSINUMBERS: - arg = xfs_ioctl32_bulkstat(arg); - break; #endif + case XFS_IOC_FSBULKSTAT_32: + case XFS_IOC_FSBULKSTAT_SINGLE_32: + case XFS_IOC_FSINUMBERS_32: + cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq); + return xfs_ioc_bulkstat_compat(XFS_BHVTOI(VNHEAD(vp))->i_mount, + cmd, (void*)arg); case XFS_IOC_FD_TO_HANDLE_32: case XFS_IOC_PATH_TO_HANDLE_32: case XFS_IOC_PATH_TO_FSHANDLE_32: --- linux-2.6.orig/fs/xfs/xfs_itable.h +++ linux-2.6/fs/xfs/xfs_itable.h @@ -70,6 +70,21 @@ xfs_bulkstat_single( int *done); int +xfs_bulkstat_one_iget( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t ino, /* inode number to get data for */ + xfs_daddr_t bno, /* starting bno of inode cluster */ + xfs_bstat_t *buf, /* return buffer */ + int *stat); /* BULKSTAT_RV_... */ + +int +xfs_bulkstat_one_dinode( + xfs_mount_t *mp, /* mount point for filesystem */ + xfs_ino_t ino, /* inode number to get data for */ + xfs_dinode_t *dip, /* dinode inode pointer */ + xfs_bstat_t *buf); /* return buffer */ + +int xfs_bulkstat_one( xfs_mount_t *mp, xfs_ino_t ino, @@ -86,11 +101,25 @@ xfs_internal_inum( xfs_mount_t *mp, xfs_ino_t ino); +typedef int (*inumbers_fmt_pf)( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written); /* # of bytes written */ + +int +xfs_inumbers_fmt( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written); /* # of bytes written */ + int /* error status */ xfs_inumbers( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *last, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_inogrp_t __user *buffer);/* buffer with inode info */ + void __user *buffer, /* buffer with inode info */ + inumbers_fmt_pf formatter); #endif /* __XFS_ITABLE_H__ */ --- linux-2.6.orig/fs/xfs/xfs_itable.c +++ linux-2.6/fs/xfs/xfs_itable.c @@ -49,7 +49,7 @@ xfs_internal_inum( (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))); } -STATIC int +int xfs_bulkstat_one_iget( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ @@ -129,7 +129,7 @@ xfs_bulkstat_one_iget( return error; } -STATIC int +int xfs_bulkstat_one_dinode( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode number to get data for */ @@ -748,6 +748,19 @@ xfs_bulkstat_single( return 0; } +int +xfs_inumbers_fmt( + void __user *ubuffer, /* buffer to write to */ + const xfs_inogrp_t *buffer, /* buffer to read from */ + long count, /* # of elements to read */ + long *written) /* # of bytes written */ +{ + if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer))) + return -EFAULT; + *written = count * sizeof(*buffer); + return 0; +} + /* * Return inode number table for the filesystem. */ @@ -756,7 +769,8 @@ xfs_inumbers( xfs_mount_t *mp, /* mount point for filesystem */ xfs_ino_t *lastino, /* last inode returned */ int *count, /* size of buffer/count returned */ - xfs_inogrp_t __user *ubuffer)/* buffer with inode descriptions */ + void __user *ubuffer,/* buffer with inode descriptions */ + inumbers_fmt_pf formatter) { xfs_buf_t *agbp; xfs_agino_t agino; @@ -835,12 +849,12 @@ xfs_inumbers( bufidx++; left--; if (bufidx == bcount) { - if (copy_to_user(ubuffer, buffer, - bufidx * sizeof(*buffer))) { + long written; + if (formatter(ubuffer, buffer, bufidx, &written)) { error = XFS_ERROR(EFAULT); break; } - ubuffer += bufidx; + ubuffer += written; *count += bufidx; bufidx = 0; } @@ -862,8 +876,8 @@ xfs_inumbers( } if (!error) { if (bufidx) { - if (copy_to_user(ubuffer, buffer, - bufidx * sizeof(*buffer))) + long written; + if (formatter(ubuffer, buffer, bufidx, &written)) error = XFS_ERROR(EFAULT); else *count += bufidx; --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl.c +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl.c @@ -1019,7 +1019,7 @@ xfs_ioc_bulkstat( if (cmd == XFS_IOC_FSINUMBERS) error = xfs_inumbers(mp, &inlast, &count, - bulkreq.ubuffer); + bulkreq.ubuffer, xfs_inumbers_fmt); else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) error = xfs_bulkstat_single(mp, &inlast, bulkreq.ubuffer, &done); ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2007-07-03 1:04 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-06-19 13:25 [patch 0/3] Fix for XFS compat ioctls (try2) mmarek 2007-06-19 13:25 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode mmarek 2007-06-28 3:06 ` David Chinner 2007-06-19 13:25 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " mmarek 2007-06-28 3:07 ` David Chinner 2007-06-19 13:25 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " mmarek 2007-06-28 3:49 ` David Chinner 2007-07-02 9:40 ` Michal Marek 2007-07-02 15:05 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode (try3) Michal Marek 2007-07-03 1:03 ` David Chinner 2007-06-28 18:15 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode Andrew Morton 2007-06-29 11:02 ` Michal Marek
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).