LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* [patch 0/3] Fix for XFS compat ioctls
@ 2007-05-30 12:59 Michal Marek
  2007-05-30 12:59 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode Michal Marek
                   ` (2 more replies)
  0 siblings, 3 replies; 18+ messages in thread
From: Michal Marek @ 2007-05-30 12:59 UTC (permalink / raw)
  To: xfs; +Cc: linux-kernel

Hi,

it looks like the XFS compat ioctl interface
(fs/xfs/linux-2.6/xfs_ioctl32.c) is quite incomplete. Attached patches
fix some ioctls to make at least xfsdump work. Tested on x86_64 with an
i386 xfsdump binary, I'll test on ppc64 later.

-- 
have a nice day,
Michal Marek

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode
  2007-05-30 12:59 [patch 0/3] Fix for XFS compat ioctls Michal Marek
@ 2007-05-30 12:59 ` Michal Marek
  2007-05-30 17:05   ` Chris Wedgwood
  2007-05-31  2:30   ` David Chinner
  2007-05-30 12:59 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " Michal Marek
  2007-05-30 12:59 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " Michal Marek
  2 siblings, 2 replies; 18+ messages in thread
From: Michal Marek @ 2007-05-30 12:59 UTC (permalink / raw)
  To: xfs; +Cc: linux-kernel

[-- Attachment #1: xfs-compat-ioctl-fsgeometry.patch --]
[-- Type: text/plain, Size: 2689 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 |   40 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 39 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,40 @@ xfs_ioctl32_flock(
 	return (unsigned long)p;
 }
 
+typedef struct xfs_fsop_geom_v132 {
+	__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)) xfs_fsop_geom_v132_t;
+#define XFS_IOC_FSGEOMETRY_V1_32     _IOR ('X', 100, struct xfs_fsop_geom_v132)
+
+STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg)
+{
+	xfs_fsop_geom_v132_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 +152,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 +199,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 = XFS_IOC_FSGEOMETRY_V1;
+		break;
 
 #else /* These are handled fine if no alignment issues */
 	case XFS_IOC_ALLOCSP:
@@ -176,6 +213,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] 18+ messages in thread

* [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE in compat mode
  2007-05-30 12:59 [patch 0/3] Fix for XFS compat ioctls Michal Marek
  2007-05-30 12:59 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode Michal Marek
@ 2007-05-30 12:59 ` Michal Marek
  2007-05-31  2:36   ` David Chinner
  2007-05-30 12:59 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " Michal Marek
  2 siblings, 1 reply; 18+ messages in thread
From: Michal Marek @ 2007-05-30 12:59 UTC (permalink / raw)
  To: xfs; +Cc: linux-kernel

[-- Attachment #1: xfs-compat-ioctl-fshandle.patch --]
[-- Type: text/plain, Size: 3224 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 |   63 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 58 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
@@ -139,6 +139,44 @@ xfs_ioctl32_bulkstat(
 }
 #endif
 
+typedef struct xfs_fsop_handlereq32 {
+	__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		*/
+} xfs_fsop_handlereq32_t;
+#define XFS_IOC_PATH_TO_FSHANDLE_32 _IOWR('X', 104, struct xfs_fsop_handlereq32)
+#define XFS_IOC_PATH_TO_HANDLE_32   _IOWR('X', 105, struct xfs_fsop_handlereq32)
+#define XFS_IOC_FD_TO_HANDLE_32	    _IOWR('X', 106, struct xfs_fsop_handlereq32)
+#define XFS_IOC_OPEN_BY_HANDLE_32   _IOWR('X', 107, struct xfs_fsop_handlereq32)
+#define XFS_IOC_READLINK_BY_HANDLE_32 _IOWR('X', 108, struct xfs_fsop_handlereq32)
+
+STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg)
+{
+	xfs_fsop_handlereq32_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,
@@ -164,12 +202,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:
 */
@@ -226,6 +259,26 @@ xfs_compat_ioctl(
 		arg = xfs_ioctl32_bulkstat(arg);
 		break;
 #endif
+	case XFS_IOC_FD_TO_HANDLE_32:
+		arg = xfs_ioctl32_fshandle(arg);
+		cmd = XFS_IOC_FD_TO_HANDLE;
+		break;
+	case XFS_IOC_PATH_TO_HANDLE_32:
+		arg = xfs_ioctl32_fshandle(arg);
+		cmd = XFS_IOC_PATH_TO_HANDLE;
+		break;
+	case XFS_IOC_PATH_TO_FSHANDLE_32:
+		arg = xfs_ioctl32_fshandle(arg);
+		cmd = XFS_IOC_PATH_TO_FSHANDLE;
+		break;
+	case XFS_IOC_OPEN_BY_HANDLE_32:
+		arg = xfs_ioctl32_fshandle(arg);
+		cmd = XFS_IOC_OPEN_BY_HANDLE;
+		break;
+	case XFS_IOC_READLINK_BY_HANDLE_32:
+		arg = xfs_ioctl32_fshandle(arg);
+		cmd = XFS_IOC_READLINK_BY_HANDLE;
+		break;
 	default:
 		return -ENOIOCTLCMD;
 	}

-- 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode
  2007-05-30 12:59 [patch 0/3] Fix for XFS compat ioctls Michal Marek
  2007-05-30 12:59 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode Michal Marek
  2007-05-30 12:59 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " Michal Marek
@ 2007-05-30 12:59 ` Michal Marek
  2007-05-31  6:37   ` David Chinner
  2007-05-31  7:06   ` Arnd Bergmann
  2 siblings, 2 replies; 18+ messages in thread
From: Michal Marek @ 2007-05-30 12:59 UTC (permalink / raw)
  To: xfs; +Cc: linux-kernel

[-- Attachment #1: xfs-compat-ioctl-bulkstat.patch --]
[-- Type: text/plain, Size: 8951 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 on 32bit (because of time_t and on
  i386 becaus of different padding). Create a new function
  xfs_ioctl32_bulkstat_wrap(), which allocates extra ->ubuffer and
  converts the elements to the 32bit format after the original ioctl
  returns. Same for i386 struct xfs_inogrp.

Signed-off-by: Michal Marek <mmarek@suse.cz>
---
 fs/xfs/linux-2.6/xfs_ioctl32.c |  262 +++++++++++++++++++++++++++++++++++++----
 1 file changed, 238 insertions(+), 24 deletions(-)

--- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -109,35 +109,249 @@ STATIC unsigned long xfs_ioctl32_geom_v1
 	return (unsigned long)p;
 }
 
-#else
+typedef struct xfs_inogrp32 {
+	__u64		xi_startino;	/* starting inode number	*/
+	__s32		xi_alloccount;	/* # bits set in allocmask	*/
+	__u64		xi_allocmask;	/* mask of allocated inodes	*/
+} __attribute__((packed)) xfs_inogrp32_t;
+
+STATIC int xfs_inogrp_store_compat(
+	xfs_inogrp32_t __user  *p32,
+	xfs_inogrp_t __user *p)
+{
+#define copy(memb) copy_in_user(&p32->memb, &p->memb, sizeof(p32->memb))
+	if (copy(xi_startino) ||
+	    copy(xi_alloccount) ||
+	    copy(xi_allocmask))
+		return -EFAULT;
+	return 0;
+#undef copy
+}
+
+#endif
+
+/* XFS_IOC_FSBULKSTAT and friends */
+
+typedef struct xfs_bstime32 {
+	__s32		tv_sec;		/* seconds		*/
+	__s32		tv_nsec;	/* and nanoseconds	*/
+} xfs_bstime32_t;
+
+static int xfs_bstime_store_compat(
+	xfs_bstime32_t __user *p32,
+	xfs_bstime_t __user *p)
+{
+	time_t sec;
+	__s32 sec32;
+
+	if (get_user(sec, &p->tv_sec))
+		return -EFAULT;
+	sec32 = sec;
+	if (put_user(sec32, &p32->tv_sec) ||
+	    copy_in_user(&p32->tv_nsec, &p->tv_nsec, sizeof(__s32)))
+		return -EFAULT;
+	return 0;
+}
+
+typedef struct xfs_bstat32 {
+	__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			*/
+	xfs_bstime32_t	bs_atime;	/* access time			*/
+	xfs_bstime32_t	bs_mtime;	/* modify time			*/
+	xfs_bstime32_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	*/
+}
+#ifdef BROKEN_X86_ALIGNMENT
+	__attribute__((packed))
+#endif
+	xfs_bstat32_t;
+
+static int xfs_bstat_store_compat(
+	xfs_bstat32_t __user *p32,
+	xfs_bstat_t __user *p)
+{
+#define copy(memb) copy_in_user(&p32->memb, &p->memb, sizeof(p32->memb))
+	if (copy(bs_ino) ||
+	    copy(bs_mode) ||
+	    copy(bs_nlink) ||
+	    copy(bs_uid) ||
+	    copy(bs_gid) ||
+	    copy(bs_rdev) ||
+	    copy(bs_blksize) ||
+	    copy(bs_size) ||
+	    xfs_bstime_store_compat(&p32->bs_atime, &p->bs_atime) ||
+	    xfs_bstime_store_compat(&p32->bs_mtime, &p->bs_mtime) ||
+	    xfs_bstime_store_compat(&p32->bs_ctime, &p->bs_ctime) ||
+	    copy(bs_blocks) ||
+	    copy(bs_xflags) ||
+	    copy(bs_extsize) ||
+	    copy(bs_extents) ||
+	    copy(bs_gen) ||
+	    copy(bs_projid) ||
+	    copy(bs_pad[14]) ||
+	    copy(bs_dmevmask) ||
+	    copy(bs_dmstate) ||
+	    copy(bs_aextents))
+		return -EFAULT;
+	return 0;
+#undef copy
+}
 
 typedef struct xfs_fsop_bulkreq32 {
 	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		*/
+	compat_uptr_t	ocount;		/* output count pointer		*/
 } xfs_fsop_bulkreq32_t;
-
-STATIC unsigned long
-xfs_ioctl32_bulkstat(
-	unsigned long		arg)
+#define XFS_IOC_FSBULKSTAT_32	     _IOWR('X', 101, struct xfs_fsop_bulkreq32)
+#define XFS_IOC_FSBULKSTAT_SINGLE_32 _IOWR('X', 102, struct xfs_fsop_bulkreq32)
+#define XFS_IOC_FSINUMBERS_32	     _IOWR('X', 103, struct xfs_fsop_bulkreq32)
+
+#define MAX_BSTAT_LEN \
+	((__s32)((64*1024 - sizeof(xfs_fsop_bulkreq_t)) / sizeof(xfs_bstat_t)))
+#define MAX_INOGRP_LEN \
+	((__s32)((64*1024 - sizeof(xfs_fsop_bulkreq_t)) / sizeof(xfs_inogrp_t)))
+
+STATIC int
+xfs_ioctl32_bulkstat_wrap(
+	bhv_vnode_t	*vp,
+	struct inode    *inode,
+	struct file     *file,
+	int             mode,
+	unsigned        cmd,
+	unsigned long   arg)
 {
-	xfs_fsop_bulkreq32_t	__user *p32 = (void __user *)arg;
-	xfs_fsop_bulkreq_t	__user *p = compat_alloc_user_space(sizeof(*p));
-	u32			addr;
-
-	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))
+	xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg;
+	xfs_fsop_bulkreq_t tmp;
+	u32 addr;
+	void *buf32;
+	int err;
+
+	if (get_user(addr, &p32->lastip))
+		return 0;
+	tmp.lastip = compat_ptr(addr);
+	if (get_user(tmp.icount, &p32->icount) ||
+	    get_user(addr, &p32->ubuffer))
 		return -EFAULT;
+	buf32 = compat_ptr(addr);
+	if (get_user(addr, &p32->ocount))
+		return -EFAULT;
+	tmp.ocount = compat_ptr(addr);
 
-	return (unsigned long)p;
-}
+	if (tmp.icount <= 0)
+		return -EINVAL;
+
+	if (cmd == XFS_IOC_FSBULKSTAT_32)
+		cmd = XFS_IOC_FSBULKSTAT;
+	if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32)
+		cmd = XFS_IOC_FSBULKSTAT_SINGLE;
+	if (cmd == XFS_IOC_FSINUMBERS_32)
+		cmd = XFS_IOC_FSINUMBERS;
+
+	if (cmd == XFS_IOC_FSBULKSTAT || cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
+		xfs_fsop_bulkreq_t __user *p;
+		xfs_bstat_t __user *bs;
+		xfs_bstat32_t __user *bs32 = buf32;
+		__s32 total_ocount = 0;
+		p = compat_alloc_user_space(sizeof(*p) +
+			sizeof(xfs_bstat_t) * min(MAX_BSTAT_LEN, tmp.icount));
+		bs = (xfs_bstat_t __user *)(p + 1);
+		tmp.ubuffer = bs;
+		if (copy_to_user(p, &tmp, sizeof(*p)))
+			return -EFAULT;
+		while (tmp.icount) {
+			__s32 icount = min(MAX_BSTAT_LEN, tmp.icount);
+			__s32 ocount;
+			int i;
+
+			if (put_user(icount, &p->icount))
+				return -EFAULT;
+			err = bhv_vop_ioctl(vp, inode, file, mode, cmd,
+					(void __user *)p);
+			if (err)
+				return err;
+			if (get_user(ocount, p->ocount))
+				return -EFAULT;
+			for (i = 0; i < ocount; i++) {
+				if (xfs_bstat_store_compat(bs32 +
+						total_ocount + i, bs + i))
+					return -EFAULT;
+			}
+			total_ocount += ocount;
+			tmp.icount -= icount;
+		}
+		if (put_user(total_ocount, p->ocount))
+			return -EFAULT;
+		return 0;
+	}
+	if (cmd == XFS_IOC_FSINUMBERS) {
+#ifdef BROKEN_X86_ALIGNMENT
+		xfs_fsop_bulkreq_t __user *p;
+		xfs_inogrp_t __user *ig;
+		xfs_inogrp32_t __user *ig32 = buf32;
+		__s32 total_ocount = 0;
+		p = compat_alloc_user_space(sizeof(*p) +
+			sizeof(xfs_inogrp_t) * min(MAX_INOGRP_LEN, tmp.icount));
+		ig = (xfs_inogrp_t __user *)(p + 1);
+		tmp.ubuffer = ig;
+		if (copy_to_user(p, &tmp, sizeof(*p)))
+			return -EFAULT;
+
+		while (tmp.icount) {
+			__s32 icount = min(MAX_INOGRP_LEN, tmp.icount);
+			__s32 ocount;
+			int i;
+
+			if (put_user(icount, &p->icount))
+				return -EFAULT;
+			err = bhv_vop_ioctl(vp, inode, file, mode, cmd,
+					(void __user *)p);
+			if (err)
+				return err;
+			if (get_user(ocount, p->ocount))
+				return -EFAULT;
+			for (i = 0; i < ocount; i++) {
+				if (xfs_inogrp_store_compat(ig32 +
+						total_ocount + i, ig + i))
+					return -EFAULT;
+			}
+			tmp.icount -= icount;
+			total_ocount += ocount;
+		}
+		if (put_user(total_ocount, p->ocount))
+			return -EFAULT;
+#else
+		xfs_fsop_bulkreq_t __user *p;
+		p = compat_alloc_user_space(sizeof(*p));
+		tmp.ubuffer = buf32;
+		if (copy_to_user(p, &tmp, sizeof(*p)))
+			return -EFAULT;
+
+		err = bhv_vop_ioctl(vp, inode, file, mode, cmd,
+				(void __user *)p);
+		if (err)
+			return err;
 #endif
+		return 0;
+	}
+	return -ENOSYS;
+}
+
 
 typedef struct xfs_fsop_handlereq32 {
 	__u32		fd;		/* fd for FD_TO_HANDLE		*/
@@ -253,12 +467,12 @@ 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:
+		return xfs_ioctl32_bulkstat_wrap(vp, inode, file, mode, cmd,
+				arg);
 	case XFS_IOC_FD_TO_HANDLE_32:
 		arg = xfs_ioctl32_fshandle(arg);
 		cmd = XFS_IOC_FD_TO_HANDLE;

-- 

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode
  2007-05-30 12:59 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode Michal Marek
@ 2007-05-30 17:05   ` Chris Wedgwood
  2007-05-30 21:48     ` Arnd Bergmann
  2007-05-31  2:30   ` David Chinner
  1 sibling, 1 reply; 18+ messages in thread
From: Chris Wedgwood @ 2007-05-30 17:05 UTC (permalink / raw)
  To: Michal Marek; +Cc: xfs, linux-kernel

On Wed, May 30, 2007 at 02:59:55PM +0200, Michal Marek wrote:

> +typedef struct xfs_fsop_geom_v132 {

wouldn't xfs_fsop_geom_v1_32
                         ^

> +	__u32		blocksize;	/* filesystem (data) block size */

[...]

> +	__u32		dirblocksize;	/* directory block size, bytes	*/
> +} __attribute__((packed)) xfs_fsop_geom_v132_t;

and xfs_fsop_geom_v1_32_t
                    ^

read better there?


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode
  2007-05-30 17:05   ` Chris Wedgwood
@ 2007-05-30 21:48     ` Arnd Bergmann
  2007-05-31  8:10       ` Michal Marek
  0 siblings, 1 reply; 18+ messages in thread
From: Arnd Bergmann @ 2007-05-30 21:48 UTC (permalink / raw)
  To: Chris Wedgwood; +Cc: Michal Marek, xfs, linux-kernel

On Wednesday 30 May 2007, Chris Wedgwood wrote:
> 
> On Wed, May 30, 2007 at 02:59:55PM +0200, Michal Marek wrote:
> 
> > +typedef struct xfs_fsop_geom_v132 {
> 
> wouldn't xfs_fsop_geom_v1_32
>                          ^
> 
> > +     __u32           blocksize;      /* filesystem (data) block size */
> 
> [...]
> 
> > +     __u32           dirblocksize;   /* directory block size, bytes  */
> > +} __attribute__((packed)) xfs_fsop_geom_v132_t;
> 
> and xfs_fsop_geom_v1_32_t
>                     ^
> 
> read better there?

Actually, the current convention would be struct compat_xfs_fsop_geom_v1
and compat_xfs_fsop_geom_v1_t.

	Arnd <><

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode
  2007-05-30 12:59 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode Michal Marek
  2007-05-30 17:05   ` Chris Wedgwood
@ 2007-05-31  2:30   ` David Chinner
  1 sibling, 0 replies; 18+ messages in thread
From: David Chinner @ 2007-05-31  2:30 UTC (permalink / raw)
  To: Michal Marek; +Cc: xfs, linux-kernel

On Wed, May 30, 2007 at 02:59:55PM +0200, Michal Marek wrote:
> i386 struct xfs_fsop_geom_v1 has no padding after the last member, so
> the size is different.

That's a pain - it's kind of clunky having to redefine the entire
structure just pack it differently. Oh well, not much that
we can do about it...

> 
> Signed-off-by: Michal Marek <mmarek@suse.cz>
> ---
>  fs/xfs/linux-2.6/xfs_ioctl32.c |   40 +++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 39 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,40 @@ xfs_ioctl32_flock(
>  	return (unsigned long)p;
>  }
>  
> +typedef struct xfs_fsop_geom_v132 {

xfs_fsop_geom_v1_32

> +	__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)) xfs_fsop_geom_v132_t;

xfs_fsop_geom_v1_32_t

> +#define XFS_IOC_FSGEOMETRY_V1_32     _IOR ('X', 100, struct xfs_fsop_geom_v132)
> +
> +STATIC unsigned long xfs_ioctl32_geom_v1(unsigned long arg)
> +{
> +	xfs_fsop_geom_v132_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 +152,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 +199,10 @@ xfs_compat_ioctl(
>  		arg = xfs_ioctl32_flock(arg);
>  		cmd = _NATIVE_IOC(cmd, struct xfs_flock64);
>  		break;

	/* xfs_fsop_geom_v1 changes size */
> +	case XFS_IOC_FSGEOMETRY_V1_32:
> +		arg = xfs_ioctl32_geom_v1(arg);
> +		cmd = XFS_IOC_FSGEOMETRY_V1;
> +		break;

cmd = _NATIVE_IOC(cmd, struct xfs_fsop_geom_v1);

Cheers,

Dave.
-- 
Dave Chinner
Principal Engineer
SGI Australian Software Group

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE in compat mode
  2007-05-30 12:59 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " Michal Marek
@ 2007-05-31  2:36   ` David Chinner
  0 siblings, 0 replies; 18+ messages in thread
From: David Chinner @ 2007-05-31  2:36 UTC (permalink / raw)
  To: Michal Marek; +Cc: xfs, linux-kernel

On Wed, May 30, 2007 at 02:59:56PM +0200, Michal Marek 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.
> 
> Signed-off-by: Michal Marek <mmarek@suse.cz>
> ---
>  fs/xfs/linux-2.6/xfs_ioctl32.c |   63 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 58 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
> @@ -139,6 +139,44 @@ xfs_ioctl32_bulkstat(
>  }
>  #endif
>  
> +typedef struct xfs_fsop_handlereq32 {

xfs_fsop_handlereq_32

> +	__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		*/
> +} xfs_fsop_handlereq32_t;

xfs_fsop_handlereq_32_t

Add a empty line here...

> +#define XFS_IOC_PATH_TO_FSHANDLE_32 _IOWR('X', 104, struct xfs_fsop_handlereq32)
> +#define XFS_IOC_PATH_TO_HANDLE_32   _IOWR('X', 105, struct xfs_fsop_handlereq32)
> +#define XFS_IOC_FD_TO_HANDLE_32	    _IOWR('X', 106, struct xfs_fsop_handlereq32)
> +#define XFS_IOC_OPEN_BY_HANDLE_32   _IOWR('X', 107, struct xfs_fsop_handlereq32)
> +#define XFS_IOC_READLINK_BY_HANDLE_32 _IOWR('X', 108, struct xfs_fsop_handlereq32)

Looks kinda whitespacey here - it's mixing spaces and tabs....

> +STATIC unsigned long xfs_ioctl32_fshandle(unsigned long arg)
> +{
> +	xfs_fsop_handlereq32_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,
> @@ -164,12 +202,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:
>  */
> @@ -226,6 +259,26 @@ xfs_compat_ioctl(
>  		arg = xfs_ioctl32_bulkstat(arg);
>  		break;
>  #endif
> +	case XFS_IOC_FD_TO_HANDLE_32:
> +		arg = xfs_ioctl32_fshandle(arg);
> +		cmd = XFS_IOC_FD_TO_HANDLE;
> +		break;
> +	case XFS_IOC_PATH_TO_HANDLE_32:
> +		arg = xfs_ioctl32_fshandle(arg);
> +		cmd = XFS_IOC_PATH_TO_HANDLE;
> +		break;
> +	case XFS_IOC_PATH_TO_FSHANDLE_32:
> +		arg = xfs_ioctl32_fshandle(arg);
> +		cmd = XFS_IOC_PATH_TO_FSHANDLE;
> +		break;
> +	case XFS_IOC_OPEN_BY_HANDLE_32:
> +		arg = xfs_ioctl32_fshandle(arg);
> +		cmd = XFS_IOC_OPEN_BY_HANDLE;
> +		break;
> +	case XFS_IOC_READLINK_BY_HANDLE_32:
> +		arg = xfs_ioctl32_fshandle(arg);
> +		cmd = XFS_IOC_READLINK_BY_HANDLE;
> +		break;

+	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;

Cheers,

Dave.
-- 
Dave Chinner
Principal Engineer
SGI Australian Software Group

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode
  2007-05-30 12:59 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " Michal Marek
@ 2007-05-31  6:37   ` David Chinner
  2007-05-31  8:52     ` Michal Marek
  2007-05-31  7:06   ` Arnd Bergmann
  1 sibling, 1 reply; 18+ messages in thread
From: David Chinner @ 2007-05-31  6:37 UTC (permalink / raw)
  To: Michal Marek; +Cc: xfs, linux-kernel

On Wed, May 30, 2007 at 02:59:57PM +0200, Michal Marek 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 on 32bit (because of time_t and on
>   i386 becaus of different padding). Create a new function
>   xfs_ioctl32_bulkstat_wrap(), which allocates extra ->ubuffer and
>   converts the elements to the 32bit format after the original ioctl
>   returns. Same for i386 struct xfs_inogrp.
> 
> Signed-off-by: Michal Marek <mmarek@suse.cz>
> ---
>  fs/xfs/linux-2.6/xfs_ioctl32.c |  262 +++++++++++++++++++++++++++++++++++++----
>  1 file changed, 238 insertions(+), 24 deletions(-)
> 
> --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl32.c
> +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl32.c
> @@ -109,35 +109,249 @@ STATIC unsigned long xfs_ioctl32_geom_v1
>  	return (unsigned long)p;
>  }
>  
> -#else
> +typedef struct xfs_inogrp32 {
> +	__u64		xi_startino;	/* starting inode number	*/
> +	__s32		xi_alloccount;	/* # bits set in allocmask	*/
> +	__u64		xi_allocmask;	/* mask of allocated inodes	*/
> +} __attribute__((packed)) xfs_inogrp32_t;

xfs_inogrp_32
xfs_inogrp_32_t

> +STATIC int xfs_inogrp_store_compat(
> +	xfs_inogrp32_t __user  *p32,
> +	xfs_inogrp_t __user *p)
> +{
> +#define copy(memb) copy_in_user(&p32->memb, &p->memb, sizeof(p32->memb))
> +	if (copy(xi_startino) ||
> +	    copy(xi_alloccount) ||
> +	    copy(xi_allocmask))

No need for the #define here....

> +		return -EFAULT;
> +	return 0;
> +#undef copy
> +}
> +
> +#endif
> +
> +/* XFS_IOC_FSBULKSTAT and friends */
> +
> +typedef struct xfs_bstime32 {
> +	__s32		tv_sec;		/* seconds		*/
> +	__s32		tv_nsec;	/* and nanoseconds	*/
> +} xfs_bstime32_t;

*_32

> +static int xfs_bstime_store_compat(
> +	xfs_bstime32_t __user *p32,
> +	xfs_bstime_t __user *p)
> +{
> +	time_t sec;
> +	__s32 sec32;
> +
> +	if (get_user(sec, &p->tv_sec))
> +		return -EFAULT;
> +	sec32 = sec;
> +	if (put_user(sec32, &p32->tv_sec) ||
> +	    copy_in_user(&p32->tv_nsec, &p->tv_nsec, sizeof(__s32)))
> +		return -EFAULT;
> +	return 0;
> +}
> +
> +typedef struct xfs_bstat32 {
> +	__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			*/
> +	xfs_bstime32_t	bs_atime;	/* access time			*/
> +	xfs_bstime32_t	bs_mtime;	/* modify time			*/
> +	xfs_bstime32_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	*/
> +}
> +#ifdef BROKEN_X86_ALIGNMENT
> +	__attribute__((packed))
> +#endif
> +	xfs_bstat32_t;

#ifdef BROKEN_X86_ALIGNMENT
#define _PACKED	__attribute__((packed))
#else
#define _PACKED
#endif

typedef struct xfs_bstat_32 {
	......
} _PACKED xfs_bstat32_t

> +
> +static int xfs_bstat_store_compat(
> +	xfs_bstat32_t __user *p32,
> +	xfs_bstat_t __user *p)
> +{
> +#define copy(memb) copy_in_user(&p32->memb, &p->memb, sizeof(p32->memb))

Hmmm - now I see why you used this.

These copies are used everywhere in this file, maybe it would be best
to define a copy_from_32() and a copy_to_32() macros and use them
everywhere in the file?

> +	if (copy(bs_ino) ||
> +	    copy(bs_mode) ||
> +	    copy(bs_nlink) ||
> +	    copy(bs_uid) ||
> +	    copy(bs_gid) ||
> +	    copy(bs_rdev) ||
> +	    copy(bs_blksize) ||
> +	    copy(bs_size) ||
> +	    xfs_bstime_store_compat(&p32->bs_atime, &p->bs_atime) ||
> +	    xfs_bstime_store_compat(&p32->bs_mtime, &p->bs_mtime) ||
> +	    xfs_bstime_store_compat(&p32->bs_ctime, &p->bs_ctime) ||
> +	    copy(bs_blocks) ||
> +	    copy(bs_xflags) ||
> +	    copy(bs_extsize) ||
> +	    copy(bs_extents) ||
> +	    copy(bs_gen) ||
> +	    copy(bs_projid) ||
> +	    copy(bs_pad[14]) ||
> +	    copy(bs_dmevmask) ||
> +	    copy(bs_dmstate) ||
> +	    copy(bs_aextents))
> +		return -EFAULT;
> +	return 0;
> +#undef copy
> +}
>  
>  typedef struct xfs_fsop_bulkreq32 {
>  	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		*/
> +	compat_uptr_t	ocount;		/* output count pointer		*/
>  } xfs_fsop_bulkreq32_t;
> -
> -STATIC unsigned long
> -xfs_ioctl32_bulkstat(
> -	unsigned long		arg)
> +#define XFS_IOC_FSBULKSTAT_32	     _IOWR('X', 101, struct xfs_fsop_bulkreq32)
> +#define XFS_IOC_FSBULKSTAT_SINGLE_32 _IOWR('X', 102, struct xfs_fsop_bulkreq32)
> +#define XFS_IOC_FSINUMBERS_32	     _IOWR('X', 103, struct xfs_fsop_bulkreq32)
> +
> +#define MAX_BSTAT_LEN \
> +	((__s32)((64*1024 - sizeof(xfs_fsop_bulkreq_t)) / sizeof(xfs_bstat_t)))
> +#define MAX_INOGRP_LEN \
> +	((__s32)((64*1024 - sizeof(xfs_fsop_bulkreq_t)) / sizeof(xfs_inogrp_t)))

Oooo magic numbers. Why were these chosen?

> +
> +STATIC int
> +xfs_ioctl32_bulkstat_wrap(
> +	bhv_vnode_t	*vp,
> +	struct inode    *inode,
> +	struct file     *file,
> +	int             mode,
> +	unsigned        cmd,
> +	unsigned long   arg)
>  {
> -	xfs_fsop_bulkreq32_t	__user *p32 = (void __user *)arg;
> -	xfs_fsop_bulkreq_t	__user *p = compat_alloc_user_space(sizeof(*p));
> -	u32			addr;
> -
> -	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))
> +	xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg;
> +	xfs_fsop_bulkreq_t tmp;
> +	u32 addr;
> +	void *buf32;
> +	int err;
> +
> +	if (get_user(addr, &p32->lastip))
> +		return 0;

return -EFAULT?

> +	tmp.lastip = compat_ptr(addr);
> +	if (get_user(tmp.icount, &p32->icount) ||
> +	    get_user(addr, &p32->ubuffer))
>  		return -EFAULT;
> +	buf32 = compat_ptr(addr);
> +	if (get_user(addr, &p32->ocount))
> +		return -EFAULT;
> +	tmp.ocount = compat_ptr(addr);
>  
> -	return (unsigned long)p;
> -}
> +	if (tmp.icount <= 0)
> +		return -EINVAL;
> +
> +	if (cmd == XFS_IOC_FSBULKSTAT_32)
> +		cmd = XFS_IOC_FSBULKSTAT;
> +	if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32)
> +		cmd = XFS_IOC_FSBULKSTAT_SINGLE;
> +	if (cmd == XFS_IOC_FSINUMBERS_32)
> +		cmd = XFS_IOC_FSINUMBERS;

	cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq);
	switch (cmd) {
	case XFS_IOC_FSBULKSTAT:
	case XFS_IOC_FSBULKSTAT_SINGLE:
> +
> +	if (cmd == XFS_IOC_FSBULKSTAT || cmd == XFS_IOC_FSBULKSTAT_SINGLE) {

Oh, now it gets messy :(

So, we do a whole lot of repacking of the bulkstat structures
once we've got the data out of the bulkstat call.

I think this is really the wrong way of doing this - the bulkstat
functions themselves take a "formatter" argument that is used to pack
the buffer in a given format. I think that we need to be supplying
the bulkstat code with different formatters in this case, not
repacking the buffer into a different format at a later time.

The formatter used by default is xfs_bulkstat_one() which 
falls down to xfs_bulkstat_one_dinode() or xfs_bulkstat_one_iget()
depending on whether we are doing icache coherent or blockdev
cache coherent lookups. It is these functions that need to be
told what format they are packing, I think, and xfs_bulkstat_single()
needs to be taught about them....

> +	if (cmd == XFS_IOC_FSINUMBERS) {

And I'm wondering if we should be doing the same thing here
(i.e. customer formatters), because this is equally ugly...

Cheers,

Dave.
-- 
Dave Chinner
Principal Engineer
SGI Australian Software Group

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode
  2007-05-30 12:59 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " Michal Marek
  2007-05-31  6:37   ` David Chinner
@ 2007-05-31  7:06   ` Arnd Bergmann
  1 sibling, 0 replies; 18+ messages in thread
From: Arnd Bergmann @ 2007-05-31  7:06 UTC (permalink / raw)
  To: Michal Marek; +Cc: xfs, linux-kernel

On Wednesday 30 May 2007, Michal Marek wrote:
> --- linux-2.6.orig/fs/xfs/linux-2.6/xfs_ioctl32.c
> +++ linux-2.6/fs/xfs/linux-2.6/xfs_ioctl32.c
> @@ -109,35 +109,249 @@ STATIC unsigned long xfs_ioctl32_geom_v1
>  	return (unsigned long)p;
>  }
>  
> -#else
> +typedef struct xfs_inogrp32 {
> +	__u64		xi_startino;	/* starting inode number	*/
> +	__s32		xi_alloccount;	/* # bits set in allocmask	*/
> +	__u64		xi_allocmask;	/* mask of allocated inodes	*/
> +} __attribute__((packed)) xfs_inogrp32_t;

__attribute__((packed)) isn't entirely correct here. You don't really
want to have the whole structure to have byte alignment, you only
want to reduce the alignment o fthe 64 bit members to 32 bit.

It would be more appropriate to define a separate type

#if defined(__x86_64__) || defined(__ia64__)
typedef unsigned long long __compat_u64 __attribute__((aligned(4)));
#else
typedef unsigned long long __compat_u64;
#endif

and use that in the data structures.

> +STATIC int xfs_inogrp_store_compat(
> +	xfs_inogrp32_t __user  *p32,
> +	xfs_inogrp_t __user *p)
> +{
> +#define copy(memb) copy_in_user(&p32->memb, &p->memb, sizeof(p32->memb))
> +	if (copy(xi_startino) ||
> +	    copy(xi_alloccount) ||
> +	    copy(xi_allocmask))
> +		return -EFAULT;
> +	return 0;
> +#undef copy
> +}

Your copy() operation looks really dangerous, it will break as soon as someone
tries to use it on a member that is actually variable length, like a pointer.
A better way would be

#define move_user(p32, p64, memb) ({ \
	typeof(p32->memb) data; \
	get_user(data, &p64->memb) || \
	put_user(data, &p32->memb); \
})

Actually, even better would be not to use the compat_alloc_userspace trick
at all, but to just interpret the 32 bit data structure directly in the
implementation instead of converting it to the 64 bit structure, whereever
that's possible.

	Arnd <><

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode
  2007-05-30 21:48     ` Arnd Bergmann
@ 2007-05-31  8:10       ` Michal Marek
  0 siblings, 0 replies; 18+ messages in thread
From: Michal Marek @ 2007-05-31  8:10 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: Chris Wedgwood, xfs, linux-kernel

Arnd Bergmann wrote:
> On Wednesday 30 May 2007, Chris Wedgwood wrote:
>> On Wed, May 30, 2007 at 02:59:55PM +0200, Michal Marek wrote:
>>
>>> +typedef struct xfs_fsop_geom_v132 {
>> wouldn't xfs_fsop_geom_v1_32
...
>> and xfs_fsop_geom_v1_32_t
>>                     ^
>>
>> read better there?
> 
> Actually, the current convention would be struct compat_xfs_fsop_geom_v1
> and compat_xfs_fsop_geom_v1_t.

I see. I'll change it to struct compat_xfs_*.

Michal

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode
  2007-05-31  6:37   ` David Chinner
@ 2007-05-31  8:52     ` Michal Marek
  2007-05-31 13:03       ` David Chinner
  0 siblings, 1 reply; 18+ messages in thread
From: Michal Marek @ 2007-05-31  8:52 UTC (permalink / raw)
  To: David Chinner; +Cc: xfs, linux-kernel

David Chinner wrote:
> On Wed, May 30, 2007 at 02:59:57PM +0200, Michal Marek wrote:
>> +typedef struct xfs_bstat32 {
>> +	__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			*/
>> +	xfs_bstime32_t	bs_atime;	/* access time			*/
>> +	xfs_bstime32_t	bs_mtime;	/* modify time			*/
>> +	xfs_bstime32_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	*/
>> +}
>> +#ifdef BROKEN_X86_ALIGNMENT
>> +	__attribute__((packed))
>> +#endif
>> +	xfs_bstat32_t;
> 
> #ifdef BROKEN_X86_ALIGNMENT
> #define _PACKED	__attribute__((packed))
> #else
> #define _PACKED
> #endif
> 
> typedef struct xfs_bstat_32 {
> 	......
> } _PACKED xfs_bstat32_t

Yes, that would look cleaner. Perhaps something like PACKED_IF_NEEDED so
that it's clear that it's not allways defined to __attribute__((packed))?


>> +static int xfs_bstat_store_compat(
>> +	xfs_bstat32_t __user *p32,
>> +	xfs_bstat_t __user *p)
>> +{
>> +#define copy(memb) copy_in_user(&p32->memb, &p->memb, sizeof(p32->memb))
> 
> Hmmm - now I see why you used this.
> 
> These copies are used everywhere in this file, maybe it would be best
> to define a copy_from_32() and a copy_to_32() macros and use them
> everywhere in the file?

OK, I'll use a "proper" (not playing with some local variables) global
macro like Arnd suggested in this thread.


>> +#define MAX_BSTAT_LEN \
>> +	((__s32)((64*1024 - sizeof(xfs_fsop_bulkreq_t)) / sizeof(xfs_bstat_t)))
>> +#define MAX_INOGRP_LEN \
>> +	((__s32)((64*1024 - sizeof(xfs_fsop_bulkreq_t)) / sizeof(xfs_inogrp_t)))
> 
> Oooo magic numbers. Why were these chosen?

I wanted to limit the argument passed to compat_alloc_user_space
somehow; 64K is probably not the best idea, but some upper bound is
needed, isn't it? OK, if we can get around without any conversions at
all (see below), then these constants can go away.


>> +
>> +STATIC int
>> +xfs_ioctl32_bulkstat_wrap(
>> +	bhv_vnode_t	*vp,
>> +	struct inode    *inode,
>> +	struct file     *file,
>> +	int             mode,
>> +	unsigned        cmd,
>> +	unsigned long   arg)
>>  {
>> -	xfs_fsop_bulkreq32_t	__user *p32 = (void __user *)arg;
>> -	xfs_fsop_bulkreq_t	__user *p = compat_alloc_user_space(sizeof(*p));
>> -	u32			addr;
>> -
>> -	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))
>> +	xfs_fsop_bulkreq32_t __user *p32 = (void __user *)arg;
>> +	xfs_fsop_bulkreq_t tmp;
>> +	u32 addr;
>> +	void *buf32;
>> +	int err;
>> +
>> +	if (get_user(addr, &p32->lastip))
>> +		return 0;
> 
> return -EFAULT?

Oops, silly mistake. Thanks!


>> +	if (cmd == XFS_IOC_FSBULKSTAT_32)
>> +		cmd = XFS_IOC_FSBULKSTAT;
>> +	if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32)
>> +		cmd = XFS_IOC_FSBULKSTAT_SINGLE;
>> +	if (cmd == XFS_IOC_FSINUMBERS_32)
>> +		cmd = XFS_IOC_FSINUMBERS;
> 
> 	cmd = _NATIVE_IOC(cmd, struct xfs_fsop_bulkreq);
> 	switch (cmd) {
> 	case XFS_IOC_FSBULKSTAT:
> 	case XFS_IOC_FSBULKSTAT_SINGLE:

Yes, I'll use _NATIVE_IOC here (also in other places as you pointed out).


>> +
>> +	if (cmd == XFS_IOC_FSBULKSTAT || cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
> 
> Oh, now it gets messy :(

True :-/


> So, we do a whole lot of repacking of the bulkstat structures
> once we've got the data out of the bulkstat call.
> 
> I think this is really the wrong way of doing this - the bulkstat
> functions themselves take a "formatter" argument that is used to pack
> the buffer in a given format. I think that we need to be supplying
> the bulkstat code with different formatters in this case, not
> repacking the buffer into a different format at a later time.
> 
> The formatter used by default is xfs_bulkstat_one() which 
> falls down to xfs_bulkstat_one_dinode() or xfs_bulkstat_one_iget()
> depending on whether we are doing icache coherent or blockdev
> cache coherent lookups. It is these functions that need to be
> told what format they are packing, I think, and xfs_bulkstat_single()
> needs to be taught about them....

Well, I didn't want to touch other files but xfs_ioctl32.c so that the
patch has a higher chance of being accepted ;-) But of course if you
think that patching the implementation to be aware of the compat ioctls
is acceptable, then I can do it.


>> +	if (cmd == XFS_IOC_FSINUMBERS) {
> 
> And I'm wondering if we should be doing the same thing here
> (i.e. customer formatters), because this is equally ugly...

I'll try to clean up the XFS_IOC_FSBULKSTAT part first...


Thanks to all for their comments and suggestions! I'll send updated
patches later.

Michal

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode
  2007-05-31  8:52     ` Michal Marek
@ 2007-05-31 13:03       ` David Chinner
  0 siblings, 0 replies; 18+ messages in thread
From: David Chinner @ 2007-05-31 13:03 UTC (permalink / raw)
  To: Michal Marek; +Cc: David Chinner, xfs, linux-kernel

On Thu, May 31, 2007 at 10:52:14AM +0200, Michal Marek wrote:
> David Chinner wrote:
> > On Wed, May 30, 2007 at 02:59:57PM +0200, Michal Marek wrote:
> >> +typedef struct xfs_bstat32 {
.......
> >> +}
> >> +#ifdef BROKEN_X86_ALIGNMENT
> >> +	__attribute__((packed))
> >> +#endif
> >> +	xfs_bstat32_t;
> > 
> > #ifdef BROKEN_X86_ALIGNMENT
> > #define _PACKED	__attribute__((packed))
> > #else
> > #define _PACKED
> > #endif
> > 
> > typedef struct xfs_bstat_32 {
> > 	......
> > } _PACKED xfs_bstat32_t
> 
> Yes, that would look cleaner. Perhaps something like PACKED_IF_NEEDED so
> that it's clear that it's not allways defined to __attribute__((packed))?

<shrug>

Not really that fussed ;)

> >> +
> >> +	if (cmd == XFS_IOC_FSBULKSTAT || cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
> > 
> > Oh, now it gets messy :(
> 
> True :-/
> 
> 
> > So, we do a whole lot of repacking of the bulkstat structures
> > once we've got the data out of the bulkstat call.
> > 
> > I think this is really the wrong way of doing this - the bulkstat
> > functions themselves take a "formatter" argument that is used to pack
> > the buffer in a given format. I think that we need to be supplying
> > the bulkstat code with different formatters in this case, not
> > repacking the buffer into a different format at a later time.
> > 
> > The formatter used by default is xfs_bulkstat_one() which 
> > falls down to xfs_bulkstat_one_dinode() or xfs_bulkstat_one_iget()
> > depending on whether we are doing icache coherent or blockdev
> > cache coherent lookups. It is these functions that need to be
> > told what format they are packing, I think, and xfs_bulkstat_single()
> > needs to be taught about them....
> 
> Well, I didn't want to touch other files but xfs_ioctl32.c so that the
> patch has a higher chance of being accepted ;-) But of course if you
> think that patching the implementation to be aware of the compat ioctls
> is acceptable, then I can do it.

I think that given we already have multiple bulkstat formatters to
support different buffer formats, we'd be silly not to use that
interface directly for the new buffer formats needed.

You can probably dup the code from xfs_ioctl.c to issue the bulkstat
calls and then modify both to take specified formatters. You could even
define the compat formatter(s) in xfs_ioctl32.c so the compat code
doesn't need to be put elsewhere....

> >> +	if (cmd == XFS_IOC_FSINUMBERS) {
> > 
> > And I'm wondering if we should be doing the same thing here
> > (i.e. customer formatters), because this is equally ugly...
> 
> I'll try to clean up the XFS_IOC_FSBULKSTAT part first...

Yup, fair enough.

Thanks!

Cheers,

Dave.
-- 
Dave Chinner
Principal Engineer
SGI Australian Software Group

^ permalink raw reply	[flat|nested] 18+ 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
  0 siblings, 0 replies; 18+ 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] 18+ messages in thread

* Re: [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode
  2007-06-28 18:15   ` Andrew Morton
@ 2007-06-29 11:02     ` Michal Marek
  0 siblings, 0 replies; 18+ 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] 18+ 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 in compat mode 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; 18+ 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] 18+ 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 in compat mode mmarek
@ 2007-06-28  3:49   ` David Chinner
  2007-07-02  9:40     ` Michal Marek
  2007-06-28 18:15   ` Andrew Morton
  1 sibling, 1 reply; 18+ 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] 18+ 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 ` mmarek
  2007-06-28  3:49   ` David Chinner
  2007-06-28 18:15   ` Andrew Morton
  0 siblings, 2 replies; 18+ 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] 18+ messages in thread

end of thread, other threads:[~2007-07-02  9:40 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-05-30 12:59 [patch 0/3] Fix for XFS compat ioctls Michal Marek
2007-05-30 12:59 ` [patch 1/3] Fix XFS_IOC_FSGEOMETRY_V1 in compat mode Michal Marek
2007-05-30 17:05   ` Chris Wedgwood
2007-05-30 21:48     ` Arnd Bergmann
2007-05-31  8:10       ` Michal Marek
2007-05-31  2:30   ` David Chinner
2007-05-30 12:59 ` [patch 2/3] Fix XFS_IOC_*_TO_HANDLE and XFS_IOC_{OPEN,READLINK}_BY_HANDLE " Michal Marek
2007-05-31  2:36   ` David Chinner
2007-05-30 12:59 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS " Michal Marek
2007-05-31  6:37   ` David Chinner
2007-05-31  8:52     ` Michal Marek
2007-05-31 13:03       ` David Chinner
2007-05-31  7:06   ` Arnd Bergmann
2007-06-19 13:25 [patch 0/3] Fix for XFS compat ioctls (try2) mmarek
2007-06-19 13:25 ` [patch 3/3] Fix XFS_IOC_FSBULKSTAT{,_SINGLE} and XFS_IOC_FSINUMBERS in compat mode mmarek
2007-06-28  3:49   ` David Chinner
2007-07-02  9:40     ` Michal Marek
2007-06-28 18:15   ` 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).