public inbox for linux-arch@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] Consolidate sys32_readv and sys32_writev
       [not found] <200404040204.03594.arnd@arndb.de>
@ 2004-04-04  0:22 ` Arnd Bergmann
  2004-04-04  0:22 ` [PATCH 2/4] Consolidate do_execve32 Arnd Bergmann
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-04  0:22 UTC (permalink / raw)
  To: linux-arch

The seven implementations of this have gone out of sync and are mostly buggy.
The new compat_sys_* version is based on the ppc64 implementation, which
most closely resembles the code in sys_readv/sys_writev.

Tested with LTP on x86_64.

===== arch/ia64/ia32/ia32_entry.S 1.35 vs edited =====
--- 1.35/arch/ia64/ia32/ia32_entry.S	Fri Mar 26 20:05:24 2004
+++ edited/arch/ia64/ia32/ia32_entry.S	Sat Apr  3 19:55:45 2004
@@ -353,8 +353,8 @@
 	data8 sys32_select
 	data8 sys_flock
 	data8 sys32_msync
-	data8 sys32_readv	  /* 145 */
-	data8 sys32_writev
+	data8 compat_sys_readv	  /* 145 */
+	data8 compat_sys_writev
 	data8 sys_getsid
 	data8 sys_fdatasync
 	data8 sys32_sysctl
===== arch/ia64/ia32/sys_ia32.c 1.93 vs edited =====
--- 1.93/arch/ia64/ia32/sys_ia32.c	Fri Mar 26 20:05:24 2004
+++ edited/arch/ia64/ia32/sys_ia32.c	Sat Apr  3 19:51:49 2004
@@ -941,85 +941,6 @@
 			    (struct compat_timeval *) A(a.tvp));
 }
 
-static struct iovec *
-get_compat_iovec (struct compat_iovec *iov32, struct iovec *iov_buf, u32 count, int type)
-{
-	u32 i, buf, len;
-	struct iovec *ivp, *iov;
-
-	/* Get the "struct iovec" from user memory */
-
-	if (!count)
-		return 0;
-	if (verify_area(VERIFY_READ, iov32, sizeof(struct compat_iovec)*count))
-		return NULL;
-	if (count > UIO_MAXIOV)
-		return NULL;
-	if (count > UIO_FASTIOV) {
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
-		if (!iov)
-			return NULL;
-	} else
-		iov = iov_buf;
-
-	ivp = iov;
-	for (i = 0; i < count; i++) {
-		if (__get_user(len, &iov32->iov_len) || __get_user(buf, &iov32->iov_base)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return NULL;
-		}
-		if (verify_area(type, (void *)A(buf), len)) {
-			if (iov != iov_buf)
-				kfree(iov);
-			return((struct iovec *)0);
-		}
-		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t) len;
-		iov32++;
-		ivp++;
-	}
-	return iov;
-}
-
-asmlinkage long
-sys32_readv (int fd, struct compat_iovec *vector, u32 count)
-{
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov;
-	long ret;
-	mm_segment_t old_fs = get_fs();
-
-	iov = get_compat_iovec(vector, iovstack, count, VERIFY_WRITE);
-	if (!iov)
-		return -EFAULT;
-	set_fs(KERNEL_DS);
-	ret = sys_readv(fd, iov, count);
-	set_fs(old_fs);
-	if (iov != iovstack)
-		kfree(iov);
-	return ret;
-}
-
-asmlinkage long
-sys32_writev (int fd, struct compat_iovec *vector, u32 count)
-{
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov;
-	long ret;
-	mm_segment_t old_fs = get_fs();
-
-	iov = get_compat_iovec(vector, iovstack, count, VERIFY_READ);
-	if (!iov)
-		return -EFAULT;
-	set_fs(KERNEL_DS);
-	ret = sys_writev(fd, iov, count);
-	set_fs(old_fs);
-	if (iov != iovstack)
-		kfree(iov);
-	return ret;
-}
-
 #define SEMOP		 1
 #define SEMGET		 2
 #define SEMCTL		 3
===== arch/mips/kernel/linux32.c 1.22 vs edited =====
--- 1.22/arch/mips/kernel/linux32.c	Wed Feb 25 11:31:12 2004
+++ edited/arch/mips/kernel/linux32.c	Sat Apr  3 19:51:49 2004
@@ -671,150 +671,6 @@
 	return sys_llseek(fd, offset_high, offset_low, result, origin);
 }
 
-typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
-
-static long
-do_readv_writev32(int type, struct file *file, const struct compat_iovec *vector,
-		  u32 count)
-{
-	unsigned long tot_len;
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
-	long retval, i;
-	IO_fn_t fn;
-
-	/* First get the "struct iovec" from user memory and
-	 * verify all the pointers
-	 */
-	if (!count)
-		return 0;
-	if(verify_area(VERIFY_READ, vector, sizeof(struct compat_iovec)*count))
-		return -EFAULT;
-	if (count > UIO_MAXIOV)
-		return -EINVAL;
-	if (count > UIO_FASTIOV) {
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
-		if (!iov)
-			return -ENOMEM;
-	}
-
-	tot_len = 0;
-	i = count;
-	ivp = iov;
-	while (i > 0) {
-		u32 len;
-		u32 buf;
-
-		__get_user(len, &vector->iov_len);
-		__get_user(buf, &vector->iov_base);
-		tot_len += len;
-		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t) len;
-		vector++;
-		ivp++;
-		i--;
-	}
-
-	inode = file->f_dentry->d_inode;
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
-	if (retval) {
-		if (iov != iovstack)
-			kfree(iov);
-		return retval;
-	}
-
-	/* Then do the actual IO.  Note that sockets need to be handled
-	 * specially as they have atomicity guarantees and can handle
-	 * iovec's natively
-	 */
-#ifdef CONFIG_NET
-	if (inode->i_sock) {
-		int err;
-		err = sock_readv_writev(type, inode, file, iov, count, tot_len);
-		if (iov != iovstack)
-			kfree(iov);
-		return err;
-	}
-#endif
-
-	if (!file->f_op) {
-		if (iov != iovstack)
-			kfree(iov);
-		return -EINVAL;
-	}
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	fn = file->f_op->read;
-	if (type == VERIFY_READ)
-		fn = (IO_fn_t) file->f_op->write;
-	ivp = iov;
-	while (count > 0) {
-		void * base;
-		int len, nr;
-
-		base = ivp->iov_base;
-		len = ivp->iov_len;
-		ivp++;
-		count--;
-		nr = fn(file, base, len, &file->f_pos);
-		if (nr < 0) {
-			if (retval)
-				break;
-			retval = nr;
-			break;
-		}
-		retval += nr;
-		if (nr != len)
-			break;
-	}
-	if (iov != iovstack)
-		kfree(iov);
-
-	return retval;
-}
-
-asmlinkage long
-sys32_readv(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	ssize_t ret;
-
-	ret = -EBADF;
-	file = fget(fd);
-	if (!file)
-		goto bad_file;
-	if (file->f_op && (file->f_mode & FMODE_READ) &&
-	    (file->f_op->readv || file->f_op->read))
-		ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
-
-	fput(file);
-
-bad_file:
-	return ret;
-}
-
-asmlinkage long
-sys32_writev(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	ssize_t ret;
-
-	ret = -EBADF;
-	file = fget(fd);
-	if(!file)
-		goto bad_file;
-	if (file->f_op && (file->f_mode & FMODE_WRITE) &&
-	    (file->f_op->writev || file->f_op->write))
-	        ret = do_readv_writev32(VERIFY_READ, file, vector, count);
-	fput(file);
-
-bad_file:
-	return ret;
-}
-
 /* From the Single Unix Spec: pread & pwrite act like lseek to pos + op +
    lseek back to original location.  They fail just like lseek does on
    non-seekable files.  */
===== arch/mips/kernel/scall64-n32.S 1.2 vs edited =====
--- 1.2/arch/mips/kernel/scall64-n32.S	Thu Feb 19 21:53:00 2004
+++ edited/arch/mips/kernel/scall64-n32.S	Sat Apr  3 19:55:52 2004
@@ -128,8 +128,8 @@
 	PTR	compat_sys_ioctl		/* 6015 */
 	PTR	sys_pread64
 	PTR	sys_pwrite64
-	PTR	sys32_readv
-	PTR	sys32_writev
+	PTR	compat_sys_readv
+	PTR	compat_sys_writev
 	PTR	sys_access			/* 6020 */
 	PTR	sys_pipe
 	PTR	sys32_select
===== arch/mips/kernel/scall64-o32.S 1.2 vs edited =====
--- 1.2/arch/mips/kernel/scall64-o32.S	Thu Feb 19 21:53:00 2004
+++ edited/arch/mips/kernel/scall64-o32.S	Sat Apr  3 19:56:24 2004
@@ -400,8 +400,8 @@
 	sys	sys32_select	5
 	sys	sys_flock	2
 	sys	sys_msync	3
-	sys	sys32_readv	3			/* 4145 */
-	sys	sys32_writev	3
+	sys	compat_sys_readv	3		/* 4145 */
+	sys	compat_sys_writev	3
 	sys	sys_cacheflush	3
 	sys	sys_cachectl	3
 	sys	sys_sysmips	4
===== arch/parisc/kernel/sys_parisc32.c 1.24 vs edited =====
--- 1.24/arch/parisc/kernel/sys_parisc32.c	Fri Mar 26 20:05:25 2004
+++ edited/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 19:51:49 2004
@@ -607,149 +607,6 @@
 	return error;
 }
 
-/* readv/writev stolen from mips64 */
-typedef ssize_t (*IO_fn_t)(struct file *, char *, size_t, loff_t *);
-
-static long
-do_readv_writev32(int type, struct file *file, const struct compat_iovec *vector,
-		  u32 count)
-{
-	unsigned long tot_len;
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
-	long retval, i;
-	IO_fn_t fn;
-
-	/* First get the "struct iovec" from user memory and
-	 * verify all the pointers
-	 */
-	if (!count)
-		return 0;
-	if(verify_area(VERIFY_READ, vector, sizeof(struct compat_iovec)*count))
-		return -EFAULT;
-	if (count > UIO_MAXIOV)
-		return -EINVAL;
-	if (count > UIO_FASTIOV) {
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
-		if (!iov)
-			return -ENOMEM;
-	}
-
-	tot_len = 0;
-	i = count;
-	ivp = iov;
-	while (i > 0) {
-		u32 len;
-		u32 buf;
-
-		__get_user(len, &vector->iov_len);
-		__get_user(buf, &vector->iov_base);
-		tot_len += len;
-		ivp->iov_base = compat_ptr(buf);
-		ivp->iov_len = (compat_size_t) len;
-		vector++;
-		ivp++;
-		i--;
-	}
-
-	inode = file->f_dentry->d_inode;
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
-	if (retval) {
-		if (iov != iovstack)
-			kfree(iov);
-		return retval;
-	}
-
-	/* Then do the actual IO.  Note that sockets need to be handled
-	 * specially as they have atomicity guarantees and can handle
-	 * iovec's natively
-	 */
-	if (inode->i_sock) {
-		int err;
-		err = sock_readv_writev(type, inode, file, iov, count, tot_len);
-		if (iov != iovstack)
-			kfree(iov);
-		return err;
-	}
-
-	if (!file->f_op) {
-		if (iov != iovstack)
-			kfree(iov);
-		return -EINVAL;
-	}
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	fn = file->f_op->read;
-	if (type == VERIFY_READ)
-		fn = (IO_fn_t) file->f_op->write;		
-	ivp = iov;
-	while (count > 0) {
-		void * base;
-		int len, nr;
-
-		base = ivp->iov_base;
-		len = ivp->iov_len;
-		ivp++;
-		count--;
-		nr = fn(file, base, len, &file->f_pos);
-		if (nr < 0) {
-			if (retval)
-				break;
-			retval = nr;
-			break;
-		}
-		retval += nr;
-		if (nr != len)
-			break;
-	}
-	if (iov != iovstack)
-		kfree(iov);
-
-	return retval;
-}
-
-asmlinkage long
-sys32_readv(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	ssize_t ret;
-
-	ret = -EBADF;
-	file = fget(fd);
-	if (!file)
-		goto bad_file;
-	if (file->f_op && (file->f_mode & FMODE_READ) &&
-	    (file->f_op->readv || file->f_op->read))
-		ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
-
-	fput(file);
-
-bad_file:
-	return ret;
-}
-
-asmlinkage long
-sys32_writev(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	ssize_t ret;
-
-	ret = -EBADF;
-	file = fget(fd);
-	if(!file)
-		goto bad_file;
-	if (file->f_op && (file->f_mode & FMODE_WRITE) &&
-	    (file->f_op->writev || file->f_op->write))
-	        ret = do_readv_writev32(VERIFY_READ, file, vector, count);
-	fput(file);
-
-bad_file:
-	return ret;
-}
-
 /*** copied from mips64 ***/
 /*
  * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
===== arch/parisc/kernel/syscall_table.S 1.5 vs edited =====
--- 1.5/arch/parisc/kernel/syscall_table.S	Sun Apr  4 00:57:02 2004
+++ edited/arch/parisc/kernel/syscall_table.S	Sat Apr  3 23:00:24 2004
@@ -236,8 +236,8 @@
 	ENTRY_SAME(flock)
 	ENTRY_SAME(msync)
 	/* struct iovec contains pointers */
-	ENTRY_DIFF(readv)		/* 145 */
-	ENTRY_DIFF(writev)
+	ENTRY_COMP(readv)		/* 145 */
+	ENTRY_COMP(writev)
 	ENTRY_SAME(getsid)
 	ENTRY_SAME(fdatasync)
 	/* struct __sysctl_args is a mess */
===== arch/ppc64/kernel/misc.S 1.74 vs edited =====
--- 1.74/arch/ppc64/kernel/misc.S	Fri Mar 26 20:05:26 2004
+++ edited/arch/ppc64/kernel/misc.S	Sat Apr  3 19:56:39 2004
@@ -717,8 +717,8 @@
 	.llong .ppc32_select
 	.llong .sys_flock
 	.llong .sys_msync
-	.llong .sys32_readv		/* 145 */
-	.llong .sys32_writev
+	.llong .compat_sys_readv	/* 145 */
+	.llong .compat_sys_writev
 	.llong .sys32_getsid
 	.llong .sys_fdatasync
 	.llong .sys32_sysctl
===== arch/ppc64/kernel/sys_ppc32.c 1.86 vs edited =====
--- 1.86/arch/ppc64/kernel/sys_ppc32.c	Wed Mar 24 13:24:38 2004
+++ edited/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 19:51:49 2004
@@ -78,178 +78,6 @@
 
 #include "pci.h"
 
-typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
-typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
-
-static long do_readv_writev32(int type, struct file *file,
-			      const struct compat_iovec *vector, u32 count)
-{
-	compat_ssize_t tot_len;
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
-	long retval, i;
-	io_fn_t fn;
-	iov_fn_t fnv;
-
-	/*
-	 * SuS says "The readv() function *may* fail if the iovcnt argument
-	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-	 * traditionally returned zero for zero segments, so...
-	 */
-	retval = 0;
-	if (count == 0)
-		goto out;
-
-	/* First get the "struct iovec" from user memory and
-	 * verify all the pointers
-	 */
-	retval = -EINVAL;
-	if (count > UIO_MAXIOV)
-		goto out;
-	if (!file->f_op)
-		goto out;
-	if (count > UIO_FASTIOV) {
-		retval = -ENOMEM;
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
-		if (!iov)
-			goto out;
-	}
-	retval = -EFAULT;
-	if (verify_area(VERIFY_READ, vector, sizeof(struct compat_iovec)*count))
-		goto out;
-
-	/*
-	 * Single unix specification:
-	 * We should -EINVAL if an element length is not >= 0 and fitting an
-	 * ssize_t.  The total length is fitting an ssize_t
-	 *
-	 * Be careful here because iov_len is a size_t not an ssize_t
-	 */
-	tot_len = 0;
-	i = count;
-	ivp = iov;
-	retval = -EINVAL;
-	while(i > 0) {
-		compat_ssize_t tmp = tot_len;
-		compat_ssize_t len;
-		u32 buf;
-
-		if (__get_user(len, &vector->iov_len) ||
-		    __get_user(buf, &vector->iov_base)) {
-			retval = -EFAULT;
-			goto out;
-		}
-		if (len < 0)	/* size_t not fitting an compat_ssize_t .. */
-			goto out;
-		tot_len += len;
-		if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
-			goto out;
-		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t) len;
-		vector++;
-		ivp++;
-		i--;
-	}
-	if (tot_len == 0) {
-		retval = 0;
-		goto out;
-	}
-
-	inode = file->f_dentry->d_inode;
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == READ
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
-	if (retval)
-		goto out;
-
-	if (type == READ) {
-		fn = file->f_op->read;
-		fnv = file->f_op->readv;
-	} else {
-		fn = (io_fn_t)file->f_op->write;
-		fnv = file->f_op->writev;
-	}
-	if (fnv) {
-		retval = fnv(file, iov, count, &file->f_pos);
-		goto out;
-	}
-
-	/* Do it by hand, with file-ops */
-	ivp = iov;
-	while (count > 0) {
-		void * base;
-		int len, nr;
-
-		base = ivp->iov_base;
-		len = ivp->iov_len;
-		ivp++;
-		count--;
-
-		nr = fn(file, base, len, &file->f_pos);
-
-		if (nr < 0) {
-			if (!retval)
-				retval = nr;
-			break;
-		}
-		retval += nr;
-		if (nr != len)
-			break;
-	}
-out:
-	if (iov != iovstack)
-		kfree(iov);
-	if ((retval + (type == READ)) > 0)
-		dnotify_parent(file->f_dentry,
-			       (type == READ) ? DN_ACCESS : DN_MODIFY);
-
-	return retval;
-}
-
-asmlinkage long sys32_readv(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	int ret = -EBADF;
-
-	file = fget(fd);
-	if (!file || !(file->f_mode & FMODE_READ))
-		goto out; 
-
-	ret = -EINVAL;
-	if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
-		goto out;
-
-	ret = do_readv_writev32(READ, file, vector, count);
-
-out:
-	if (file)
-		fput(file);
-	return ret;
-}
-
-asmlinkage long sys32_writev(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	int ret = -EBADF;
-
-	file = fget(fd);
-	if (!file || !(file->f_mode & FMODE_WRITE))
-		goto out;
-
-	ret = -EINVAL;
-	if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
-		goto out;
-
-	ret = do_readv_writev32(WRITE, file, vector, count);
-
-out:
-	if (file)
-		fput(file);
-	return ret;
-}
-
 /* readdir & getdents */
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 #define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
===== arch/s390/kernel/compat_linux.c 1.19 vs edited =====
--- 1.19/arch/s390/kernel/compat_linux.c	Sat Mar 27 22:46:54 2004
+++ edited/arch/s390/kernel/compat_linux.c	Sat Apr  3 19:51:49 2004
@@ -373,144 +373,6 @@
 		return sys_ftruncate(fd, (high << 32) | low);
 }
 
-typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
-typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
-
-static long do_readv_writev32(int type, struct file *file,
-			      const struct compat_iovec *vector, u32 count)
-{
-	unsigned long tot_len;
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
-	long retval, i;
-	io_fn_t fn;
-	iov_fn_t fnv;
-
-	/* First get the "struct iovec" from user memory and
-	 * verify all the pointers
-	 */
-	if (!count)
-		return 0;
-	if (verify_area(VERIFY_READ, vector, sizeof(struct compat_iovec)*count))
-		return -EFAULT;
-	if (count > UIO_MAXIOV)
-		return -EINVAL;
-	if (count > UIO_FASTIOV) {
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
-		if (!iov)
-			return -ENOMEM;
-	}
-
-	tot_len = 0;
-	i = count;
-	ivp = iov;
-	retval = -EINVAL;
-	while(i > 0) {
-		compat_ssize_t tmp = tot_len;
-		compat_ssize_t len;
-		u32 buf;
-
-		if (__get_user(len, &vector->iov_len) ||
-		    __get_user(buf, &vector->iov_base)) {
-			retval = -EFAULT;
-			goto out;
-		}
-		if (len < 0)	/* size_t not fitting an ssize_t32 .. */
-			goto out;
-		tot_len += len;
-		if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
-			goto out;
-		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t) len;
-		vector++;
-		ivp++;
-		i--;
-	}
-	if (tot_len == 0) {
-		retval = 0;
-		goto out;
-	}
-
-	inode = file->f_dentry->d_inode;
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == VERIFY_WRITE
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
-	if (retval)
-		goto out;
-
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
-	if (fnv) {
-		retval = fnv(file, iov, count, &file->f_pos);
-		goto out;
-	}
-
-	fn = (type == VERIFY_WRITE ? file->f_op->read :
-	      (io_fn_t) file->f_op->write);
-
-	ivp = iov;
-	while (count > 0) {
-		void * base;
-		int len, nr;
-
-		base = ivp->iov_base;
-		len = ivp->iov_len;
-		ivp++;
-		count--;
-		nr = fn(file, base, len, &file->f_pos);
-		if (nr < 0) {
-			if (!retval)
-				retval = nr;
-			break;
-		}
-		retval += nr;
-		if (nr != len)
-			break;
-	}
-out:
-	if (iov != iovstack)
-		kfree(iov);
-
-	return retval;
-}
-
-asmlinkage long sys32_readv(int fd, struct compat_iovec *vector, unsigned long count)
-{
-	struct file *file;
-	long ret = -EBADF;
-
-	file = fget(fd);
-	if(!file)
-		goto bad_file;
-
-	if (file->f_op && (file->f_mode & FMODE_READ) &&
-	    (file->f_op->readv || file->f_op->read))
-		ret = do_readv_writev32(VERIFY_WRITE, file, vector, count);
-	fput(file);
-
-bad_file:
-	return ret;
-}
-
-asmlinkage long sys32_writev(int fd, struct compat_iovec *vector, unsigned long count)
-{
-	struct file *file;
-	int ret = -EBADF;
-
-	file = fget(fd);
-	if(!file)
-		goto bad_file;
-	if (file->f_op && (file->f_mode & FMODE_WRITE) &&
-	    (file->f_op->writev || file->f_op->write))
-		ret = do_readv_writev32(VERIFY_READ, file, vector, count);
-	fput(file);
-
-bad_file:
-	return ret;
-}
-
 /* readdir & getdents */
 
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
===== arch/s390/kernel/compat_wrapper.S 1.9 vs edited =====
--- 1.9/arch/s390/kernel/compat_wrapper.S	Sat Mar 27 22:43:12 2004
+++ edited/arch/s390/kernel/compat_wrapper.S	Sat Apr  3 19:57:56 2004
@@ -663,19 +663,19 @@
 	lgfr	%r4,%r4			# int
 	jg	sys_msync		# branch to system call
 
-	.globl  sys32_readv_wrapper 
-sys32_readv_wrapper:
+	.globl  compat_sys_readv_wrapper 
+compat_sys_readv_wrapper:
 	lgfr	%r2,%r2			# int
-	llgtr	%r3,%r3			# const struct iovec_emu31 *
+	llgtr	%r3,%r3			# const struct compat_iovec *
 	llgfr	%r4,%r4			# unsigned long
-	jg	sys32_readv		# branch to system call
+	jg	compat_sys_readv	# branch to system call
 
-	.globl  sys32_writev_wrapper 
-sys32_writev_wrapper:
+	.globl  compat_sys_writev_wrapper 
+compat_sys_writev_wrapper:
 	lgfr	%r2,%r2			# int
-	llgtr	%r3,%r3			# const struct iovec_emu31 *
+	llgtr	%r3,%r3			# const struct compat_iovec *
 	llgfr	%r4,%r4			# unsigned long
-	jg	sys32_writev		# branch to system call
+	jg	compat_sys_writev	# branch to system call
 
 	.globl  sys32_getsid_wrapper 
 sys32_getsid_wrapper:
===== arch/s390/kernel/syscalls.S 1.9 vs edited =====
--- 1.9/arch/s390/kernel/syscalls.S	Wed Mar 17 13:02:24 2004
+++ edited/arch/s390/kernel/syscalls.S	Sat Apr  3 19:58:13 2004
@@ -153,8 +153,8 @@
 SYSCALL(sys_select,sys_select,sys32_select_wrapper)
 SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
 SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
-SYSCALL(sys_readv,sys_readv,sys32_readv_wrapper)		/* 145 */
-SYSCALL(sys_writev,sys_writev,sys32_writev_wrapper)
+SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper)		/* 145 */
+SYSCALL(sys_writev,sys_writev,compat_sys_writev_wrapper)
 SYSCALL(sys_getsid,sys_getsid,sys32_getsid_wrapper)
 SYSCALL(sys_fdatasync,sys_fdatasync,sys32_fdatasync_wrapper)
 SYSCALL(sys_sysctl,sys_sysctl,sys32_sysctl_wrapper)
===== arch/sparc64/kernel/sys_sparc32.c 1.95 vs edited =====
--- 1.95/arch/sparc64/kernel/sys_sparc32.c	Sat Mar 27 22:46:54 2004
+++ edited/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 19:51:49 2004
@@ -832,182 +832,6 @@
 		return sys_ftruncate(fd, (high << 32) | low);
 }
 
-typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
-typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
-
-static long do_readv_writev32(int type, struct file *file,
-			      const struct compat_iovec *vector, u32 count)
-{
-	compat_ssize_t tot_len;
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov=iovstack, *ivp;
-	struct inode *inode;
-	long retval, i;
-	io_fn_t fn;
-	iov_fn_t fnv;
-
-	/*
-	 * SuS says "The readv() function *may* fail if the iovcnt argument
-	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
-	 * traditionally returned zero for zero segments, so...
-	 */
-	retval = 0;
-	if (count == 0)
-		goto out;
-
-	/* First get the "struct iovec" from user memory and
-	 * verify all the pointers
-	 */
-	retval = -EINVAL;
-	if (count > UIO_MAXIOV)
-		goto out;
-	if (!file->f_op)
-		goto out;
-	if (count > UIO_FASTIOV) {
-		retval = -ENOMEM;
-		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
-		if (!iov)
-			goto out;
-	}
-	retval = -EFAULT;
-	if (verify_area(VERIFY_READ, vector, sizeof(struct compat_iovec)*count))
-		goto out;
-
-	/*
-	 * Single unix specification:
-	 * We should -EINVAL if an element length is not >= 0 and fitting an
-	 * ssize_t.  The total length is fitting an ssize_t
-	 *
-	 * Be careful here because iov_len is a size_t not an ssize_t
-	 */
-	tot_len = 0;
-	i = count;
-	ivp = iov;
-	retval = -EINVAL;
-	while(i > 0) {
-		compat_ssize_t tmp = tot_len;
-		compat_ssize_t len;
-		u32 buf;
-
-		if (__get_user(len, &vector->iov_len) ||
-		    __get_user(buf, &vector->iov_base)) {
-			retval = -EFAULT;
-			goto out;
-		}
-		if (len < 0)	/* size_t not fitting an ssize_t32 .. */
-			goto out;
-		tot_len += len;
-		if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
-			goto out;
-		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t) len;
-		vector++;
-		ivp++;
-		i--;
-	}
-	if (tot_len == 0) {
-		retval = 0;
-		goto out;
-	}
-
-	inode = file->f_dentry->d_inode;
-	/* VERIFY_WRITE actually means a read, as we write to user space */
-	retval = locks_verify_area((type == READ
-				    ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				   inode, file, file->f_pos, tot_len);
-	if (retval)
-		goto out;
-
-	if (type == READ) {
-		fn = file->f_op->read;
-		fnv = file->f_op->readv;
-	} else {
-		fn = (io_fn_t)file->f_op->write;
-		fnv = file->f_op->writev;
-	}
-	if (fnv) {
-		retval = fnv(file, iov, count, &file->f_pos);
-		goto out;
-	}
-
-	/* Do it by hand, with file-ops */
-	ivp = iov;
-	while (count > 0) {
-		void * base;
-		int len, nr;
-
-		base = ivp->iov_base;
-		len = ivp->iov_len;
-		ivp++;
-		count--;
-
-		nr = fn(file, base, len, &file->f_pos);
-
-		if (nr < 0) {
-			if (!retval)
-				retval = nr;
-			break;
-		}
-		retval += nr;
-		if (nr != len)
-			break;
-	}
-out:
-	if (iov != iovstack)
-		kfree(iov);
-	if ((retval + (type == READ)) > 0)
-		dnotify_parent(file->f_dentry,
-			(type == READ) ? DN_ACCESS : DN_MODIFY);
-
-	return retval;
-}
-
-asmlinkage long sys32_readv(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	int ret;
-
-	file = fget(fd);
-	if(!file)
-		return -EBADF;
-
-	ret = -EBADF;
-	if (!(file->f_mode & FMODE_READ))
-		goto out;
-	ret = -EINVAL;
-	if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
-		goto out;
-
-	ret = do_readv_writev32(READ, file, vector, count);
-
-out:
-	fput(file);
-	return ret;
-}
-
-asmlinkage long sys32_writev(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct file *file;
-	int ret;
-
-	file = fget(fd);
-	if(!file)
-		return -EBADF;
-
-	ret = -EBADF;
-	if (!(file->f_mode & FMODE_WRITE))
-		goto out;
-	ret = -EINVAL;
-	if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
-		goto out;
-
-	ret = do_readv_writev32(WRITE, file, vector, count);
-
-out:
-	fput(file);
-	return ret;
-}
-
 /* readdir & getdents */
 
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
===== arch/sparc64/kernel/sys_sunos32.c 1.39 vs edited =====
--- 1.39/arch/sparc64/kernel/sys_sunos32.c	Fri Mar 26 23:16:26 2004
+++ edited/arch/sparc64/kernel/sys_sunos32.c	Sat Apr  3 20:06:40 2004
@@ -1203,9 +1203,6 @@
 	return ret;
 }
 
-extern asmlinkage int sys32_readv(u32 fd, u32 vector, s32 count);
-extern asmlinkage int sys32_writev(u32 fd, u32 vector, s32 count);
-
 asmlinkage int sunos_read(unsigned int fd, u32 buf, u32 count)
 {
 	int ret;
@@ -1218,7 +1215,7 @@
 {
 	int ret;
 
-	ret = check_nonblock(sys32_readv(fd, vector, count), fd);
+	ret = check_nonblock(compat_sys_readv(fd, (void*)A(vector), count), fd);
 	return ret;
 }
 
@@ -1234,7 +1231,7 @@
 {
 	int ret;
 
-	ret = check_nonblock(sys32_writev(fd, vector, count), fd);
+	ret = check_nonblock(compat_sys_writev(fd, (void*)A(vector), count), fd);
 	return ret;
 }
 
===== arch/sparc64/kernel/systbls.S 1.52 vs edited =====
--- 1.52/arch/sparc64/kernel/systbls.S	Fri Mar 26 20:05:27 2004
+++ edited/arch/sparc64/kernel/systbls.S	Sat Apr  3 20:00:19 2004
@@ -43,7 +43,7 @@
 	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid
 /*110*/	.word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
 	.word sys_getgroups, sys32_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd
-/*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
+/*120*/	.word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
 	.word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate
 /*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64
===== arch/x86_64/ia32/ia32entry.S 1.30 vs edited =====
--- 1.30/arch/x86_64/ia32/ia32entry.S	Fri Mar 26 20:05:27 2004
+++ edited/arch/x86_64/ia32/ia32entry.S	Sat Apr  3 20:00:33 2004
@@ -450,8 +450,8 @@
 	.quad sys32_select
 	.quad sys_flock
 	.quad sys_msync
-	.quad sys32_readv		/* 145 */
-	.quad sys32_writev
+	.quad compat_sys_readv		/* 145 */
+	.quad compat_sys_writev
 	.quad sys_getsid
 	.quad sys_fdatasync
 	.quad sys32_sysctl	/* sysctl */
===== arch/x86_64/ia32/sys_ia32.c 1.56 vs edited =====
--- 1.56/arch/x86_64/ia32/sys_ia32.c	Mon Mar 29 15:38:03 2004
+++ edited/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 19:51:49 2004
@@ -726,104 +726,6 @@
 			    (struct compat_timeval *)A(a.tvp));
 }
 
-static struct iovec *
-get_compat_iovec(struct compat_iovec *iov32, struct iovec *iov_buf, u32 *count, int type, int *errp)
-{
-	int i;
-	u32 buf, len;
-	struct iovec *ivp, *iov;
-	unsigned long totlen; 
-
-	/* Get the "struct iovec" from user memory */
-
-	*errp = 0;
-	if (!*count)
-		return 0;
-	*errp = -EINVAL;
-	if (*count > UIO_MAXIOV)
-		return(struct iovec *)0;
-	*errp = -EFAULT;
-	if(verify_area(VERIFY_READ, iov32, sizeof(struct compat_iovec)*(*count)))
-		return(struct iovec *)0;
-	if (*count > UIO_FASTIOV) {
-		*errp = -ENOMEM; 
-		iov = kmalloc(*count*sizeof(struct iovec), GFP_KERNEL);
-		if (!iov)
-			return((struct iovec *)0);
-	} else
-		iov = iov_buf;
-
-	ivp = iov;
-	totlen = 0;
-	for (i = 0; i < *count; i++) {
-		*errp = __get_user(len, &iov32->iov_len) |
-		  	__get_user(buf, &iov32->iov_base);	
-		if (*errp)
-			goto error;
-		*errp = verify_area(type, (void *)A(buf), len);
-		if (*errp) {
-			if (i > 0) { 
-				*count = i;
-				break;
-			} 
-			goto error;
-		}
-		/* SuS checks: */
-		*errp = -EINVAL; 
-		if ((int)len < 0)
-			goto error;
-		if ((totlen += len) >= 0x7fffffff)
-			goto error;			
-		ivp->iov_base = (void *)A(buf);
-		ivp->iov_len = (__kernel_size_t)len;
-		iov32++;
-		ivp++;
-	}
-	*errp = 0;
-	return(iov);
-
-error:
-	if (iov != iov_buf)
-		kfree(iov);
-	return NULL;
-}
-
-asmlinkage long
-sys32_readv(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	if ((iov = get_compat_iovec(vector, iovstack, &count, VERIFY_WRITE, &ret)) == NULL)
-		return ret;
-	set_fs(KERNEL_DS);
-	ret = sys_readv(fd, iov, count);
-	set_fs(old_fs);
-	if (iov != iovstack)
-		kfree(iov);
-	return ret;
-}
-
-asmlinkage long
-sys32_writev(int fd, struct compat_iovec *vector, u32 count)
-{
-	struct iovec iovstack[UIO_FASTIOV];
-	struct iovec *iov;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	if ((iov = get_compat_iovec(vector, iovstack, &count, VERIFY_READ, &ret)) == NULL)
-		return ret;
-	set_fs(KERNEL_DS);
-	ret = sys_writev(fd, iov, count);
-	set_fs(old_fs);
-	if (iov != iovstack)
-		kfree(iov);
-	return ret;
-}
-
 /*
  * sys_time() can be implemented in user-level using
  * sys_gettimeofday().  x86-64 did this but i386 Linux did not
===== fs/compat.c 1.22 vs edited =====
--- 1.22/fs/compat.c	Fri Mar 26 20:05:31 2004
+++ edited/fs/compat.c	Sat Apr  3 19:51:49 2004
@@ -34,9 +34,17 @@
 #include <linux/syscalls.h>
 #include <linux/ctype.h>
 #include <linux/module.h>
+#include <linux/dnotify.h>
+#include <linux/highuid.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/syscall.h>
+#include <linux/personality.h>
+
 #include <net/sock.h>		/* siocdevprivate_ioctl */
 
 #include <asm/uaccess.h>
+#include <asm/mmu_context.h>
 
 /*
  * Not all architectures have sys_utime, so implement this in terms
@@ -794,3 +802,181 @@
 	return retval;
 }
 
+static ssize_t compat_do_readv_writev(int type, struct file *file,
+			       const struct compat_iovec __user *uvector,
+			       unsigned long nr_segs, loff_t *pos)
+{
+	typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
+	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
+
+	compat_ssize_t tot_len;
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov=iovstack, *vector;
+	ssize_t ret;
+	int seg;
+	io_fn_t fn;
+	iov_fn_t fnv;
+	struct inode *inode;
+
+	/*
+	 * SuS says "The readv() function *may* fail if the iovcnt argument
+	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has
+	 * traditionally returned zero for zero segments, so...
+	 */
+	ret = 0;
+	if (nr_segs == 0)
+		goto out;
+
+	/*
+	 * First get the "struct iovec" from user memory and
+	 * verify all the pointers
+	 */
+	ret = -EINVAL;
+	if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))
+		goto out;
+	if (!file->f_op)
+		goto out;
+	if (nr_segs > UIO_FASTIOV) {
+		ret = -ENOMEM;
+		iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
+		if (!iov)
+			goto out;
+	}
+	ret = -EFAULT;
+	if (verify_area(VERIFY_READ, uvector, nr_segs*sizeof(*uvector)))
+		goto out;
+
+	/*
+	 * Single unix specification:
+	 * We should -EINVAL if an element length is not >= 0 and fitting an
+	 * ssize_t.  The total length is fitting an ssize_t
+	 *
+	 * Be careful here because iov_len is a size_t not an ssize_t
+	 */
+	tot_len = 0;
+	vector = iov;
+	ret = -EINVAL;
+	for (seg = 0 ; seg < nr_segs; seg++) {
+		compat_ssize_t tmp = tot_len;
+		compat_ssize_t len;
+		compat_uptr_t buf;
+
+		if (__get_user(len, &uvector->iov_len) ||
+		    __get_user(buf, &uvector->iov_base)) {
+			ret = -EFAULT;
+			goto out;
+		}
+		if (len < 0)	/* size_t not fitting an compat_ssize_t .. */
+			goto out;
+		tot_len += len;
+		if (tot_len < tmp) /* maths overflow on the compat_ssize_t */
+			goto out;
+		vector->iov_base = compat_ptr(buf);
+		vector->iov_len = (compat_size_t) len;
+		uvector++;
+		vector++;
+	}
+	if (tot_len == 0) {
+		ret = 0;
+		goto out;
+	}
+
+	inode = file->f_dentry->d_inode;
+	/* VERIFY_WRITE actually means a read, as we write to user space */
+	ret = locks_verify_area((type == READ 
+				 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
+				inode, file, *pos, tot_len);
+	if (ret)
+		goto out;
+
+	fnv = NULL;
+	if (type == READ) {
+		fn = file->f_op->read;
+		fnv = file->f_op->readv;
+	} else {
+		fn = (io_fn_t)file->f_op->write;
+		fnv = file->f_op->writev;
+	}
+	if (fnv) {
+		ret = fnv(file, iov, nr_segs, pos);
+		goto out;
+	}
+
+	/* Do it by hand, with file-ops */
+	ret = 0;
+	vector = iov;
+	while (nr_segs > 0) {
+		void __user * base;
+		size_t len;
+		ssize_t nr;
+
+		base = vector->iov_base;
+		len = vector->iov_len;
+		vector++;
+		nr_segs--;
+
+		nr = fn(file, base, len, pos);
+
+		if (nr < 0) {
+			if (!ret) ret = nr;
+			break;
+		}
+		ret += nr;
+		if (nr != len)
+			break;
+	}
+out:
+	if (iov != iovstack)
+		kfree(iov);
+	if ((ret + (type == READ)) > 0)
+		dnotify_parent(file->f_dentry,
+				(type == READ) ? DN_ACCESS : DN_MODIFY);
+	return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+{
+	struct file *file;
+	ssize_t ret = -EBADF;
+
+	file = fget(fd);
+	if (!file)
+		return -EBADF;
+
+	if (!(file->f_mode & FMODE_READ))
+		goto out; 
+
+	ret = -EINVAL;
+	if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
+		goto out;
+
+	ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
+
+out:
+	fput(file);
+	return ret;
+}
+
+asmlinkage ssize_t
+compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen)
+{
+	struct file *file;
+	ssize_t ret = -EBADF;
+
+	file = fget(fd);
+	if (!file)
+		return -EBADF;
+	if (!(file->f_mode & FMODE_WRITE))
+		goto out;
+
+	ret = -EINVAL;
+	if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
+		goto out;
+
+	ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
+
+out:
+	fput(file);
+	return ret;
+}
===== include/linux/compat.h 1.19 vs edited =====
--- 1.19/include/linux/compat.h	Mon Mar 15 15:22:46 2004
+++ edited/include/linux/compat.h	Sat Apr  3 20:03:56 2004
@@ -100,5 +100,11 @@
 long compat_sys_shmctl(int first, int second, void __user *uptr);
 long compat_sys_semtimedop(int semid, struct sembuf __user *tsems,
 		unsigned nsems, const struct compat_timespec __user *timeout);
+
+asmlinkage ssize_t compat_sys_readv(unsigned long fd,
+		const struct compat_iovec __user *vec, unsigned long vlen);
+asmlinkage ssize_t compat_sys_writev(unsigned long fd,
+		const struct compat_iovec __user *vec, unsigned long vlen);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */

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

* [PATCH 2/4] Consolidate do_execve32
       [not found] <200404040204.03594.arnd@arndb.de>
  2004-04-04  0:22 ` [PATCH 1/4] Consolidate sys32_readv and sys32_writev Arnd Bergmann
@ 2004-04-04  0:22 ` Arnd Bergmann
  2004-04-13 18:45   ` Arun Sharma
  2004-04-04  0:22 ` [PATCH 3/4] Consolidate sys32_select Arnd Bergmann
  2004-04-04  0:22 ` [PATCH 4/4] Consolidate sys32_nfsservctl Arnd Bergmann
  3 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-04  0:22 UTC (permalink / raw)
  To: linux-arch

The code for sys32_execve/do_execve32 in most of the seven versions
was copied from fs/exec.c but not kept up-to-date. The new
compat_do_execve() function is based on the mips code and has been
resync'ed with do_execve().

IA64 has some special fixup code in sys32_execve, so I'm not touching
that.

Tested with LTP and more 32 bit binaries on x86_64, which previously
used an implementation derived from ia64. The consolidated version
is larger than that but should perform better.

===== arch/mips/kernel/linux32.c 1.23 vs edited =====
--- 1.23/arch/mips/kernel/linux32.c	Sat Apr  3 21:51:49 2004
+++ edited/arch/mips/kernel/linux32.c	Sat Apr  3 21:20:39 2004
@@ -142,228 +142,6 @@
 }
 
 /*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv, int max)
-{
-	int i = 0;
-
-	if (argv != NULL) {
-		for (;;) {
-			u32 p; int error;
-
-			error = get_user(p,argv);
-			if (error)
-				return error;
-			if (!p)
-				break;
-			argv++;
-			if (++i > max)
-				return -E2BIG;
-		}
-	}
-	return i;
-}
-
-
-/*
- * 'copy_strings32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
-	struct page *kmapped_page = NULL;
-	char *kaddr = NULL;
-	int ret;
-
-	while (argc-- > 0) {
-		u32 str;
-		int len;
-		unsigned long pos;
-
-		if (get_user(str, argv+argc) || !str ||
-		     !(len = strnlen_user((char *)A(str), bprm->p))) {
-			ret = -EFAULT;
-			goto out;
-		}
-
-		if (bprm->p < len)  {
-			ret = -E2BIG;
-			goto out;
-		}
-
-		bprm->p -= len;
-		/* XXX: add architecture specific overflow check here. */
-
-		pos = bprm->p;
-		while (len > 0) {
-			int i, new, err;
-			int offset, bytes_to_copy;
-			struct page *page;
-
-			offset = pos % PAGE_SIZE;
-			i = pos/PAGE_SIZE;
-			page = bprm->page[i];
-			new = 0;
-			if (!page) {
-				page = alloc_page(GFP_HIGHUSER);
-				bprm->page[i] = page;
-				if (!page) {
-					ret = -ENOMEM;
-					goto out;
-				}
-				new = 1;
-			}
-
-			if (page != kmapped_page) {
-				if (kmapped_page)
-					kunmap(kmapped_page);
-				kmapped_page = page;
-				kaddr = kmap(kmapped_page);
-			}
-			if (new && offset)
-				memset(kaddr, 0, offset);
-			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len) {
-				bytes_to_copy = len;
-				if (new)
-					memset(kaddr+offset+len, 0,
-					       PAGE_SIZE-offset-len);
-			}
-			err = copy_from_user(kaddr + offset, (char *)A(str),
-			                     bytes_to_copy);
-			if (err) {
-				ret = -EFAULT;
-				goto out;
-			}
-
-			pos += bytes_to_copy;
-			str += bytes_to_copy;
-			len -= bytes_to_copy;
-		}
-	}
-	ret = 0;
-out:
-	if (kmapped_page)
-		kunmap(kmapped_page);
-	return ret;
-}
-
-#ifdef CONFIG_MMU
-
-#define free_arg_pages(bprm) do { } while (0)
-
-#else
-
-static inline void free_arg_pages(struct linux_binprm *bprm)
-{
-	int i;
-
-	for (i = 0; i < MAX_ARG_PAGES; i++) {
-		if (bprm->page[i])
-			__free_page(bprm->page[i]);
-		bprm->page[i] = NULL;
-	}
-}
-
-#endif /* CONFIG_MMU */
-
-/*
- * sys32_execve() executes a new program.
- */
-static inline int 
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
-	struct linux_binprm bprm;
-	struct file * file;
-	int retval;
-
-	sched_balance_exec();
-
-	file = open_exec(filename);
-
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		return retval;
-
-	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
-	bprm.file = file;
-	bprm.filename = filename;
-	bprm.interp = filename;
-	bprm.sh_bang = 0;
-	bprm.loader = 0;
-	bprm.exec = 0;
-	bprm.security = NULL;
-	bprm.mm = mm_alloc();
-	retval = -ENOMEM;
-	if (!bprm.mm) 
-		goto out_file;
-
-	retval = init_new_context(current, bprm.mm);
-	if (retval < 0)
-		goto out_mm;
-
-	bprm.argc = count32(argv, bprm.p / sizeof(u32));
-	if ((retval = bprm.argc) < 0)
-		goto out_mm;
-
-	bprm.envc = count32(envp, bprm.p / sizeof(u32));
-	if ((retval = bprm.envc) < 0)
-		goto out_mm;
-
-	retval = security_bprm_alloc(&bprm);
-	if (retval)
-		goto out;
-
-	retval = prepare_binprm(&bprm);
-	if (retval < 0)
-		goto out;
-	
-	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
-	if (retval < 0)
-		goto out;
-
-	bprm.exec = bprm.p;
-	retval = copy_strings32(bprm.envc, envp, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = copy_strings32(bprm.argc, argv, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = search_binary_handler(&bprm, regs);
-	if (retval >= 0) {
-		free_arg_pages(&bprm);
-
-		/* execve success */
-		security_bprm_free(&bprm);
-		return retval;
-	}
-
-out:
-	/* Something went wrong, return the inode and free the argument pages*/
-	free_arg_pages(&bprm);
-
-	if (bprm.security)
-		security_bprm_free(&bprm);
-
-out_mm:
-	if (bprm.mm)
-		mmdrop(bprm.mm);
-
-out_file:
-	if (bprm.file) {
-		allow_write_access(bprm.file);
-		fput(bprm.file);
-	}
-	return retval;
-}
-
-/*
  * sys_execve() executes a new program.
  */
 asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
@@ -371,12 +149,12 @@
 	int error;
 	char * filename;
 
-	filename = getname((char *) (long)regs.regs[4]);
+	filename = getname(compat_ptr(regs.regs[4]));
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
-	error = do_execve32(filename, (u32 *) (long)regs.regs[5],
-	                  (u32 *) (long)regs.regs[6], &regs);
+	error = compat_do_execve(filename, compat_ptr(regs.regs[5]),
+				 compat_ptr(regs.regs[6]), &regs);
 	putname(filename);
 
 out:
===== arch/parisc/kernel/sys_parisc32.c 1.25 vs edited =====
--- 1.25/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 21:51:49 2004
+++ edited/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 21:16:03 2004
@@ -65,189 +65,6 @@
 #endif
 
 /*
- * count32() counts the number of arguments/envelopes. It is basically
- *           a copy of count() from fs/exec.c, except that it works
- *           with 32 bit argv and envp pointers.
- */
-
-static int count32(u32 *argv, int max)
-{
-	int i = 0;
-
-	if (argv != NULL) {
-		for (;;) {
-			u32 p;
-			int error;
-
-			error = get_user(p,argv);
-			if (error)
-				return error;
-			if (!p)
-				break;
-			argv++;
-			if(++i > max)
-				return -E2BIG;
-		}
-	}
-	return i;
-}
-
-
-/*
- * copy_strings32() is basically a copy of copy_strings() from fs/exec.c
- *                  except that it works with 32 bit argv and envp pointers.
- */
-
-
-static int copy_strings32(int argc, u32 *argv, struct linux_binprm *bprm)
-{
-	while (argc-- > 0) {
-		u32 str;
-		int len;
-		unsigned long pos;
-
-		if (get_user(str, argv + argc) ||
-		    !str ||
-		    !(len = strnlen_user((char *)compat_ptr(str), bprm->p)))
-			return -EFAULT;
-
-		if (bprm->p < len) 
-			return -E2BIG; 
-
-		bprm->p -= len;
-
-		pos = bprm->p;
-		while (len > 0) {
-			char *kaddr;
-			int i, new, err;
-			struct page *page;
-			int offset, bytes_to_copy;
-
-			offset = pos % PAGE_SIZE;
-			i = pos/PAGE_SIZE;
-			page = bprm->page[i];
-			new = 0;
-			if (!page) {
-				page = alloc_page(GFP_HIGHUSER);
-				bprm->page[i] = page;
-				if (!page)
-					return -ENOMEM;
-				new = 1;
-			}
-			kaddr = (char *)kmap(page);
-
-			if (new && offset)
-				memset(kaddr, 0, offset);
-			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len) {
-				bytes_to_copy = len;
-				if (new)
-					memset(kaddr+offset+len, 0, PAGE_SIZE-offset-len);
-			}
-			err = copy_from_user(kaddr + offset, (char *)compat_ptr(str), bytes_to_copy);
-			flush_dcache_page(page);
-			kunmap(page);
-
-			if (err)
-				return -EFAULT; 
-
-			pos += bytes_to_copy;
-			str += bytes_to_copy;
-			len -= bytes_to_copy;
-		}
-	}
-	return 0;
-}
-
-/*
- * do_execve32() is mostly a copy of do_execve(), with the exception
- * that it processes 32 bit argv and envp pointers.
- */
-
-static inline int 
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
-	struct linux_binprm bprm;
-	struct file *file;
-	int retval;
-	int i;
-
-	file = open_exec(filename);
-
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		return retval;
-
-	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
-
-	DBG(("do_execve32(%s, %p, %p, %p)\n", filename, argv, envp, regs));
-
-	bprm.file = file;
-	bprm.filename = filename;
-	bprm.interp = filename;
-	bprm.sh_bang = 0;
-	bprm.loader = 0;
-	bprm.exec = 0;
-
-	bprm.mm = mm_alloc();
-	retval = -ENOMEM;
-	if (!bprm.mm)
-		goto out_file;
-
-	retval = init_new_context(current, bprm.mm);
-	if (retval < 0)
-		goto out_mm;
-
-	if ((bprm.argc = count32(argv, bprm.p / sizeof(u32))) < 0) 
-		goto out_mm;
-
-	if ((bprm.envc = count32(envp, bprm.p / sizeof(u32))) < 0) 
-		goto out_mm;
-
-	retval = prepare_binprm(&bprm);
-	if (retval < 0)
-		goto out;
-	
-	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
-	if (retval < 0)
-		goto out;
-
-	bprm.exec = bprm.p;
-	retval = copy_strings32(bprm.envc, envp, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = copy_strings32(bprm.argc, argv, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = search_binary_handler(&bprm,regs);
-	if (retval >= 0)
-		/* execve success */
-		return retval;
-
-out:
-	/* Something went wrong, return the inode and free the argument pages*/
-	for (i = 0; i < MAX_ARG_PAGES; i++) {
-		struct page *page = bprm.page[i];
-		if (page)
-			__free_page(page);
-	}
-
-out_mm:
-	mmdrop(bprm.mm);
-
-out_file:
-	if (bprm.file) {
-		allow_write_access(bprm.file);
-		fput(bprm.file);
-	}
-
-	return retval;
-}
-
-/*
  * sys32_execve() executes a new program.
  */
 
@@ -261,8 +78,8 @@
 	error = PTR_ERR(filename);
 	if (IS_ERR(filename))
 		goto out;
-	error = do_execve32(filename, (u32 *) regs->gr[25],
-		(u32 *) regs->gr[24], regs);
+	error = compat_do_execve(filename, compat_ptr(regs->gr[25]),
+				 compat_ptr(regs->gr[24]), regs);
 	if (error == 0)
 		current->ptrace &= ~PT_DTRACE;
 	putname(filename);
===== arch/ppc64/kernel/sys_ppc32.c 1.87 vs edited =====
--- 1.87/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 21:51:49 2004
+++ edited/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 21:16:41 2004
@@ -1549,191 +1549,6 @@
 	return ret;
 }
 
-/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv, int max)
-{
-	int i = 0;
-
-	if (argv != NULL) {
-		for (;;) {
-			u32 p; int error;
-
-			error = get_user(p,argv);
-			if (error)
-				return error;
-			if (!p)
-				break;
-			argv++;
-			if (++i > max)
-				return -E2BIG;
-		}
-	}
-	return i;
-}
-
-/*
- * 'copy_string32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
-	while (argc-- > 0) {
-		u32 str;
-		int len;
-		unsigned long pos;
-
-		if (get_user(str, argv + argc) ||
-		    !str ||
-		    !(len = strnlen_user((char *)A(str), bprm->p)))
-			return -EFAULT;
-
-		if (bprm->p < len)
-			return -E2BIG;
-
-		bprm->p -= len;
-
-		pos = bprm->p;
-		while (len) {
-			char *kaddr;
-			struct page *page;
-			int offset, bytes_to_copy, new, err;
-
-			offset = pos % PAGE_SIZE;
-			page = bprm->page[pos / PAGE_SIZE];
-			new = 0;
-			if (!page) {
-				page = alloc_page(GFP_USER);
-				bprm->page[pos / PAGE_SIZE] = page;
-				if (!page)
-					return -ENOMEM;
-				new = 1;
-			}
-			kaddr = (char *)kmap(page);
-
-			if (new && offset)
-				memset(kaddr, 0, offset);
-			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len) {
-				bytes_to_copy = len;
-				if (new)
-					memset(kaddr+offset+len, 0,
-					       PAGE_SIZE-offset-len);
-			}
-
-			err = copy_from_user(kaddr + offset, (char *)A(str),
-					     bytes_to_copy);
-			kunmap((unsigned long)kaddr);
-
-			if (err)
-				return -EFAULT;
-
-			pos += bytes_to_copy;
-			str += bytes_to_copy;
-			len -= bytes_to_copy;
-		}
-	}
-	return 0;
-}
-
-/*
- * sys32_execve() executes a new program.
- */
-static int do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
-	struct linux_binprm bprm;
-	struct file * file;
-	int retval;
-	int i;
-
-	sched_balance_exec();
-
-	file = open_exec(filename);
-
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		return retval;
-
-	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
-	bprm.file = file;
-	bprm.filename = filename;
-	bprm.interp = filename;
-	bprm.sh_bang = 0;
-	bprm.loader = 0;
-	bprm.exec = 0;
-	bprm.security = NULL;
-	bprm.mm = mm_alloc();
-	retval = -ENOMEM;
-	if (!bprm.mm)
-		goto out_file;
-
-	retval = init_new_context(current, bprm.mm);
-	if (retval < 0)
-		goto out_mm;
-
-	bprm.argc = count32(argv, bprm.p / sizeof(u32));
-	if ((retval = bprm.argc) < 0)
-		goto out_mm;
-
-	bprm.envc = count32(envp, bprm.p / sizeof(u32));
-	if ((retval = bprm.envc) < 0)
-		goto out_mm;
-
-	retval = security_bprm_alloc(&bprm);
-	if (retval)
-		goto out;
-
-	retval = prepare_binprm(&bprm);
-	if (retval < 0) 
-		goto out; 
-
-	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
-	if (retval < 0) 
-		goto out; 
-
-	bprm.exec = bprm.p;
-	retval = copy_strings32(bprm.envc, envp, &bprm);
-	if (retval < 0) 
-		goto out; 
-
-	retval = copy_strings32(bprm.argc, argv, &bprm);
-	if (retval < 0) 
-		goto out; 
-
-	retval = search_binary_handler(&bprm,regs);
-	if (retval >= 0) {
-		/* execve success */
-		security_bprm_free(&bprm);
-		return retval;
-	}
-
-out:
-	/* Something went wrong, return the inode and free the argument pages*/
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page * page = bprm.page[i];
-		if (page)
-			__free_page(page);
-	}
-
-	if (bprm.security)
-		security_bprm_free(&bprm);
-
-out_mm:
-	if (bprm.mm)
-		mmdrop(bprm.mm);
-
-out_file:
-	if (bprm.file) {
-		allow_write_access(bprm.file);
-		fput(bprm.file);
-	}
-	return retval;
-}
-
 long sys32_execve(unsigned long a0, unsigned long a1, unsigned long a2,
 		  unsigned long a3, unsigned long a4, unsigned long a5,
 		  struct pt_regs *regs)
@@ -1752,7 +1567,7 @@
 		giveup_altivec(current);
 #endif /* CONFIG_ALTIVEC */
 
-	error = do_execve32(filename, (u32*) a1, (u32*) a2, regs);
+	error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs);
 
 	if (error == 0)
 		current->ptrace &= ~PT_DTRACE;
===== arch/s390/kernel/compat_linux.c 1.20 vs edited =====
--- 1.20/arch/s390/kernel/compat_linux.c	Sat Apr  3 21:51:49 2004
+++ edited/arch/s390/kernel/compat_linux.c	Sat Apr  3 21:17:59 2004
@@ -906,188 +906,6 @@
 	return ret;
 }
 
-extern void check_pending(int signum);
-
-/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv)
-{
-	int i = 0;
-
-	if (argv != NULL) {
-		for (;;) {
-			u32 p; int error;
-
-			error = get_user(p,argv);
-			if (error) return error;
-			if (!p) break;
-			argv++; i++;
-		}
-	}
-	return i;
-}
-
-/*
- * 'copy_string32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
-	while (argc-- > 0) {
-		u32 str;
-		int len;
-		unsigned long pos;
-
-		if (get_user(str, argv + argc) ||
-		    !str ||
-		    !(len = strnlen_user((char *)A(str), bprm->p)))
-			return -EFAULT;
-
-		if (bprm->p < len)
-			return -E2BIG;
-
-		bprm->p -= len;
-
-		pos = bprm->p;
-		while (len) {
-			char *kaddr;
-			struct page *page;
-			int offset, bytes_to_copy, new, err;
-
-			offset = pos % PAGE_SIZE;
-			page = bprm->page[pos / PAGE_SIZE];
-			new = 0;
-			if (!page) {
-				page = alloc_page(GFP_USER);
-				bprm->page[pos / PAGE_SIZE] = page;
-				if (!page)
-					return -ENOMEM;
-				new = 1;
-			}
-			kaddr = (char *)kmap(page);
-
-			if (new && offset)
-				memset(kaddr, 0, offset);
-			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len) {
-				bytes_to_copy = len;
-				if (new)
-					memset(kaddr+offset+len, 0,
-					       PAGE_SIZE-offset-len);
-			}
-
-			err = copy_from_user(kaddr + offset, (char *)A(str),
-					     bytes_to_copy);
-			kunmap(page);
-
-			if (err)
-				return -EFAULT;
-
-			pos += bytes_to_copy;
-			str += bytes_to_copy;
-			len -= bytes_to_copy;
-		}
-	}
-	return 0;
-}
-
-/*
- * sys32_execve() executes a new program.
- */
-static inline int 
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
-	struct linux_binprm bprm;
-	struct file * file;
-	int retval;
-	int i;
-
-	sched_balance_exec();
-
-	file = open_exec(filename);
-
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		return retval;
-
-	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
-	bprm.file = file;
-	bprm.filename = filename;
-	bprm.interp = filename;
-	bprm.sh_bang = 0;
-	bprm.loader = 0;
-	bprm.exec = 0;
-	bprm.mm = mm_alloc();
-	retval = -ENOMEM;
-	if (!bprm.mm)
-		goto out_file;
-
-	/* init_new_context is empty for s390x. */
-
-	bprm.argc = count32(argv);
-	if ((retval = bprm.argc) < 0)
-		goto out_mm;
-
-	bprm.envc = count32(envp);
-	if ((retval = bprm.envc) < 0)
-		goto out_mm;
-
-	retval = security_bprm_alloc(&bprm);
-	if (retval)
-		goto out;
-
-	retval = prepare_binprm(&bprm);
-	if (retval < 0)
-		goto out;
-	
-	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
-	if (retval < 0)
-		goto out;
-
-	bprm.exec = bprm.p;
-	retval = copy_strings32(bprm.envc, envp, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = copy_strings32(bprm.argc, argv, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = search_binary_handler(&bprm, regs);
-	if (retval >= 0) {
-		/* execve success */
-		security_bprm_free(&bprm);
-		return retval;
-	}
-
-out:
-	/* Something went wrong, return the inode and free the argument pages*/
-	for (i=0 ; i<MAX_ARG_PAGES ; i++) {
-		struct page * page = bprm.page[i];
-		if (page)
-			__free_page(page);
-	}
-
-	if (bprm.security)
-		security_bprm_free(&bprm);
-
-out_mm:
-	if (bprm.mm)
-		mmdrop(bprm.mm);
-
-out_file:
-	if (bprm.file) {
-		allow_write_access(bprm.file);
-		fput(bprm.file);
-	}
-
-	return retval;
-}
-
 /*
  * sys32_execve() executes a new program after the asm stub has set
  * things up for us.  This should basically do what I want it to.
@@ -1098,11 +916,12 @@
         int error;
         char * filename;
 
-        filename = getname((char *)A(regs.orig_gpr2));
+        filename = getname(compat_ptr(regs.orig_gpr2));
         error = PTR_ERR(filename);
         if (IS_ERR(filename))
                 goto out;
-        error = do_execve32(filename, (u32 *)A(regs.gprs[3]), (u32 *)A(regs.gprs[4]), &regs);
+        error = compat_do_execve(filename, compat_ptr(regs.gprs[3]),
+				 compat_ptr(regs.gprs[4]), &regs);
 	if (error == 0)
 	{
 		current->ptrace &= ~PT_DTRACE;
===== arch/sparc64/kernel/sys_sparc32.c 1.96 vs edited =====
--- 1.96/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 21:51:49 2004
+++ edited/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 21:19:17 2004
@@ -1386,8 +1386,6 @@
 	return ret;
 }
 
-extern void check_pending(int signum);
-
 asmlinkage int sys32_sigaction (int sig, struct old_sigaction32 *act, struct old_sigaction32 *oact)
 {
         struct k_sigaction new_ka, old_ka;
@@ -1483,193 +1481,6 @@
         return ret;
 }
 
-
-/*
- * count32() counts the number of arguments/envelopes
- */
-static int count32(u32 * argv, int max)
-{
-	int i = 0;
-
-	if (argv != NULL) {
-		for (;;) {
-			u32 p; int error;
-
-			error = get_user(p,argv);
-			if (error)
-				return error;
-			if (!p)
-				break;
-			argv++;
-			if (++i > max)
-				return -E2BIG;
-		}
-	}
-	return i;
-}
-
-/*
- * 'copy_string32()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- */
-static int copy_strings32(int argc, u32 * argv, struct linux_binprm *bprm)
-{
-	while (argc-- > 0) {
-		u32 str;
-		int len;
-		unsigned long pos;
-
-		if (get_user(str, argv + argc) ||
-		    !str ||
-		    !(len = strnlen_user((char *)A(str), bprm->p)))
-			return -EFAULT;
-
-		if (bprm->p < len)
-			return -E2BIG;
-
-		bprm->p -= len;
-
-		pos = bprm->p;
-		while (len) {
-			char *kaddr;
-			struct page *page;
-			int offset, bytes_to_copy, new, err;
-
-			offset = pos % PAGE_SIZE;
-			page = bprm->page[pos / PAGE_SIZE];
-			new = 0;
-			if (!page) {
-				page = alloc_page(GFP_USER);
-				bprm->page[pos / PAGE_SIZE] = page;
-				if (!page)
-					return -ENOMEM;
-				new = 1;
-			}
-			kaddr = kmap(page);
-
-			if (new && offset)
-				memset(kaddr, 0, offset);
-			bytes_to_copy = PAGE_SIZE - offset;
-			if (bytes_to_copy > len) {
-				bytes_to_copy = len;
-				if (new)
-					memset(kaddr+offset+len, 0,
-					       PAGE_SIZE-offset-len);
-			}
-
-			err = copy_from_user(kaddr + offset, (char *)A(str),
-					     bytes_to_copy);
-			kunmap(page);
-
-			if (err)
-				return -EFAULT;
-
-			pos += bytes_to_copy;
-			str += bytes_to_copy;
-			len -= bytes_to_copy;
-		}
-	}
-	return 0;
-}
-
-/*
- * sys32_execve() executes a new program.
- */
-static inline int 
-do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs)
-{
-	struct linux_binprm bprm;
-	struct file * file;
-	int retval;
-	int i;
-
-	sched_balance_exec();
-
-	file = open_exec(filename);
-
-	retval = PTR_ERR(file);
-	if (IS_ERR(file))
-		return retval;
-
-	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
-	memset(bprm.page, 0, MAX_ARG_PAGES * sizeof(bprm.page[0]));
-
-	bprm.file = file;
-	bprm.filename = filename;
-	bprm.interp = filename;
-	bprm.sh_bang = 0;
-	bprm.loader = 0;
-	bprm.exec = 0;
-	bprm.security = NULL;
-	bprm.mm = mm_alloc();
-	retval = -ENOMEM;
-	if (!bprm.mm) 
-		goto out_file;
-
-	retval = init_new_context(current, bprm.mm);
-	if (retval < 0)
-		goto out_mm;
-
-	bprm.argc = count32(argv, bprm.p / sizeof(u32));
-	if ((retval = bprm.argc) < 0)
-		goto out_mm;
-
-	bprm.envc = count32(envp, bprm.p / sizeof(u32));
-	if ((retval = bprm.envc) < 0)
-		goto out_mm;
-
-	retval = security_bprm_alloc(&bprm);
-	if (retval)
-		goto out;
-
-	retval = prepare_binprm(&bprm);
-	if (retval < 0)
-		goto out;
-	
-	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
-	if (retval < 0)
-		goto out;
-
-	bprm.exec = bprm.p;
-	retval = copy_strings32(bprm.envc, envp, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = copy_strings32(bprm.argc, argv, &bprm);
-	if (retval < 0)
-		goto out;
-
-	retval = search_binary_handler(&bprm, regs);
-	if (retval >= 0) {
-		/* execve success */
-		security_bprm_free(&bprm);
-		return retval;
-	}
-
-out:
-	/* Something went wrong, return the inode and free the argument pages*/
-	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-		struct page * page = bprm.page[i];
-		if (page)
-			__free_page(page);
-	}
-
-	if (bprm.security)
-		security_bprm_free(&bprm);
-
-out_mm:
-	if (bprm.mm)
-		mmdrop(bprm.mm);
-
-out_file:
-	if (bprm.file) {
-		allow_write_access(bprm.file);
-		fput(bprm.file);
-	}
-	return retval;
-}
-
 /*
  * sparc32_execve() executes a new program after the asm stub has set
  * things up for us.  This should basically do what I want it to.
@@ -1689,9 +1500,9 @@
 	error = PTR_ERR(filename);
         if(IS_ERR(filename))
                 goto out;
-        error = do_execve32(filename,
-        	(u32 *)AA((u32)regs->u_regs[base + UREG_I1]),
-        	(u32 *)AA((u32)regs->u_regs[base + UREG_I2]), regs);
+        error = compat_do_execve(filename,
+        	compat_ptr((u32)regs->u_regs[base + UREG_I1]),
+        	compat_ptr((u32)regs->u_regs[base + UREG_I2]), regs);
         putname(filename);
 
 	if(!error) {
===== arch/x86_64/ia32/sys_ia32.c 1.57 vs edited =====
--- 1.57/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 21:51:49 2004
+++ edited/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 20:53:02 2004
@@ -1224,93 +1224,22 @@
 	return ret;
 } 
 
-static int nargs(u32 src, char **dst) 
-{ 
-	int cnt;
-	u32 val; 
-
-	cnt = 0; 
-	do { 		
-		int ret = get_user(val, (__u32 *)(u64)src); 
-		if (ret)
-			return ret;
-		if (dst)
-			dst[cnt] = (char *)(u64)val; 
-		cnt++;
-		src += 4; 	
-		if (cnt >= (MAX_ARG_PAGES*PAGE_SIZE)/sizeof(void*))
-			return -E2BIG; 
-	} while(val); 
-	if (dst)
-		dst[cnt-1] = 0; 
-	return cnt; 
-} 
-
-asmlinkage long sys32_execve(char *name, u32 argv, u32 envp, struct pt_regs regs)
-{ 
-	mm_segment_t oldseg; 
-	char **buf = NULL; 
-	int na = 0,ne = 0;
-	int ret;
-	unsigned sz = 0; 
-
-	if (argv) {
-	na = nargs(argv, NULL); 
-	if (na < 0) 
-		return -EFAULT; 
-	} 	
-	if (envp) { 
-	ne = nargs(envp, NULL); 
-	if (ne < 0) 
-		return -EFAULT; 
-	}
-
-	if (argv || envp) { 
-	sz = (na+ne)*sizeof(void *); 
-	if (sz > PAGE_SIZE) 
-		buf = vmalloc(sz); 
-	else
-		buf = kmalloc(sz, GFP_KERNEL); 
-	if (!buf)
-		return -ENOMEM; 
-	} 
-	
-	if (argv) { 
-	ret = nargs(argv, buf);
-	if (ret < 0)
-		goto free;
-	}
-
-	if (envp) { 
-	ret = nargs(envp, buf + na); 
-	if (ret < 0)
-		goto free; 
-	}
-
-	name = getname(name); 
-	ret = PTR_ERR(name); 
-	if (IS_ERR(name))
-		goto free; 
-
-	oldseg = get_fs(); 
-	set_fs(KERNEL_DS);
-	ret = do_execve(name, argv ? buf : NULL, envp ? buf+na : NULL, &regs);  
-	set_fs(oldseg); 
-
-	if (ret == 0)
+asmlinkage long sys32_execve(char *name, compat_uptr_t __user *argv,
+			     compat_uptr_t __user *envp, struct pt_regs regs)
+{
+	long error;
+	char * filename;
+
+	filename = getname(name);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename)) 
+		return error;
+	error = compat_do_execve(filename, argv, envp, &regs); 
+	if (error == 0)
 		current->ptrace &= ~PT_DTRACE;
-
-	putname(name);
- 
-free:
-	if (argv || envp) { 
-	if (sz > PAGE_SIZE)
-		vfree(buf); 
-	else
-	kfree(buf);
-	}
-	return ret; 
-} 
+	putname(filename);
+	return error;
+}
 
 asmlinkage long sys32_clone(unsigned int clone_flags, unsigned int newsp, struct pt_regs regs)
 {
===== fs/compat.c 1.23 vs edited =====
--- 1.23/fs/compat.c	Sat Apr  3 21:51:49 2004
+++ edited/fs/compat.c	Sat Apr  3 21:01:36 2004
@@ -980,3 +980,236 @@
 	fput(file);
 	return ret;
 }
+
+#ifndef __ia64__ /* ia64 needs some extra tweaks */
+/*
+ * compat_count() counts the number of arguments/envelopes. It is basically
+ * a copy of count() from fs/exec.c, except that it works with 32 bit argv
+ * and envp pointers.
+ */
+static int compat_count(compat_uptr_t *argv, int max)
+{
+	int i = 0;
+
+	if (argv != NULL) {
+		for (;;) {
+			compat_uptr_t p;
+
+			if (get_user(p, argv))
+				return -EFAULT;
+			if (!p)
+				break;
+			argv++;
+			if(++i > max)
+				return -E2BIG;
+		}
+	}
+	return i;
+}
+
+/*
+ * compat_copy_strings() is basically a copy of copy_strings() from fs/exec.c
+ * except that it works with 32 bit argv and envp pointers.
+ */
+static int compat_copy_strings(int argc, compat_uptr_t __user *argv,
+				struct linux_binprm *bprm)
+{
+	struct page *kmapped_page = NULL;
+	char *kaddr = NULL;
+	int ret;
+
+	while (argc-- > 0) {
+		compat_uptr_t str;
+		int len;
+		unsigned long pos;
+
+		if (get_user(str, argv+argc) ||
+			!(len = strnlen_user(compat_ptr(str), bprm->p))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		if (bprm->p < len)  {
+			ret = -E2BIG;
+			goto out;
+		}
+
+		bprm->p -= len;
+		/* XXX: add architecture specific overflow check here. */
+		pos = bprm->p;
+
+		while (len > 0) {
+			int i, new, err;
+			int offset, bytes_to_copy;
+			struct page *page;
+
+			offset = pos % PAGE_SIZE;
+			i = pos/PAGE_SIZE;
+			page = bprm->page[i];
+			new = 0;
+			if (!page) {
+				page = alloc_page(GFP_HIGHUSER);
+				bprm->page[i] = page;
+				if (!page) {
+					ret = -ENOMEM;
+					goto out;
+				}
+				new = 1;
+			}
+
+			if (page != kmapped_page) {
+				if (kmapped_page)
+					kunmap(kmapped_page);
+				kmapped_page = page;
+				kaddr = kmap(kmapped_page);
+			}
+			if (new && offset)
+				memset(kaddr, 0, offset);
+			bytes_to_copy = PAGE_SIZE - offset;
+			if (bytes_to_copy > len) {
+				bytes_to_copy = len;
+				if (new)
+					memset(kaddr+offset+len, 0,
+						PAGE_SIZE-offset-len);
+			}
+			err = copy_from_user(kaddr+offset, compat_ptr(str),
+						bytes_to_copy);
+			if (err) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			pos += bytes_to_copy;
+			str += bytes_to_copy;
+			len -= bytes_to_copy;
+		}
+	}
+	ret = 0;
+out:
+	if (kmapped_page)
+		kunmap(kmapped_page);
+	return ret;
+}
+
+#ifdef CONFIG_MMU
+
+#define free_arg_pages(bprm) do { } while (0)
+
+#else
+
+static inline void free_arg_pages(struct linux_binprm *bprm)
+{
+	int i;
+
+	for (i = 0; i < MAX_ARG_PAGES; i++) {
+		if (bprm->page[i])
+			__free_page(bprm->page[i]);
+		bprm->page[i] = NULL;
+	}
+}
+
+#endif /* CONFIG_MMU */
+
+/*
+ * compat_do_execve() is mostly a copy of do_execve(), with the exception
+ * that it processes 32 bit argv and envp pointers.
+ */
+int compat_do_execve(char * filename,
+	compat_uptr_t __user *argv,
+	compat_uptr_t __user *envp,
+	struct pt_regs * regs)
+{
+	struct linux_binprm bprm;
+	struct file *file;
+	int retval;
+	int i;
+
+	sched_balance_exec();
+
+	file = open_exec(filename);
+
+	retval = PTR_ERR(file);
+	if (IS_ERR(file))
+		return retval;
+
+	bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *);
+	memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0]));
+
+	bprm.file = file;
+	bprm.filename = filename;
+	bprm.interp = filename;
+	bprm.sh_bang = 0;
+	bprm.loader = 0;
+	bprm.exec = 0;
+	bprm.security = NULL;
+	bprm.mm = mm_alloc();
+	retval = -ENOMEM;
+	if (!bprm.mm)
+		goto out_file;
+
+	retval = init_new_context(current, bprm.mm);
+	if (retval < 0)
+		goto out_mm;
+
+	bprm.argc = compat_count(argv, bprm.p / sizeof(compat_uptr_t));
+	if ((retval = bprm.argc) < 0)
+		goto out_mm;
+
+	bprm.envc = compat_count(envp, bprm.p / sizeof(compat_uptr_t));
+	if ((retval = bprm.envc) < 0)
+		goto out_mm;
+
+	retval = security_bprm_alloc(&bprm);
+	if (retval)
+		goto out;
+
+	retval = prepare_binprm(&bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = copy_strings_kernel(1, &bprm.filename, &bprm);
+	if (retval < 0)
+		goto out;
+
+	bprm.exec = bprm.p;
+	retval = compat_copy_strings(bprm.envc, envp, &bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = compat_copy_strings(bprm.argc, argv, &bprm);
+	if (retval < 0)
+		goto out;
+
+	retval = search_binary_handler(&bprm,regs);
+	if (retval >= 0) {
+		free_arg_pages(&bprm);
+
+		/* execve success */
+		security_bprm_free(&bprm);
+		return retval;
+	}
+
+out:
+	/* Something went wrong, return the inode and free the argument pages*/
+	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+		struct page * page = bprm.page[i];
+		if (page)
+			__free_page(page);
+	}
+
+	if (bprm.security)
+		security_bprm_free(&bprm);
+
+out_mm:
+	if (bprm.mm)
+		mmdrop(bprm.mm);
+
+out_file:
+	if (bprm.file) {
+		allow_write_access(bprm.file);
+		fput(bprm.file);
+	}
+
+	return retval;
+}
+#endif /* !__ia64__ */
===== include/linux/compat.h 1.20 vs edited =====
--- 1.20/include/linux/compat.h	Sat Apr  3 22:03:56 2004
+++ edited/include/linux/compat.h	Sat Apr  3 20:43:52 2004
@@ -106,5 +106,8 @@
 asmlinkage ssize_t compat_sys_writev(unsigned long fd,
 		const struct compat_iovec __user *vec, unsigned long vlen);
 
+int compat_do_execve(char * filename, compat_uptr_t __user *argv,
+	        compat_uptr_t __user *envp, struct pt_regs * regs);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */

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

* [PATCH 3/4] Consolidate sys32_select
       [not found] <200404040204.03594.arnd@arndb.de>
  2004-04-04  0:22 ` [PATCH 1/4] Consolidate sys32_readv and sys32_writev Arnd Bergmann
  2004-04-04  0:22 ` [PATCH 2/4] Consolidate do_execve32 Arnd Bergmann
@ 2004-04-04  0:22 ` Arnd Bergmann
  2004-04-04 10:24   ` Andi Kleen
  2004-04-07 20:46   ` Arun Sharma
  2004-04-04  0:22 ` [PATCH 4/4] Consolidate sys32_nfsservctl Arnd Bergmann
  3 siblings, 2 replies; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-04  0:22 UTC (permalink / raw)
  To: linux-arch

sys32_select has seven mostly but not exactly identical versions,
so consolidate them as compat_sys_select. Based on the ppc64
implementation, which most closely resembles sys_select.

Passes relevant LTP test cases on x86_64.

===== arch/ia64/ia32/ia32_entry.S 1.36 vs edited =====
--- 1.36/arch/ia64/ia32/ia32_entry.S	Sat Apr  3 21:55:45 2004
+++ edited/arch/ia64/ia32/ia32_entry.S	Sat Apr  3 22:41:48 2004
@@ -350,7 +350,7 @@
 	data8 sys_setfsgid	/* 16-bit version */
 	data8 sys_llseek	  /* 140 */
 	data8 sys32_getdents
-	data8 sys32_select
+	data8 compat_sys_select
 	data8 sys_flock
 	data8 sys32_msync
 	data8 compat_sys_readv	  /* 145 */
===== arch/ia64/ia32/sys_ia32.c 1.94 vs edited =====
--- 1.94/arch/ia64/ia32/sys_ia32.c	Sat Apr  3 21:51:49 2004
+++ edited/arch/ia64/ia32/sys_ia32.c	Sat Apr  3 22:06:36 2004
@@ -818,110 +818,6 @@
 	return error;
 }
 
-/*
- * We can actually return ERESTARTSYS instead of EINTR, but I'd
- * like to be certain this leads to no problems. So I return
- * EINTR just for safety.
- *
- * Update: ERESTARTSYS breaks at least the xview clock binary, so
- * I'm trying ERESTARTNOHAND which restart only when you want to.
- */
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-#define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y))
-
-asmlinkage long
-sys32_select (int n, fd_set *inp, fd_set *outp, fd_set *exp, struct compat_timeval *tvp32)
-{
-	fd_set_bits fds;
-	char *bits;
-	long timeout;
-	int ret, size;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp32) {
-		time_t sec, usec;
-
-		ret = -EFAULT;
-		if (get_user(sec, &tvp32->tv_sec) || get_user(usec, &tvp32->tv_usec))
-			goto out_nofds;
-
-		ret = -EINVAL;
-		if (sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = ROUND_UP_TIME(usec, 1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
-	ret = -EINVAL;
-	if (n < 0)
-		goto out_nofds;
-
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
-
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words.
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = kmalloc(6 * size, GFP_KERNEL);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	if ((ret = get_fd_set(n, inp, fds.in)) ||
-	    (ret = get_fd_set(n, outp, fds.out)) ||
-	    (ret = get_fd_set(n, exp, fds.ex)))
-		goto out;
-	zero_fd_set(n, fds.res_in);
-	zero_fd_set(n, fds.res_out);
-	zero_fd_set(n, fds.res_ex);
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp32 && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		if (put_user(sec, &tvp32->tv_sec) || put_user(usec, &tvp32->tv_usec)) {
-			ret = -EFAULT;
-			goto out;
-		}
-	}
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-
-	set_fd_set(n, inp, fds.res_in);
-	set_fd_set(n, outp, fds.res_out);
-	set_fd_set(n, exp, fds.res_ex);
-
-out:
-	kfree(bits);
-out_nofds:
-	return ret;
-}
-
 struct sel_arg_struct {
 	unsigned int n;
 	unsigned int inp;
@@ -937,8 +833,8 @@
 
 	if (copy_from_user(&a, arg, sizeof(a)))
 		return -EFAULT;
-	return sys32_select(a.n, (fd_set *) A(a.inp), (fd_set *) A(a.outp), (fd_set *) A(a.exp),
-			    (struct compat_timeval *) A(a.tvp));
+	return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
+				 compat_ptr(a.exp), compat_ptr(a.tvp));
 }
 
 #define SEMOP		 1
===== arch/mips/kernel/linux32.c 1.24 vs edited =====
--- 1.24/arch/mips/kernel/linux32.c	Sat Apr  3 23:20:39 2004
+++ edited/arch/mips/kernel/linux32.c	Sat Apr  3 21:39:56 2004
@@ -519,167 +519,6 @@
 bad_file:
 	return ret;
 }
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-
-static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
-{
-	if (ufdset) {
-		unsigned long odd;
-
-		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
-			return -EFAULT;
-
-		odd = n & 1UL;
-		n &= ~1UL;
-		while (n) {
-			unsigned long h, l;
-			__get_user(l, ufdset);
-			__get_user(h, ufdset+1);
-			ufdset += 2;
-			*fdset++ = h << 32 | l;
-			n -= 2;
-		}
-		if (odd)
-			__get_user(*fdset, ufdset);
-	} else {
-		/* Tricky, must clear full unsigned long in the
-		 * kernel fdset at the end, this makes sure that
-		 * actually happens.
-		 */
-		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-	}
-	return 0;
-}
-
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-	unsigned long odd;
-
-	if (!ufdset)
-		return;
-
-	odd = n & 1UL;
-	n &= ~1UL;
-	while (n) {
-		unsigned long h, l;
-		l = *fdset++;
-		h = l >> 32;
-		__put_user(l, ufdset);
-		__put_user(h, ufdset+1);
-		ufdset += 2;
-		n -= 2;
-	}
-	if (odd)
-		__put_user(*fdset, ufdset);
-}
-
-/*
- * We can actually return ERESTARTSYS instead of EINTR, but I'd
- * like to be certain this leads to no problems. So I return
- * EINTR just for safety.
- *
- * Update: ERESTARTSYS breaks at least the xview clock binary, so
- * I'm trying ERESTARTNOHAND which restart only when you want to.
- */
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
-asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, struct compat_timeval *tvp)
-{
-	fd_set_bits fds;
-	char *bits;
-	unsigned long nn;
-	long timeout;
-	int ret, size;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		time_t sec, usec;
-
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
-			goto out_nofds;
-
-		ret = -EINVAL;
-		if(sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
-	ret = -EINVAL;
-	if (n < 0)
-		goto out_nofds;
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
-
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words.
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = kmalloc(6 * size, GFP_KERNEL);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-	if ((ret = get_fd_set32(nn, fds.in, inp)) ||
-	    (ret = get_fd_set32(nn, fds.out, outp)) ||
-	    (ret = get_fd_set32(nn, fds.ex, exp)))
-		goto out;
-	zero_fd_set(n, fds.res_in);
-	zero_fd_set(n, fds.res_out);
-	zero_fd_set(n, fds.res_ex);
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		put_user(sec, &tvp->tv_sec);
-		put_user(usec, &tvp->tv_usec);
-	}
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-
-	set_fd_set32(nn, inp, fds.res_in);
-	set_fd_set32(nn, outp, fds.res_out);
-	set_fd_set32(nn, exp, fds.res_ex);
-
-out:
-	kfree(bits);
-out_nofds:
-	return ret;
-}
-
 
 asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
 	struct compat_timespec *interval)
===== arch/mips/kernel/scall64-n32.S 1.3 vs edited =====
--- 1.3/arch/mips/kernel/scall64-n32.S	Sat Apr  3 21:55:52 2004
+++ edited/arch/mips/kernel/scall64-n32.S	Sat Apr  3 22:41:53 2004
@@ -132,7 +132,7 @@
 	PTR	compat_sys_writev
 	PTR	sys_access			/* 6020 */
 	PTR	sys_pipe
-	PTR	sys32_select
+	PTR	compat_sys_select
 	PTR	sys_sched_yield
 	PTR	sys_mremap
 	PTR	sys_msync			/* 6025 */
===== arch/mips/kernel/scall64-o32.S 1.3 vs edited =====
--- 1.3/arch/mips/kernel/scall64-o32.S	Sat Apr  3 21:56:24 2004
+++ edited/arch/mips/kernel/scall64-o32.S	Sat Apr  3 22:42:06 2004
@@ -397,7 +397,7 @@
 	sys	sys_setfsgid	1
 	sys	sys32_llseek	5			/* 4140 */
 	sys	sys32_getdents	3
-	sys	sys32_select	5
+	sys	compat_sys_select	5
 	sys	sys_flock	2
 	sys	sys_msync	3
 	sys	compat_sys_readv	3		/* 4145 */
===== arch/parisc/kernel/sys_parisc32.c 1.26 vs edited =====
--- 1.26/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 23:16:03 2004
+++ edited/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 21:39:56 2004
@@ -486,126 +486,6 @@
 		__put_user(*fdset, ufdset);
 }
 
-/*** This is a virtual copy of sys_select from fs/select.c and probably
- *** should be compared to it from time to time
- ***/
-static inline void *select_bits_alloc(int size)
-{
-	return kmalloc(6 * size, GFP_KERNEL);
-}
-
-static inline void select_bits_free(void *bits, int size)
-{
-	kfree(bits);
-}
-
-/*
- * We can actually return ERESTARTSYS instead of EINTR, but I'd
- * like to be certain this leads to no problems. So I return
- * EINTR just for safety.
- *
- * Update: ERESTARTSYS breaks at least the xview clock binary, so
- * I'm trying ERESTARTNOHAND which restart only when you want to.
- */
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-#define DIVIDE_ROUND_UP(x,y) (((x)+(y)-1)/(y))
-
-asmlinkage long
-sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, struct compat_timeval *tvp)
-{
-	fd_set_bits fds;
-	char *bits;
-	long timeout;
-	int ret, size, err;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		struct compat_timeval tv32;
-		time_t sec, usec;
-
-		if ((ret = copy_from_user(&tv32, tvp, sizeof tv32)))
-			goto out_nofds;
-
-		sec = tv32.tv_sec;
-		usec = tv32.tv_usec;
-
-		ret = -EINVAL;
-		if (sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = DIVIDE_ROUND_UP(usec, 1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
-	ret = -EINVAL;
-	if (n < 0)
-		goto out_nofds;
-
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
-
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = select_bits_alloc(size);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	if ((ret = get_fd_set32(n, inp, fds.in)) ||
-	    (ret = get_fd_set32(n, outp, fds.out)) ||
-	    (ret = get_fd_set32(n, exp, fds.ex)))
-		goto out;
-	zero_fd_set(n, fds.res_in);
-	zero_fd_set(n, fds.res_out);
-	zero_fd_set(n, fds.res_ex);
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		err = put_user(sec, &tvp->tv_sec);
-		err |= __put_user(usec, &tvp->tv_usec);
-		if (err)
-			ret = -EFAULT;
-	}
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-
-	set_fd_set32(n, inp, fds.res_in);
-	set_fd_set32(n, outp, fds.res_out);
-	set_fd_set32(n, exp, fds.res_ex);
-
-out:
-	select_bits_free(bits, size);
-out_nofds:
-	return ret;
-}
-
 struct msgbuf32 {
     int mtype;
     char mtext[1];
@@ -662,7 +542,6 @@
 	kfree(mb);
 	return err;
 }
-
 
 asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t *offset, s32 count)
 {
===== arch/parisc/kernel/syscall_table.S 1.4 vs edited =====
--- 1.4/arch/parisc/kernel/syscall_table.S	Fri Mar 26 20:05:25 2004
+++ edited/arch/parisc/kernel/syscall_table.S	Sat Apr  3 22:57:02 2004
@@ -232,7 +232,7 @@
 	ENTRY_DIFF(getdents)
 	/* it is POSSIBLE that select will be OK because even though fd_set
 	 * contains longs, the macros and sizes are clever. */
-	ENTRY_DIFF(select)
+	ENTRY_COMP(select)
 	ENTRY_SAME(flock)
 	ENTRY_SAME(msync)
 	/* struct iovec contains pointers */
===== arch/ppc64/kernel/sys_ppc32.c 1.88 vs edited =====
--- 1.88/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 23:16:41 2004
+++ edited/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 22:11:06 2004
@@ -226,167 +226,12 @@
 	return error;
 }
 
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
-{
-	if (ufdset) {
-		unsigned long odd;
-
-		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
-			return -EFAULT;
-
-		odd = n & 1UL;
-		n &= ~1UL;
-		while (n) {
-			unsigned long h, l;
-			__get_user(l, ufdset);
-			__get_user(h, ufdset+1);
-			ufdset += 2;
-			*fdset++ = h << 32 | l;
-			n -= 2;
-		}
-		if (odd)
-			__get_user(*fdset, ufdset);
-	} else {
-		/* Tricky, must clear full unsigned long in the
-		 * kernel fdset at the end, this makes sure that
-		 * actually happens.
-		 */
-		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-	}
-	return 0;
-}
-
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-	unsigned long odd;
-
-	if (!ufdset)
-		return;
-
-	odd = n & 1UL;
-	n &= ~1UL;
-	while (n) {
-		unsigned long h, l;
-		l = *fdset++;
-		h = l >> 32;
-		__put_user(l, ufdset);
-		__put_user(h, ufdset+1);
-		ufdset += 2;
-		n -= 2;
-	}
-	if (odd)
-		__put_user(*fdset, ufdset);
-}
-
-
-
-#define MAX_SELECT_SECONDS ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
-asmlinkage long sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
-{
-	fd_set_bits fds;
-	struct compat_timeval *tvp = (struct compat_timeval *)AA(tvp_x);
-	char *bits;
-	unsigned long nn;
-	long timeout;
-	int ret, size, max_fdset;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		time_t sec, usec;
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
-			goto out_nofds;
-
-		ret = -EINVAL;
-		if(sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
-	ret = -EINVAL;
-	if (n < 0)
-		goto out_nofds;
-
-	/* max_fdset can increase, so grab it once to avoid race */
-	max_fdset = current->files->max_fdset;
-	if (n > max_fdset)
-		n = max_fdset;
-
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = kmalloc(6 * size, GFP_KERNEL);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-	if ((ret = get_fd_set32(nn, fds.in, inp)) ||
-	    (ret = get_fd_set32(nn, fds.out, outp)) ||
-	    (ret = get_fd_set32(nn, fds.ex, exp)))
-		goto out;
-	zero_fd_set(n, fds.res_in);
-	zero_fd_set(n, fds.res_out);
-	zero_fd_set(n, fds.res_ex);
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		put_user(sec, &tvp->tv_sec);
-		put_user(usec, &tvp->tv_usec);
-	}
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-
-	set_fd_set32(nn, inp, fds.res_in);
-	set_fd_set32(nn, outp, fds.res_out);
-	set_fd_set32(nn, exp, fds.res_ex);
-  
-out:
-	kfree(bits);
-
-out_nofds:
-	return ret;
-}
-
-int ppc32_select(u32 n, u32* inp, u32* outp, u32* exp, u32 tvp_x)
+asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
+		compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+		compat_uptr_t tvp_x)
 {
 	/* sign extend n */
-	return sys32_select((int)n, inp, outp, exp, tvp_x);
+	return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));
 }
 
 int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
===== arch/s390/kernel/compat_linux.c 1.21 vs edited =====
--- 1.21/arch/s390/kernel/compat_linux.c	Sat Apr  3 23:17:59 2004
+++ edited/arch/s390/kernel/compat_linux.c	Sat Apr  3 21:39:56 2004
@@ -503,160 +503,6 @@
 
 /* end of readdir & getdents */
 
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-
-static inline int
-get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
-{
-	if (ufdset) {
-		unsigned long odd;
-
-		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
-			return -EFAULT;
-
-		odd = n & 1UL;
-		n &= ~1UL;
-		while (n) {
-			unsigned long h, l;
-			__get_user(l, ufdset);
-			__get_user(h, ufdset+1);
-			ufdset += 2;
-			*fdset++ = h << 32 | l;
-			n -= 2;
-		}
-		if (odd)
-			__get_user(*fdset, ufdset);
-	} else {
-		/* Tricky, must clear full unsigned long in the
-		 * kernel fdset at the end, this makes sure that
-		 * actually happens.
-		 */
-		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-	}
-	return 0;
-}
-
-static inline void
-set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-	unsigned long odd;
-
-	if (!ufdset)
-		return;
-
-	odd = n & 1UL;
-	n &= ~1UL;
-	while (n) {
-		unsigned long h, l;
-		l = *fdset++;
-		h = l >> 32;
-		__put_user(l, ufdset);
-		__put_user(h, ufdset+1);
-		ufdset += 2;
-		n -= 2;
-	}
-	if (odd)
-		__put_user(*fdset, ufdset);
-}
-
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
-asmlinkage long sys32_select(int n, u32 *inp, u32 *outp, u32 *exp,
-				struct compat_timeval *tvp)
-{
-	fd_set_bits fds;
-	char *bits;
-	unsigned long nn;
-	long timeout;
-	int ret, size;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		int sec, usec;
-
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
-			goto out_nofds;
-
-		ret = -EINVAL;
-		if(sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
-	ret = -EINVAL;
-	if (n < 0)
-		goto out_nofds;
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
-
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = kmalloc(6 * size, GFP_KERNEL);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-	if ((ret = get_fd_set32(nn, fds.in, inp)) ||
-	    (ret = get_fd_set32(nn, fds.out, outp)) ||
-	    (ret = get_fd_set32(nn, fds.ex, exp)))
-		goto out;
-	zero_fd_set(n, fds.res_in);
-	zero_fd_set(n, fds.res_out);
-	zero_fd_set(n, fds.res_ex);
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		int sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		put_user(sec, &tvp->tv_sec);
-		put_user(usec, &tvp->tv_usec);
-	}
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-
-	set_fd_set32(nn, inp, fds.res_in);
-	set_fd_set32(nn, outp, fds.res_out);
-	set_fd_set32(nn, exp, fds.res_ex);
-
-out:
-	kfree(bits);
-out_nofds:
-	return ret;
-}
-
 int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
 {
 	int err;
===== arch/s390/kernel/compat_wrapper.S 1.10 vs edited =====
--- 1.10/arch/s390/kernel/compat_wrapper.S	Sat Apr  3 21:57:56 2004
+++ edited/arch/s390/kernel/compat_wrapper.S	Sat Apr  3 22:11:49 2004
@@ -641,14 +641,14 @@
 	llgfr	%r4,%r4			# unsigned int
 	jg	sys32_getdents		# branch to system call
 
-	.globl  sys32_select_wrapper 
-sys32_select_wrapper:
+	.globl  compat_sys_select_wrapper 
+compat_sys_select_wrapper:
 	lgfr	%r2,%r2			# int
-	llgtr	%r3,%r3			# fd_set *
-	llgtr	%r4,%r4			# fd_set *
-	llgtr	%r5,%r5			# fd_set *
-	llgtr	%r6,%r6			# struct timeval_emu31 *
-	jg	sys32_select		# branch to system call
+	llgtr	%r3,%r3			# compat_fd_set *
+	llgtr	%r4,%r4			# compat_fd_set *
+	llgtr	%r5,%r5			# compat_fd_set *
+	llgtr	%r6,%r6			# struct compat_timeval *
+	jg	compat_sys_select	# branch to system call
 
 	.globl  sys32_flock_wrapper 
 sys32_flock_wrapper:
===== arch/s390/kernel/syscalls.S 1.10 vs edited =====
--- 1.10/arch/s390/kernel/syscalls.S	Sat Apr  3 21:58:13 2004
+++ edited/arch/s390/kernel/syscalls.S	Sat Apr  3 22:12:19 2004
@@ -150,7 +150,7 @@
 SYSCALL(sys_setfsgid16,sys_ni_syscall,sys32_setfsgid16_wrapper)	/* old setfsgid16 syscall */
 SYSCALL(sys_llseek,sys_llseek,sys32_llseek_wrapper)		/* 140 */
 SYSCALL(sys_getdents,sys_getdents,sys32_getdents_wrapper)
-SYSCALL(sys_select,sys_select,sys32_select_wrapper)
+SYSCALL(sys_select,sys_select,compat_sys_select_wrapper)
 SYSCALL(sys_flock,sys_flock,sys32_flock_wrapper)
 SYSCALL(sys_msync,sys_msync,sys32_msync_wrapper)
 SYSCALL(sys_readv,sys_readv,compat_sys_readv_wrapper)		/* 145 */
===== arch/sparc64/kernel/sys_sparc32.c 1.97 vs edited =====
--- 1.97/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 23:19:17 2004
+++ edited/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 21:39:56 2004
@@ -964,158 +964,6 @@
 
 /* end of readdir & getdents */
 
-/*
- * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
- * 64-bit unsigned longs.
- */
-
-static int get_fd_set32(unsigned long n, unsigned long *fdset, u32 *ufdset)
-{
-	if (ufdset) {
-		unsigned long odd;
-
-		if (verify_area(VERIFY_WRITE, ufdset, n*sizeof(u32)))
-			return -EFAULT;
-
-		odd = n & 1UL;
-		n &= ~1UL;
-		while (n) {
-			unsigned long h, l;
-			__get_user(l, ufdset);
-			__get_user(h, ufdset+1);
-			ufdset += 2;
-			*fdset++ = h << 32 | l;
-			n -= 2;
-		}
-		if (odd)
-			__get_user(*fdset, ufdset);
-	} else {
-		/* Tricky, must clear full unsigned long in the
-		 * kernel fdset at the end, this makes sure that
-		 * actually happens.
-		 */
-		memset(fdset, 0, ((n + 1) & ~1)*sizeof(u32));
-	}
-	return 0;
-}
-
-static void set_fd_set32(unsigned long n, u32 *ufdset, unsigned long *fdset)
-{
-	unsigned long odd;
-
-	if (!ufdset)
-		return;
-
-	odd = n & 1UL;
-	n &= ~1UL;
-	while (n) {
-		unsigned long h, l;
-		l = *fdset++;
-		h = l >> 32;
-		__put_user(l, ufdset);
-		__put_user(h, ufdset+1);
-		ufdset += 2;
-		n -= 2;
-	}
-	if (odd)
-		__put_user(*fdset, ufdset);
-}
-
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-
-asmlinkage int sys32_select(int n, u32 *inp, u32 *outp, u32 *exp, u32 tvp_x)
-{
-	fd_set_bits fds;
-	struct compat_timeval *tvp = (struct compat_timeval *)AA(tvp_x);
-	char *bits;
-	unsigned long nn;
-	long timeout;
-	int ret, size;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp) {
-		time_t sec, usec;
-
-		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
-		    || (ret = __get_user(sec, &tvp->tv_sec))
-		    || (ret = __get_user(usec, &tvp->tv_usec)))
-			goto out_nofds;
-
-		ret = -EINVAL;
-		if(sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
-	ret = -EINVAL;
-	if (n < 0)
-		goto out_nofds;
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
-
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = kmalloc(6 * size, GFP_KERNEL);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	nn = (n + 8*sizeof(u32) - 1) / (8*sizeof(u32));
-	if ((ret = get_fd_set32(nn, fds.in, inp)) ||
-	    (ret = get_fd_set32(nn, fds.out, outp)) ||
-	    (ret = get_fd_set32(nn, fds.ex, exp)))
-		goto out;
-	zero_fd_set(n, fds.res_in);
-	zero_fd_set(n, fds.res_out);
-	zero_fd_set(n, fds.res_ex);
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		put_user(sec, &tvp->tv_sec);
-		put_user(usec, &tvp->tv_usec);
-	}
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-
-	set_fd_set32(nn, inp, fds.res_in);
-	set_fd_set32(nn, outp, fds.res_out);
-	set_fd_set32(nn, exp, fds.res_ex);
-
-out:
-	kfree(bits);
-out_nofds:
-	return ret;
-}
-
 int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
 {
 	int err;
===== arch/sparc64/kernel/sys_sunos32.c 1.40 vs edited =====
--- 1.40/arch/sparc64/kernel/sys_sunos32.c	Sat Apr  3 22:06:40 2004
+++ edited/arch/sparc64/kernel/sys_sunos32.c	Sat Apr  3 22:45:08 2004
@@ -528,18 +528,15 @@
 	return ret;
 }
 
-/* SunOS mount system call emulation */
-extern asmlinkage int
-sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp);
-
 asmlinkage int sunos_select(int width, u32 inp, u32 outp, u32 exp, u32 tvp_x)
 {
 	int ret;
 
 	/* SunOS binaries expect that select won't change the tvp contents */
-	ret = sys32_select (width, inp, outp, exp, tvp_x);
+	ret = compat_sys_select(width, compat_ptr(inp), compat_ptr(outp),
+				compat_ptr(exp), compat_ptr(tvp_x));
 	if (ret == -EINTR && tvp_x) {
-		struct compat_timeval *tvp = (struct compat_timeval *)A(tvp_x);
+		struct compat_timeval *tvp = compat_ptr(tvp_x);
 		time_t sec, usec;
 
 		__get_user(sec, &tvp->tv_sec);
===== arch/sparc64/kernel/systbls.S 1.53 vs edited =====
--- 1.53/arch/sparc64/kernel/systbls.S	Sat Apr  3 22:00:19 2004
+++ edited/arch/sparc64/kernel/systbls.S	Sat Apr  3 22:46:01 2004
@@ -37,7 +37,7 @@
 	.word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys32_getgroups16
 /*80*/	.word sys32_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64
 	.word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
-/*90*/	.word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid
+/*90*/	.word sys_dup2, sys_setfsuid, compat_sys_fcntl, compat_sys_select, sys_setfsgid
 	.word sys_fsync, sys_setpriority32, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
 /*100*/ .word sys_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
 	.word sys32_rt_sigtimedwait, sys32_rt_sigqueueinfo, sys32_rt_sigsuspend, sys_setresuid, sys_getresuid
@@ -65,7 +65,7 @@
 	.word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
 /*220*/	.word compat_sys_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys_getpgid
 	.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
-/*230*/	.word sys32_select, sys_time, sys_nis_syscall, sys_stime, compat_statfs64
+/*230*/	.word compat_sys_select, sys_time, sys_nis_syscall, sys_stime, compat_statfs64
 	.word compat_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
===== arch/x86_64/ia32/ia32entry.S 1.31 vs edited =====
--- 1.31/arch/x86_64/ia32/ia32entry.S	Sat Apr  3 22:00:33 2004
+++ edited/arch/x86_64/ia32/ia32entry.S	Sat Apr  3 22:13:48 2004
@@ -447,7 +447,7 @@
 	.quad sys_setfsgid16
 	.quad sys_llseek		/* 140 */
 	.quad sys32_getdents
-	.quad sys32_select
+	.quad compat_sys_select
 	.quad sys_flock
 	.quad sys_msync
 	.quad compat_sys_readv		/* 145 */
===== arch/x86_64/ia32/sys_ia32.c 1.58 vs edited =====
--- 1.58/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 22:53:02 2004
+++ edited/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 22:13:24 2004
@@ -606,107 +606,6 @@
 	return error;
 }
 
-/*
- * We can actually return ERESTARTSYS instead of EINTR, but I'd
- * like to be certain this leads to no problems. So I return
- * EINTR just for safety.
- *
- * Update: ERESTARTSYS breaks at least the xview clock binary, so
- * I'm trying ERESTARTNOHAND which restart only when you want to.
- */
-#define MAX_SELECT_SECONDS \
-	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-#define ROUND_UP_TIME(x,y) (((x)+(y)-1)/(y))
-
-asmlinkage long
-sys32_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct compat_timeval *tvp32)
-{
-	fd_set_bits fds;
-	char *bits;
-	long timeout;
-	int ret, size;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	if (tvp32) {
-		time_t sec, usec;
-
-		get_user(sec, &tvp32->tv_sec);
-		get_user(usec, &tvp32->tv_usec);
-
-		ret = -EINVAL;
-		if (sec < 0 || usec < 0)
-			goto out_nofds;
-
-		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
-			timeout = ROUND_UP_TIME(usec, 1000000/HZ);
-			timeout += sec * (unsigned long) HZ;
-		}
-	}
-
-	ret = -EINVAL;
-	if (n < 0)
-		goto out_nofds;
-
-	if (n > current->files->max_fdset)
-		n = current->files->max_fdset;
-
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = kmalloc(6 * size, GFP_KERNEL);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	if ((ret = get_fd_set(n, inp, fds.in)) ||
-	    (ret = get_fd_set(n, outp, fds.out)) ||
-	    (ret = get_fd_set(n, exp, fds.ex)))
-		goto out;
-	zero_fd_set(n, fds.res_in);
-	zero_fd_set(n, fds.res_out);
-	zero_fd_set(n, fds.res_ex);
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (tvp32 && !(current->personality & STICKY_TIMEOUTS)) {
-		time_t sec = 0, usec = 0;
-		if (timeout) {
-			sec = timeout / HZ;
-			usec = timeout % HZ;
-			usec *= (1000000/HZ);
-		}
-		put_user(sec, (int *)&tvp32->tv_sec);
-		put_user(usec, (int *)&tvp32->tv_usec);
-	}
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-
-	set_fd_set(n, inp, fds.res_in);
-	set_fd_set(n, outp, fds.res_out);
-	set_fd_set(n, exp, fds.res_ex);
-
-out:
-	kfree(bits);
-out_nofds:
-	return ret;
-}
-
 struct sel_arg_struct {
 	unsigned int n;
 	unsigned int inp;
@@ -722,8 +621,8 @@
 
 	if (copy_from_user(&a, arg, sizeof(a)))
 		return -EFAULT;
-	return sys32_select(a.n, (fd_set *)A(a.inp), (fd_set *)A(a.outp), (fd_set *)A(a.exp),
-			    (struct compat_timeval *)A(a.tvp));
+	return compat_sys_select(a.n, compat_ptr(a.inp), compat_ptr(a.outp),
+				 compat_ptr(a.exp), compat_ptr(a.tvp));
 }
 
 /*
===== fs/compat.c 1.24 vs edited =====
--- 1.24/fs/compat.c	Sat Apr  3 23:01:36 2004
+++ edited/fs/compat.c	Sat Apr  3 21:51:59 2004
@@ -1213,3 +1213,190 @@
 	return retval;
 }
 #endif /* !__ia64__ */
+
+#define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
+
+#define ROUND_UP(x,y) (((x)+(y)-1)/(y))
+
+/*
+ * Ooo, nasty.  We need here to frob 32-bit unsigned longs to
+ * 64-bit unsigned longs.
+ */
+static inline
+int compat_get_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
+			unsigned long *fdset)
+{
+	nr = ROUND_UP(nr, __COMPAT_NFDBITS);
+	if (ufdset) {
+		unsigned long odd;
+
+		if (verify_area(VERIFY_WRITE, ufdset, nr*sizeof(compat_ulong_t)))
+			return -EFAULT;
+
+		odd = nr & 1UL;
+		nr &= ~1UL;
+		while (nr) {
+			unsigned long h, l;
+			__get_user(l, ufdset);
+			__get_user(h, ufdset+1);
+			ufdset += 2;
+			*fdset++ = h << 32 | l;
+			nr -= 2;
+		}
+		if (odd)
+			__get_user(*fdset, ufdset);
+	} else {
+		/* Tricky, must clear full unsigned long in the
+		 * kernel fdset at the end, this makes sure that
+		 * actually happens.
+		 */
+		memset(fdset, 0, ((nr + 1) & ~1)*sizeof(compat_ulong_t));
+	}
+	return 0;
+}
+
+static inline
+void compat_set_fd_set(unsigned long nr, compat_ulong_t __user *ufdset,
+			unsigned long *fdset)
+{
+	unsigned long odd;
+	nr = ROUND_UP(nr, __COMPAT_NFDBITS);
+
+	if (!ufdset)
+		return;
+
+	odd = nr & 1UL;
+	nr &= ~1UL;
+	while (nr) {
+		unsigned long h, l;
+		l = *fdset++;
+		h = l >> 32;
+		__put_user(l, ufdset);
+		__put_user(h, ufdset+1);
+		ufdset += 2;
+		nr -= 2;
+	}
+	if (odd)
+		__put_user(*fdset, ufdset);
+}
+
+
+/*
+ * This is a virtual copy of sys_select from fs/select.c and probably
+ * should be compared to it from time to time
+ */
+static void *select_bits_alloc(int size)
+{
+	return kmalloc(6 * size, GFP_KERNEL);
+}
+
+static void select_bits_free(void *bits, int size)
+{
+	kfree(bits);
+}
+
+/*
+ * We can actually return ERESTARTSYS instead of EINTR, but I'd
+ * like to be certain this leads to no problems. So I return
+ * EINTR just for safety.
+ *
+ * Update: ERESTARTSYS breaks at least the xview clock binary, so
+ * I'm trying ERESTARTNOHAND which restart only when you want to.
+ */
+#define MAX_SELECT_SECONDS \
+	((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
+
+asmlinkage long
+compat_sys_select(int n, compat_ulong_t __user *inp, compat_ulong_t __user *outp,
+		compat_ulong_t __user *exp, struct compat_timeval __user *tvp)
+{
+	fd_set_bits fds;
+	char *bits;
+	long timeout;
+	int ret, size, max_fdset;
+
+	timeout = MAX_SCHEDULE_TIMEOUT;
+	if (tvp) {
+		time_t sec, usec;
+
+		if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp)))
+		    || (ret = __get_user(sec, &tvp->tv_sec))
+		    || (ret = __get_user(usec, &tvp->tv_usec)))
+			goto out_nofds;
+
+		ret = -EINVAL;
+		if (sec < 0 || usec < 0)
+			goto out_nofds;
+
+		if ((unsigned long) sec < MAX_SELECT_SECONDS) {
+			timeout = ROUND_UP(usec, 1000000/HZ);
+			timeout += sec * (unsigned long) HZ;
+		}
+	}
+
+	ret = -EINVAL;
+	if (n < 0)
+		goto out_nofds;
+
+	/* max_fdset can increase, so grab it once to avoid race */
+	max_fdset = current->files->max_fdset;
+	if (n > max_fdset)
+		n = max_fdset;
+
+	/*
+	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
+	 * since we used fdset we need to allocate memory in units of
+	 * long-words. 
+	 */
+	ret = -ENOMEM;
+	size = FDS_BYTES(n);
+	bits = select_bits_alloc(size);
+	if (!bits)
+		goto out_nofds;
+	fds.in      = (unsigned long *)  bits;
+	fds.out     = (unsigned long *) (bits +   size);
+	fds.ex      = (unsigned long *) (bits + 2*size);
+	fds.res_in  = (unsigned long *) (bits + 3*size);
+	fds.res_out = (unsigned long *) (bits + 4*size);
+	fds.res_ex  = (unsigned long *) (bits + 5*size);
+
+	if ((ret = compat_get_fd_set(n, inp, fds.in)) ||
+	    (ret = compat_get_fd_set(n, outp, fds.out)) ||
+	    (ret = compat_get_fd_set(n, exp, fds.ex)))
+		goto out;
+	zero_fd_set(n, fds.res_in);
+	zero_fd_set(n, fds.res_out);
+	zero_fd_set(n, fds.res_ex);
+
+	ret = do_select(n, &fds, &timeout);
+
+	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
+		time_t sec = 0, usec = 0;
+		if (timeout) {
+			sec = timeout / HZ;
+			usec = timeout % HZ;
+			usec *= (1000000/HZ);
+		}
+		ret = __put_user(sec, &tvp->tv_sec);
+		ret |= __put_user(usec, &tvp->tv_usec);
+	}
+
+	if (ret < 0)
+		goto out;
+	if (!ret) {
+		ret = -ERESTARTNOHAND;
+		if (signal_pending(current))
+			goto out;
+		ret = 0;
+	}
+
+	compat_set_fd_set(n, inp, fds.res_in);
+	compat_set_fd_set(n, outp, fds.res_out);
+	compat_set_fd_set(n, exp, fds.res_ex);
+
+out:
+	select_bits_free(bits, size);
+out_nofds:
+	return ret;
+}
+
===== include/linux/compat.h 1.21 vs edited =====
--- 1.21/include/linux/compat.h	Sat Apr  3 22:43:52 2004
+++ edited/include/linux/compat.h	Sat Apr  3 22:16:07 2004
@@ -109,5 +109,9 @@
 int compat_do_execve(char * filename, compat_uptr_t __user *argv,
 	        compat_uptr_t __user *envp, struct pt_regs * regs);
 
+asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
+		compat_ulong_t __user *outp, compat_ulong_t __user *exp,
+		struct compat_timeval __user *tvp);
+
 #endif /* CONFIG_COMPAT */
 #endif /* _LINUX_COMPAT_H */

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

* [PATCH 4/4] Consolidate sys32_nfsservctl
       [not found] <200404040204.03594.arnd@arndb.de>
                   ` (2 preceding siblings ...)
  2004-04-04  0:22 ` [PATCH 3/4] Consolidate sys32_select Arnd Bergmann
@ 2004-04-04  0:22 ` Arnd Bergmann
  3 siblings, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-04  0:22 UTC (permalink / raw)
  To: linux-arch

sys32_nfsservctl is the largest remaining syscall emulation handler that
can be consolidated. mips and ia64 currently don't use this at all,
parisc has a simpler implementation than the one used by s390, sparc, ppc
and mips that the new compat_sys_nfsservctl is based on.

The user access checks in the code are inconsistant at least, which
should be fixed here.

Compile tested only due to lack of proper test setup.

===== arch/ia64/ia32/sys_ia32.c 1.95 vs edited =====
--- 1.95/arch/ia64/ia32/sys_ia32.c	Sun Apr  4 00:06:36 2004
+++ edited/arch/ia64/ia32/sys_ia32.c	Sat Apr  3 23:09:57 2004
@@ -2241,176 +2241,6 @@
 	return sys_setresgid(srgid, segid, ssgid);
 }
 
-/* Stuff for NFS server syscalls... */
-struct nfsctl_svc32 {
-	u16			svc32_port;
-	s32			svc32_nthreads;
-};
-
-struct nfsctl_client32 {
-	s8			cl32_ident[NFSCLNT_IDMAX+1];
-	s32			cl32_naddr;
-	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
-	s32			cl32_fhkeytype;
-	s32			cl32_fhkeylen;
-	u8			cl32_fhkey[NFSCLNT_KEYMAX];
-};
-
-struct nfsctl_export32 {
-	s8			ex32_client[NFSCLNT_IDMAX+1];
-	s8			ex32_path[NFS_MAXPATHLEN+1];
-	compat_dev_t	ex32_dev;
-	compat_ino_t	ex32_ino;
-	s32			ex32_flags;
-	compat_uid_t	ex32_anon_uid;
-	compat_gid_t	ex32_anon_gid;
-};
-
-struct nfsctl_arg32 {
-	s32			ca32_version;	/* safeguard */
-	union {
-		struct nfsctl_svc32	u32_svc;
-		struct nfsctl_client32	u32_client;
-		struct nfsctl_export32	u32_export;
-		u32			u32_debug;
-	} u;
-#define ca32_svc	u.u32_svc
-#define ca32_client	u.u32_client
-#define ca32_export	u.u32_export
-#define ca32_debug	u.u32_debug
-};
-
-union nfsctl_res32 {
-	struct knfs_fh		cr32_getfh;
-	u32			cr32_debug;
-};
-
-static int
-nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
-	err |= __get_user(karg->ca_svc.svc_nthreads,
-			  &arg32->ca32_svc.svc32_nthreads);
-	return err;
-}
-
-static int
-nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_client.cl_ident[0],
-			  &arg32->ca32_client.cl32_ident[0],
-			  NFSCLNT_IDMAX);
-	err |= __get_user(karg->ca_client.cl_naddr,
-			  &arg32->ca32_client.cl32_naddr);
-	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
-			  &arg32->ca32_client.cl32_addrlist[0],
-			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
-	err |= __get_user(karg->ca_client.cl_fhkeytype,
-		      &arg32->ca32_client.cl32_fhkeytype);
-	err |= __get_user(karg->ca_client.cl_fhkeylen,
-		      &arg32->ca32_client.cl32_fhkeylen);
-	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
-			  &arg32->ca32_client.cl32_fhkey[0],
-			  NFSCLNT_KEYMAX);
-	return err;
-}
-
-static int
-nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_export.ex_client[0],
-			  &arg32->ca32_export.ex32_client[0],
-			  NFSCLNT_IDMAX);
-	err |= copy_from_user(&karg->ca_export.ex_path[0],
-			  &arg32->ca32_export.ex32_path[0],
-			  NFS_MAXPATHLEN);
-	err |= __get_user(karg->ca_export.ex_dev,
-		      &arg32->ca32_export.ex32_dev);
-	err |= __get_user(karg->ca_export.ex_ino,
-		      &arg32->ca32_export.ex32_ino);
-	err |= __get_user(karg->ca_export.ex_flags,
-		      &arg32->ca32_export.ex32_flags);
-	err |= __get_user(karg->ca_export.ex_anon_uid,
-		      &arg32->ca32_export.ex32_anon_uid);
-	err |= __get_user(karg->ca_export.ex_anon_gid,
-		      &arg32->ca32_export.ex32_anon_gid);
-	return err;
-}
-
-static int
-nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
-{
-	int err;
-
-	err = copy_to_user(&res32->cr32_getfh,
-			&kres->cr_getfh,
-			sizeof(res32->cr32_getfh));
-	err |= __put_user(kres->cr_debug, &res32->cr32_debug);
-	return err;
-}
-
-int asmlinkage
-sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
-{
-	struct nfsctl_arg *karg = NULL;
-	union nfsctl_res *kres = NULL;
-	mm_segment_t oldfs;
-	int err;
-
-	karg = kmalloc(sizeof(*karg), GFP_USER);
-	if(!karg)
-		return -ENOMEM;
-	if(res32) {
-		kres = kmalloc(sizeof(*kres), GFP_USER);
-		if(!kres) {
-			kfree(karg);
-			return -ENOMEM;
-		}
-	}
-	switch(cmd) {
-	case NFSCTL_SVC:
-		err = nfs_svc32_trans(karg, arg32);
-		break;
-	case NFSCTL_ADDCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_DELCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_EXPORT:
-		err = nfs_exp32_trans(karg, arg32);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	if(err)
-		goto done;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_nfsservctl(cmd, karg, kres);
-	set_fs(oldfs);
-
-	if(!err && cmd == NFSCTL_GETFS)
-		err = nfs_getfh32_res_trans(kres, res32);
-
-done:
-	if(karg)
-		kfree(karg);
-	if(kres)
-		kfree(kres);
-	return err;
-}
-
 /* Handle adjtimex compatibility. */
 
 struct timex32 {
===== arch/parisc/kernel/sys_parisc32.c 1.27 vs edited =====
--- 1.27/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 23:39:56 2004
+++ edited/arch/parisc/kernel/sys_parisc32.c	Sat Apr  3 23:09:57 2004
@@ -562,94 +562,6 @@
         return ret;
 }
 
-/* EXPORT/UNEXPORT */
-struct nfsctl_export32 {
-	char		ex_client[NFSCLNT_IDMAX+1];
-	char		ex_path[NFS_MAXPATHLEN+1];
-	__kernel_old_dev_t ex_dev;
-	compat_ino_t	ex_ino;
-	int		ex_flags;
-	__kernel_uid_t	ex_anon_uid;
-	__kernel_gid_t	ex_anon_gid;
-};
-
-struct nfsctl_arg32 {
-	int			ca_version;	/* safeguard */
-	/* wide kernel places this union on 8-byte boundary, narrow on 4 */
-	union {
-		struct nfsctl_svc	u_svc;
-		struct nfsctl_client	u_client;
-		struct nfsctl_export32	u_export;
-		struct nfsctl_fdparm	u_getfd;
-		struct nfsctl_fsparm	u_getfs;
-	} u;
-};
-
-asmlinkage int sys32_nfsservctl(int cmd, void *argp, void *resp)
-{
-	int ret, tmp;
-	struct nfsctl_arg32 n32;
-	struct nfsctl_arg n;
-
-	ret = copy_from_user(&n, argp, sizeof n.ca_version);
-	if (ret != 0)
-		return ret;
-
-	/* adjust argp to point at the union inside the user's n32 struct */
-	tmp = (unsigned long)&n32.u - (unsigned long)&n32;
-	argp = (void *)((unsigned long)argp + tmp);
-	switch(cmd) {
-	case NFSCTL_SVC:
-		ret = copy_from_user(&n.u, argp, sizeof n.u.u_svc);
-		break;
-
-	case NFSCTL_ADDCLIENT:
-	case NFSCTL_DELCLIENT:
-		ret = copy_from_user(&n.u, argp, sizeof n.u.u_client);
-		break;
-
-	case NFSCTL_GETFD:
-		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfd);
-		break;
-
-	case NFSCTL_GETFS:
-		ret = copy_from_user(&n.u, argp, sizeof n.u.u_getfs);
-		break;
-
-	case NFSCTL_UNEXPORT:		/* nfsctl_export */
-	case NFSCTL_EXPORT:		/* nfsctl_export */
-		ret = copy_from_user(&n32.u, argp, sizeof n32.u.u_export);
-#undef CP
-#define CP(x)	n.u.u_export.ex_##x = n32.u.u_export.ex_##x
-		memcpy(n.u.u_export.ex_client, n32.u.u_export.ex_client, sizeof n32.u.u_export.ex_client);
-		memcpy(n.u.u_export.ex_path, n32.u.u_export.ex_path, sizeof n32.u.u_export.ex_path);
-		CP(dev);
-		CP(ino);
-		CP(flags);
-		CP(anon_uid);
-		CP(anon_gid);
-		break;
-
-	default:
-		/* lockd probes for some other values (0x10000);
-		 * so don't BUG() */
-		ret = -EINVAL;
-		break;
-	}
-
-	if (ret == 0) {
-		unsigned char rbuf[NFS_FHSIZE + sizeof (struct knfsd_fh)];
-		KERNEL_SYSCALL(ret, sys_nfsservctl, cmd, &n, &rbuf);
-		if (cmd == NFSCTL_GETFD) {
-			ret = copy_to_user(resp, rbuf, NFS_FHSIZE);
-		} else if (cmd == NFSCTL_GETFS) {
-			ret = copy_to_user(resp, rbuf, sizeof (struct knfsd_fh));
-		}
-	}
-
-	return ret;
-}
-
 typedef long __kernel_loff_t32;		/* move this to asm/posix_types.h? */
 
 asmlinkage int sys32_sendfile64(int out_fd, int in_fd, __kernel_loff_t32 *offset, s32 count)
===== arch/parisc/kernel/syscall_table.S 1.6 vs edited =====
--- 1.6/arch/parisc/kernel/syscall_table.S	Sat Apr  3 23:05:38 2004
+++ edited/arch/parisc/kernel/syscall_table.S	Sat Apr  3 23:43:02 2004
@@ -266,7 +266,7 @@
 	ENTRY_SAME(ni_syscall)		/* query_module */
 	ENTRY_SAME(poll)
 	/* structs contain pointers and an in_addr... */
-	ENTRY_DIFF(nfsservctl)
+	ENTRY_COMP(nfsservctl)
 	ENTRY_SAME(setresgid)		/* 170 */
 	ENTRY_SAME(getresgid)
 	ENTRY_SAME(prctl)
===== arch/ppc64/kernel/misc.S 1.75 vs edited =====
--- 1.75/arch/ppc64/kernel/misc.S	Sat Apr  3 21:56:39 2004
+++ edited/arch/ppc64/kernel/misc.S	Sat Apr  3 23:40:44 2004
@@ -740,7 +740,7 @@
 	.llong .sys_getresuid	        /* 165 */
 	.llong .sys_ni_syscall		/* old query_module syscall */
 	.llong .sys_poll
-	.llong .sys32_nfsservctl
+	.llong .compat_sys_nfsservctl
 	.llong .sys_setresgid
 	.llong .sys_getresgid	        /* 170 */
 	.llong .sys32_prctl
===== arch/ppc64/kernel/sys_ppc32.c 1.89 vs edited =====
--- 1.89/arch/ppc64/kernel/sys_ppc32.c	Sun Apr  4 00:11:06 2004
+++ edited/arch/ppc64/kernel/sys_ppc32.c	Sat Apr  3 23:09:57 2004
@@ -351,245 +351,6 @@
 	return ret;
 }
 
-/* Stuff for NFS server syscalls... */
-struct nfsctl_svc32 {
-	u16			svc32_port;
-	s32			svc32_nthreads;
-};
-
-struct nfsctl_client32 {
-	s8			cl32_ident[NFSCLNT_IDMAX+1];
-	s32			cl32_naddr;
-	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
-	s32			cl32_fhkeytype;
-	s32			cl32_fhkeylen;
-	u8			cl32_fhkey[NFSCLNT_KEYMAX];
-};
-
-struct nfsctl_export32 {
-	s8			ex32_client[NFSCLNT_IDMAX+1];
-	s8			ex32_path[NFS_MAXPATHLEN+1];
-	compat_dev_t	ex32_dev;
-	compat_ino_t	ex32_ino;
-	s32			ex32_flags;
-	compat_uid_t	ex32_anon_uid;
-	compat_gid_t	ex32_anon_gid;
-};
-
-struct nfsctl_fdparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_version;
-};
-
-struct nfsctl_fsparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_maxlen;
-};
-
-struct nfsctl_arg32 {
-	s32			ca32_version;	/* safeguard */
-	union {
-		struct nfsctl_svc32	u32_svc;
-		struct nfsctl_client32	u32_client;
-		struct nfsctl_export32	u32_export;
-		struct nfsctl_fdparm32	u32_getfd;
-		struct nfsctl_fsparm32	u32_getfs;
-	} u;
-#define ca32_svc	u.u32_svc
-#define ca32_client	u.u32_client
-#define ca32_export	u.u32_export
-#define ca32_getfd	u.u32_getfd
-#define ca32_getfs	u.u32_getfs
-};
-
-union nfsctl_res32 {
-	__u8			cr32_getfh[NFS_FHSIZE];
-	struct knfsd_fh		cr32_getfs;
-};
-
-static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
-	err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
-	return err;
-}
-
-static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_client.cl_ident[0],
-			  &arg32->ca32_client.cl32_ident[0],
-			  NFSCLNT_IDMAX);
-	err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
-	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
-			  &arg32->ca32_client.cl32_addrlist[0],
-			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
-	err |= __get_user(karg->ca_client.cl_fhkeytype,
-		      &arg32->ca32_client.cl32_fhkeytype);
-	err |= __get_user(karg->ca_client.cl_fhkeylen,
-		      &arg32->ca32_client.cl32_fhkeylen);
-	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
-			  &arg32->ca32_client.cl32_fhkey[0],
-			  NFSCLNT_KEYMAX);
-
-	if(err) return -EFAULT;
-	return 0;
-}
-
-static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_export.ex_client[0],
-			  &arg32->ca32_export.ex32_client[0],
-			  NFSCLNT_IDMAX);
-	err |= copy_from_user(&karg->ca_export.ex_path[0],
-			  &arg32->ca32_export.ex32_path[0],
-			  NFS_MAXPATHLEN);
-	err |= __get_user(karg->ca_export.ex_dev,
-		      &arg32->ca32_export.ex32_dev);
-	err |= __get_user(karg->ca_export.ex_ino,
-		      &arg32->ca32_export.ex32_ino);
-	err |= __get_user(karg->ca_export.ex_flags,
-		      &arg32->ca32_export.ex32_flags);
-	err |= __get_user(karg->ca_export.ex_anon_uid,
-		      &arg32->ca32_export.ex32_anon_uid);
-	err |= __get_user(karg->ca_export.ex_anon_gid,
-		      &arg32->ca32_export.ex32_anon_gid);
-	karg->ca_export.ex_anon_uid = karg->ca_export.ex_anon_uid;
-	karg->ca_export.ex_anon_gid = karg->ca_export.ex_anon_gid;
-
-	if(err) return -EFAULT;
-	return 0;
-}
-
-static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfd.gd_addr,
-			  &arg32->ca32_getfd.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfd.gd_path,
-			  &arg32->ca32_getfd.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= __get_user(karg->ca_getfd.gd_version,
-		      &arg32->ca32_getfd.gd32_version);
-
-	if(err) return -EFAULT;
-	return 0;
-}
-
-static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfs.gd_addr,
-			  &arg32->ca32_getfs.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfs.gd_path,
-			  &arg32->ca32_getfs.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= __get_user(karg->ca_getfs.gd_maxlen,
-		      &arg32->ca32_getfs.gd32_maxlen);
-
-	if(err) return -EFAULT;
-	return 0;
-}
-
-/* This really doesn't need translations, we are only passing
- * back a union which contains opaque nfs file handle data.
- */
-static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
-{
-	int err;
-
-	err = copy_to_user(res32, kres, sizeof(*res32));
-
-	if(err) return -EFAULT;
-	return 0;
-}
-
-/* Note: it is necessary to treat cmd_parm as an unsigned int, 
- * with the corresponding cast to a signed int to insure that the 
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-int asmlinkage sys32_nfsservctl(u32 cmd_parm, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
-{
-  int cmd = (int)cmd_parm;
-	struct nfsctl_arg *karg = NULL;
-	union nfsctl_res *kres = NULL;
-	mm_segment_t oldfs;
-	int err;
-
-	karg = kmalloc(sizeof(*karg), GFP_USER);
-	if(!karg)
-		return -ENOMEM;
-	if(res32) {
-		kres = kmalloc(sizeof(*kres), GFP_USER);
-		if(!kres) {
-			kfree(karg);
-			return -ENOMEM;
-		}
-	}
-	switch(cmd) {
-	case NFSCTL_SVC:
-		err = nfs_svc32_trans(karg, arg32);
-		break;
-	case NFSCTL_ADDCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_DELCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_EXPORT:
-	case NFSCTL_UNEXPORT:
-		err = nfs_exp32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFD:
-		err = nfs_getfd32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFS:
-		err = nfs_getfs32_trans(karg, arg32);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	if(err)
-		goto done;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_nfsservctl(cmd, karg, kres);
-	set_fs(oldfs);
-
-	if (err)
-		goto done;
-
-	if((cmd == NFSCTL_GETFD) ||
-	   (cmd == NFSCTL_GETFS))
-		err = nfs_getfh32_res_trans(kres, res32);
-
-done:
-	if(karg)
-		kfree(karg);
-	if(kres)
-		kfree(kres);
-	return err;
-}
-
-
 
 /* These are here just in case some old sparc32 binary calls it. */
 asmlinkage long sys32_pause(void)
===== arch/s390/kernel/compat_linux.c 1.22 vs edited =====
--- 1.22/arch/s390/kernel/compat_linux.c	Sat Apr  3 23:39:56 2004
+++ edited/arch/s390/kernel/compat_linux.c	Sat Apr  3 23:09:57 2004
@@ -815,226 +815,6 @@
 
 #endif  /* CONFIG_MODULES */
 
-/* Stuff for NFS server syscalls... */
-struct nfsctl_svc32 {
-	u16			svc32_port;
-	s32			svc32_nthreads;
-};
-
-struct nfsctl_client32 {
-	s8			cl32_ident[NFSCLNT_IDMAX+1];
-	s32			cl32_naddr;
-	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
-	s32			cl32_fhkeytype;
-	s32			cl32_fhkeylen;
-	u8			cl32_fhkey[NFSCLNT_KEYMAX];
-};
-
-struct nfsctl_export32 {
-	s8			ex32_client[NFSCLNT_IDMAX+1];
-	s8			ex32_path[NFS_MAXPATHLEN+1];
-	compat_dev_t	ex32_dev;
-	compat_ino_t	ex32_ino;
-	s32			ex32_flags;
-	compat_uid_t	ex32_anon_uid;
-	compat_gid_t	ex32_anon_gid;
-};
-
-struct nfsctl_fdparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_version;
-};
-
-struct nfsctl_fsparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_maxlen;
-};
-
-struct nfsctl_arg32 {
-	s32			ca32_version;	/* safeguard */
-	union {
-		struct nfsctl_svc32	u32_svc;
-		struct nfsctl_client32	u32_client;
-		struct nfsctl_export32	u32_export;
-		struct nfsctl_fdparm32	u32_getfd;
-		struct nfsctl_fsparm32	u32_getfs;
-	} u;
-#define ca32_svc	u.u32_svc
-#define ca32_client	u.u32_client
-#define ca32_export	u.u32_export
-#define ca32_getfd	u.u32_getfd
-#define ca32_getfs	u.u32_getfs
-#define ca32_authd	u.u32_authd
-};
-
-union nfsctl_res32 {
-	__u8			cr32_getfh[NFS_FHSIZE];
-	struct knfsd_fh		cr32_getfs;
-};
-
-static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
-	err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
-	return err;
-}
-
-static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_client.cl_ident[0],
-			  &arg32->ca32_client.cl32_ident[0],
-			  NFSCLNT_IDMAX);
-	err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
-	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
-			  &arg32->ca32_client.cl32_addrlist[0],
-			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
-	err |= __get_user(karg->ca_client.cl_fhkeytype,
-		      &arg32->ca32_client.cl32_fhkeytype);
-	err |= __get_user(karg->ca_client.cl_fhkeylen,
-		      &arg32->ca32_client.cl32_fhkeylen);
-	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
-			  &arg32->ca32_client.cl32_fhkey[0],
-			  NFSCLNT_KEYMAX);
-	return err;
-}
-
-static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_export.ex_client[0],
-			  &arg32->ca32_export.ex32_client[0],
-			  NFSCLNT_IDMAX);
-	err |= copy_from_user(&karg->ca_export.ex_path[0],
-			  &arg32->ca32_export.ex32_path[0],
-			  NFS_MAXPATHLEN);
-	err |= __get_user(karg->ca_export.ex_dev,
-		      &arg32->ca32_export.ex32_dev);
-	err |= __get_user(karg->ca_export.ex_ino,
-		      &arg32->ca32_export.ex32_ino);
-	err |= __get_user(karg->ca_export.ex_flags,
-		      &arg32->ca32_export.ex32_flags);
-	err |= __get_user(karg->ca_export.ex_anon_uid,
-		      &arg32->ca32_export.ex32_anon_uid);
-	err |= __get_user(karg->ca_export.ex_anon_gid,
-		      &arg32->ca32_export.ex32_anon_gid);
-	karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid);
-	karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid);
-	return err;
-}
-
-static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfd.gd_addr,
-			  &arg32->ca32_getfd.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfd.gd_path,
-			  &arg32->ca32_getfd.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= __get_user(karg->ca_getfd.gd_version,
-		      &arg32->ca32_getfd.gd32_version);
-	return err;
-}
-
-static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfs.gd_addr,
-			  &arg32->ca32_getfs.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfs.gd_path,
-			  &arg32->ca32_getfs.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= __get_user(karg->ca_getfs.gd_maxlen,
-		      &arg32->ca32_getfs.gd32_maxlen);
-	return err;
-}
-
-/* This really doesn't need translations, we are only passing
- * back a union which contains opaque nfs file handle data.
- */
-static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
-{
-	return copy_to_user(res32, kres, sizeof(*res32)) ? -EFAULT : 0;
-}
-
-long asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
-{
-	struct nfsctl_arg *karg = NULL;
-	union nfsctl_res *kres = NULL;
-	mm_segment_t oldfs;
-	int err;
-
-	karg = kmalloc(sizeof(*karg), GFP_USER);
-	if(!karg)
-		return -ENOMEM;
-	if(res32) {
-		kres = kmalloc(sizeof(*kres), GFP_USER);
-		if(!kres) {
-			kfree(karg);
-			return -ENOMEM;
-		}
-	}
-	switch(cmd) {
-	case NFSCTL_SVC:
-		err = nfs_svc32_trans(karg, arg32);
-		break;
-	case NFSCTL_ADDCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_DELCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_EXPORT:
-	case NFSCTL_UNEXPORT:
-		err = nfs_exp32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFD:
-		err = nfs_getfd32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFS:
-		err = nfs_getfs32_trans(karg, arg32);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	if(err)
-		goto done;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_nfsservctl(cmd, karg, kres);
-	set_fs(oldfs);
-
-	if (err)
-		goto done;
-
-	if((cmd == NFSCTL_GETFD) ||
-	   (cmd == NFSCTL_GETFS))
-		err = nfs_getfh32_res_trans(kres, res32);
-
-done:
-	if(karg)
-		kfree(karg);
-	if(kres)
-		kfree(kres);
-	return err;
-}
-
 /* Translations due to time_t size differences.  Which affects all
    sorts of things, like timeval and itimerval.  */
 
===== arch/s390/kernel/compat_wrapper.S 1.11 vs edited =====
--- 1.11/arch/s390/kernel/compat_wrapper.S	Sun Apr  4 00:11:49 2004
+++ edited/arch/s390/kernel/compat_wrapper.S	Sat Apr  3 23:42:13 2004
@@ -786,12 +786,12 @@
 	lgfr	%r4,%r4			# long 
 	jg	sys_poll		# branch to system call
 
-	.globl  sys32_nfsservctl_wrapper 
-sys32_nfsservctl_wrapper:
+	.globl  compat_sys_nfsservctl_wrapper 
+compat_sys_nfsservctl_wrapper:
 	lgfr	%r2,%r2			# int 
-	llgtr	%r3,%r3			# struct nfsctl_arg_emu31 * 
-	llgtr	%r4,%r4			# union nfsctl_res_emu31 * 
-	jg	sys32_nfsservctl	# branch to system call
+	llgtr	%r3,%r3			# struct compat_nfsctl_arg* 
+	llgtr	%r4,%r4			# union compat_nfsctl_res* 
+	jg	compat_sys_nfsservctl	# branch to system call
 
 	.globl  sys32_setresgid16_wrapper 
 sys32_setresgid16_wrapper:
===== arch/s390/kernel/syscalls.S 1.11 vs edited =====
--- 1.11/arch/s390/kernel/syscalls.S	Sun Apr  4 00:12:19 2004
+++ edited/arch/s390/kernel/syscalls.S	Sat Apr  3 23:42:25 2004
@@ -177,7 +177,7 @@
 NI_SYSCALL							/* for vm86 */
 NI_SYSCALL							/* old sys_query_module */
 SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
-SYSCALL(sys_nfsservctl,sys_nfsservctl,sys32_nfsservctl_wrapper)
+SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper)
 SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper)	/* 170 old setresgid16 syscall */
 SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper)	/* old getresgid16 syscall */
 SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
===== arch/sparc64/kernel/sys_sparc32.c 1.98 vs edited =====
--- 1.98/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 23:39:56 2004
+++ edited/arch/sparc64/kernel/sys_sparc32.c	Sat Apr  3 23:09:57 2004
@@ -1392,232 +1392,6 @@
 
 #endif  /* CONFIG_MODULES */
 
-#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
-/* Stuff for NFS server syscalls... */
-struct nfsctl_svc32 {
-	u16			svc32_port;
-	s32			svc32_nthreads;
-};
-
-struct nfsctl_client32 {
-	s8			cl32_ident[NFSCLNT_IDMAX+1];
-	s32			cl32_naddr;
-	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
-	s32			cl32_fhkeytype;
-	s32			cl32_fhkeylen;
-	u8			cl32_fhkey[NFSCLNT_KEYMAX];
-};
-
-struct nfsctl_export32 {
-	s8			ex32_client[NFSCLNT_IDMAX+1];
-	s8			ex32_path[NFS_MAXPATHLEN+1];
-	compat_dev_t	ex32_dev;
-	compat_ino_t	ex32_ino;
-	s32			ex32_flags;
-	compat_uid_t	ex32_anon_uid;
-	compat_gid_t	ex32_anon_gid;
-};
-
-struct nfsctl_fdparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_version;
-};
-
-struct nfsctl_fsparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_maxlen;
-};
-
-struct nfsctl_arg32 {
-	s32			ca32_version;	/* safeguard */
-	union {
-		struct nfsctl_svc32	u32_svc;
-		struct nfsctl_client32	u32_client;
-		struct nfsctl_export32	u32_export;
-		struct nfsctl_fdparm32	u32_getfd;
-		struct nfsctl_fsparm32	u32_getfs;
-	} u;
-#define ca32_svc	u.u32_svc
-#define ca32_client	u.u32_client
-#define ca32_export	u.u32_export
-#define ca32_getfd	u.u32_getfd
-#define ca32_getfs	u.u32_getfs
-};
-
-union nfsctl_res32 {
-	__u8			cr32_getfh[NFS_FHSIZE];
-	struct knfsd_fh		cr32_getfs;
-};
-
-static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
-	err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
-	return err;
-}
-
-static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_client.cl_ident[0],
-			  &arg32->ca32_client.cl32_ident[0],
-			  NFSCLNT_IDMAX);
-	err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
-	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
-			  &arg32->ca32_client.cl32_addrlist[0],
-			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
-	err |= __get_user(karg->ca_client.cl_fhkeytype,
-		      &arg32->ca32_client.cl32_fhkeytype);
-	err |= __get_user(karg->ca_client.cl_fhkeylen,
-		      &arg32->ca32_client.cl32_fhkeylen);
-	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
-			  &arg32->ca32_client.cl32_fhkey[0],
-			  NFSCLNT_KEYMAX);
-	return (err ? -EFAULT : 0);
-}
-
-static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_export.ex_client[0],
-			  &arg32->ca32_export.ex32_client[0],
-			  NFSCLNT_IDMAX);
-	err |= copy_from_user(&karg->ca_export.ex_path[0],
-			  &arg32->ca32_export.ex32_path[0],
-			  NFS_MAXPATHLEN);
-	err |= __get_user(karg->ca_export.ex_dev,
-		      &arg32->ca32_export.ex32_dev);
-	err |= __get_user(karg->ca_export.ex_ino,
-		      &arg32->ca32_export.ex32_ino);
-	err |= __get_user(karg->ca_export.ex_flags,
-		      &arg32->ca32_export.ex32_flags);
-	err |= __get_user(karg->ca_export.ex_anon_uid,
-		      &arg32->ca32_export.ex32_anon_uid);
-	err |= __get_user(karg->ca_export.ex_anon_gid,
-		      &arg32->ca32_export.ex32_anon_gid);
-	karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid);
-	karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid);
-	return (err ? -EFAULT : 0);
-}
-
-static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfd.gd_addr,
-			  &arg32->ca32_getfd.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfd.gd_path,
-			  &arg32->ca32_getfd.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= __get_user(karg->ca_getfd.gd_version,
-		      &arg32->ca32_getfd.gd32_version);
-	return (err ? -EFAULT : 0);
-}
-
-static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = __get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfs.gd_addr,
-			  &arg32->ca32_getfs.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfs.gd_path,
-			  &arg32->ca32_getfs.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= __get_user(karg->ca_getfs.gd_maxlen,
-		      &arg32->ca32_getfs.gd32_maxlen);
-	return (err ? -EFAULT : 0);
-}
-
-/* This really doesn't need translations, we are only passing
- * back a union which contains opaque nfs file handle data.
- */
-static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
-{
-	return (copy_to_user(res32, kres, sizeof(*res32)) ? -EFAULT : 0);
-}
-
-int asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
-{
-	struct nfsctl_arg *karg = NULL;
-	union nfsctl_res *kres = NULL;
-	mm_segment_t oldfs;
-	int err;
-
-	karg = kmalloc(sizeof(*karg), GFP_USER);
-	if(!karg)
-		return -ENOMEM;
-	if(res32) {
-		kres = kmalloc(sizeof(*kres), GFP_USER);
-		if(!kres) {
-			kfree(karg);
-			return -ENOMEM;
-		}
-	}
-	switch(cmd) {
-	case NFSCTL_SVC:
-		err = nfs_svc32_trans(karg, arg32);
-		break;
-	case NFSCTL_ADDCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_DELCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_EXPORT:
-	case NFSCTL_UNEXPORT:
-		err = nfs_exp32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFD:
-		err = nfs_getfd32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFS:
-		err = nfs_getfs32_trans(karg, arg32);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	if(err)
-		goto done;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_nfsservctl(cmd, karg, kres);
-	set_fs(oldfs);
-
-	if (err)
-		goto done;
-
-	if((cmd == NFSCTL_GETFD) ||
-	   (cmd == NFSCTL_GETFS))
-		err = nfs_getfh32_res_trans(kres, res32);
-
-done:
-	if(karg)
-		kfree(karg);
-	if(kres)
-		kfree(kres);
-	return err;
-}
-#else /* !NFSD */
-int asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
-{
-	return sys_ni_syscall();
-}
-#endif
-
 /* Translations due to time_t size differences.  Which affects all
    sorts of things, like timeval and itimerval.  */
 
===== arch/sparc64/kernel/systbls.S 1.54 vs edited =====
--- 1.54/arch/sparc64/kernel/systbls.S	Sun Apr  4 00:46:01 2004
+++ edited/arch/sparc64/kernel/systbls.S	Sat Apr  3 23:42:29 2004
@@ -69,7 +69,7 @@
 	.word compat_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
 /*240*/	.word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
 	.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
-/*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
+/*250*/	.word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, compat_sys_nfsservctl
 	.word sys_ni_syscall, compat_clock_settime, compat_clock_gettime, compat_clock_getres, compat_clock_nanosleep
 /*260*/	.word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, compat_timer_settime, compat_timer_gettime, sys_timer_getoverrun
 	.word sys_timer_delete, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
===== arch/x86_64/ia32/ia32entry.S 1.32 vs edited =====
--- 1.32/arch/x86_64/ia32/ia32entry.S	Sun Apr  4 00:13:48 2004
+++ edited/arch/x86_64/ia32/ia32entry.S	Sat Apr  3 23:42:43 2004
@@ -474,7 +474,7 @@
 	.quad sys32_vm86_warning	/* vm86 */ 
 	.quad quiet_ni_syscall	/* query_module */
 	.quad sys_poll
-	.quad sys32_nfsservctl
+	.quad compat_sys_nfsservctl
 	.quad sys_setresgid16	/* 170 */
 	.quad sys_getresgid16
 	.quad sys_prctl
===== arch/x86_64/ia32/sys_ia32.c 1.59 vs edited =====
--- 1.59/arch/x86_64/ia32/sys_ia32.c	Sun Apr  4 00:13:24 2004
+++ edited/arch/x86_64/ia32/sys_ia32.c	Sat Apr  3 23:09:57 2004
@@ -1165,233 +1165,6 @@
 }
  
 
-#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
-/* Stuff for NFS server syscalls... */
-struct nfsctl_svc32 {
-	u16			svc32_port;
-	s32			svc32_nthreads;
-};
-
-struct nfsctl_client32 {
-	s8			cl32_ident[NFSCLNT_IDMAX+1];
-	s32			cl32_naddr;
-	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
-	s32			cl32_fhkeytype;
-	s32			cl32_fhkeylen;
-	u8			cl32_fhkey[NFSCLNT_KEYMAX];
-};
-
-struct nfsctl_export32 {
-	s8			ex32_client[NFSCLNT_IDMAX+1];
-	s8			ex32_path[NFS_MAXPATHLEN+1];
-	compat_dev_t	ex32_dev;
-	compat_ino_t	ex32_ino;
-	s32			ex32_flags;
-	compat_pid_t	ex32_anon_uid;
-	compat_gid_t	ex32_anon_gid;
-};
-
-struct nfsctl_fdparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_version;
-};
-
-struct nfsctl_fsparm32 {
-	struct sockaddr		gd32_addr;
-	s8			gd32_path[NFS_MAXPATHLEN+1];
-	s32			gd32_maxlen;
-};
-
-struct nfsctl_arg32 {
-	s32			ca32_version;	/* safeguard */
-	union {
-		struct nfsctl_svc32	u32_svc;
-		struct nfsctl_client32	u32_client;
-		struct nfsctl_export32	u32_export;
-		struct nfsctl_fdparm32	u32_getfd;
-		struct nfsctl_fsparm32	u32_getfs;
-	} u;
-#define ca32_svc	u.u32_svc
-#define ca32_client	u.u32_client
-#define ca32_export	u.u32_export
-#define ca32_getfd	u.u32_getfd
-#define ca32_getfs	u.u32_getfs
-};
-
-union nfsctl_res32 {
-	__u8			cr32_getfh[NFS_FHSIZE];
-	struct knfsd_fh		cr32_getfs;
-};
-
-static int nfs_svc32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = get_user(karg->ca_version, &arg32->ca32_version);
-	err |= __get_user(karg->ca_svc.svc_port, &arg32->ca32_svc.svc32_port);
-	err |= __get_user(karg->ca_svc.svc_nthreads, &arg32->ca32_svc.svc32_nthreads);
-	return err;
-}
-
-static int nfs_clnt32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_client.cl_ident[0],
-			  &arg32->ca32_client.cl32_ident[0],
-			  NFSCLNT_IDMAX);
-	err |= __get_user(karg->ca_client.cl_naddr, &arg32->ca32_client.cl32_naddr);
-	err |= copy_from_user(&karg->ca_client.cl_addrlist[0],
-			  &arg32->ca32_client.cl32_addrlist[0],
-			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
-	err |= __get_user(karg->ca_client.cl_fhkeytype,
-		      &arg32->ca32_client.cl32_fhkeytype);
-	err |= __get_user(karg->ca_client.cl_fhkeylen,
-		      &arg32->ca32_client.cl32_fhkeylen);
-	err |= copy_from_user(&karg->ca_client.cl_fhkey[0],
-			  &arg32->ca32_client.cl32_fhkey[0],
-			  NFSCLNT_KEYMAX);
-	return err;
-}
-
-static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_export.ex_client[0],
-			  &arg32->ca32_export.ex32_client[0],
-			  NFSCLNT_IDMAX);
-	err |= copy_from_user(&karg->ca_export.ex_path[0],
-			  &arg32->ca32_export.ex32_path[0],
-			  NFS_MAXPATHLEN);
-	err |= __get_user(karg->ca_export.ex_dev,
-		      &arg32->ca32_export.ex32_dev);
-	err |= __get_user(karg->ca_export.ex_ino,
-		      &arg32->ca32_export.ex32_ino);
-	err |= __get_user(karg->ca_export.ex_flags,
-		      &arg32->ca32_export.ex32_flags);
-	err |= __get_user(karg->ca_export.ex_anon_uid,
-		      &arg32->ca32_export.ex32_anon_uid);
-	err |= __get_user(karg->ca_export.ex_anon_gid,
-		      &arg32->ca32_export.ex32_anon_gid);
-	SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
-	SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
-	return err;
-}
-
-
-static int nfs_getfd32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfd.gd_addr,
-			  &arg32->ca32_getfd.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfd.gd_path,
-			  &arg32->ca32_getfd.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= get_user(karg->ca_getfd.gd_version,
-		      &arg32->ca32_getfd.gd32_version);
-	return err;
-}
-
-static int nfs_getfs32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
-{
-	int err;
-	
-	err = get_user(karg->ca_version, &arg32->ca32_version);
-	err |= copy_from_user(&karg->ca_getfs.gd_addr,
-			  &arg32->ca32_getfs.gd32_addr,
-			  (sizeof(struct sockaddr)));
-	err |= copy_from_user(&karg->ca_getfs.gd_path,
-			  &arg32->ca32_getfs.gd32_path,
-			  (NFS_MAXPATHLEN+1));
-	err |= get_user(karg->ca_getfs.gd_maxlen,
-		      &arg32->ca32_getfs.gd32_maxlen);
-	return err;
-}
-
-/* This really doesn't need translations, we are only passing
- * back a union which contains opaque nfs file handle data.
- */
-static int nfs_getfh32_res_trans(union nfsctl_res *kres, union nfsctl_res32 *res32)
-{
-	return copy_to_user(res32, kres, sizeof(*res32)) ? -EFAULT : 0;
-}
-
-long asmlinkage sys32_nfsservctl(int cmd, struct nfsctl_arg32 *arg32, union nfsctl_res32 *res32)
-{
-	struct nfsctl_arg *karg = NULL;
-	union nfsctl_res *kres = NULL;
-	mm_segment_t oldfs;
-	int err;
-
-	karg = kmalloc(sizeof(*karg), GFP_USER);
-	if(!karg)
-		return -ENOMEM;
-	if(res32) {
-		kres = kmalloc(sizeof(*kres), GFP_USER);
-		if(!kres) {
-			kfree(karg);
-			return -ENOMEM;
-		}
-	}
-	switch(cmd) {
-	case NFSCTL_SVC:
-		err = nfs_svc32_trans(karg, arg32);
-		break;
-	case NFSCTL_ADDCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_DELCLIENT:
-		err = nfs_clnt32_trans(karg, arg32);
-		break;
-	case NFSCTL_EXPORT:
-	case NFSCTL_UNEXPORT:
-		err = nfs_exp32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFD:
-		err = nfs_getfd32_trans(karg, arg32);
-		break;
-	case NFSCTL_GETFS:
-		err = nfs_getfs32_trans(karg, arg32);
-		break;
-	default:
-		err = -EINVAL;
-		break;
-	}
-	if(err)
-		goto done;
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	err = sys_nfsservctl(cmd, karg, kres);
-	set_fs(oldfs);
-
-	if (err)
-		goto done;
-
-	if((cmd == NFSCTL_GETFD) ||
-	   (cmd == NFSCTL_GETFS))
-		err = nfs_getfh32_res_trans(kres, res32);
-
-done:
-	if(karg)
-		kfree(karg);
-	if(kres)
-		kfree(kres);
-	return err;
-}
-#else /* !NFSD */
-long asmlinkage sys32_nfsservctl(int cmd, void *notused, void *notused2)
-{
-	return sys_ni_syscall();
-}
-#endif
-
 long sys32_io_setup(unsigned nr_reqs, u32 *ctx32p)
 { 
 	long ret; 
===== fs/compat.c 1.25 vs edited =====
--- 1.25/fs/compat.c	Sat Apr  3 23:51:59 2004
+++ edited/fs/compat.c	Sat Apr  3 23:13:39 2004
@@ -1400,3 +1400,242 @@
 	return ret;
 }
 
+#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
+/* Stuff for NFS server syscalls... */
+struct compat_nfsctl_svc {
+	u16			svc32_port;
+	s32			svc32_nthreads;
+};
+
+struct compat_nfsctl_client {
+	s8			cl32_ident[NFSCLNT_IDMAX+1];
+	s32			cl32_naddr;
+	struct in_addr		cl32_addrlist[NFSCLNT_ADDRMAX];
+	s32			cl32_fhkeytype;
+	s32			cl32_fhkeylen;
+	u8			cl32_fhkey[NFSCLNT_KEYMAX];
+};
+
+struct compat_nfsctl_export {
+	char		ex32_client[NFSCLNT_IDMAX+1];
+	char		ex32_path[NFS_MAXPATHLEN+1];
+	compat_dev_t	ex32_dev;
+	compat_ino_t	ex32_ino;
+	compat_int_t	ex32_flags;
+	compat_uid_t	ex32_anon_uid;
+	compat_gid_t	ex32_anon_gid;
+};
+
+struct compat_nfsctl_fdparm {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	compat_int_t		gd32_version;
+};
+
+struct compat_nfsctl_fsparm {
+	struct sockaddr		gd32_addr;
+	s8			gd32_path[NFS_MAXPATHLEN+1];
+	compat_int_t		gd32_maxlen;
+};
+
+struct compat_nfsctl_arg {
+	compat_int_t		ca32_version;	/* safeguard */
+	union {
+		struct compat_nfsctl_svc	u32_svc;
+		struct compat_nfsctl_client	u32_client;
+		struct compat_nfsctl_export	u32_export;
+		struct compat_nfsctl_fdparm	u32_getfd;
+		struct compat_nfsctl_fsparm	u32_getfs;
+	} u;
+#define ca32_svc	u.u32_svc
+#define ca32_client	u.u32_client
+#define ca32_export	u.u32_export
+#define ca32_getfd	u.u32_getfd
+#define ca32_getfs	u.u32_getfs
+};
+
+union compat_nfsctl_res {
+	__u8			cr32_getfh[NFS_FHSIZE];
+	struct knfsd_fh		cr32_getfs;
+};
+
+static int compat_nfs_svc_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg *arg)
+{
+	int err;
+
+	err = access_ok(VERIFY_READ, &arg->ca32_svc, sizeof(arg->ca32_svc));
+	err |= get_user(karg->ca_version, &arg->ca32_version);
+	err |= __get_user(karg->ca_svc.svc_port, &arg->ca32_svc.svc32_port);
+	err |= __get_user(karg->ca_svc.svc_nthreads, &arg->ca32_svc.svc32_nthreads);
+	return (err) ? -EFAULT : 0;
+}
+
+static int compat_nfs_clnt_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg *arg)
+{
+	int err;
+
+	err = access_ok(VERIFY_READ, &arg->ca32_client, sizeof(arg->ca32_client));
+	err |= get_user(karg->ca_version, &arg->ca32_version);
+	err |= __copy_from_user(&karg->ca_client.cl_ident[0],
+			  &arg->ca32_client.cl32_ident[0],
+			  NFSCLNT_IDMAX);
+	err |= __get_user(karg->ca_client.cl_naddr, &arg->ca32_client.cl32_naddr);
+	err |= __copy_from_user(&karg->ca_client.cl_addrlist[0],
+			  &arg->ca32_client.cl32_addrlist[0],
+			  (sizeof(struct in_addr) * NFSCLNT_ADDRMAX));
+	err |= __get_user(karg->ca_client.cl_fhkeytype,
+		      &arg->ca32_client.cl32_fhkeytype);
+	err |= __get_user(karg->ca_client.cl_fhkeylen,
+		      &arg->ca32_client.cl32_fhkeylen);
+	err |= __copy_from_user(&karg->ca_client.cl_fhkey[0],
+			  &arg->ca32_client.cl32_fhkey[0],
+			  NFSCLNT_KEYMAX);
+
+	return (err) ? -EFAULT : 0;
+}
+
+static int compat_nfs_exp_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg *arg)
+{
+	int err;
+
+	err = access_ok(VERIFY_READ, &arg->ca32_export, sizeof(arg->ca32_export));
+	err |= get_user(karg->ca_version, &arg->ca32_version);
+	err |= __copy_from_user(&karg->ca_export.ex_client[0],
+			  &arg->ca32_export.ex32_client[0],
+			  NFSCLNT_IDMAX);
+	err |= __copy_from_user(&karg->ca_export.ex_path[0],
+			  &arg->ca32_export.ex32_path[0],
+			  NFS_MAXPATHLEN);
+	err |= __get_user(karg->ca_export.ex_dev,
+		      &arg->ca32_export.ex32_dev);
+	err |= __get_user(karg->ca_export.ex_ino,
+		      &arg->ca32_export.ex32_ino);
+	err |= __get_user(karg->ca_export.ex_flags,
+		      &arg->ca32_export.ex32_flags);
+	err |= __get_user(karg->ca_export.ex_anon_uid,
+		      &arg->ca32_export.ex32_anon_uid);
+	err |= __get_user(karg->ca_export.ex_anon_gid,
+		      &arg->ca32_export.ex32_anon_gid);
+	SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
+	SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
+
+	return (err) ? -EFAULT : 0;
+}
+
+static int compat_nfs_getfd_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg *arg)
+{
+	int err;
+	
+	err = access_ok(VERIFY_READ, &arg->ca32_getfd, sizeof(arg->ca32_getfd));
+	err |= get_user(karg->ca_version, &arg->ca32_version);
+	err |= __copy_from_user(&karg->ca_getfd.gd_addr,
+			  &arg->ca32_getfd.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= __copy_from_user(&karg->ca_getfd.gd_path,
+			  &arg->ca32_getfd.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= __get_user(karg->ca_getfd.gd_version,
+		      &arg->ca32_getfd.gd32_version);
+
+	return (err) ? -EFAULT : 0;
+}
+
+static int compat_nfs_getfs_trans(struct nfsctl_arg *karg, struct compat_nfsctl_arg *arg)
+{
+	int err;
+
+	err = access_ok(VERIFY_READ, &arg->ca32_getfs, sizeof(arg->ca32_getfs));
+	err |= get_user(karg->ca_version, &arg->ca32_version);
+	err |= __copy_from_user(&karg->ca_getfs.gd_addr,
+			  &arg->ca32_getfs.gd32_addr,
+			  (sizeof(struct sockaddr)));
+	err |= __copy_from_user(&karg->ca_getfs.gd_path,
+			  &arg->ca32_getfs.gd32_path,
+			  (NFS_MAXPATHLEN+1));
+	err |= __get_user(karg->ca_getfs.gd_maxlen,
+		      &arg->ca32_getfs.gd32_maxlen);
+
+	return (err) ? -EFAULT : 0;
+}
+
+/* This really doesn't need translations, we are only passing
+ * back a union which contains opaque nfs file handle data.
+ */
+static int compat_nfs_getfh_res_trans(union nfsctl_res *kres, union compat_nfsctl_res *res)
+{
+	int err;
+
+	err = copy_to_user(res, kres, sizeof(*res));
+
+	return (err) ? -EFAULT : 0;
+}
+
+asmlinkage long compat_sys_nfsservctl(int cmd, struct compat_nfsctl_arg *arg,
+					union compat_nfsctl_res *res)
+{
+	struct nfsctl_arg *karg;
+	union nfsctl_res *kres;
+	mm_segment_t oldfs;
+	int err;
+
+	karg = kmalloc(sizeof(*karg), GFP_USER);
+	kres = kmalloc(sizeof(*kres), GFP_USER);
+	if(!karg || !kres) {
+		err = -ENOMEM;
+		goto done;
+	}
+
+	switch(cmd) {
+	case NFSCTL_SVC:
+		err = compat_nfs_svc_trans(karg, arg);
+		break;
+
+	case NFSCTL_ADDCLIENT:
+		err = compat_nfs_clnt_trans(karg, arg);
+		break;
+
+	case NFSCTL_DELCLIENT:
+		err = compat_nfs_clnt_trans(karg, arg);
+		break;
+
+	case NFSCTL_EXPORT:
+	case NFSCTL_UNEXPORT:
+		err = compat_nfs_exp_trans(karg, arg);
+		break;
+
+	case NFSCTL_GETFD:
+		err = compat_nfs_getfd_trans(karg, arg);
+		break;
+
+	case NFSCTL_GETFS:
+		err = compat_nfs_getfs_trans(karg, arg);
+		break;
+
+	default:
+		err = -EINVAL;
+		goto done;
+	}
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_nfsservctl(cmd, karg, kres);
+	set_fs(oldfs);
+
+	if (err)
+		goto done;
+
+	if((cmd == NFSCTL_GETFD) ||
+	   (cmd == NFSCTL_GETFS))
+		err = compat_nfs_getfh_res_trans(kres, res);
+
+done:
+	kfree(karg);
+	kfree(kres);
+	return err;
+}
+#else /* !NFSD */
+long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
+{
+	return sys_ni_syscall();
+}
+#endif

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04  0:22 ` [PATCH 3/4] Consolidate sys32_select Arnd Bergmann
@ 2004-04-04 10:24   ` Andi Kleen
  2004-04-04 10:36     ` Arnd Bergmann
  2004-04-04 11:07     ` William Lee Irwin III
  2004-04-07 20:46   ` Arun Sharma
  1 sibling, 2 replies; 15+ messages in thread
From: Andi Kleen @ 2004-04-04 10:24 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-arch

On Sun, 4 Apr 2004 02:22:40 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> sys32_select has seven mostly but not exactly identical versions,
> so consolidate them as compat_sys_select. Based on the ppc64
> implementation, which most closely resembles sys_select.
> 
> Passes relevant LTP test cases on x86_64.

I'm a bit dubious about LTP - often their test cases are very poor
and just check EFAULT behaviour. For testing it's better to just boot 
a 32bit distribution and make sure that at least some X desktop
works. That said your patches look fine to me.

-Andi

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04 10:24   ` Andi Kleen
@ 2004-04-04 10:36     ` Arnd Bergmann
  2004-04-04 11:04       ` Andi Kleen
  2004-04-04 11:07     ` William Lee Irwin III
  1 sibling, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-04 10:36 UTC (permalink / raw)
  To: Andi Kleen; +Cc: linux-arch

On Sunday 04 April 2004 12:24, Andi Kleen wrote:
> I'm a bit dubious about LTP - often their test cases are very poor
> and just check EFAULT behaviour. For testing it's better to just boot 
> a 32bit distribution and make sure that at least some X desktop
> works.

Right, the quality of LTP testcases varies a lot, but they tend to
check the more obscure stuff that you might not hit when everything
goes right.

I forgot to say that I'm running mostly 32 bit user space on my
Opteron box, so the good path was probably exercised as well.

	Arnd <><

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04 10:36     ` Arnd Bergmann
@ 2004-04-04 11:04       ` Andi Kleen
  0 siblings, 0 replies; 15+ messages in thread
From: Andi Kleen @ 2004-04-04 11:04 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-arch

On Sun, 4 Apr 2004 12:36:49 +0200
Arnd Bergmann <arnd@arndb.de> wrote:

> On Sunday 04 April 2004 12:24, Andi Kleen wrote:
> > I'm a bit dubious about LTP - often their test cases are very poor
> > and just check EFAULT behaviour. For testing it's better to just boot 
> > a 32bit distribution and make sure that at least some X desktop
> > works.
> 
> Right, the quality of LTP testcases varies a lot, but they tend to
> check the more obscure stuff that you might not hit when everything
> goes right.

Well, barely. The LSB test suite is a bit better, but it takes forever 
to run. There is also another test suite called ballista, but I never
got it to run properly.

 
> I forgot to say that I'm running mostly 32 bit user space on my
> Opteron box, so the good path was probably exercised as well.

Ok fine. I do too actually on my workstation, but I haven't booted your
patches yet ;-)

-Andi

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04 10:24   ` Andi Kleen
  2004-04-04 10:36     ` Arnd Bergmann
@ 2004-04-04 11:07     ` William Lee Irwin III
  2004-04-04 22:51       ` Arnd Bergmann
  1 sibling, 1 reply; 15+ messages in thread
From: William Lee Irwin III @ 2004-04-04 11:07 UTC (permalink / raw)
  To: Andi Kleen; +Cc: Arnd Bergmann, linux-arch

On Sun, 4 Apr 2004 02:22:40 +0200 Arnd Bergmann <arnd@arndb.de> wrote:
>> sys32_select has seven mostly but not exactly identical versions,
>> so consolidate them as compat_sys_select. Based on the ppc64
>> implementation, which most closely resembles sys_select.
>> Passes relevant LTP test cases on x86_64.

On Sun, Apr 04, 2004 at 12:24:04PM +0200, Andi Kleen wrote:
> I'm a bit dubious about LTP - often their test cases are very poor
> and just check EFAULT behaviour. For testing it's better to just boot 
> a 32bit distribution and make sure that at least some X desktop
> works. That said your patches look fine to me.
> -Andi

I can second that one; I've seen stuff that "passes LTP" but blatantly
flunks rather simplistic off-the-cuff a priori sanity checks. One
example that stands out is a recent patch ppl were rather foolishly
trying to get my endorsement on that pandered to (ir)Rational crap code.
I've also found LTP to be insufficient/useless in a number of userspace
ABI compatibility tests as well, where running a different distro
sufficed and full-blown LTP did not.


-- wli

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04 11:07     ` William Lee Irwin III
@ 2004-04-04 22:51       ` Arnd Bergmann
  2004-04-04 23:35         ` Andi Kleen
  0 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-04 22:51 UTC (permalink / raw)
  To: William Lee Irwin III; +Cc: Andi Kleen, linux-arch

On Sunday 04 April 2004 13:07, William Lee Irwin III wrote:
> I can second that one; I've seen stuff that "passes LTP" but blatantly
> flunks rather simplistic off-the-cuff a priori sanity checks. One
> example that stands out is a recent patch ppl were rather foolishly
> trying to get my endorsement on that pandered to (ir)Rational crap code.

I just found another example when I tried to open a ppp connection
with my patches :(

This needs to be applied on top of the sys32_select consolidation
patch to get the correct return value from select when called with
nonzero timeout.

===== fs/compat.c 1.25 vs edited =====
--- 1.25/fs/compat.c	Sat Apr  3 23:51:59 2004
+++ edited/fs/compat.c	Mon Apr  5 00:48:52 2004
@@ -1377,8 +1377,9 @@
 			usec = timeout % HZ;
 			usec *= (1000000/HZ);
 		}
-		ret = __put_user(sec, &tvp->tv_sec);
-		ret |= __put_user(usec, &tvp->tv_usec);
+		if (put_user(sec, &tvp->tv_sec) ||
+		    put_user(usec, &tvp->tv_usec))
+			ret = -EFAULT;
 	}
 
 	if (ret < 0)

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04 22:51       ` Arnd Bergmann
@ 2004-04-04 23:35         ` Andi Kleen
  2004-04-04 23:41           ` Arnd Bergmann
  0 siblings, 1 reply; 15+ messages in thread
From: Andi Kleen @ 2004-04-04 23:35 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: William Lee Irwin III, Andi Kleen, linux-arch

> ===== fs/compat.c 1.25 vs edited =====
> --- 1.25/fs/compat.c	Sat Apr  3 23:51:59 2004
> +++ edited/fs/compat.c	Mon Apr  5 00:48:52 2004
> @@ -1377,8 +1377,9 @@
>  			usec = timeout % HZ;
>  			usec *= (1000000/HZ);
>  		}
> -		ret = __put_user(sec, &tvp->tv_sec);
> -		ret |= __put_user(usec, &tvp->tv_usec);
> +		if (put_user(sec, &tvp->tv_sec) ||
> +		    put_user(usec, &tvp->tv_usec))
> +			ret = -EFAULT;

Are you sure? They should be equivalent. __put_user returns -EFAULT
on error.

-Andi

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04 23:35         ` Andi Kleen
@ 2004-04-04 23:41           ` Arnd Bergmann
  0 siblings, 0 replies; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-04 23:41 UTC (permalink / raw)
  To: Andi Kleen; +Cc: William Lee Irwin III, linux-arch

On Monday 05 April 2004 01:35, Andi Kleen wrote:
> > ===== fs/compat.c 1.25 vs edited =====
> > --- 1.25/fs/compat.c	Sat Apr  3 23:51:59 2004
> > +++ edited/fs/compat.c	Mon Apr  5 00:48:52 2004
> > @@ -1377,8 +1377,9 @@
> >  			usec = timeout % HZ;
> >  			usec *= (1000000/HZ);
> >  		}
> > -		ret = __put_user(sec, &tvp->tv_sec);
> > -		ret |= __put_user(usec, &tvp->tv_usec);
> > +		if (put_user(sec, &tvp->tv_sec) ||
> > +		    put_user(usec, &tvp->tv_usec))
> > +			ret = -EFAULT;
> 
> Are you sure? They should be equivalent. __put_user returns -EFAULT
> on error.

Yes, but if put_user succeeds, the value of ret must not be
set to zero here, it already contains the number of descriptors.

	Arnd <><

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-04  0:22 ` [PATCH 3/4] Consolidate sys32_select Arnd Bergmann
  2004-04-04 10:24   ` Andi Kleen
@ 2004-04-07 20:46   ` Arun Sharma
  2004-04-08  8:22     ` Arnd Bergmann
  1 sibling, 1 reply; 15+ messages in thread
From: Arun Sharma @ 2004-04-07 20:46 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-arch

On 4/3/2004 4:22 PM, Arnd Bergmann wrote:

> sys32_select has seven mostly but not exactly identical versions,
> so consolidate them as compat_sys_select. Based on the ppc64
> implementation, which most closely resembles sys_select.
> 
> Passes relevant LTP test cases on x86_64.
> 

While your patches improved compatibility with respect to LSB/LTP, we saw the following regressions on LTP on ia64:

recv01      PASS->BROK
recvmsg01    PASS->BROK
recvfrom01    PASS->BROK

While we're looking into it, did others see this ? Is it fixed already ?

	-Arun

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-07 20:46   ` Arun Sharma
@ 2004-04-08  8:22     ` Arnd Bergmann
  2004-04-12 18:55       ` Arun Sharma
  0 siblings, 1 reply; 15+ messages in thread
From: Arnd Bergmann @ 2004-04-08  8:22 UTC (permalink / raw)
  To: Arun Sharma; +Cc: linux-arch

On Wednesday 07 April 2004 22:46, you wrote:
> While your patches improved compatibility with respect to LSB/LTP,
> we saw the following regressions on LTP on ia64: 
> 
> recv01      PASS->BROK
> recvmsg01    PASS->BROK
> recvfrom01    PASS->BROK
> 
> While we're looking into it, did others see this ? 
> Is it fixed already ? 

Did you apply the patch I sent in the followup mail? It looks
like you ran into the problem. Here it is again in case you
missed it.

	Arnd <><

===== fs/compat.c 1.25 vs edited =====
--- 1.25/fs/compat.c	Sat Apr  3 23:51:59 2004
+++ edited/fs/compat.c	Mon Apr  5 00:48:52 2004
@@ -1377,8 +1377,9 @@
 			usec = timeout % HZ;
 			usec *= (1000000/HZ);
 		}
-		ret = __put_user(sec, &tvp->tv_sec);
-		ret |= __put_user(usec, &tvp->tv_usec);
+		if (put_user(sec, &tvp->tv_sec) ||
+		    put_user(usec, &tvp->tv_usec))
+			ret = -EFAULT;
 	}
 
 	if (ret < 0)

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

* Re: [PATCH 3/4] Consolidate sys32_select
  2004-04-08  8:22     ` Arnd Bergmann
@ 2004-04-12 18:55       ` Arun Sharma
  0 siblings, 0 replies; 15+ messages in thread
From: Arun Sharma @ 2004-04-12 18:55 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-arch

On 4/8/2004 1:22 AM, Arnd Bergmann wrote:

> On Wednesday 07 April 2004 22:46, you wrote:
>  > While your patches improved compatibility with respect to LSB/LTP,
>  > we saw the following regressions on LTP on ia64:
>  >
>  > recv01      PASS->BROK
>  > recvmsg01    PASS->BROK
>  > recvfrom01    PASS->BROK
>  >
>  > While we're looking into it, did others see this ?
>  > Is it fixed already ?
> 
> Did you apply the patch I sent in the followup mail? It looks
> like you ran into the problem. Here it is again in case you
> missed it.

Yes, that fixed it. Thanks!

	-Arun

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

* Re: [PATCH 2/4] Consolidate do_execve32
  2004-04-04  0:22 ` [PATCH 2/4] Consolidate do_execve32 Arnd Bergmann
@ 2004-04-13 18:45   ` Arun Sharma
  0 siblings, 0 replies; 15+ messages in thread
From: Arun Sharma @ 2004-04-13 18:45 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linux-arch

[-- Attachment #1: Type: text/plain, Size: 413 bytes --]

On 4/3/2004 4:22 PM, Arnd Bergmann wrote:

> The code for sys32_execve/do_execve32 in most of the seven versions
> was copied from fs/exec.c but not kept up-to-date. The new
> compat_do_execve() function is based on the mips code and has been
> resync'ed with do_execve().
> 
> IA64 has some special fixup code in sys32_execve, so I'm not touching
> that.
> 

Attached is a patch that takes care of ia64.

	-Arun

[-- Attachment #2: compat_execve_ive.patch --]
[-- Type: text/plain, Size: 3104 bytes --]

diff -purN -X dontdiff linux-2.6.5-compat4/arch/ia64/ia32/sys_ia32.c linux-2.6.5-compat/arch/ia64/ia32/sys_ia32.c
--- linux-2.6.5-compat4/arch/ia64/ia32/sys_ia32.c	2004-04-06 09:54:19.000000000 +0800
+++ linux-2.6.5-compat/arch/ia64/ia32/sys_ia32.c	2004-04-08 15:33:24.000000000 +0800
@@ -90,58 +90,17 @@ extern unsigned long arch_get_unmapped_a
 /* XXX make per-mm: */
 static DECLARE_MUTEX(ia32_mmap_sem);
 
-static int
-nargs (unsigned int arg, char **ap)
-{
-	unsigned int addr;
-	int n, err;
-
-	if (!arg)
-		return 0;
-
-	n = 0;
-	do {
-		err = get_user(addr, (unsigned int *)A(arg));
-		if (err)
-			return err;
-		if (ap)
-			*ap++ = (char *) A(addr);
-		arg += sizeof(unsigned int);
-		n++;
-	} while (addr);
-	return n - 1;
-}
-
 asmlinkage long
-sys32_execve (char *filename, unsigned int argv, unsigned int envp,
-	      struct pt_regs *regs)
+sys32_execve (char *name, compat_uptr_t __user *argv, compat_uptr_t __user *envp, struct pt_regs *regs)
 {
+	long error;
+	char *filename;
 	unsigned long old_map_base, old_task_size, tssd;
-	char **av, **ae;
-	int na, ne, len;
-	long r;
-
-	na = nargs(argv, NULL);
-	if (na < 0)
-		return na;
-	ne = nargs(envp, NULL);
-	if (ne < 0)
-		return ne;
-	len = (na + ne + 2) * sizeof(*av);
-	av = kmalloc(len, GFP_KERNEL);
-	if (!av)
-		return -ENOMEM;
-
-	ae = av + na + 1;
-	av[na] = NULL;
-	ae[ne] = NULL;
 
-	r = nargs(argv, av);
-	if (r < 0)
-		goto out;
-	r = nargs(envp, ae);
-	if (r < 0)
-		goto out;
+	filename = getname(name);
+	error = PTR_ERR(filename);
+	if (IS_ERR(filename))
+		return error;
 
 	old_map_base  = current->thread.map_base;
 	old_task_size = current->thread.task_size;
@@ -152,20 +111,19 @@ sys32_execve (char *filename, unsigned i
 	current->thread.task_size = DEFAULT_TASK_SIZE;
 	ia64_set_kr(IA64_KR_IO_BASE, current->thread.old_iob);
 	ia64_set_kr(IA64_KR_TSSD, current->thread.old_k1);
+
+	error = compat_do_execve(filename, argv, envp, regs);
+	putname(filename);
 
-	set_fs(KERNEL_DS);
-	r = sys_execve(filename, av, ae, regs);
-	if (r < 0) {
+	if (error < 0) {
 		/* oops, execve failed, switch back to old values... */
 		ia64_set_kr(IA64_KR_IO_BASE, IA32_IOBASE);
 		ia64_set_kr(IA64_KR_TSSD, tssd);
 		current->thread.map_base  = old_map_base;
 		current->thread.task_size = old_task_size;
-		set_fs(USER_DS);	/* establish new task-size as the address-limit */
 	}
-  out:
-	kfree(av);
-	return r;
+
+	return error;
 }
 
 int cp_compat_stat(struct kstat *stat, struct compat_stat *ubuf)
diff -purN -X dontdiff linux-2.6.5-compat4/fs/compat.c linux-2.6.5-compat/fs/compat.c
--- linux-2.6.5-compat4/fs/compat.c	2004-04-06 09:54:19.000000000 +0800
+++ linux-2.6.5-compat/fs/compat.c	2004-04-08 18:21:51.000000000 +0800
@@ -981,7 +981,6 @@ out:
 	return ret;
 }
 
-#ifndef __ia64__ /* ia64 needs some extra tweaks */
 /*
  * compat_count() counts the number of arguments/envelopes. It is basically
  * a copy of count() from fs/exec.c, except that it works with 32 bit argv
@@ -1212,7 +1211,6 @@ out_file:
 
 	return retval;
 }
-#endif /* !__ia64__ */
 
 #define __COMPAT_NFDBITS       (8 * sizeof(compat_ulong_t))
 

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

end of thread, other threads:[~2004-04-13 18:46 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <200404040204.03594.arnd@arndb.de>
2004-04-04  0:22 ` [PATCH 1/4] Consolidate sys32_readv and sys32_writev Arnd Bergmann
2004-04-04  0:22 ` [PATCH 2/4] Consolidate do_execve32 Arnd Bergmann
2004-04-13 18:45   ` Arun Sharma
2004-04-04  0:22 ` [PATCH 3/4] Consolidate sys32_select Arnd Bergmann
2004-04-04 10:24   ` Andi Kleen
2004-04-04 10:36     ` Arnd Bergmann
2004-04-04 11:04       ` Andi Kleen
2004-04-04 11:07     ` William Lee Irwin III
2004-04-04 22:51       ` Arnd Bergmann
2004-04-04 23:35         ` Andi Kleen
2004-04-04 23:41           ` Arnd Bergmann
2004-04-07 20:46   ` Arun Sharma
2004-04-08  8:22     ` Arnd Bergmann
2004-04-12 18:55       ` Arun Sharma
2004-04-04  0:22 ` [PATCH 4/4] Consolidate sys32_nfsservctl Arnd Bergmann

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox