[Pvfs2-cvs] commit by slang in pvfs2/patches/posix-ext: SERIES
posix-direntplus-lite.patch posix-direntplus.patch
posix-extensions-cvs.patch posix-readwritex.patch
posix-statlite-fix.patch posix-statlite-x86_64.patch
posix-statlite.patch
CVS commit program
cvs at parl.clemson.edu
Mon Jan 7 17:27:26 EST 2008
Update of /projects/cvsroot/pvfs2/patches/posix-ext
In directory parlweb1:/tmp/cvs-serv26113/posix-ext
Added Files:
SERIES posix-direntplus-lite.patch posix-direntplus.patch
posix-extensions-cvs.patch posix-readwritex.patch
posix-statlite-fix.patch posix-statlite-x86_64.patch
posix-statlite.patch
Log Message:
Added Dean's cleaned up pNFS patches for PVFS to the patches directory, along with a brief description of each. Thanks Dean! Moved the posix extensions patches to a subdir.
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ SERIES 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,24 @@
+Apply the patches to a vanilla 2.6.16 kernel in the following order
+
+a) posix-extensions-cvs.patch : This implements the sys call stubs for
+ openg/openfh and the VFS hooks for file system specific implementations.
+
+b) posix-statlite.patch : This implements the sys call stubs for the statlite()
+ family of system calls and the VFS hooks for file system specific
+ implementations.
+
+c) posix-statlite-x86_64.patch : Bug fix/build fix patch for the x86-64 machine.
+
+d) posix-direntplus.patch: This implements the sys call stubs for the
+ readdir_plus() family of system calls and the corresponding VFS hooks for FS
+ specific implementations.
+
+e) posix-readwritex.patch: Implements the sys call stubs for the readx/writex
+ family of system calls and the corresponding VFS hooks for FS specific
+ implementations.
+
+f) posix-statlite-fix.patch: Bug fix for the statlite system call.
+
+g) posix-direntplus-lite.patch: Implements the syscall stubs for the
+ readdir_plus_lite() family of system calls and the corresponding VFS hooks
+ for FS specific implementations.
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ posix-direntplus-lite.patch 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,441 @@
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/i386/kernel/syscall_table.S vanilla-new/arch/i386/kernel/syscall_table.S
+--- vanilla/arch/i386/kernel/syscall_table.S 2006-08-29 17:56:17.000000000 -0500
++++ vanilla-new/arch/i386/kernel/syscall_table.S 2006-09-04 05:03:44.000000000 -0500
+@@ -322,3 +322,5 @@
+ .long sys_getdents64_plus /* 320 */
+ .long sys_readx
+ .long sys_writex
++ .long sys_getdents_plus_lite
++ .long sys_getdents64_plus_lite
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/readdir.c vanilla-new/fs/readdir.c
+--- vanilla/fs/readdir.c 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/fs/readdir.c 2006-09-04 04:49:14.000000000 -0500
+@@ -69,6 +69,33 @@
+
+ EXPORT_SYMBOL_GPL(vfs_readdirplus);
+
++int vfs_readdirplus_lite(struct file *file, unsigned long lite_mask,
++ filldirpluslite_t fillerpluslite, void *buf)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ int res = -ENOTDIR;
++ if (!file->f_op || !file->f_op->readdirplus_lite)
++ goto out;
++
++ res = security_file_permission(file, MAY_READ);
++ if (res)
++ goto out;
++
++ mutex_lock(&inode->i_mutex);
++ res = -ENOENT;
++ if (!IS_DEADDIR(inode)) {
++ res = file->f_op->readdirplus_lite(file, lite_mask, buf, fillerpluslite);
++ file_accessed(file);
++ }
++ mutex_unlock(&inode->i_mutex);
++out:
++ if (file->f_op && file->f_op->readdir && !file->f_op->readdirplus_lite)
++ res = -EOPNOTSUPP;
++ return res;
++}
++
++EXPORT_SYMBOL_GPL(vfs_readdirplus_lite);
++
+ /*
+ * Traditional linux readdir() handling..
+ *
+@@ -343,6 +370,112 @@
+ return error;
+ }
+
++/* getdents_plus_lite implementation */
++#define DIRENT_OFFSET(de) ((unsigned long) &((de)->dp_dirent) - (unsigned long) (char __user *) (de))
++
++struct linux_dirent_plus_lite {
++ struct stat_lite dp_stat_lite;
++ int dp_stat_lite_err;
++ struct linux_dirent dp_dirent;
++};
++
++struct getdentspluslite_callback {
++ struct linux_dirent_plus_lite __user * current_dir;
++ struct linux_dirent_plus_lite __user * previous;
++ int count;
++ int error;
++};
++
++static int filldirpluslite(void * __buf, const char * name, int namlen, loff_t offset,
++ ino_t ino, unsigned int d_type, struct kstat_lite *statp)
++{
++ struct linux_dirent __user *de;
++ struct linux_dirent_plus_lite __user * dirent;
++ struct getdentspluslite_callback * buf = (struct getdentspluslite_callback *) __buf;
++ int err, reclen = ROUND_UP(NAME_OFFSET(de) + namlen + DIRENT_OFFSET(dirent) + 2);
++
++ buf->error = -EINVAL; /* only used if we fail.. */
++ if (reclen > buf->count)
++ return -EINVAL;
++ dirent = buf->previous;
++ if (dirent) {
++ if (__put_user(offset, &dirent->dp_dirent.d_off))
++ goto efault;
++ }
++ dirent = buf->current_dir;
++ err = 0;
++ if (IS_ERR(statp)) {
++ err = PTR_ERR(statp);
++ if (__put_user(err, &dirent->dp_stat_lite_err))
++ goto efault;
++ }
++ else {
++ if (__put_user(err, &dirent->dp_stat_lite_err))
++ goto efault;
++ if (cp_new_statlite(statp, &dirent->dp_stat_lite))
++ goto efault;
++ }
++ if (__put_user(ino, &dirent->dp_dirent.d_ino))
++ goto efault;
++ if (__put_user(reclen, &dirent->dp_dirent.d_reclen))
++ goto efault;
++ if (copy_to_user(dirent->dp_dirent.d_name, name, namlen))
++ goto efault;
++ if (__put_user(0, dirent->dp_dirent.d_name + namlen))
++ goto efault;
++ if (__put_user(d_type, (char __user *) dirent + reclen - 1))
++ goto efault;
++ buf->previous = dirent;
++ dirent = (void __user *)dirent + reclen;
++ buf->current_dir = dirent;
++ buf->count -= reclen;
++ return 0;
++efault:
++ buf->error = -EFAULT;
++ return -EFAULT;
++}
++
++asmlinkage long sys_getdents_plus_lite(unsigned int fd, unsigned long lite_mask,
++ struct linux_dirent_plus_lite __user * dirent, unsigned int count)
++{
++ struct file * file;
++ struct linux_dirent_plus_lite __user * lastdirent;
++ struct getdentspluslite_callback buf;
++ int error;
++
++ error = -EFAULT;
++ if (!access_ok(VERIFY_WRITE, dirent, count))
++ goto out;
++
++ error = -EBADF;
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ buf.current_dir = dirent;
++ buf.previous = NULL;
++ buf.count = count;
++ buf.error = 0;
++
++ error = vfs_readdirplus_lite(file, lite_mask, filldirpluslite, &buf);
++ if (error < 0)
++ goto out_putf;
++ error = buf.error;
++ lastdirent = buf.previous;
++ if (lastdirent) {
++ typeof(lastdirent->dp_dirent.d_off) d_off = file->f_pos;
++ error = -EFAULT;
++ if (__put_user(d_off, &lastdirent->dp_dirent.d_off))
++ goto out_putf;
++ error = count - buf.count;
++ }
++
++out_putf:
++ fput(file);
++out:
++ return error;
++}
++
+ #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
+
+ struct getdents_callback64 {
+@@ -531,3 +664,106 @@
+ out:
+ return error;
+ }
++
++struct getdentspluslite_callback64 {
++ struct linux_dirent64_plus_lite __user * current_dir;
++ struct linux_dirent64_plus_lite __user * previous;
++ int count;
++ int error;
++};
++
++static int filldir64_plus_lite(void * __buf, const char * name, int namlen, loff_t offset,
++ ino_t ino, unsigned int d_type, struct kstat_lite *statp)
++{
++ struct linux_dirent64 __user *de;
++ struct linux_dirent64_plus_lite __user *dirent;
++ struct getdentspluslite_callback64 * buf = (struct getdentspluslite_callback64 *) __buf;
++ int err, reclen = ROUND_UP64(NAME_OFFSET(de) + namlen + 1 + DIRENT_OFFSET(dirent));
++
++ buf->error = -EINVAL; /* only used if we fail.. */
++ if (reclen > buf->count)
++ return -EINVAL;
++ dirent = buf->previous;
++ if (dirent) {
++ if (__put_user(offset, &dirent->dp_dirent.d_off))
++ goto efault;
++ }
++ dirent = buf->current_dir;
++ err = 0;
++ if (IS_ERR(statp)) {
++ err = PTR_ERR(statp);
++ if (__put_user(err, &dirent->dp_stat_lite_err))
++ goto efault;
++ }
++ else {
++ if (__put_user(err, &dirent->dp_stat_lite_err))
++ goto efault;
++#ifdef __ARCH_WANT_STAT64
++ if (cp_new_stat64_lite(statp, &dirent->dp_stat_lite))
++#else
++ if (cp_new_statlite(statp, &dirent->dp_stat_lite))
++#endif
++ goto efault;
++ }
++ if (__put_user(ino, &dirent->dp_dirent.d_ino))
++ goto efault;
++ if (__put_user(0, &dirent->dp_dirent.d_off))
++ goto efault;
++ if (__put_user(reclen, &dirent->dp_dirent.d_reclen))
++ goto efault;
++ if (__put_user(d_type, &dirent->dp_dirent.d_type))
++ goto efault;
++ if (copy_to_user(dirent->dp_dirent.d_name, name, namlen))
++ goto efault;
++ if (__put_user(0, dirent->dp_dirent.d_name + namlen))
++ goto efault;
++ buf->previous = dirent;
++ dirent = (void __user *)dirent + reclen;
++ buf->current_dir = dirent;
++ buf->count -= reclen;
++ return 0;
++efault:
++ buf->error = -EFAULT;
++ return -EFAULT;
++}
++
++asmlinkage long sys_getdents64_plus_lite(unsigned int fd, unsigned long lite_mask,
++ struct linux_dirent64_plus_lite __user * dirent, unsigned int count)
++{
++ struct file * file;
++ struct linux_dirent64_plus_lite __user * lastdirent;
++ struct getdentspluslite_callback64 buf;
++ int error;
++
++ error = -EFAULT;
++ if (!access_ok(VERIFY_WRITE, dirent, count))
++ goto out;
++
++ error = -EBADF;
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ buf.current_dir = dirent;
++ buf.previous = NULL;
++ buf.count = count;
++ buf.error = 0;
++
++ error = vfs_readdirplus_lite(file, lite_mask, filldir64_plus_lite, &buf);
++ if (error < 0)
++ goto out_putf;
++ error = buf.error;
++ lastdirent = buf.previous;
++ if (lastdirent) {
++ typeof(lastdirent->dp_dirent.d_off) d_off = file->f_pos;
++ error = -EFAULT;
++ if (__put_user(d_off, &lastdirent->dp_dirent.d_off))
++ goto out_putf;
++ error = count - buf.count;
++ }
++
++out_putf:
++ fput(file);
++out:
++ return error;
++}
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/dirent.h vanilla-new/include/asm-i386/dirent.h
+--- vanilla/include/asm-i386/dirent.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/asm-i386/dirent.h 2006-09-04 04:59:36.000000000 -0500
+@@ -9,12 +9,24 @@
+ struct dirent dp_dirent;
+ };
+
++struct dirent_plus_lite {
++ struct stat_lite dp_stat_lite;
++ int dp_stat_lite_err;
++ struct dirent dp_dirent;
++};
++
+ struct dirent64_plus {
+ struct stat64 dp_stat;
+ int dp_stat_err;
+ struct dirent64 dp_dirent;
+ };
+
++struct dirent64_plus_lite {
++ struct stat64_lite dp_stat_lite;
++ int dp_stat_lite_err;
++ struct dirent64 dp_dirent;
++};
++
+ #ifdef __KERNEL__
+
+ struct linux_dirent64_plus {
+@@ -23,6 +35,12 @@
+ struct linux_dirent64 dp_dirent;
+ };
+
++struct linux_dirent64_plus_lite {
++ struct stat64_lite dp_stat_lite;
++ int dp_stat_lite_err;
++ struct linux_dirent64 dp_dirent;
++};
++
+ #endif
+
+ #endif
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/unistd.h vanilla-new/include/asm-i386/unistd.h
+--- vanilla/include/asm-i386/unistd.h 2006-08-29 17:56:17.000000000 -0500
++++ vanilla-new/include/asm-i386/unistd.h 2006-09-04 05:04:09.000000000 -0500
+@@ -328,8 +328,10 @@
+ #define __NR_getdents64_plus 320
+ #define __NR_readx 321
+ #define __NR_writex 322
++#define __NR_getdents_plus_lite 323
++#define __NR_getdents64_plus_lite 324
+
+-#define NR_syscalls 323
++#define NR_syscalls 325
+
+ /*
+ * user-visible error numbers are in the range -1 - -128: see
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/dirent.h vanilla-new/include/asm-x86_64/dirent.h
+--- vanilla/include/asm-x86_64/dirent.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/asm-x86_64/dirent.h 2006-09-04 04:57:56.000000000 -0500
+@@ -9,12 +9,24 @@
+ struct dirent dp_dirent;
+ };
+
++struct dirent_plus_lite {
++ struct stat_lite dp_stat_lite;
++ int dp_stat_lite_err;
++ struct dirent dp_dirent;
++};
++
+ struct dirent64_plus {
+ struct stat dp_stat;
+ int dp_stat_err;
+ struct dirent64 dp_dirent;
+ };
+
++struct dirent64_plus_lite {
++ struct stat_lite dp_stat_lite;
++ int dp_stat_lite_err;
++ struct dirent64 dp_dirent;
++};
++
+ #ifdef __KERNEL__
+
+ struct linux_dirent64_plus {
+@@ -23,6 +35,12 @@
+ struct linux_dirent64 dp_dirent;
+ };
+
++struct linux_dirent64_plus_lite {
++ struct stat_lite dp_stat_lite;
++ int dp_stat_lite_err;
++ struct linux_dirent64 dp_dirent;
++};
++
+ #endif
+
+ #endif
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/unistd.h vanilla-new/include/asm-x86_64/unistd.h
+--- vanilla/include/asm-x86_64/unistd.h 2006-08-29 17:56:17.000000000 -0500
++++ vanilla-new/include/asm-x86_64/unistd.h 2006-09-04 05:04:44.000000000 -0500
+@@ -623,8 +623,12 @@
+ __SYSCALL(__NR_readx, sys_readx)
+ #define __NR_writex 281
+ __SYSCALL(__NR_writex, sys_writex)
++#define __NR_getdents_plus_lite 282
++__SYSCALL(__NR_getdents_plus_lite, sys_getdents_plus_lite)
++#define __NR_getdents64_plus_lite 283
++__SYSCALL(__NR_getdents64_plus_lite, sys_getdents64_plus_lite)
+
+-#define __NR_syscall_max __NR_writex
++#define __NR_syscall_max __NR_getdents64_plus_lite
+
+ #ifndef __NO_STUBS
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/fs.h vanilla-new/include/linux/fs.h
+--- vanilla/include/linux/fs.h 2006-08-29 17:56:17.000000000 -0500
++++ vanilla-new/include/linux/fs.h 2006-09-04 04:55:48.000000000 -0500
+@@ -957,6 +957,13 @@
+ */
+ typedef int (*filldirplus_t)(void *, const char *, int, loff_t, ino_t, unsigned, struct kstat *);
+
++/*
++ * This is the "filldirplus_lite function type, used by readdirplus_lite() to let
++ * the kernel specify the kind of dirent layout and the stat_lite information
++ * all in one shot
++ */
++typedef int (*filldirpluslite_t)(void *, const char *, int, loff_t, ino_t, unsigned, struct kstat_lite *);
++
+ struct block_device_operations {
+ int (*open) (struct inode *, struct file *);
+ int (*release) (struct inode *, struct file *);
+@@ -1032,6 +1039,7 @@
+ ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
+ int (*readdir) (struct file *, void *, filldir_t);
+ int (*readdirplus) (struct file *, void *, filldirplus_t);
++ int (*readdirplus_lite) (struct file *, unsigned long, void *, filldirpluslite_t);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+ long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+@@ -1728,6 +1736,7 @@
+
+ extern int vfs_readdir(struct file *, filldir_t, void *);
+ extern int vfs_readdirplus(struct file *, filldirplus_t, void *);
++extern int vfs_readdirplus_lite(struct file *file, unsigned long, filldirpluslite_t fillerpluslite, void *buf);
+ extern int cp_new_stat(struct kstat *stat, struct stat __user *statbuf);
+ extern int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf);
+ #ifdef __ARCH_WANT_STAT64
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/syscalls.h vanilla-new/include/linux/syscalls.h
+--- vanilla/include/linux/syscalls.h 2006-08-29 17:56:17.000000000 -0500
++++ vanilla-new/include/linux/syscalls.h 2006-09-04 05:00:20.000000000 -0500
+@@ -25,6 +25,8 @@
+ struct linux_dirent64;
+ struct linux_dirent_plus;
+ struct linux_dirent64_plus;
++struct linux_dirent_plus_lite;
++struct linux_dirent64_plus_lite;
+ struct list_head;
+ struct msgbuf;
+ struct msghdr;
+@@ -434,9 +436,15 @@
+ asmlinkage long sys_getdents_plus(unsigned int fd,
+ struct linux_dirent_plus __user *dirent,
+ unsigned int count);
++asmlinkage long sys_getdents_plus_lite(unsigned int fd, unsigned long lite_mask,
++ struct linux_dirent_plus_lite __user *dirent,
++ unsigned int count);
+ asmlinkage long sys_getdents64_plus(unsigned int fd,
+ struct linux_dirent64_plus __user *dirent,
+ unsigned int count);
++asmlinkage long sys_getdents64_plus_lite(unsigned int fd, unsigned long lite_mask,
++ struct linux_dirent64_plus_lite __user *dirent,
++ unsigned int count);
+
+ asmlinkage long sys_setsockopt(int fd, int level, int optname,
+ char __user *optval, int optlen);
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ posix-direntplus.patch 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,555 @@
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/i386/kernel/syscall_table.S vanilla-new/arch/i386/kernel/syscall_table.S
+--- vanilla/arch/i386/kernel/syscall_table.S 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/arch/i386/kernel/syscall_table.S 2006-05-11 14:03:04.000000000 -0500
+@@ -314,7 +314,9 @@
+ .long sys_openfh
+ .long sys_newstatlite
+ .long sys_newlstatlite
+- .long sys_newfstatlite
++ .long sys_newfstatlite /* 315 */
+ .long sys_statlite64
+ .long sys_lstatlite64
+ .long sys_fstatlite64
++ .long sys_getdents_plus
++ .long sys_getdents64_plus /* 320 */
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/ia64/kernel/entry.S vanilla-new/arch/ia64/kernel/entry.S
+--- vanilla/arch/ia64/kernel/entry.S 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/arch/ia64/kernel/entry.S 2006-05-11 14:10:30.000000000 -0500
+@@ -1624,5 +1624,7 @@
+ data8 sys_newstatlite
+ data8 sys_newlstatlite
+ data8 sys_newfstatlite
++ data8 sys_getdents_plus
++ data8 sys_getdents64_plus
+
+ .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/powerpc/kernel/systbl.S vanilla-new/arch/powerpc/kernel/systbl.S
+--- vanilla/arch/powerpc/kernel/systbl.S 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/arch/powerpc/kernel/systbl.S 2006-05-11 14:12:20.000000000 -0500
+@@ -327,3 +327,5 @@
+ SYSCALL(newstatlite)
+ SYSCALL(newlstatlite)
+ SYSCALL(newfstatlite)
++SYSCALL(sys_getdents_plus)
++SYSCALL(sys_getdents64_plus)
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/ia32entry.S vanilla-new/arch/x86_64/ia32/ia32entry.S
+--- vanilla/arch/x86_64/ia32/ia32entry.S 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/arch/x86_64/ia32/ia32entry.S 2006-05-11 14:09:30.000000000 -0500
+@@ -696,6 +696,8 @@
+ .quad sys32_statlite64
+ .quad sys32_lstatlite64
+ .quad sys32_fstatlite64
++ .quad sys_ni_syscall /* getdents_plus */
++ .quad sys_ni_syscall /* getdents64_plus */
+ ia32_syscall_end:
+ .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
+ .quad ni_syscall
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/readdir.c vanilla-new/fs/readdir.c
+--- vanilla/fs/readdir.c 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/fs/readdir.c 2006-05-18 19:25:06.000000000 -0500
+@@ -43,6 +43,32 @@
+
+ EXPORT_SYMBOL(vfs_readdir);
+
++int vfs_readdirplus(struct file *file, filldirplus_t fillerplus, void *buf)
++{
++ struct inode *inode = file->f_dentry->d_inode;
++ int res = -ENOTDIR;
++ if (!file->f_op || !file->f_op->readdirplus)
++ goto out;
++
++ res = security_file_permission(file, MAY_READ);
++ if (res)
++ goto out;
++
++ mutex_lock(&inode->i_mutex);
++ res = -ENOENT;
++ if (!IS_DEADDIR(inode)) {
++ res = file->f_op->readdirplus(file, buf, fillerplus);
++ file_accessed(file);
++ }
++ mutex_unlock(&inode->i_mutex);
++out:
++ if (file->f_op && file->f_op->readdir && !file->f_op->readdirplus)
++ res = -EOPNOTSUPP;
++ return res;
++}
++
++EXPORT_SYMBOL_GPL(vfs_readdirplus);
++
+ /*
+ * Traditional linux readdir() handling..
+ *
+@@ -212,6 +238,111 @@
+ return error;
+ }
+
++/* getdents_plus implementation */
++#define DIRENT_OFFSET(de) ((unsigned long) &((de)->dp_dirent) - (unsigned long) (char __user *) (de))
++
++struct linux_dirent_plus {
++ struct stat dp_stat;
++ int dp_stat_err;
++ struct linux_dirent dp_dirent;
++};
++
++struct getdentsplus_callback {
++ struct linux_dirent_plus __user * current_dir;
++ struct linux_dirent_plus __user * previous;
++ int count;
++ int error;
++};
++
++static int filldirplus(void * __buf, const char * name, int namlen, loff_t offset,
++ ino_t ino, unsigned int d_type, struct kstat *statp)
++{
++ struct linux_dirent __user *de;
++ struct linux_dirent_plus __user * dirent;
++ struct getdentsplus_callback * buf = (struct getdentsplus_callback *) __buf;
++ int err, reclen = ROUND_UP(NAME_OFFSET(de) + namlen + DIRENT_OFFSET(dirent) + 2);
++
++ buf->error = -EINVAL; /* only used if we fail.. */
++ if (reclen > buf->count)
++ return -EINVAL;
++ dirent = buf->previous;
++ if (dirent) {
++ if (__put_user(offset, &dirent->dp_dirent.d_off))
++ goto efault;
++ }
++ dirent = buf->current_dir;
++ err = 0;
++ if (IS_ERR(statp)) {
++ err = PTR_ERR(statp);
++ if (__put_user(err, &dirent->dp_stat_err))
++ goto efault;
++ }
++ else {
++ if (__put_user(err, &dirent->dp_stat_err))
++ goto efault;
++ if (cp_new_stat(statp, &dirent->dp_stat))
++ goto efault;
++ }
++ if (__put_user(ino, &dirent->dp_dirent.d_ino))
++ goto efault;
++ if (__put_user(reclen, &dirent->dp_dirent.d_reclen))
++ goto efault;
++ if (copy_to_user(dirent->dp_dirent.d_name, name, namlen))
++ goto efault;
++ if (__put_user(0, dirent->dp_dirent.d_name + namlen))
++ goto efault;
++ if (__put_user(d_type, (char __user *) dirent + reclen - 1))
++ goto efault;
++ buf->previous = dirent;
++ dirent = (void __user *)dirent + reclen;
++ buf->current_dir = dirent;
++ buf->count -= reclen;
++ return 0;
++efault:
++ buf->error = -EFAULT;
++ return -EFAULT;
++}
++
++asmlinkage long sys_getdents_plus(unsigned int fd, struct linux_dirent_plus __user * dirent, unsigned int count)
++{
++ struct file * file;
++ struct linux_dirent_plus __user * lastdirent;
++ struct getdentsplus_callback buf;
++ int error;
++
++ error = -EFAULT;
++ if (!access_ok(VERIFY_WRITE, dirent, count))
++ goto out;
++
++ error = -EBADF;
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ buf.current_dir = dirent;
++ buf.previous = NULL;
++ buf.count = count;
++ buf.error = 0;
++
++ error = vfs_readdirplus(file, filldirplus, &buf);
++ if (error < 0)
++ goto out_putf;
++ error = buf.error;
++ lastdirent = buf.previous;
++ if (lastdirent) {
++ typeof(lastdirent->dp_dirent.d_off) d_off = file->f_pos;
++ error = -EFAULT;
++ if (__put_user(d_off, &lastdirent->dp_dirent.d_off))
++ goto out_putf;
++ error = count - buf.count;
++ }
++
++out_putf:
++ fput(file);
++out:
++ return error;
++}
++
+ #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
+
+ struct getdents_callback64 {
+@@ -298,3 +429,105 @@
+ out:
+ return error;
+ }
++
++struct getdentsplus_callback64 {
++ struct linux_dirent64_plus __user * current_dir;
++ struct linux_dirent64_plus __user * previous;
++ int count;
++ int error;
++};
++
++static int filldir64_plus(void * __buf, const char * name, int namlen, loff_t offset,
++ ino_t ino, unsigned int d_type, struct kstat *statp)
++{
++ struct linux_dirent64 __user *de;
++ struct linux_dirent64_plus __user *dirent;
++ struct getdentsplus_callback64 * buf = (struct getdentsplus_callback64 *) __buf;
++ int err, reclen = ROUND_UP64(NAME_OFFSET(de) + namlen + 1 + DIRENT_OFFSET(dirent));
++
++ buf->error = -EINVAL; /* only used if we fail.. */
++ if (reclen > buf->count)
++ return -EINVAL;
++ dirent = buf->previous;
++ if (dirent) {
++ if (__put_user(offset, &dirent->dp_dirent.d_off))
++ goto efault;
++ }
++ dirent = buf->current_dir;
++ err = 0;
++ if (IS_ERR(statp)) {
++ err = PTR_ERR(statp);
++ if (__put_user(err, &dirent->dp_stat_err))
++ goto efault;
++ }
++ else {
++ if (__put_user(err, &dirent->dp_stat_err))
++ goto efault;
++#ifdef __ARCH_WANT_STAT64
++ if (cp_new_stat64(statp, &dirent->dp_stat))
++#else
++ if (cp_new_stat(statp, &dirent->dp_stat))
++#endif
++ goto efault;
++ }
++ if (__put_user(ino, &dirent->dp_dirent.d_ino))
++ goto efault;
++ if (__put_user(0, &dirent->dp_dirent.d_off))
++ goto efault;
++ if (__put_user(reclen, &dirent->dp_dirent.d_reclen))
++ goto efault;
++ if (__put_user(d_type, &dirent->dp_dirent.d_type))
++ goto efault;
++ if (copy_to_user(dirent->dp_dirent.d_name, name, namlen))
++ goto efault;
++ if (__put_user(0, dirent->dp_dirent.d_name + namlen))
++ goto efault;
++ buf->previous = dirent;
++ dirent = (void __user *)dirent + reclen;
++ buf->current_dir = dirent;
++ buf->count -= reclen;
++ return 0;
++efault:
++ buf->error = -EFAULT;
++ return -EFAULT;
++}
++
++asmlinkage long sys_getdents64_plus(unsigned int fd, struct linux_dirent64_plus __user * dirent, unsigned int count)
++{
++ struct file * file;
++ struct linux_dirent64_plus __user * lastdirent;
++ struct getdentsplus_callback64 buf;
++ int error;
++
++ error = -EFAULT;
++ if (!access_ok(VERIFY_WRITE, dirent, count))
++ goto out;
++
++ error = -EBADF;
++ file = fget(fd);
++ if (!file)
++ goto out;
++
++ buf.current_dir = dirent;
++ buf.previous = NULL;
++ buf.count = count;
++ buf.error = 0;
++
++ error = vfs_readdirplus(file, filldir64_plus, &buf);
++ if (error < 0)
++ goto out_putf;
++ error = buf.error;
++ lastdirent = buf.previous;
++ if (lastdirent) {
++ typeof(lastdirent->dp_dirent.d_off) d_off = file->f_pos;
++ error = -EFAULT;
++ if (__put_user(d_off, &lastdirent->dp_dirent.d_off))
++ goto out_putf;
++ error = count - buf.count;
++ }
++
++out_putf:
++ fput(file);
++out:
++ return error;
++}
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/stat.c vanilla-new/fs/stat.c
+--- vanilla/fs/stat.c 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/fs/stat.c 2006-05-11 13:35:08.000000000 -0500
+@@ -297,7 +297,7 @@
+
+ #endif /* __ARCH_WANT_OLD_STAT */
+
+-static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
++int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
+ {
+ struct stat tmp;
+
+@@ -345,7 +345,7 @@
+ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+ }
+
+-static int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf)
++int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf)
+ {
+ struct stat_lite tmp;
+
+@@ -545,7 +545,7 @@
+ /* ---------- LFS-64 ----------- */
+ #ifdef __ARCH_WANT_STAT64
+
+-static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
++long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
+ {
+ struct stat64 tmp;
+
+@@ -580,7 +580,7 @@
+ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+ }
+
+-static long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf)
++long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf)
+ {
+ struct stat64_lite tmp;
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/dirent.h vanilla-new/include/asm-i386/dirent.h
+--- vanilla/include/asm-i386/dirent.h 1969-12-31 18:00:00.000000000 -0600
++++ vanilla-new/include/asm-i386/dirent.h 2006-05-18 19:25:26.000000000 -0500
+@@ -0,0 +1,28 @@
++#ifndef _I386_DIRENT_H
++#define _I386_DIRENT_H
++
++#include <asm/stat.h>
++
++struct dirent_plus {
++ struct stat dp_stat;
++ int dp_stat_err;
++ struct dirent dp_dirent;
++};
++
++struct dirent64_plus {
++ struct stat64 dp_stat;
++ int dp_stat_err;
++ struct dirent64 dp_dirent;
++};
++
++#ifdef __KERNEL__
++
++struct linux_dirent64_plus {
++ struct stat64 dp_stat;
++ int dp_stat_err;
++ struct linux_dirent64 dp_dirent;
++};
++
++#endif
++
++#endif
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/unistd.h vanilla-new/include/asm-i386/unistd.h
+--- vanilla/include/asm-i386/unistd.h 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/include/asm-i386/unistd.h 2006-05-11 14:00:29.000000000 -0500
+@@ -324,8 +324,10 @@
+ #define __NR_statlite64 316
+ #define __NR_lstatlite64 317
+ #define __NR_fstatlite64 318
++#define __NR_getdents_plus 319
++#define __NR_getdents64_plus 320
+
+-#define NR_syscalls 319
++#define NR_syscalls 321
+
+ /*
+ * user-visible error numbers are in the range -1 - -128: see
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-ia64/unistd.h vanilla-new/include/asm-ia64/unistd.h
+--- vanilla/include/asm-ia64/unistd.h 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/include/asm-ia64/unistd.h 2006-05-11 14:05:50.000000000 -0500
+@@ -290,12 +290,14 @@
+ #define __NR_statlite 1299
+ #define __NR_lstatlite 1300
+ #define __NR_fstatlite 1301
++#define __NR_getdents_plus 1302
++#define __NR_getdents64_plus 1303
+
+ #ifdef __KERNEL__
+
+ #include <linux/config.h>
+
+-#define NR_syscalls 278 /* length of syscall table */
++#define NR_syscalls 280 /* length of syscall table */
+
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-powerpc/unistd.h vanilla-new/include/asm-powerpc/unistd.h
+--- vanilla/include/asm-powerpc/unistd.h 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/include/asm-powerpc/unistd.h 2006-05-11 14:14:28.000000000 -0500
+@@ -303,8 +303,13 @@
+ #define __NR_unshare 282
+ #define __NR_openg 283
+ #define __NR_openfh 284
++#define __NR_statlite 285
++#define __NR_lstatlite 286
++#define __NR_fstatlite 287
++#define __NR_getdents_plus 288
++#define __NR_getdents64_plus 289
+
+-#define __NR_syscalls 285
++#define __NR_syscalls 290
+
+ #ifdef __KERNEL__
+ #define __NR__exit __NR_exit
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/dirent.h vanilla-new/include/asm-x86_64/dirent.h
+--- vanilla/include/asm-x86_64/dirent.h 1969-12-31 18:00:00.000000000 -0600
++++ vanilla-new/include/asm-x86_64/dirent.h 2006-05-18 19:25:47.000000000 -0500
+@@ -0,0 +1,28 @@
++#ifndef _ASM_X86_64_DIRENT_H
++#define _ASM_X86_64_DIRENT_H
++
++#include <asm/stat.h>
++
++struct dirent_plus {
++ struct stat dp_stat;
++ int dp_stat_err;
++ struct dirent dp_dirent;
++};
++
++struct dirent64_plus {
++ struct stat dp_stat;
++ int dp_stat_err;
++ struct dirent64 dp_dirent;
++};
++
++#ifdef __KERNEL__
++
++struct linux_dirent64_plus {
++ struct stat dp_stat;
++ int dp_stat_err;
++ struct linux_dirent64 dp_dirent;
++};
++
++#endif
++
++#endif
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/unistd.h vanilla-new/include/asm-x86_64/unistd.h
+--- vanilla/include/asm-x86_64/unistd.h 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/include/asm-x86_64/unistd.h 2006-05-11 14:04:27.000000000 -0500
+@@ -615,8 +615,12 @@
+ __SYSCALL(__NR_newlstatlite, sys_newlstatlite)
+ #define __NR_newfstatlite 277
+ __SYSCALL(__NR_newfstatlite, sys_newfstatlite)
++#define __NR_getdents_plus 278
++__SYSCALL(__NR_getdents_plus, sys_getdents_plus)
++#define __NR_getdents64_plus 279
++__SYSCALL(__NR_getdents64_plus, sys_getdents64_plus)
+
+-#define __NR_syscall_max __NR_newfstatlite
++#define __NR_syscall_max __NR_getdents64_plus
+
+ #ifndef __NO_STUBS
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/dirent.h vanilla-new/include/linux/dirent.h
+--- vanilla/include/linux/dirent.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/dirent.h 2006-05-18 19:29:03.000000000 -0500
+@@ -28,5 +28,6 @@
+
+ #endif /* __KERNEL__ */
+
++#include <asm/dirent.h>
+
+ #endif
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/fs.h vanilla-new/include/linux/fs.h
+--- vanilla/include/linux/fs.h 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/include/linux/fs.h 2006-05-18 19:28:16.000000000 -0500
+@@ -9,6 +9,7 @@
+ #include <linux/config.h>
+ #include <linux/limits.h>
+ #include <linux/ioctl.h>
++#include <linux/unistd.h>
+
+ /*
+ * It's silly to have NR_OPEN bigger than NR_FILE, but you can change
+@@ -951,6 +952,13 @@
+ */
+ typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned);
+
++/*
++ * This is the "filldirplus" function type, used by readdirplus() to let
++ * the kernel specify the kind of dirent layout and the stat information
++ * all in one shot
++ */
++typedef int (*filldirplus_t)(void *, const char *, int, loff_t, ino_t, unsigned, struct kstat *);
++
+ struct block_device_operations {
+ int (*open) (struct inode *, struct file *);
+ int (*release) (struct inode *, struct file *);
+@@ -1025,6 +1033,7 @@
+ ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
+ ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
+ int (*readdir) (struct file *, void *, filldir_t);
++ int (*readdirplus) (struct file *, void *, filldirplus_t);
+ unsigned int (*poll) (struct file *, struct poll_table_struct *);
+ int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
+ long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
+@@ -1712,7 +1721,13 @@
+ void inode_set_bytes(struct inode *inode, loff_t bytes);
+
+ extern int vfs_readdir(struct file *, filldir_t, void *);
+-
++extern int vfs_readdirplus(struct file *, filldirplus_t, void *);
++extern int cp_new_stat(struct kstat *stat, struct stat __user *statbuf);
++extern int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf);
++#ifdef __ARCH_WANT_STAT64
++extern long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf);
++extern long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf);
++#endif
+ extern int vfs_stat(char __user *, struct kstat *);
+ extern int vfs_statlite(char __user *, struct kstat_lite *);
+ extern int vfs_lstat(char __user *, struct kstat *);
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/syscalls.h vanilla-new/include/linux/syscalls.h
+--- vanilla/include/linux/syscalls.h 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/include/linux/syscalls.h 2006-05-11 14:01:51.000000000 -0500
+@@ -22,6 +22,8 @@
+ struct kexec_segment;
+ struct linux_dirent;
+ struct linux_dirent64;
++struct linux_dirent_plus;
++struct linux_dirent64_plus;
+ struct list_head;
+ struct msgbuf;
+ struct msghdr;
+@@ -418,6 +420,12 @@
+ asmlinkage long sys_getdents64(unsigned int fd,
+ struct linux_dirent64 __user *dirent,
+ unsigned int count);
++asmlinkage long sys_getdents_plus(unsigned int fd,
++ struct linux_dirent_plus __user *dirent,
++ unsigned int count);
++asmlinkage long sys_getdents64_plus(unsigned int fd,
++ struct linux_dirent64_plus __user *dirent,
++ unsigned int count);
+
+ asmlinkage long sys_setsockopt(int fd, int level, int optname,
+ char __user *optval, int optlen);
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ posix-extensions-cvs.patch 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,1038 @@
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/i386/kernel/syscall_table.S vanilla-new/arch/i386/kernel/syscall_table.S
+--- vanilla/arch/i386/kernel/syscall_table.S 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/arch/i386/kernel/syscall_table.S 2006-04-07 10:28:39.000000000 -0500
+@@ -310,3 +310,5 @@
+ .long sys_pselect6
+ .long sys_ppoll
+ .long sys_unshare /* 310 */
++ .long sys_openg
++ .long sys_openfh
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/ia64/kernel/entry.S vanilla-new/arch/ia64/kernel/entry.S
+--- vanilla/arch/ia64/kernel/entry.S 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/arch/ia64/kernel/entry.S 2006-04-07 10:28:39.000000000 -0500
+@@ -1619,5 +1619,7 @@
+ data8 sys_ni_syscall // reserved for pselect
+ data8 sys_ni_syscall // 1295 reserved for ppoll
+ data8 sys_unshare
++ data8 sys_openg
++ data8 sys_openfh
+
+ .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/powerpc/kernel/systbl.S vanilla-new/arch/powerpc/kernel/systbl.S
+--- vanilla/arch/powerpc/kernel/systbl.S 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/arch/powerpc/kernel/systbl.S 2006-04-07 10:28:39.000000000 -0500
+@@ -322,3 +322,5 @@
+ COMPAT_SYS(pselect6)
+ COMPAT_SYS(ppoll)
+ SYSCALL(unshare)
++SYSCALL(openg)
++SYSCALL(openfh)
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/ia32entry.S vanilla-new/arch/x86_64/ia32/ia32entry.S
+--- vanilla/arch/x86_64/ia32/ia32entry.S 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/arch/x86_64/ia32/ia32entry.S 2006-04-07 10:28:39.000000000 -0500
+@@ -688,6 +688,8 @@
+ .quad sys_ni_syscall /* pselect6 for now */
+ .quad sys_ni_syscall /* ppoll for now */
+ .quad sys_unshare /* 310 */
++ .quad compat_sys_openg
++ .quad compat_sys_openfh
+ ia32_syscall_end:
+ .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
+ .quad ni_syscall
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/compat.c vanilla-new/fs/compat.c
+--- vanilla/fs/compat.c 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/fs/compat.c 2006-04-07 13:39:13.000000000 -0500
+@@ -1332,6 +1332,27 @@
+ }
+
+ /*
++ * Exactly like fs/open.c: sys_openg(), except that it doesn't set the
++ * O_LARGEFILE flag.
++ */
++asmlinkage long
++compat_sys_openg(const char __user *pathname, void __user *uhandle, size_t __user *uhandle_len,
++ int flags, int mode)
++{
++ return do_sys_openg(pathname, uhandle, uhandle_len, flags, mode);
++}
++
++/*
++ * Exactly like fs/open.c: sys_openg(), except that it doesn't set the
++ * O_LARGEFILE flag.
++ */
++asmlinkage long
++compat_sys_openfh(const char __user *uhandle, int uhandle_len)
++{
++ return do_sys_openfh(uhandle, uhandle_len);
++}
++
++/*
+ * 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.
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/open.c vanilla-new/fs/open.c
+--- vanilla/fs/open.c 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/fs/open.c 2006-04-26 22:06:15.000000000 -0500
+@@ -27,9 +27,37 @@
+ #include <linux/pagemap.h>
+ #include <linux/syscalls.h>
+ #include <linux/rcupdate.h>
++#include <linux/scatterlist.h>
++#include <linux/crypto.h>
++#include <linux/types.h>
+
+ #include <asm/unistd.h>
+
++void get_filesystem(struct file_system_type *fs);
++void put_filesystem(struct file_system_type *fs);
++struct file_system_type *get_fs_type(const char *name);
++
++int vfs_statfs_lite(struct super_block *sb, struct kstatfs *buf, int statfs_mask)
++{
++ int retval = -ENODEV;
++
++ if (sb) {
++ retval = -ENOSYS;
++ if (sb->s_op->statfs_lite) {
++ memset(buf, 0, sizeof(*buf));
++ retval = security_sb_statfs(sb);
++ if (retval)
++ return retval;
++ retval = sb->s_op->statfs_lite(sb, buf, statfs_mask);
++ if (retval == 0 && buf->f_frsize == 0 && (statfs_mask & STATFS_M_FRSIZE) != 0)
++ buf->f_frsize = buf->f_bsize;
++ }
++ }
++ return retval;
++}
++
++EXPORT_SYMBOL(vfs_statfs_lite);
++
+ int vfs_statfs(struct super_block *sb, struct kstatfs *buf)
+ {
+ int retval = -ENODEV;
+@@ -1100,6 +1128,638 @@
+ }
+ EXPORT_SYMBOL_GPL(sys_openat);
+
++static unsigned int diff(struct timeval *end, struct timeval *begin)
++{
++ if (end->tv_usec < begin->tv_usec) {
++ end->tv_usec += 1000000; end->tv_sec--;
++ }
++ end->tv_sec -= begin->tv_sec;
++ end->tv_usec -= begin->tv_usec;
++ return ((end->tv_sec * 1000000) + (end->tv_usec));
++}
++
++/*
++ * Compute a simple crc checksum
++ */
++static inline __u32 simple_crc_csum(struct file_handle *fhandle)
++{
++ struct file_handle_generic *fhg;
++ __le32 *u;
++ __u8 *c;
++ __u32 i, j;
++
++ fhg = &fhandle->fh_generic;
++ /* upto and not including the fhg_crc_csum field */
++ for (i = 0, u = (__le32 *) fhg; u < (__le32 *)(&fhg->fhg_crc_csum); ++u)
++ i += le32_to_cpup(u);
++ /* and over the entire fh_private buffer */
++ c = (__u8 *) fhandle->fh_private;
++ for (j = 0; j < fhandle->fh_private_length; ++j)
++ i += *(c + j);
++ return i;
++}
++
++/*
++ * Compute and return a crc32c checksum using the crypto subsystem
++ * API
++ */
++static __u32 compute_crc32_csum(struct file_handle *fhandle)
++{
++#define MAX_SG_LIST 8
++ __u32 csum;
++ __u32 i;
++ struct crypto_tfm *tfm;
++ struct scatterlist sg[MAX_SG_LIST];
++ struct timeval begin, end;
++
++ do_gettimeofday(&begin);
++ if (crypto_alg_available("crc32c", 0) == 0) {
++ csum = simple_crc_csum(fhandle);
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "compute_crc32_csum[simple]: took %d usecs\n", diff(&end, &begin));
++ goto out;
++ }
++
++ tfm = crypto_alloc_tfm("crc32c", 0);
++ if (tfm == NULL) {
++ csum = simple_crc_csum(fhandle);
++ goto out;
++ }
++
++ crypto_digest_init(tfm);
++
++ i = 0;
++ sg_set_buf(&sg[i++], &fhandle->fh_generic,
++ offsetof(struct file_handle_generic, fhg_crc_csum));
++ sg_set_buf(&sg[i++], fhandle->fh_private, fhandle->fh_private_length);
++
++ crypto_digest_update(tfm, sg, i);
++ crypto_digest_final(tfm, (__u8*)&csum);
++ crypto_free_tfm(tfm);
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "compute_crc32_csum[tfm]: took %d usecs\n", diff(&end, &begin));
++out:
++ return csum;
++#undef MAX_SG_LIST
++}
++
++/*
++ * Store a crc32 check sum into the handle buffer
++ * NOTE: We expect fhandle->fh_private and fhandle->fh_private_length
++ * to be initialized prior to this call!
++ */
++static inline void store_crc32_csum(struct file_handle *fhandle)
++{
++ /* Compute the CRC checksum over the handle buffer */
++ __u32 csum = compute_crc32_csum(fhandle);
++ /* Set the CRC checksum into the handle buffer */
++ set_fh_field(&fhandle->fh_generic, crc_csum, csum);
++ return;
++}
++
++/*
++ * Verifies if a file handle's structure's check sum
++ * matches with what user-space indicates.
++ * This should catch most of the simple buffer handle corruption
++ * cases (but not the maliciously crafted ones!) for which
++ * we have the keyed SHA1 (HMAC-SHA1) algorithm verification.
++ * NOTE: We expect fhandle->fh_private and fhandle->fh_private_length
++ * to be initialized prior to this call!
++ * Returns 1 in case verification was successful and 0
++ * otherwise.
++ */
++static inline int verify_crc32_csum(struct file_handle *fhandle)
++{
++ __u32 csum, crc_csum;
++
++ /* Compute the CRC checksum over the handle buffer */
++ csum = compute_crc32_csum(fhandle);
++ /* Retrieve the CRC checksum from the handle buffer */
++ get_fh_field(&fhandle->fh_generic, crc_csum, crc_csum);
++ return (crc_csum == csum);
++}
++
++/*
++ * Compute a hmac-sha1 crypto check sum using a specified
++ * key and store it in the buffer pointed to by result.
++ * NOTE: We assume that fhandle->fh_private and
++ * fhandle->fh_private_length are initialized prior to this call.
++ * Returns 0 in case SHA1/HMAC-SHA1 was not built-in/compiled
++ * for the kernel
++ * Else returns length of the digest generated.
++ */
++static unsigned int compute_hmac_sha1_csum(struct file_handle *fhandle,
++ char *key, int keylen, char *result)
++{
++#define MAX_SG_LIST 8
++ __u32 i;
++ struct crypto_tfm *tfm;
++ struct scatterlist sg[MAX_SG_LIST];
++ unsigned int ret;
++ struct timeval begin, end;
++
++ do_gettimeofday(&begin);
++
++ /* SHA1 is not available */
++ if (crypto_alg_available("sha1", 0) == 0)
++ return 0;
++
++ tfm = crypto_alloc_tfm("sha1", 0);
++ if (tfm == NULL)
++ return 0;
++
++ i = 0;
++ sg_set_buf(&sg[i++], &fhandle->fh_generic,
++ offsetof(struct file_handle_generic, fhg_hmac_sha1));
++ sg_set_buf(&sg[i++], fhandle->fh_private, fhandle->fh_private_length);
++
++ crypto_hmac(tfm, key, &keylen, sg, i, result);
++ ret = crypto_tfm_alg_digestsize(tfm);
++ crypto_free_tfm(tfm);
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "compute_hmac_sha1_csum: took %d usecs\n", diff(&end, &begin));
++ return ret;
++#undef MAX_SG_LIST
++}
++
++/*
++ * Store a hmac-sha1 crypto check sum into the handle
++ * buffer.
++ */
++static inline void store_hmac_csum(struct file_handle *fhandle,
++ char *key, int keylen)
++{
++ compute_hmac_sha1_csum(fhandle, key, keylen,
++ fhandle->fh_generic.fhg_hmac_sha1);
++ return;
++}
++
++/*
++ * Verifies if a file handle buffer's computed hmac-sha1 crypto
++ * check sum matches with whatever the user-space buffer claims
++ * Returns 1 in case verification was succesful and 0
++ * otherwise
++ */
++static int verify_hmac_csum(struct file_handle *fhandle, char *key, int keylen)
++{
++ __u8 result[24];
++ unsigned int result_len;
++
++ result_len = compute_hmac_sha1_csum(fhandle, key, keylen, result);
++ /* Crypto is not supported. deny verification */
++ if (result_len == 0)
++ return 0;
++
++ /* Check if user has tampered with the buffer */
++ if (memcmp(fhandle->fh_generic.fhg_hmac_sha1, result, result_len) == 0)
++ return 1;
++ return 0;
++}
++
++/*
++ * Copy the constructed file handle to a user-specified buffer.
++ * NOTE: We assume that fhandle->fh_private and
++ * fhandle->fh_private_length have been initialized
++ * prior to this routine
++ */
++static int copy_handle(const void __user *uaddr, struct file_handle *fhandle)
++{
++ char __user *ptr = (char __user *) uaddr;
++ struct timeval begin, end;
++
++ do_gettimeofday(&begin);
++
++ /* Copy the VFS generic part of the handle */
++ if (copy_to_user(ptr, &fhandle->fh_generic,
++ sizeof(struct file_handle_generic)))
++ return -EFAULT;
++
++ /* Advance the user-buffer pointer */
++ ptr += sizeof(struct file_handle_generic);
++ /* Copy the FS specific part of the handle */
++ if (copy_to_user(ptr, fhandle->fh_private, fhandle->fh_private_length))
++ return -EFAULT;
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "copy_handle: took %d usecs\n", diff(&end, &begin));
++ return 0;
++}
++
++/*
++ * Copy a user-specified handle buffer to a temporary
++ * kernel buffer.
++ */
++static void* move_handle_to_kernel(const void __user *uaddr,
++ size_t ulen, void *kaddr)
++{
++ if (uaddr != NULL) {
++ if (copy_from_user(kaddr, uaddr, ulen))
++ return ERR_PTR(-EFAULT);
++ }
++ return kaddr;
++}
++
++/*
++ * Copy a specified size user-space handle buffer to a temporary
++ * kernel buffer and return a pointer to the kernel buffer.
++ * Encodes error in return pointer in case
++ * operation failed for some reason.
++ */
++static void *gethandle(const void __user *uhandle, size_t uhandle_len)
++{
++ void *tmp = NULL, *result = ERR_PTR(-EINVAL);
++ struct timeval begin, end;
++
++ do_gettimeofday(&begin);
++
++ do {
++ if (uhandle_len <= 0 || uhandle_len > MAX_HANDLE_LEN)
++ break;
++ result = ERR_PTR(-ENOMEM);
++ tmp = kmalloc(uhandle_len, GFP_KERNEL);
++ if (tmp == NULL)
++ break;
++ result = move_handle_to_kernel(uhandle, uhandle_len, tmp);
++ } while (0);
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "gethandle: took %d usecs\n", diff(&end, &begin));
++ return result;
++}
++/*
++ * Frees memory allocated to a temporary kernel space buffer
++ * used for staging the handle copy from user-space.
++ */
++static void puthandle(void *handle)
++{
++ if (handle)
++ kfree(handle);
++ return;
++}
++
++/*
++ * Wrapper routine to obtain any FS specific keys that can be used
++ * for the HMAC-SHA1 calculation to make the handle returned
++ * by openg() tamper-proof or atleast tamper-detectable.
++ * We dont use any keys in case FS does not provide one!
++ */
++static void get_fs_key(struct super_block *sb, char **ppkey, int *keylen)
++{
++ struct timeval begin, end;
++
++ *ppkey = NULL;
++ *keylen = 0;
++ do_gettimeofday(&begin);
++ /* underlying fs wishes to provide a key */
++ if (sb && sb->s_op && sb->s_op->get_fs_key)
++ sb->s_op->get_fs_key(sb, ppkey, keylen);
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "get_fs_key: took %d usecs\n", diff(&end, &begin));
++ return;
++}
++
++/*
++ * Free the memory allocated to fhandle->fh_private.
++ * This is done by either calling the provided destructor
++ * function if any (supplied by fill_handle callback of FS).
++ * or by calling kfree(). We expect FS to either use kmalloc()
++ * or supply a dtor function so that fh_private can be properly
++ * deallocated.
++ */
++static void drop_file_handle_private(struct file_handle *fhandle)
++{
++ if (!fhandle || !fhandle->fh_private)
++ return;
++ if (fhandle->fh_private_dtor)
++ fhandle->fh_private_dtor(fhandle->fh_private);
++ else
++ kfree(fhandle->fh_private);
++ fhandle->fh_private = NULL;
++ return;
++}
++
++/*
++ * Associate and establish a file handle to a struct file mapping.
++ * NOTE: Linux VFS is inherently based off a dentry cache model
++ * and since we dont have any pathnames/filenames we need to create a anon.
++ * dentry to represent files opened using this system call.
++ */
++static struct file *do_fh_open(const void *handle, size_t handle_len)
++{
++ struct file *filp = NULL;
++ struct super_block *sb;
++ struct inode *inode = NULL;
++ struct file_handle fhandle;
++ size_t min_len = sizeof(struct file_handle_generic);
++ char *key = NULL;
++ int keylen = 0;
++ struct timeval begin, end;
++
++ /* Do some sanity checks on the handle lengths and handle buffer */
++ if (handle_len <= min_len)
++ return ERR_PTR(-EINVAL);
++
++ memcpy(&fhandle.fh_generic, handle, min_len);
++ /* set the fields of the file handle prior to verification */
++ fhandle.fh_private = (char *) handle + min_len;
++ fhandle.fh_private_length = (handle_len - min_len);
++ fhandle.fh_private_dtor = NULL;
++ /* verify crc32 checksum on the handle buffer */
++ if (!verify_crc32_csum(&fhandle))
++ return ERR_PTR(-EACCES);
++
++ /*
++ * Verification of HMAC SHA1 csum on the handle buffer cannot be
++ * done at this point since we don't know which file
++ * system/superblock it belongs to.
++ */
++
++ /* Locate and get an active reference to a
++ * super-block that matches a given handle
++ */
++ do_gettimeofday(&begin);
++ sb = get_sb_handle(&fhandle);
++ /* could not find any valid FS that owns this handle */
++ if (!sb)
++ return ERR_PTR(-EINVAL);
++
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "get_sb_handle: took %d usecs\n", diff(&end, &begin));
++ /* FS has not implemented a routine to query inode based on handle */
++ if (!sb->s_op || !sb->s_op->find_inode_handle) {
++ filp = ERR_PTR(-EOPNOTSUPP);
++ goto out;
++ }
++ /* Check if underlying FS wishes to use a key */
++ get_fs_key(sb, &key, &keylen);
++ /* and verify the authenticity of the handle buffer */
++ if (verify_hmac_csum(&fhandle, key, keylen) == 0) {
++ /* Permission denied */
++ filp = ERR_PTR(-EACCES);
++ goto out;
++ }
++ do_gettimeofday(&begin);
++ /* find an inode or allocate/lookup an inode based on the handle */
++ inode = sb->s_op->find_inode_handle(sb, &fhandle);
++ if (!IS_ERR(inode)) {
++ struct dentry *anon_dentry;
++ int flags = 0;
++
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "s_op->find_inode_handle: took %d usecs\n", diff(&end, &begin));
++
++ get_fh_field(&fhandle.fh_generic, flags, flags);
++ /*
++ * Associate a anonymous dentry to this inode in case there is none.
++ * d_prune_aliases() will take care of freeeing all these dentries
++ * which is called when the last reference to iput() calls
++ * put_inode() which in turn calls the above function.
++ */
++ do_gettimeofday(&begin);
++ anon_dentry = d_alloc_anon(inode);
++ if (anon_dentry == NULL) {
++ filp = ERR_PTR(-ENOMEM);
++ goto drop_inode;
++ }
++ /* and setup file and inode mapping */
++ filp = get_empty_filp();
++ if (filp == NULL) {
++ filp = ERR_PTR(-ENFILE);
++ goto drop_dentry;
++ }
++ filp = __dentry_open(anon_dentry, NULL, flags, filp, NULL);
++ if (IS_ERR(filp)) {
++ /* in case of error __dentry_open drops the anon_dentry */
++ goto drop_inode;
++ drop_dentry:
++ dput(anon_dentry);
++ drop_inode:
++ iput(inode);
++ }
++ else {
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "d_alloc_anon + misc.: took %d usecs\n", diff(&end, &begin));
++ }
++ }
++ else {
++ /* in case of error */
++ filp = ERR_PTR(PTR_ERR(inode));
++ }
++out:
++ /* drop our active reference to sb */
++ drop_super(sb);
++ return filp;
++}
++
++long do_sys_openfh(const void __user *uhandle, size_t handle_len)
++{
++ void *tmp = gethandle(uhandle, handle_len);
++ int fd = PTR_ERR(tmp);
++
++ if (!IS_ERR(tmp)) {
++ struct timeval begin, end;
++
++ do_gettimeofday(&begin);
++ fd = get_unused_fd();
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "get_unused_fd: took %d usecs\n", diff(&end, &begin));
++ if (fd >= 0) {
++ struct file *f;
++
++ do_gettimeofday(&begin);
++ f = do_fh_open(tmp, handle_len);
++ if (IS_ERR(f)) {
++ put_unused_fd(fd);
++ fd = PTR_ERR(f);
++ } else {
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "do_fh_open: took %d usecs\n", diff(&end, &begin));
++ do_gettimeofday(&begin);
++ /* this file descriptor needs to be closed on exec */
++ set_close_on_exec(fd, 1);
++ fd_install(fd, f);
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "set_close, fd_install: took %d usecs\n", diff(&end, &begin));
++ }
++ }
++ puthandle(tmp);
++ }
++ return fd;
++}
++
++asmlinkage long sys_openfh(const void __user *uhandle, size_t handle_len)
++{
++ return do_sys_openfh(uhandle, handle_len);
++}
++
++EXPORT_SYMBOL_GPL(sys_openfh);
++
++long do_sys_openg(const char __user *pathname, void __user *uhandle,
++ size_t __user *uhandle_len, int flags, int mode)
++{
++ char *tmp = getname(pathname);
++ long err = PTR_ERR(tmp);
++
++ if (!IS_ERR(tmp))
++ {
++ struct file *f = NULL;
++ size_t handle_len = 0;
++ size_t min_len = sizeof(struct file_handle_generic);
++ struct file_handle fhandle;
++ struct timeval begin, end;
++
++ memset(&fhandle, 0, sizeof(fhandle));
++ if (get_user(handle_len, uhandle_len)) {
++ err = -EFAULT;
++ goto drop_name;
++ }
++ /* discard bogus values */
++ if (handle_len < 0)
++ {
++ err = -EINVAL;
++ goto drop_name;
++ }
++ /* or definitely insufficient buffer length */
++ else if (handle_len > 0 &&
++ handle_len < min_len)
++ {
++ err = -ERANGE;
++ goto drop_name;
++ }
++ err = 0;
++ do_gettimeofday(&begin);
++ /* Try to open the file now */
++ f = do_filp_open(AT_FDCWD, tmp, flags, mode);
++ if (IS_ERR(f)) {
++ /* File does not exist */
++ err = PTR_ERR(f);
++ goto drop_name;
++ }
++ else {
++ /* Is this even possible? */
++ if (!f->f_dentry || !f->f_dentry->d_inode)
++ {
++ err = -EINVAL;
++ goto drop_filp;
++ }
++ /* Diallow anything but regular files */
++ if (!S_ISREG(f->f_dentry->d_inode->i_mode)) {
++ err = -EACCES;
++ goto drop_filp;
++ }
++ else {
++ /* Does FS define callback for openg? */
++ if (!f->f_dentry->d_inode->i_op->fill_handle) {
++ /* not supported */
++ err = -EOPNOTSUPP;
++ goto drop_filp;
++ }
++ else {
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "do_filp_open: took %d usecs\n", diff(&end, &begin));
++ fhandle.fh_private = NULL;
++ fhandle.fh_private_length =
++ handle_len ? (handle_len - min_len) : 0;
++ fhandle.fh_private_dtor = NULL;
++ /*
++ * if handle_len == 0,
++ * FS is expected to give us the handle length it needs.
++ */
++ do_gettimeofday(&begin);
++ err = f->f_dentry->d_inode->i_op->fill_handle(
++ f->f_dentry->d_inode, &fhandle);
++ if (err)
++ goto drop_filp;
++
++ /* make sure that FS does not set it to an invalid length */
++ if (fhandle.fh_private_length <= 0) {
++ err = -EINVAL;
++ goto drop_private;
++ }
++
++ /* try to copy the handle if requested */
++ if (handle_len > 0) {
++ __u32 magic, fsid;
++ struct kstatfs st;
++ char *key = NULL;
++ int keylen = 0, statfs_mask = STATFS_M_TYPE | STATFS_M_FSID;
++ /*
++ * Check if fhandle.fh_private was not set.
++ */
++ if (fhandle.fh_private == NULL) {
++ err = -EINVAL;
++ goto drop_filp;
++ }
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "fill_handle: took %d usecs\n", diff(&end, &begin));
++ /*
++ * Check if the underlying FS wishes to supply a key for
++ * the message authentication code.
++ * If it does not or in case of errors, we use a NULL key
++ * for the MAC
++ */
++ get_fs_key(f->f_dentry->d_inode->i_sb, &key, &keylen);
++ /*
++ * Currently, we issue a statfs on the superblock to figure
++ * out the magic number and fsid for the file system.
++ * But this might translate to many network messages for many
++ * distributed/parallel file systems. Therefore, we need a
++ * sb->statfs_lite() callback mechanism to get only those
++ * fields that don't require a network message.
++ * If FS does not support the callback, fallback to using statfs.
++ */
++ do_gettimeofday(&begin);
++ if ((err = vfs_statfs_lite(f->f_dentry->d_inode->i_sb, &st, statfs_mask)) < 0) {
++ //err = vfs_statfs(f->f_dentry->d_inode->i_sb, &st);
++ //if (err)
++ goto drop_private;
++ }
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "statfs_lite: took %d usecs\n", diff(&end, &begin));
++ magic = st.f_type;
++ memcpy(&fsid, &st.f_fsid, sizeof(__u32));
++ /* set magic number, fsid, flags */
++ set_fh_field(&fhandle.fh_generic, magic, magic);
++ set_fh_field(&fhandle.fh_generic, fsid, fsid);
++ set_fh_field(&fhandle.fh_generic, flags, flags);
++
++ do_gettimeofday(&begin);
++ /* Compute and store crc check sum */
++ store_crc32_csum(&fhandle);
++ /* Compute and store HMAC-SHA1 crypto check sum */
++ store_hmac_csum(&fhandle, key, keylen);
++ /* copy opaque handle to user buffer */
++ err = copy_handle(uhandle, &fhandle);
++ if (err)
++ goto drop_private;
++ do_gettimeofday(&end);
++ printk(KERN_DEBUG "(crc, hmac, copy_handle): took %d usecs\n", diff(&end, &begin));
++ }
++ /* update the handle length reported to user-space */
++ handle_len = fhandle.fh_private_length + min_len;
++ /* and copy the new length to user space */
++ err = put_user(handle_len, uhandle_len);
++ drop_private:
++ drop_file_handle_private(&fhandle);
++ }
++ }
++drop_filp:
++ filp_close(f, NULL);
++ }
++drop_name:
++ putname(tmp);
++ }
++ return err;
++}
++
++asmlinkage long sys_openg(const char __user *pathname, void __user *uhandle,
++ size_t __user *uhandle_len, int flags, int mode)
++{
++ if (force_o_largefile())
++ flags |= O_LARGEFILE;
++ return do_sys_openg(pathname, uhandle, uhandle_len, flags, mode);
++}
++
++EXPORT_SYMBOL_GPL(sys_openg);
++
+ #ifndef __alpha__
+
+ /*
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/super.c vanilla-new/fs/super.c
+--- vanilla/fs/super.c 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/fs/super.c 2006-04-26 22:06:36.000000000 -0500
+@@ -799,6 +799,58 @@
+
+ EXPORT_SYMBOL(get_sb_single);
+
++struct super_block *get_sb_handle(const struct file_handle *fhandle)
++{
++ /* walk through the list of superblocks */
++ struct super_block *sb;
++
++ spin_lock(&sb_lock);
++ list_for_each_entry (sb, &super_blocks, s_list) {
++ struct kstatfs st;
++
++ sb->s_count++;
++ spin_unlock(&sb_lock);
++ down_read(&sb->s_umount);
++ if (sb->s_root)
++ {
++ int err, statfs_mask = STATFS_M_TYPE | STATFS_M_FSID;
++ /*
++ * Currently, we issue a statfs on the superblock to figure
++ * out the type and fsid for the file system.
++ * But this might translate to network messages for many
++ * distributed/parallel file systems. Therefore, we need a
++ * statfs_lite() callback mechanism to get only those
++ * fields that don't require a network message. We fall back to a
++ * regular statfs in case the file system does not support a statfs_lite()
++ * callback.
++ */
++ if ((err = vfs_statfs_lite(sb, &st, statfs_mask)) < 0) {
++ //err = vfs_statfs(sb, &st);
++ }
++
++ if (err == 0) {
++ __u32 fsid, magic;
++
++ get_fh_field(&fhandle->fh_generic, fsid, fsid);
++ get_fh_field(&fhandle->fh_generic, magic, magic);
++ /* check if magic numbers and fsid matches */
++ if (st.f_type == magic
++ && memcmp(&st.f_fsid, &fsid, sizeof(__u32)) == 0)
++ {
++ return sb;
++ }
++ }
++ }
++ drop_super(sb);
++ spin_lock(&sb_lock);
++ }
++ spin_unlock(&sb_lock);
++ /* This function will not create a new superblock! */
++ return NULL;
++}
++
++EXPORT_SYMBOL_GPL(get_sb_handle);
++
+ struct vfsmount *
+ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
+ {
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/unistd.h vanilla-new/include/asm-i386/unistd.h
+--- vanilla/include/asm-i386/unistd.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-i386/unistd.h 2006-04-07 10:28:39.000000000 -0500
+@@ -316,8 +316,10 @@
+ #define __NR_pselect6 308
+ #define __NR_ppoll 309
+ #define __NR_unshare 310
++#define __NR_openg 311
++#define __NR_openfh 312
+
+-#define NR_syscalls 311
++#define NR_syscalls 313
+
+ /*
+ * user-visible error numbers are in the range -1 - -128: see
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-ia64/unistd.h vanilla-new/include/asm-ia64/unistd.h
+--- vanilla/include/asm-ia64/unistd.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-ia64/unistd.h 2006-04-07 10:28:39.000000000 -0500
+@@ -285,12 +285,14 @@
+ #define __NR_faccessat 1293
+ /* 1294, 1295 reserved for pselect/ppoll */
+ #define __NR_unshare 1296
++#define __NR_openg 1297
++#define __NR_openfh 1298
+
+ #ifdef __KERNEL__
+
+ #include <linux/config.h>
+
+-#define NR_syscalls 273 /* length of syscall table */
++#define NR_syscalls 275 /* length of syscall table */
+
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-powerpc/unistd.h vanilla-new/include/asm-powerpc/unistd.h
+--- vanilla/include/asm-powerpc/unistd.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-powerpc/unistd.h 2006-04-07 10:28:39.000000000 -0500
+@@ -301,8 +301,10 @@
+ #define __NR_pselect6 280
+ #define __NR_ppoll 281
+ #define __NR_unshare 282
++#define __NR_openg 283
++#define __NR_openfh 284
+
+-#define __NR_syscalls 283
++#define __NR_syscalls 285
+
+ #ifdef __KERNEL__
+ #define __NR__exit __NR_exit
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/unistd.h vanilla-new/include/asm-x86_64/unistd.h
+--- vanilla/include/asm-x86_64/unistd.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-x86_64/unistd.h 2006-04-07 10:28:39.000000000 -0500
+@@ -605,8 +605,12 @@
+ __SYSCALL(__NR_ppoll, sys_ni_syscall) /* for now */
+ #define __NR_unshare 272
+ __SYSCALL(__NR_unshare, sys_unshare)
++#define __NR_openg 273
++__SYSCALL(__NR_openg, sys_openg)
++#define __NR_openfh 274
++__SYSCALL(__NR_openfh, sys_openfh)
+
+-#define __NR_syscall_max __NR_unshare
++#define __NR_syscall_max __NR_openfh
+
+ #ifndef __NO_STUBS
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/fs.h vanilla-new/include/linux/fs.h
+--- vanilla/include/linux/fs.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/fs.h 2006-04-17 13:35:37.000000000 -0500
+@@ -991,6 +991,27 @@
+ #define HAVE_COMPAT_IOCTL 1
+ #define HAVE_UNLOCKED_IOCTL 1
+
++struct file_handle_generic {
++ /* Filled by VFS */
++ __le32 fhg_magic; /* magic number */
++ __le32 fhg_fsid; /* file system identifier */
++ __le32 fhg_flags; /* flags associated with the file object */
++ __le32 fhg_crc_csum; /* crc32c check sum of the blob */
++ __u8 fhg_hmac_sha1[24]; /* hmac-sha1 message authentication code */
++};
++
++struct file_handle {
++ /* generic part filled by VFS */
++ struct file_handle_generic fh_generic;
++ /* FS specific part */
++ void *fh_private;
++ size_t fh_private_length;
++ void (*fh_private_dtor)(void *);
++};
++
++#define set_fh_field(X, Y, Z) (X)->fhg_##Y = cpu_to_le32(Z)
++#define get_fh_field(X, Y, Z) Z = le32_to_cpu((X)->fhg_##Y)
++
+ /*
+ * NOTE:
+ * read, write, poll, fsync, readv, writev, unlocked_ioctl and compat_ioctl
+@@ -1049,6 +1070,8 @@
+ ssize_t (*listxattr) (struct dentry *, char *, size_t);
+ int (*removexattr) (struct dentry *, const char *);
+ void (*truncate_range)(struct inode *, loff_t, loff_t);
++ /* method needed for filling up handle */
++ int (*fill_handle)(struct inode *, struct file_handle *);
+ };
+
+ struct seq_file;
+@@ -1065,12 +1088,12 @@
+ * without the big kernel lock held in all filesystems.
+ */
+ struct super_operations {
+- struct inode *(*alloc_inode)(struct super_block *sb);
++ struct inode *(*alloc_inode)(struct super_block *sb);
+ void (*destroy_inode)(struct inode *);
+
+ void (*read_inode) (struct inode *);
+
+- void (*dirty_inode) (struct inode *);
++ void (*dirty_inode) (struct inode *);
+ int (*write_inode) (struct inode *, int);
+ void (*put_inode) (struct inode *);
+ void (*drop_inode) (struct inode *);
+@@ -1081,6 +1104,7 @@
+ void (*write_super_lockfs) (struct super_block *);
+ void (*unlockfs) (struct super_block *);
+ int (*statfs) (struct super_block *, struct kstatfs *);
++ int (*statfs_lite) (struct super_block *, struct kstatfs *, int statfs_mask);
+ int (*remount_fs) (struct super_block *, int *, char *);
+ void (*clear_inode) (struct inode *);
+ void (*umount_begin) (struct super_block *);
+@@ -1089,6 +1113,8 @@
+
+ ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
+ ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
++ struct inode *(*find_inode_handle)(struct super_block *, const struct file_handle *);
++ void (*get_fs_key)(struct super_block *, char **ppkey, int *keylen);
+ };
+
+ /* Inode state bits. Protected by inode_lock. */
+@@ -1257,6 +1283,7 @@
+ struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+ int flags, void *data,
+ int (*fill_super)(struct super_block *, void *, int));
++struct super_block *get_sb_handle(const struct file_handle *handle);
+ void generic_shutdown_super(struct super_block *sb);
+ void kill_block_super(struct super_block *sb);
+ void kill_anon_super(struct super_block *sb);
+@@ -1292,6 +1319,7 @@
+ struct vfsmount *);
+
+ extern int vfs_statfs(struct super_block *, struct kstatfs *);
++extern int vfs_statfs_lite(struct super_block *, struct kstatfs *, int statfs_mask);
+
+ /* /sys/fs */
+ extern struct subsystem fs_subsys;
+@@ -1345,6 +1373,10 @@
+ struct file *filp);
+ extern long do_sys_open(int fdf, const char __user *filename, int flags,
+ int mode);
++
++extern long do_sys_openfh(const void __user *uhandle, size_t handle_len);
++extern long do_sys_openg(const char __user *pathname, void __user *uhandle,
++ size_t __user *uhandle_len, int flags, int mode);
+ extern struct file *filp_open(const char *, int, int);
+ extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);
+ extern int filp_close(struct file *, fl_owner_t id);
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/limits.h vanilla-new/include/linux/limits.h
+--- vanilla/include/linux/limits.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/limits.h 2006-04-07 17:25:07.000000000 -0500
+@@ -16,6 +16,7 @@
+ #define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */
+ #define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */
+ #define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */
++#define MAX_HANDLE_LEN 128 /* maximum size of a handle used by the openfh system call */
+
+ #define RTSIG_MAX 32
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/statfs.h vanilla-new/include/linux/statfs.h
+--- vanilla/include/linux/statfs.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/statfs.h 2006-04-17 11:38:07.000000000 -0500
+@@ -5,6 +5,18 @@
+
+ #include <asm/statfs.h>
+
++/* Masks used by statfs_lite callback */
++#define STATFS_M_TYPE (1 << 0)
++#define STATFS_M_BSIZE (1 << 1)
++#define STATFS_M_BLOCKS (1 << 2)
++#define STATFS_M_BFREE (1 << 3)
++#define STATFS_M_BAVAIL (1 << 4)
++#define STATFS_M_FILES (1 << 5)
++#define STATFS_M_FFREE (1 << 6)
++#define STATFS_M_FSID (1 << 7)
++#define STATFS_M_NAMELEN (1 << 8)
++#define STATFS_M_FRSIZE (1 << 9)
++
+ struct kstatfs {
+ long f_type;
+ long f_bsize;
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/syscalls.h vanilla-new/include/linux/syscalls.h
+--- vanilla/include/linux/syscalls.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/syscalls.h 2006-04-07 13:56:07.000000000 -0500
+@@ -327,6 +327,10 @@
+ asmlinkage long sys_creat(const char __user *pathname, int mode);
+ asmlinkage long sys_open(const char __user *filename,
+ int flags, int mode);
++asmlinkage long sys_openfh(const void __user *uhandle,
++ size_t handle_len);
++asmlinkage long sys_openg(const char __user *pathname, void __user *uhandle,
++ size_t *uhandle_len, int flags, int mode);
+ asmlinkage long sys_close(unsigned int fd);
+ asmlinkage long sys_access(const char __user *filename, int mode);
+ asmlinkage long sys_vhangup(void);
+@@ -566,7 +570,10 @@
+ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename,
+ struct compat_stat __user *statbuf,
+ int flag);
++asmlinkage long compat_sys_open(const char __user *filename, int flags, int mode);
+ asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename,
+ int flags, int mode);
+-
++asmlinkage long compat_sys_openg(const char __user *pathname, void __user *uhandle,
++ size_t __user *uhandle_len, int flags, int mode);
++asmlinkage long compat_sys_openfh(const void __user *uhandle, size_t uhandle_len);
+ #endif
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ posix-readwritex.patch 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,898 @@
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/i386/kernel/syscall_table.S vanilla-new/arch/i386/kernel/syscall_table.S
+--- vanilla/arch/i386/kernel/syscall_table.S 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/arch/i386/kernel/syscall_table.S 2006-05-24 16:31:20.000000000 -0500
+@@ -320,3 +320,5 @@
+ .long sys_fstatlite64
+ .long sys_getdents_plus
+ .long sys_getdents64_plus /* 320 */
++ .long sys_readx
++ .long sys_writex
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/ia64/kernel/entry.S vanilla-new/arch/ia64/kernel/entry.S
+--- vanilla/arch/ia64/kernel/entry.S 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/arch/ia64/kernel/entry.S 2006-05-24 16:32:28.000000000 -0500
+@@ -1626,5 +1626,7 @@
+ data8 sys_newfstatlite
+ data8 sys_getdents_plus
+ data8 sys_getdents64_plus
++ data8 sys_readx
++ data8 sys_writex
+
+ .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/powerpc/kernel/systbl.S vanilla-new/arch/powerpc/kernel/systbl.S
+--- vanilla/arch/powerpc/kernel/systbl.S 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/arch/powerpc/kernel/systbl.S 2006-05-24 16:34:44.000000000 -0500
+@@ -329,3 +329,5 @@
+ SYSCALL(newfstatlite)
+ SYSCALL(sys_getdents_plus)
+ SYSCALL(sys_getdents64_plus)
++SYSCALL(sys_readx)
++SYSCALL(sys_writex)
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/ia32entry.S vanilla-new/arch/x86_64/ia32/ia32entry.S
+--- vanilla/arch/x86_64/ia32/ia32entry.S 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/arch/x86_64/ia32/ia32entry.S 2006-05-24 16:32:01.000000000 -0500
+@@ -698,6 +698,8 @@
+ .quad sys32_fstatlite64
+ .quad sys_ni_syscall /* getdents_plus */
+ .quad sys_ni_syscall /* getdents64_plus */
++ .quad compat_sys_readx
++ .quad compat_sys_writex
+ ia32_syscall_end:
+ .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
+ .quad ni_syscall
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/compat.c vanilla-new/fs/compat.c
+--- vanilla/fs/compat.c 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/fs/compat.c 2006-05-24 16:26:00.000000000 -0500
+@@ -1344,6 +1344,322 @@
+ return ret;
+ }
+
++static ssize_t compat_do_readx_writex(int type, struct file *file,
++ const struct compat_iovec __user * uvector,
++ unsigned long nr_segs,
++ const struct compat_xtvec __user * xtuvector,
++ unsigned long xtnr_segs)
++{
++ 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 *);
++ typedef ssize_t (*iox_fn_t)(struct file *, const struct iovec *, unsigned long,
++ const struct xtvec *, unsigned long);
++
++ compat_ssize_t tot_len, tot_xtlen;
++ struct iovec iovstack[UIO_FASTIOV];
++ struct iovec *iov=iovstack;
++ struct xtvec xtvstack[UIO_FASTIOV];
++ struct xtvec *xtv=xtvstack;
++ ssize_t ret;
++ int seg;
++ io_fn_t fn = NULL;
++ iov_fn_t fnv = NULL;
++ iox_fn_t fnx = NULL;
++
++ /*
++ * readx does not make much sense if nr_segs <= 0 (OR) xtnr_segs <= 0
++ * We return 0 similar to how readv/writev do.
++ */
++ ret = 0;
++ if (nr_segs == 0 || xtnr_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 ((xtnr_segs > UIO_MAXIOV) || (xtnr_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;
++ }
++ if (xtnr_segs > UIO_FASTIOV) {
++ ret = -ENOMEM;
++ xtv = kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
++ if (!xtv) {
++ goto out;
++ }
++ }
++ ret = -EFAULT;
++ if (!access_ok(VERIFY_READ, uvector, nr_segs * sizeof(*uvector)))
++ goto out;
++ if (!access_ok(VERIFY_READ, xtuvector, xtnr_segs * sizeof(*xtuvector)))
++ 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;
++ ret = -EINVAL;
++ for (seg = 0; seg < nr_segs; seg++) {
++ compat_ssize_t tmp = tot_len, 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;
++ iov[seg].iov_base = compat_ptr(buf);
++ iov[seg].iov_len = (compat_size_t) len;
++ uvector++;
++ }
++ if (tot_len == 0) {
++ ret = 0;
++ goto out;
++ }
++ tot_xtlen = 0;
++ ret = -EINVAL;
++ for (seg = 0; seg < xtnr_segs; seg++) {
++ compat_ssize_t tmp = tot_xtlen, len;
++ compat_off_t off;
++ loff_t foff;
++
++ if (__get_user(off, &xtuvector->xtv_off) ||
++ __get_user(len, &xtuvector->xtv_len)) {
++ ret = -EFAULT;
++ goto out;
++ }
++ if (len < 0) /* size_t not fitting an compat_ssize_t .. */
++ goto out;
++ if (off < 0) /* off_t not fitting an loff_t */
++ goto out;
++ tot_xtlen += len;
++ if (tot_xtlen < tmp) /* overflow on the compat_ssize_t */
++ goto out;
++ foff = (loff_t) off;
++ ret = rw_verify_area(type, file, &foff, len);
++ if (ret < 0)
++ goto out;
++ xtv[seg].xtv_off = (compat_off_t) off;
++ xtv[seg].xtv_len = (compat_size_t) len;
++ xtuvector++;
++ }
++ /* if sizes of file and mem don't match up, error out */
++ if (tot_xtlen != tot_len) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (type == READ) {
++ fn = (io_fn_t)file->f_op->read;
++ fnv = (iov_fn_t)file->f_op->readv;
++ fnx = (iox_fn_t)file->f_op->readx;
++ } else {
++ fn = (io_fn_t)file->f_op->write;
++ fnv = (iov_fn_t)file->f_op->writev;
++ fnx = (iox_fn_t)file->f_op->writex;
++ }
++ /* if we had a scatter-gather callback in memory and file, go for it */
++ if (fnx) {
++ ret = fnx(file, iov, nr_segs, xtv, xtnr_segs);
++ goto out;
++ }
++ /* else try to do it by hand using readv/writev operations */
++ else if (fnv) {
++ unsigned long xtiov_index = 0, op_iov_index = 0, iov_index = 0;
++ struct iovec *op_iov = NULL, *copied_iovector = NULL;
++ struct xtvec *copied_xtvector = NULL;
++
++ ret = -ENOMEM;
++ op_iov = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
++ if (!op_iov)
++ goto err_out1;
++ copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
++ if (!copied_iovector)
++ goto err_out1;
++ copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
++ if (!copied_xtvector)
++ goto err_out1;
++ memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
++ memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
++ ret = 0;
++ iov_index = 0;
++ for (xtiov_index = 0; xtiov_index < xtnr_segs; xtiov_index++) {
++ loff_t pos;
++ ssize_t nr, tot_nr;
++
++ pos = copied_xtvector[xtiov_index].xtv_off;
++ op_iov_index = 0;
++ tot_nr = 0;
++
++ /* Finish an entire stream and .. */
++ while (copied_xtvector[xtiov_index].xtv_len > 0) {
++ size_t min_len;
++ if (unlikely((iov_index >= nr_segs) || (op_iov_index >= nr_segs))) {
++ printk(KERN_ERR "iov_index %ld or op_iov_index %ld cannot exceed number of iov segments (%ld)\n",
++ iov_index, op_iov_index, nr_segs);
++ ret = -EINVAL;
++ goto err_out1;
++ }
++ min_len = min(copied_xtvector[xtiov_index].xtv_len, copied_iovector[iov_index].iov_len);
++ op_iov[op_iov_index].iov_base = copied_iovector[iov_index].iov_base;
++ op_iov[op_iov_index++].iov_len = min_len;
++ copied_xtvector[xtiov_index].xtv_len -= min_len;
++ copied_iovector[iov_index].iov_len -= min_len;
++ copied_iovector[iov_index].iov_base += min_len;
++ tot_nr += min_len;
++ /* Advance memory stream if we have exhausted it */
++ if (copied_iovector[iov_index].iov_len <= 0) {
++ iov_index++;
++ }
++ }
++ /* .. issue a vectored operation for that region */
++ nr = fnv(file, op_iov, op_iov_index, &pos);
++ if (nr < 0) {
++ if (!ret) ret = nr;
++ break;
++ }
++ ret += nr;
++ if (nr != tot_nr)
++ break;
++ }
++err_out1:
++ kfree(op_iov);
++ kfree(copied_iovector);
++ kfree(copied_xtvector);
++ goto out;
++ }
++ /* Do it by hand, with plain read/write operations */
++ else {
++ unsigned long mem_ct = 0, str_ct = 0;
++ struct xtvec *copied_xtvector = NULL;
++ struct iovec *copied_iovector = NULL;
++
++ ret = -ENOMEM;
++ copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
++ if (!copied_iovector)
++ goto err_out2;
++ copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
++ if (!copied_xtvector)
++ goto err_out2;
++ memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
++ memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
++
++ ret = 0;
++ mem_ct = 0;
++ str_ct = 0;
++ while ((mem_ct < nr_segs) && (str_ct < xtnr_segs)) {
++ size_t min_len;
++ loff_t pos;
++ ssize_t nr;
++ void __user *base;
++
++ pos = copied_xtvector[str_ct].xtv_off;
++ base = copied_iovector[mem_ct].iov_base;
++ min_len = min(copied_xtvector[str_ct].xtv_len, copied_iovector[mem_ct].iov_len);
++ copied_xtvector[str_ct].xtv_len -= min_len;
++ copied_xtvector[str_ct].xtv_off += min_len;
++ copied_iovector[mem_ct].iov_len -= min_len;
++ copied_iovector[mem_ct].iov_base += min_len;
++ if (copied_iovector[mem_ct].iov_len <= 0)
++ mem_ct++;
++ if (copied_xtvector[str_ct].xtv_len <= 0)
++ str_ct++;
++ /* Issue the smallest region that is contiguous in memory and on file */
++ nr = fn(file, base, min_len, &pos);
++ if (nr < 0) {
++ if (!ret) ret = nr;
++ break;
++ }
++ ret += nr;
++ if (nr != min_len)
++ break;
++ }
++err_out2:
++ kfree(copied_xtvector);
++ kfree(copied_iovector);
++ }
++out:
++ if (iov != iovstack)
++ kfree(iov);
++ if (xtv != xtvstack)
++ kfree(xtv);
++ if ((ret + (type == READ)) > 0) {
++ if (type == READ)
++ fsnotify_access(file->f_dentry);
++ else
++ fsnotify_modify(file->f_dentry);
++ }
++ return ret;
++}
++
++asmlinkage ssize_t
++compat_sys_readx(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen,
++ const struct compat_xtvec __user *xtv, unsigned long xtvlen)
++{
++ 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->readx && !file->f_op->readv && !file->f_op->read))
++ goto out;
++
++ ret = compat_do_readx_writex(READ, file, vec, vlen, xtv, xtvlen);
++
++out:
++ fput(file);
++ return ret;
++}
++
++asmlinkage ssize_t
++compat_sys_writex(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen,
++ const struct compat_xtvec __user *xtv, unsigned long xtvlen)
++{
++ 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->writex && !file->f_op->writev && !file->f_op->write))
++ goto out;
++
++ ret = compat_do_readx_writex(WRITE, file, vec, vlen, xtv, xtvlen);
++
++out:
++ fput(file);
++ return ret;
++}
++
+ /*
+ * Exactly like fs/open.c:sys_open(), except that it doesn't set the
+ * O_LARGEFILE flag.
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/read_write.c vanilla-new/fs/read_write.c
+--- vanilla/fs/read_write.c 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/fs/read_write.c 2006-05-24 16:22:20.000000000 -0500
+@@ -374,6 +374,8 @@
+ return ret;
+ }
+
++EXPORT_SYMBOL_GPL(sys_write);
++
+ asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
+ size_t count, loff_t pos)
+ {
+@@ -636,6 +638,334 @@
+ return ret;
+ }
+
++static ssize_t do_readx_writex(int type, struct file *file,
++ const struct iovec __user * uvector,
++ unsigned long nr_segs,
++ const struct xtvec __user * xtuvector,
++ unsigned long xtnr_segs)
++{
++ 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 *);
++ typedef ssize_t (*iox_fn_t)(struct file *, const struct iovec *, unsigned long,
++ const struct xtvec *, unsigned long);
++
++ size_t tot_len, tot_xtlen;
++ struct iovec iovstack[UIO_FASTIOV];
++ struct iovec *iov=iovstack;
++ struct xtvec xtvstack[UIO_FASTIOV];
++ struct xtvec *xtv=xtvstack;
++ ssize_t ret;
++ int seg;
++ io_fn_t fn = NULL;
++ iov_fn_t fnv = NULL;
++ iox_fn_t fnx = NULL;
++
++ /*
++ * readx does not make much sense if nr_segs <= 0 (OR) xtnr_segs <= 0
++ * We return 0 similar to how readv/writev do.
++ */
++ ret = 0;
++ if (nr_segs == 0 || xtnr_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 ((xtnr_segs > UIO_MAXIOV) || (xtnr_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;
++ }
++ if (xtnr_segs > UIO_FASTIOV) {
++ ret = -ENOMEM;
++ xtv = kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
++ if (!xtv) {
++ goto out;
++ }
++ }
++ ret = -EFAULT;
++ if (copy_from_user(iov, uvector, nr_segs * sizeof(*uvector)))
++ goto out;
++ if (copy_from_user(xtv, xtuvector, xtnr_segs * sizeof(*xtuvector)))
++ 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;
++ ret = -EINVAL;
++ for (seg = 0; seg < nr_segs; seg++) {
++ void __user *buf = iov[seg].iov_base;
++ ssize_t len = (ssize_t)iov[seg].iov_len;
++
++ if (len < 0) /* size_t not fitting an ssize_t .. */
++ goto out;
++ if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
++ goto Efault;
++ tot_len += len;
++ if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
++ goto out;
++ }
++ if (tot_len == 0) {
++ ret = 0;
++ goto out;
++ }
++ tot_xtlen = 0;
++ ret = -EINVAL;
++ for (seg = 0; seg < xtnr_segs; seg++) {
++ loff_t off = (loff_t) xtv[seg].xtv_off;
++ ssize_t len = (ssize_t)xtv[seg].xtv_len;
++
++ if (len < 0) /* size_t not fitting an ssize_t .. */
++ goto out;
++ if (off < 0) /* off_t not fitting an loff_t */
++ goto out;
++ tot_xtlen += len;
++ if ((ssize_t)tot_xtlen < 0) /* overflow on the ssize_t */
++ goto out;
++ ret = rw_verify_area(type, file, &off, len);
++ if (ret < 0)
++ goto out;
++ }
++ /* if sizes of file and mem don't match up, error out */
++ if (tot_xtlen != tot_len) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE);
++ if (ret)
++ goto out;
++
++ if (type == READ) {
++ fn = (io_fn_t)file->f_op->read;
++ fnv = (iov_fn_t)file->f_op->readv;
++ fnx = (iox_fn_t)file->f_op->readx;
++ } else {
++ fn = (io_fn_t)file->f_op->write;
++ fnv = (iov_fn_t)file->f_op->writev;
++ fnx = (iox_fn_t)file->f_op->writex;
++ }
++ /* if we had a scatter-gather callback in memory and file, go for it */
++ if (fnx) {
++ ret = fnx(file, iov, nr_segs, xtv, xtnr_segs);
++ goto out;
++ }
++ /* else try to do it by hand using readv/writev operations */
++ else if (fnv) {
++ unsigned long xtiov_index = 0, op_iov_index = 0, iov_index = 0;
++ struct iovec *op_iov = NULL, *copied_iovector = NULL;
++ struct xtvec *copied_xtvector = NULL;
++
++ ret = -ENOMEM;
++ op_iov = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
++ if (!op_iov)
++ goto err_out1;
++ copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
++ if (!copied_iovector)
++ goto err_out1;
++ copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
++ if (!copied_xtvector)
++ goto err_out1;
++ memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
++ memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
++ ret = 0;
++ iov_index = 0;
++ for (xtiov_index = 0; xtiov_index < xtnr_segs; xtiov_index++) {
++ loff_t pos;
++ ssize_t nr, tot_nr;
++
++ pos = copied_xtvector[xtiov_index].xtv_off;
++ op_iov_index = 0;
++ tot_nr = 0;
++
++ /* Finish an entire stream and .. */
++ while (copied_xtvector[xtiov_index].xtv_len > 0) {
++ size_t min_len;
++ if (unlikely((iov_index >= nr_segs) || (op_iov_index >= nr_segs))) {
++ printk(KERN_ERR "iov_index %ld or op_iov_index %ld cannot exceed number of iov segments (%ld)\n",
++ iov_index, op_iov_index, nr_segs);
++ ret = -EINVAL;
++ goto err_out1;
++ }
++ min_len = min(copied_xtvector[xtiov_index].xtv_len, copied_iovector[iov_index].iov_len);
++ op_iov[op_iov_index].iov_base = copied_iovector[iov_index].iov_base;
++ op_iov[op_iov_index++].iov_len = min_len;
++ copied_xtvector[xtiov_index].xtv_len -= min_len;
++ copied_iovector[iov_index].iov_len -= min_len;
++ copied_iovector[iov_index].iov_base += min_len;
++ tot_nr += min_len;
++ /* Advance memory stream if we have exhausted it */
++ if (copied_iovector[iov_index].iov_len <= 0) {
++ iov_index++;
++ }
++ }
++ /* .. issue a vectored operation for that region */
++ nr = fnv(file, op_iov, op_iov_index, &pos);
++ if (nr < 0) {
++ if (!ret) ret = nr;
++ break;
++ }
++ ret += nr;
++ if (nr != tot_nr)
++ break;
++ }
++err_out1:
++ kfree(op_iov);
++ kfree(copied_iovector);
++ kfree(copied_xtvector);
++ goto out;
++ }
++ /* Do it by hand, with plain read/write operations */
++ else {
++ unsigned long mem_ct = 0, str_ct = 0;
++ struct xtvec *copied_xtvector = NULL;
++ struct iovec *copied_iovector = NULL;
++
++ ret = -ENOMEM;
++ copied_iovector = (struct iovec *) kmalloc(nr_segs * sizeof(struct iovec), GFP_KERNEL);
++ if (!copied_iovector)
++ goto err_out2;
++ copied_xtvector = (struct xtvec *) kmalloc(xtnr_segs * sizeof(struct xtvec), GFP_KERNEL);
++ if (!copied_xtvector)
++ goto err_out2;
++ memcpy(copied_iovector, iov, nr_segs * sizeof(struct iovec));
++ memcpy(copied_xtvector, xtv, xtnr_segs * sizeof(struct xtvec));
++
++ ret = 0;
++ mem_ct = 0;
++ str_ct = 0;
++ while ((mem_ct < nr_segs) && (str_ct < xtnr_segs)) {
++ size_t min_len;
++ loff_t pos;
++ ssize_t nr;
++ void __user *base;
++
++ pos = copied_xtvector[str_ct].xtv_off;
++ base = copied_iovector[mem_ct].iov_base;
++ min_len = min(copied_xtvector[str_ct].xtv_len, copied_iovector[mem_ct].iov_len);
++ copied_xtvector[str_ct].xtv_len -= min_len;
++ copied_xtvector[str_ct].xtv_off += min_len;
++ copied_iovector[mem_ct].iov_len -= min_len;
++ copied_iovector[mem_ct].iov_base += min_len;
++ if (copied_iovector[mem_ct].iov_len <= 0)
++ mem_ct++;
++ if (copied_xtvector[str_ct].xtv_len <= 0)
++ str_ct++;
++ /* Issue the smallest region that is contiguous in memory and on file */
++ nr = fn(file, base, min_len, &pos);
++ if (nr < 0) {
++ if (!ret) ret = nr;
++ break;
++ }
++ ret += nr;
++ if (nr != min_len)
++ break;
++ }
++err_out2:
++ kfree(copied_xtvector);
++ kfree(copied_iovector);
++ }
++out:
++ if (iov != iovstack)
++ kfree(iov);
++ if (xtv != xtvstack)
++ kfree(xtv);
++ if ((ret + (type == READ)) > 0) {
++ if (type == READ)
++ fsnotify_access(file->f_dentry);
++ else
++ fsnotify_modify(file->f_dentry);
++ }
++ return ret;
++Efault:
++ ret = -EFAULT;
++ goto out;
++}
++
++ssize_t vfs_readx(struct file *file, const struct iovec __user *vec,
++ unsigned long vlen, const struct xtvec __user *xtvec, unsigned long xtvlen)
++{
++ if (!(file->f_mode & FMODE_READ))
++ return -EBADF;
++ if (!file->f_op || (!file->f_op->readx && !file->f_op->readv && !file->f_op->read))
++ return -EINVAL;
++
++ return do_readx_writex(READ, file, vec, vlen, xtvec, xtvlen);
++}
++
++EXPORT_SYMBOL_GPL(vfs_readx);
++
++ssize_t vfs_writex(struct file *file, const struct iovec __user *vec,
++ unsigned long vlen, const struct xtvec __user *xtvec, unsigned long xtvlen)
++{
++ if (!(file->f_mode & FMODE_WRITE))
++ return -EBADF;
++ if (!file->f_op || (!file->f_op->writex && !file->f_op->writev && !file->f_op->write))
++ return -EINVAL;
++
++ return do_readx_writex(WRITE, file, vec, vlen, xtvec, xtvlen);
++}
++
++EXPORT_SYMBOL_GPL(vfs_writex);
++
++asmlinkage ssize_t sys_readx(unsigned long fd,
++ const struct iovec __user *vec,
++ unsigned long vlen,
++ const struct xtvec __user *xtvec,
++ unsigned long xtvlen)
++{
++ struct file *file;
++ ssize_t ret = -EBADF;
++ int fput_needed;
++
++ file = fget_light(fd, &fput_needed);
++ if (file) {
++ ret = vfs_readx(file, vec, vlen, xtvec, xtvlen);
++ fput_light(file, fput_needed);
++ }
++
++ if (ret > 0)
++ current->rchar += ret;
++ current->syscr++;
++ return ret;
++}
++
++asmlinkage ssize_t sys_writex(unsigned long fd,
++ const struct iovec __user *vec,
++ unsigned long vlen,
++ const struct xtvec __user *xtvec,
++ unsigned long xtvlen)
++{
++ struct file *file;
++ ssize_t ret = -EBADF;
++ int fput_needed;
++
++ file = fget_light(fd, &fput_needed);
++ if (file) {
++ ret = vfs_writex(file, vec, vlen, xtvec, xtvlen);
++ fput_light(file, fput_needed);
++ }
++
++ if (ret > 0)
++ current->wchar += ret;
++ current->syscw++;
++ return ret;
++}
++
+ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
+ size_t count, loff_t max)
+ {
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/unistd.h vanilla-new/include/asm-i386/unistd.h
+--- vanilla/include/asm-i386/unistd.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/asm-i386/unistd.h 2006-05-24 16:27:28.000000000 -0500
+@@ -326,8 +326,10 @@
+ #define __NR_fstatlite64 318
+ #define __NR_getdents_plus 319
+ #define __NR_getdents64_plus 320
++#define __NR_readx 321
++#define __NR_writex 322
+
+-#define NR_syscalls 321
++#define NR_syscalls 323
+
+ /*
+ * user-visible error numbers are in the range -1 - -128: see
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-ia64/unistd.h vanilla-new/include/asm-ia64/unistd.h
+--- vanilla/include/asm-ia64/unistd.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/asm-ia64/unistd.h 2006-05-24 16:29:19.000000000 -0500
+@@ -292,12 +292,14 @@
+ #define __NR_fstatlite 1301
+ #define __NR_getdents_plus 1302
+ #define __NR_getdents64_plus 1303
++#define __NR_readx 1304
++#define __NR_writex 1305
+
+ #ifdef __KERNEL__
+
+ #include <linux/config.h>
+
+-#define NR_syscalls 280 /* length of syscall table */
++#define NR_syscalls 282 /* length of syscall table */
+
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-powerpc/unistd.h vanilla-new/include/asm-powerpc/unistd.h
+--- vanilla/include/asm-powerpc/unistd.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/asm-powerpc/unistd.h 2006-05-24 16:30:04.000000000 -0500
+@@ -308,8 +308,10 @@
+ #define __NR_fstatlite 287
+ #define __NR_getdents_plus 288
+ #define __NR_getdents64_plus 289
++#define __NR_readx 290
++#define __NR_writex 291
+
+-#define __NR_syscalls 290
++#define __NR_syscalls 292
+
+ #ifdef __KERNEL__
+ #define __NR__exit __NR_exit
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/unistd.h vanilla-new/include/asm-x86_64/unistd.h
+--- vanilla/include/asm-x86_64/unistd.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/asm-x86_64/unistd.h 2006-05-24 16:28:26.000000000 -0500
+@@ -619,8 +619,12 @@
+ __SYSCALL(__NR_getdents_plus, sys_getdents_plus)
+ #define __NR_getdents64_plus 279
+ __SYSCALL(__NR_getdents64_plus, sys_getdents64_plus)
++#define __NR_readx 280
++__SYSCALL(__NR_readx, sys_readx)
++#define __NR_writex 281
++__SYSCALL(__NR_writex, sys_writex)
+
+-#define __NR_syscall_max __NR_getdents64_plus
++#define __NR_syscall_max __NR_writex
+
+ #ifndef __NO_STUBS
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/compat.h vanilla-new/include/linux/compat.h
+--- vanilla/include/linux/compat.h 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/include/linux/compat.h 2006-05-24 16:26:29.000000000 -0500
+@@ -61,6 +61,11 @@
+ compat_size_t iov_len;
+ };
+
++struct compat_xtvec {
++ compat_off_t xtv_off;
++ compat_size_t xtv_len;
++};
++
+ struct compat_rlimit {
+ compat_ulong_t rlim_cur;
+ compat_ulong_t rlim_max;
+@@ -141,6 +146,13 @@
+ asmlinkage ssize_t compat_sys_writev(unsigned long fd,
+ const struct compat_iovec __user *vec, unsigned long vlen);
+
++asmlinkage ssize_t compat_sys_readx(unsigned long fd,
++ const struct compat_iovec __user *vec, unsigned long vlen,
++ const struct compat_xtvec __user *xtvec, unsigned long xtvlen);
++asmlinkage ssize_t compat_sys_writex(unsigned long fd,
++ const struct compat_iovec __user *vec, unsigned long vlen,
++ const struct compat_xtvec __user *xtvec, unsigned long xtvlen);
++
+ int compat_do_execve(char * filename, compat_uptr_t __user *argv,
+ compat_uptr_t __user *envp, struct pt_regs * regs);
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/fs.h vanilla-new/include/linux/fs.h
+--- vanilla/include/linux/fs.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/linux/fs.h 2006-05-24 16:20:15.000000000 -0500
+@@ -226,6 +226,7 @@
+
+ struct hd_geometry;
+ struct iovec;
++struct xtvec;
+ struct nameidata;
+ struct kiocb;
+ struct pipe_inode_info;
+@@ -1048,6 +1049,8 @@
+ int (*lock) (struct file *, int, struct file_lock *);
+ ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
+ ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
++ ssize_t (*readx) (struct file *, const struct iovec *, unsigned long, const struct xtvec *, unsigned long);
++ ssize_t (*writex) (struct file *, const struct iovec *, unsigned long, const struct xtvec *, unsigned long);
+ ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
+ ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
+ unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
+@@ -1092,6 +1095,11 @@
+ unsigned long, loff_t *);
+ extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
+ unsigned long, loff_t *);
++extern ssize_t vfs_readx(struct file *, const struct iovec __user *,
++ unsigned long, const struct xtvec __user *, unsigned long);
++extern ssize_t vfs_writex(struct file *, const struct iovec __user *,
++ unsigned long, const struct xtvec __user *, unsigned long);
++
+
+ /*
+ * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/syscalls.h vanilla-new/include/linux/syscalls.h
+--- vanilla/include/linux/syscalls.h 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/include/linux/syscalls.h 2006-05-24 16:23:31.000000000 -0500
+@@ -17,6 +17,7 @@
+ struct iocb;
+ struct io_event;
+ struct iovec;
++struct xtvec;
+ struct itimerspec;
+ struct itimerval;
+ struct kexec_segment;
+@@ -402,6 +403,16 @@
+ asmlinkage ssize_t sys_writev(unsigned long fd,
+ const struct iovec __user *vec,
+ unsigned long vlen);
++asmlinkage ssize_t sys_readx(unsigned long fd,
++ const struct iovec __user *vec,
++ unsigned long vlen,
++ const struct xtvec __user *xtvec,
++ unsigned long xtvlen);
++asmlinkage ssize_t sys_writex(unsigned long fd,
++ const struct iovec __user *vec,
++ unsigned long vlen,
++ const struct xtvec __user *xtvec,
++ unsigned long xtvlen);
+ asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf,
+ size_t count, loff_t pos);
+ asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf,
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/uio.h vanilla-new/include/linux/uio.h
+--- vanilla/include/linux/uio.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/uio.h 2006-05-24 16:24:20.000000000 -0500
+@@ -23,6 +23,12 @@
+ __kernel_size_t iov_len; /* Must be size_t (1003.1g) */
+ };
+
++struct xtvec
++{
++ __kernel_off_t xtv_off; /* must be off_t */
++ __kernel_size_t xtv_len; /* must be size_t */
++};
++
+ #ifdef __KERNEL__
+
+ struct kvec {
+@@ -30,6 +36,12 @@
+ size_t iov_len;
+ };
+
++struct kxtvec
++{
++ off_t xtv_off;
++ size_t xtv_len;
++};
++
+ #endif
+
+ /*
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ posix-statlite-fix.patch 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,125 @@
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/stat.c vanilla-new/fs/stat.c
+--- vanilla/fs/stat.c 2006-05-24 16:19:07.000000000 -0500
++++ vanilla-new/fs/stat.c 2006-08-29 17:58:48.000000000 -0500
+@@ -345,6 +345,15 @@
+ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+ }
+
++static long get_stat_lite_mask(struct stat_lite __user *statlitebuf)
++{
++ struct stat_lite tmp;
++
++ if (copy_from_user(&tmp,statlitebuf,sizeof(tmp)))
++ return -EFAULT;
++ return tmp.st_litemask;
++}
++
+ int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf)
+ {
+ struct stat_lite tmp;
+@@ -434,7 +443,13 @@
+ asmlinkage long sys_newstatlite(char __user *filename, struct stat_lite __user *statlitebuf)
+ {
+ struct kstat_lite stat_lite;
+- int error = vfs_statlite_fd(AT_FDCWD, filename, &stat_lite);
++ int error;
++
++ stat_lite.lite_mask = get_stat_lite_mask(statlitebuf);
++ if (stat_lite.lite_mask < 0)
++ return stat_lite.lite_mask;
++
++ error = vfs_statlite_fd(AT_FDCWD, filename, &stat_lite);
+
+ if (!error)
+ error = cp_new_statlite(&stat_lite, statlitebuf);
+@@ -456,7 +471,13 @@
+ asmlinkage long sys_newlstatlite(char __user *filename, struct stat_lite __user *statlitebuf)
+ {
+ struct kstat_lite stat_lite;
+- int error = vfs_lstatlite_fd(AT_FDCWD, filename, &stat_lite);
++ int error;
++
++ stat_lite.lite_mask = get_stat_lite_mask(statlitebuf);
++ if (stat_lite.lite_mask < 0)
++ return stat_lite.lite_mask;
++
++ error = vfs_lstatlite_fd(AT_FDCWD, filename, &stat_lite);
+
+ if (!error)
+ error = cp_new_statlite(&stat_lite, statlitebuf);
+@@ -501,7 +522,13 @@
+ asmlinkage long sys_newfstatlite(unsigned int fd, struct stat_lite __user *statlitebuf)
+ {
+ struct kstat_lite stat_lite;
+- int error = vfs_fstatlite(fd, &stat_lite);
++ int error;
++
++ stat_lite.lite_mask = get_stat_lite_mask(statlitebuf);
++ if (stat_lite.lite_mask < 0)
++ return stat_lite.lite_mask;
++
++ error = vfs_fstatlite(fd, &stat_lite);
+
+ if (!error)
+ error = cp_new_statlite(&stat_lite, statlitebuf);
+@@ -580,6 +607,15 @@
+ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+ }
+
++static long get_stat64_lite_mask(struct stat64_lite __user *statlitebuf)
++{
++ struct stat64_lite tmp;
++
++ if (copy_from_user(&tmp,statlitebuf,sizeof(tmp)))
++ return -EFAULT;
++ return tmp.st_litemask;
++}
++
+ long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf)
+ {
+ struct stat64_lite tmp;
+@@ -648,7 +684,13 @@
+ asmlinkage long sys_statlite64(char __user * filename, struct stat64_lite __user * statlitebuf)
+ {
+ struct kstat_lite stat_lite;
+- int error = vfs_statlite(filename, &stat_lite);
++ int error;
++
++ stat_lite.lite_mask = get_stat64_lite_mask(statlitebuf);
++ if (stat_lite.lite_mask < 0)
++ return stat_lite.lite_mask;
++
++ error = vfs_statlite(filename, &stat_lite);
+
+ if (!error)
+ error = cp_new_stat64_lite(&stat_lite, statlitebuf);
+@@ -670,7 +712,13 @@
+ asmlinkage long sys_lstatlite64(char __user * filename, struct stat64_lite __user * statlitebuf)
+ {
+ struct kstat_lite stat_lite;
+- int error = vfs_lstatlite(filename, &stat_lite);
++ int error;
++
++ stat_lite.lite_mask = get_stat64_lite_mask(statlitebuf);
++ if (stat_lite.lite_mask < 0)
++ return stat_lite.lite_mask;
++
++ error = vfs_lstatlite(filename, &stat_lite);
+
+ if (!error)
+ error = cp_new_stat64_lite(&stat_lite, statlitebuf);
+@@ -692,7 +740,13 @@
+ asmlinkage long sys_fstatlite64(unsigned long fd, struct stat64_lite __user * statlitebuf)
+ {
+ struct kstat_lite stat_lite;
+- int error = vfs_fstatlite(fd, &stat_lite);
++ int error;
++
++ stat_lite.lite_mask = get_stat64_lite_mask(statlitebuf);
++ if (stat_lite.lite_mask < 0)
++ return stat_lite.lite_mask;
++
++ error = vfs_fstatlite(fd, &stat_lite);
+
+ if (!error)
+ error = cp_new_stat64_lite(&stat_lite, statlitebuf);
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ posix-statlite-x86_64.patch 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,77 @@
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/sys_ia32.c vanilla-new/arch/x86_64/ia32/sys_ia32.c
+--- vanilla/arch/x86_64/ia32/sys_ia32.c 2006-05-09 18:53:48.000000000 -0500
++++ vanilla-new/arch/x86_64/ia32/sys_ia32.c 2006-05-18 20:35:24.000000000 -0500
+@@ -234,13 +234,13 @@
+ return -EFAULT;
+ }
+ if (SLITE_MTIME(stat_lite->lite_mask)) {
+- if (__put_user (stat->mtime.tv_sec, &ubuf->st_mtime) ||
+- __put_user (stat->mtime.tv_nsec, &ubuf->st_mtime_nsec))
++ if (__put_user (stat_lite->mtime.tv_sec, &ubuf->st_mtime) ||
++ __put_user (stat_lite->mtime.tv_nsec, &ubuf->st_mtime_nsec))
+ return -EFAULT;
+ }
+ if (SLITE_CTIME(stat_lite->lite_mask)) {
+- if (__put_user (stat->ctime.tv_sec, &ubuf->st_ctime) ||
+- __put_user (stat->ctime.tv_nsec, &ubuf->st_ctime_nsec))
++ if (__put_user (stat_lite->ctime.tv_sec, &ubuf->st_ctime) ||
++ __put_user (stat_lite->ctime.tv_nsec, &ubuf->st_ctime_nsec))
+ return -EFAULT;
+ }
+ if (SLITE_BLKSIZE(stat_lite->lite_mask)) {
+@@ -248,7 +248,7 @@
+ return -EFAULT;
+ }
+ if (SLITE_BLOCKS(stat_lite->lite_mask)) {
+- if (__put_user (stat->blocks, &ubuf->st_blocks))
++ if (__put_user (stat_lite->blocks, &ubuf->st_blocks))
+ return -EFAULT;
+ }
+ return 0;
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/ia32.h vanilla-new/include/asm-x86_64/ia32.h
+--- vanilla/include/asm-x86_64/ia32.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-x86_64/ia32.h 2006-05-18 20:34:22.000000000 -0500
+@@ -78,6 +78,43 @@
+ unsigned long long st_ino;
+ } __attribute__((packed));
+
++/* This matches struct stat64_lite in glibc2.2, hence the absolutely
++ * insane amounts of padding around dev_t's.
++ */
++struct stat64_lite {
++ unsigned long long st_dev;
++ unsigned char __pad0[4];
++
++#define STAT64_HAS_BROKEN_ST_INO 1
++ unsigned int __st_ino;
++
++ unsigned int st_mode;
++ unsigned int st_nlink;
++
++ unsigned int st_uid;
++ unsigned int st_gid;
++
++ unsigned long long st_rdev;
++ unsigned char __pad3[4];
++
++ unsigned long st_litemask;
++ unsigned char __pad5[4];
++
++ long long st_size;
++ unsigned int st_blksize;
++
++ long long st_blocks;/* Number 512-byte blocks allocated. */
++
++ unsigned st_atime;
++ unsigned st_atime_nsec;
++ unsigned st_mtime;
++ unsigned st_mtime_nsec;
++ unsigned st_ctime;
++ unsigned st_ctime_nsec;
++
++ unsigned long long st_ino;
++} __attribute__((packed));
++
+ typedef struct compat_siginfo{
+ int si_signo;
+ int si_errno;
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ posix-statlite.patch 2008-01-07 17:27:26.000000000 -0500
@@ -0,0 +1,1112 @@
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/i386/kernel/syscall_table.S vanilla-new/arch/i386/kernel/syscall_table.S
+--- vanilla/arch/i386/kernel/syscall_table.S 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/arch/i386/kernel/syscall_table.S 2006-05-05 15:14:31.000000000 -0500
+@@ -312,3 +312,9 @@
+ .long sys_unshare /* 310 */
+ .long sys_openg
+ .long sys_openfh
++ .long sys_newstatlite
++ .long sys_newlstatlite
++ .long sys_newfstatlite
++ .long sys_statlite64
++ .long sys_lstatlite64
++ .long sys_fstatlite64
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/ia64/kernel/entry.S vanilla-new/arch/ia64/kernel/entry.S
+--- vanilla/arch/ia64/kernel/entry.S 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/arch/ia64/kernel/entry.S 2006-05-05 15:29:07.000000000 -0500
+@@ -1621,5 +1621,8 @@
+ data8 sys_unshare
+ data8 sys_openg
+ data8 sys_openfh
++ data8 sys_newstatlite
++ data8 sys_newlstatlite
++ data8 sys_newfstatlite
+
+ .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/powerpc/kernel/systbl.S vanilla-new/arch/powerpc/kernel/systbl.S
+--- vanilla/arch/powerpc/kernel/systbl.S 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/arch/powerpc/kernel/systbl.S 2006-05-05 17:02:20.000000000 -0500
+@@ -324,3 +324,6 @@
+ SYSCALL(unshare)
+ SYSCALL(openg)
+ SYSCALL(openfh)
++SYSCALL(newstatlite)
++SYSCALL(newlstatlite)
++SYSCALL(newfstatlite)
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/ia32entry.S vanilla-new/arch/x86_64/ia32/ia32entry.S
+--- vanilla/arch/x86_64/ia32/ia32entry.S 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/arch/x86_64/ia32/ia32entry.S 2006-05-05 15:15:16.000000000 -0500
+@@ -690,6 +690,12 @@
+ .quad sys_unshare /* 310 */
+ .quad compat_sys_openg
+ .quad compat_sys_openfh
++ .quad compat_sys_newstatlite
++ .quad compat_sys_newlstatlite
++ .quad compat_sys_newfstatlite
++ .quad sys32_statlite64
++ .quad sys32_lstatlite64
++ .quad sys32_fstatlite64
+ ia32_syscall_end:
+ .rept IA32_NR_syscalls-(ia32_syscall_end-ia32_sys_call_table)/8
+ .quad ni_syscall
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/arch/x86_64/ia32/sys_ia32.c vanilla-new/arch/x86_64/ia32/sys_ia32.c
+--- vanilla/arch/x86_64/ia32/sys_ia32.c 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/arch/x86_64/ia32/sys_ia32.c 2006-05-05 16:17:51.000000000 -0500
+@@ -106,6 +106,59 @@
+ return 0;
+ }
+
++int cp_compat_statlite(struct kstat_lite *kbuf, struct compat_stat_lite __user *ubuf)
++{
++ typeof(ubuf->st_uid) uid = 0;
++ typeof(ubuf->st_gid) gid = 0;
++ SET_UID(uid, kbuf->uid);
++ SET_GID(gid, kbuf->gid);
++ if (!old_valid_dev(kbuf->dev) || !old_valid_dev(kbuf->rdev))
++ return -EOVERFLOW;
++ if (SLITE_SIZET(kbuf->lite_mask) && kbuf->size >= 0x7fffffff)
++ return -EOVERFLOW;
++ if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat_lite)) ||
++ __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
++ __put_user (kbuf->ino, &ubuf->st_ino) ||
++ __put_user (kbuf->mode, &ubuf->st_mode) ||
++ __put_user (kbuf->nlink, &ubuf->st_nlink) ||
++ __put_user (uid, &ubuf->st_uid) ||
++ __put_user (gid, &ubuf->st_gid) ||
++ __put_user (old_encode_dev(kbuf->rdev), &ubuf->st_rdev))
++ return -EFAULT;
++
++ if (__put_user (kbuf->lite_mask, &ubuf->st_litemask))
++ return -EFAULT;
++
++ if (SLITE_SIZET(kbuf->lite_mask)) {
++ if (__put_user (kbuf->size, &ubuf->st_size))
++ return -EFAULT;
++ }
++ if (SLITE_ATIME(kbuf->lite_mask)) {
++ if (__put_user (kbuf->atime.tv_sec, &ubuf->st_atime) ||
++ __put_user (kbuf->atime.tv_nsec, &ubuf->st_atime_nsec))
++ return -EFAULT;
++ }
++ if (SLITE_MTIME(kbuf->lite_mask)) {
++ if (__put_user (kbuf->mtime.tv_sec, &ubuf->st_mtime) ||
++ __put_user (kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec))
++ return -EFAULT;
++ }
++ if (SLITE_CTIME(kbuf->lite_mask)) {
++ if (__put_user (kbuf->ctime.tv_sec, &ubuf->st_ctime) ||
++ __put_user (kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec))
++ return -EFAULT;
++ }
++ if (SLITE_BLKSIZE(kbuf->lite_mask)) {
++ if (__put_user (kbuf->blksize, &ubuf->st_blksize))
++ return -EFAULT;
++ }
++ if (SLITE_BLOCKS(kbuf->lite_mask)) {
++ if (__put_user (kbuf->blocks, &ubuf->st_blocks))
++ return -EFAULT;
++ }
++ return 0;
++}
++
+ asmlinkage long
+ sys32_truncate64(char __user * filename, unsigned long offset_low, unsigned long offset_high)
+ {
+@@ -150,6 +203,57 @@
+ return 0;
+ }
+
++static int
++cp_stat64_lite(struct stat64_lite __user *ubuf, struct kstat_lite *stat_lite)
++{
++ typeof(ubuf->st_uid) uid = 0;
++ typeof(ubuf->st_gid) gid = 0;
++ SET_UID(uid, stat_lite->uid);
++ SET_GID(gid, stat_lite->gid);
++ if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct stat64_lite)) ||
++ __put_user(huge_encode_dev(stat_lite->dev), &ubuf->st_dev) ||
++ __put_user (stat_lite->ino, &ubuf->__st_ino) ||
++ __put_user (stat_lite->ino, &ubuf->st_ino) ||
++ __put_user (stat_lite->mode, &ubuf->st_mode) ||
++ __put_user (stat_lite->nlink, &ubuf->st_nlink) ||
++ __put_user (uid, &ubuf->st_uid) ||
++ __put_user (gid, &ubuf->st_gid) ||
++ __put_user (huge_encode_dev(stat_lite->rdev), &ubuf->st_rdev))
++ return -EFAULT;
++
++ if (__put_user (stat_lite->lite_mask, &ubuf->st_litemask))
++ return -EFAULT;
++
++ if (SLITE_SIZET(stat_lite->lite_mask)) {
++ if (__put_user (stat_lite->size, &ubuf->st_size))
++ return -EFAULT;
++ }
++ if (SLITE_ATIME(stat_lite->lite_mask)) {
++ if (__put_user (stat_lite->atime.tv_sec, &ubuf->st_atime) ||
++ __put_user (stat_lite->atime.tv_nsec, &ubuf->st_atime_nsec))
++ return -EFAULT;
++ }
++ if (SLITE_MTIME(stat_lite->lite_mask)) {
++ if (__put_user (stat->mtime.tv_sec, &ubuf->st_mtime) ||
++ __put_user (stat->mtime.tv_nsec, &ubuf->st_mtime_nsec))
++ return -EFAULT;
++ }
++ if (SLITE_CTIME(stat_lite->lite_mask)) {
++ if (__put_user (stat->ctime.tv_sec, &ubuf->st_ctime) ||
++ __put_user (stat->ctime.tv_nsec, &ubuf->st_ctime_nsec))
++ return -EFAULT;
++ }
++ if (SLITE_BLKSIZE(stat_lite->lite_mask)) {
++ if (__put_user (stat_lite->blksize, &ubuf->st_blksize))
++ return -EFAULT;
++ }
++ if (SLITE_BLOCKS(stat_lite->lite_mask)) {
++ if (__put_user (stat->blocks, &ubuf->st_blocks))
++ return -EFAULT;
++ }
++ return 0;
++}
++
+ asmlinkage long
+ sys32_stat64(char __user * filename, struct stat64 __user *statbuf)
+ {
+@@ -161,6 +265,16 @@
+ }
+
+ asmlinkage long
++sys32_statlite64(char __user * filename, struct stat64_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int ret = vfs_statlite(filename, &stat_lite);
++ if (!ret)
++ ret = cp_stat64_lite(statlitebuf, &stat_lite);
++ return ret;
++}
++
++asmlinkage long
+ sys32_lstat64(char __user * filename, struct stat64 __user *statbuf)
+ {
+ struct kstat stat;
+@@ -171,6 +285,16 @@
+ }
+
+ asmlinkage long
++sys32_lstatlite64(char __user * filename, struct stat64_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int ret = vfs_lstatlite(filename, &stat_lite);
++ if (!ret)
++ ret = cp_stat64_lite(statlitebuf, &stat_lite);
++ return ret;
++}
++
++asmlinkage long
+ sys32_fstat64(unsigned int fd, struct stat64 __user *statbuf)
+ {
+ struct kstat stat;
+@@ -181,6 +305,16 @@
+ }
+
+ asmlinkage long
++sys32_fstatlite64(unsigned int fd, struct stat64_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int ret = vfs_fstatlite(fd, &stat_lite);
++ if (!ret)
++ ret = cp_stat64_lite(statlitebuf, &stat_lite);
++ return ret;
++}
++
++asmlinkage long
+ sys32_fstatat(unsigned int dfd, char __user *filename,
+ struct stat64 __user* statbuf, int flag)
+ {
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/compat.c vanilla-new/fs/compat.c
+--- vanilla/fs/compat.c 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/fs/compat.c 2006-05-05 14:16:16.000000000 -0500
+@@ -103,6 +103,17 @@
+ return error;
+ }
+
++asmlinkage long compat_sys_newstatlite(char __user * filename,
++ struct compat_stat_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_statlite_fd(AT_FDCWD, filename, &stat_lite);
++
++ if (!error)
++ error = cp_compat_statlite(&stat_lite, statlitebuf);
++ return error;
++}
++
+ asmlinkage long compat_sys_newlstat(char __user * filename,
+ struct compat_stat __user *statbuf)
+ {
+@@ -114,6 +125,17 @@
+ return error;
+ }
+
++asmlinkage long compat_sys_newlstatlite(char __user * filename,
++ struct compat_stat_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_lstatlite_fd(AT_FDCWD, filename, &stat_lite);
++
++ if (!error)
++ error = cp_compat_statlite(&stat_lite, statlitebuf);
++ return error;
++}
++
+ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user *filename,
+ struct compat_stat __user *statbuf, int flag)
+ {
+@@ -146,6 +168,17 @@
+ return error;
+ }
+
++asmlinkage long compat_sys_newfstatlite(unsigned int fd,
++ struct compat_stat_lite __user * statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_fstatlite(fd, &stat_lite);
++
++ if (!error)
++ error = cp_compat_statlite(&stat_lite, statlitebuf);
++ return error;
++}
++
+ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *kbuf)
+ {
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/fs/stat.c vanilla-new/fs/stat.c
+--- vanilla/fs/stat.c 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/fs/stat.c 2006-05-05 17:12:15.000000000 -0500
+@@ -38,6 +38,33 @@
+
+ EXPORT_SYMBOL(generic_fillattr);
+
++void generic_fillattr_lite(struct inode *inode, struct kstat_lite *stat_lite)
++{
++ unsigned long lite_mask = stat_lite->lite_mask;
++
++ stat_lite->dev = inode->i_sb->s_dev;
++ stat_lite->ino = inode->i_ino;
++ stat_lite->mode = inode->i_mode;
++ stat_lite->nlink = inode->i_nlink;
++ stat_lite->uid = inode->i_uid;
++ stat_lite->gid = inode->i_gid;
++ stat_lite->rdev = inode->i_rdev;
++ if (SLITE_ATIME(lite_mask))
++ stat_lite->atime = inode->i_atime;
++ if (SLITE_MTIME(lite_mask))
++ stat_lite->mtime = inode->i_mtime;
++ if (SLITE_CTIME(lite_mask))
++ stat_lite->ctime = inode->i_ctime;
++ if (SLITE_SIZET(lite_mask))
++ stat_lite->size = i_size_read(inode);
++ if (SLITE_BLOCKS(lite_mask))
++ stat_lite->blocks = inode->i_blocks;
++ if (SLITE_BLKSIZE(lite_mask))
++ stat_lite->blksize = inode->i_blksize;
++}
++
++EXPORT_SYMBOL_GPL(generic_fillattr_lite);
++
+ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+ {
+ struct inode *inode = dentry->d_inode;
+@@ -63,6 +90,31 @@
+
+ EXPORT_SYMBOL(vfs_getattr);
+
++int vfs_getattr_lite(struct vfsmount *mnt, struct dentry *dentry, struct kstat_lite *stat_lite)
++{
++ struct inode *inode = dentry->d_inode;
++ int retval;
++
++ retval = security_inode_getattr(mnt, dentry);
++ if (retval)
++ return retval;
++
++ if (inode->i_op->getattr_lite)
++ return inode->i_op->getattr_lite(mnt, dentry, stat_lite);
++
++ generic_fillattr_lite(inode, stat_lite);
++ if (!stat_lite->blksize) {
++ struct super_block *s = inode->i_sb;
++ unsigned blocks;
++ blocks = (stat_lite->size+s->s_blocksize-1) >> s->s_blocksize_bits;
++ stat_lite->blocks = (s->s_blocksize / 512) * blocks;
++ stat_lite->blksize = s->s_blocksize;
++ }
++ return 0;
++}
++
++EXPORT_SYMBOL_GPL(vfs_getattr_lite);
++
+ int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
+ {
+ struct nameidata nd;
+@@ -76,6 +128,19 @@
+ return error;
+ }
+
++int vfs_statlite_fd(int dfd, char __user *name, struct kstat_lite *stat_lite)
++{
++ struct nameidata nd;
++ int error;
++
++ error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd);
++ if (!error) {
++ error = vfs_getattr_lite(nd.mnt, nd.dentry, stat_lite);
++ path_release(&nd);
++ }
++ return error;
++}
++
+ int vfs_stat(char __user *name, struct kstat *stat)
+ {
+ return vfs_stat_fd(AT_FDCWD, name, stat);
+@@ -83,6 +148,13 @@
+
+ EXPORT_SYMBOL(vfs_stat);
+
++int vfs_statlite(char __user *name, struct kstat_lite *stat_lite)
++{
++ return vfs_statlite_fd(AT_FDCWD, name, stat_lite);
++}
++
++EXPORT_SYMBOL_GPL(vfs_statlite);
++
+ int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
+ {
+ struct nameidata nd;
+@@ -96,6 +168,19 @@
+ return error;
+ }
+
++int vfs_lstatlite_fd(int dfd, char __user *name, struct kstat_lite *stat_lite)
++{
++ struct nameidata nd;
++ int error;
++
++ error = __user_walk_fd(dfd, name, 0, &nd);
++ if (!error) {
++ error = vfs_getattr_lite(nd.mnt, nd.dentry, stat_lite);
++ path_release(&nd);
++ }
++ return error;
++}
++
+ int vfs_lstat(char __user *name, struct kstat *stat)
+ {
+ return vfs_lstat_fd(AT_FDCWD, name, stat);
+@@ -103,6 +188,13 @@
+
+ EXPORT_SYMBOL(vfs_lstat);
+
++int vfs_lstatlite(char __user *name, struct kstat_lite *stat_lite)
++{
++ return vfs_lstatlite_fd(AT_FDCWD, name, stat_lite);
++}
++
++EXPORT_SYMBOL_GPL(vfs_lstatlite);
++
+ int vfs_fstat(unsigned int fd, struct kstat *stat)
+ {
+ struct file *f = fget(fd);
+@@ -117,6 +209,20 @@
+
+ EXPORT_SYMBOL(vfs_fstat);
+
++int vfs_fstatlite(unsigned int fd, struct kstat_lite *stat_lite)
++{
++ struct file *f = fget(fd);
++ int error = -EBADF;
++
++ if (f) {
++ error = vfs_getattr_lite(f->f_vfsmnt, f->f_dentry, stat_lite);
++ fput(f);
++ }
++ return error;
++}
++
++EXPORT_SYMBOL_GPL(vfs_fstatlite);
++
+ #ifdef __ARCH_WANT_OLD_STAT
+
+ /*
+@@ -239,6 +345,81 @@
+ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+ }
+
++static int cp_new_statlite(struct kstat_lite *stat_lite, struct stat_lite __user *statlitebuf)
++{
++ struct stat_lite tmp;
++
++#if BITS_PER_LONG == 32
++ if (!old_valid_dev(stat_lite->dev) || !old_valid_dev(stat_lite->rdev))
++ return -EOVERFLOW;
++#else
++ if (!new_valid_dev(stat_lite->dev) || !new_valid_dev(stat_lite->rdev))
++ return -EOVERFLOW;
++#endif
++
++ memset(&tmp, 0, sizeof(tmp));
++#if BITS_PER_LONG == 32
++ tmp.st_dev = old_encode_dev(stat_lite->dev);
++#else
++ tmp.st_dev = new_encode_dev(stat_lite->dev);
++#endif
++ tmp.st_ino = stat_lite->ino;
++ tmp.st_mode = stat_lite->mode;
++ tmp.st_nlink = stat_lite->nlink;
++ if (tmp.st_nlink != stat_lite->nlink)
++ return -EOVERFLOW;
++ SET_UID(tmp.st_uid, stat_lite->uid);
++ SET_GID(tmp.st_gid, stat_lite->gid);
++#if BITS_PER_LONG == 32
++ tmp.st_rdev = old_encode_dev(stat_lite->rdev);
++#else
++ tmp.st_rdev = new_encode_dev(stat_lite->rdev);
++#endif
++#if BITS_PER_LONG == 32
++ if (SLITE_SIZET(stat_lite->lite_mask) && stat_lite->size > MAX_NON_LFS)
++ return -EOVERFLOW;
++#endif
++ if (SLITE_SIZET(stat_lite->lite_mask)) {
++ tmp.st_size = stat_lite->size;
++ tmp.st_litemask |= S_SLITE_SIZET;
++ }
++ if (SLITE_ATIME(stat_lite->lite_mask)) {
++ tmp.st_atime = stat_lite->atime.tv_sec;
++ tmp.st_litemask |= S_SLITE_ATIME;
++ }
++ if (SLITE_MTIME(stat_lite->lite_mask)) {
++ tmp.st_mtime = stat_lite->mtime.tv_sec;
++ tmp.st_litemask |= S_SLITE_MTIME;
++ }
++ if (SLITE_CTIME(stat_lite->lite_mask)) {
++ tmp.st_ctime = stat_lite->ctime.tv_sec;
++ tmp.st_litemask |= S_SLITE_CTIME;
++ }
++#ifdef STAT_HAVE_NSEC
++ if (SLITE_ATIME(stat_lite->lite_mask)) {
++ tmp.st_atime_nsec = stat_lite->atime.tv_nsec;
++ tmp.st_litemask |= S_SLITE_ATIME;
++ }
++ if (SLITE_MTIME(stat_lite->lite_mask)) {
++ tmp.st_mtime_nsec = stat_lite->mtime.tv_nsec;
++ tmp.st_litemask |= S_SLITE_MTIME;
++ }
++ if (SLITE_CTIME(stat_lite->lite_mask)) {
++ tmp.st_ctime_nsec = stat_lite->ctime.tv_nsec;
++ tmp.st_litemask |= S_SLITE_CTIME;
++ }
++#endif
++ if (SLITE_BLOCKS(stat_lite->lite_mask)) {
++ tmp.st_blocks = stat_lite->blocks;
++ tmp.st_litemask |= S_SLITE_BLOCKS;
++ }
++ if (SLITE_BLKSIZE(stat_lite->lite_mask)) {
++ tmp.st_blksize = stat_lite->blksize;
++ tmp.st_litemask |= S_SLITE_BLKSIZE;
++ }
++ return copy_to_user(statlitebuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
++}
++
+ asmlinkage long sys_newstat(char __user *filename, struct stat __user *statbuf)
+ {
+ struct kstat stat;
+@@ -250,6 +431,17 @@
+ return error;
+ }
+
++asmlinkage long sys_newstatlite(char __user *filename, struct stat_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_statlite_fd(AT_FDCWD, filename, &stat_lite);
++
++ if (!error)
++ error = cp_new_statlite(&stat_lite, statlitebuf);
++
++ return error;
++}
++
+ asmlinkage long sys_newlstat(char __user *filename, struct stat __user *statbuf)
+ {
+ struct kstat stat;
+@@ -261,6 +453,17 @@
+ return error;
+ }
+
++asmlinkage long sys_newlstatlite(char __user *filename, struct stat_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_lstatlite_fd(AT_FDCWD, filename, &stat_lite);
++
++ if (!error)
++ error = cp_new_statlite(&stat_lite, statlitebuf);
++
++ return error;
++}
++
+ #ifndef __ARCH_WANT_STAT64
+ asmlinkage long sys_newfstatat(int dfd, char __user *filename,
+ struct stat __user *statbuf, int flag)
+@@ -295,6 +498,17 @@
+ return error;
+ }
+
++asmlinkage long sys_newfstatlite(unsigned int fd, struct stat_lite __user *statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_fstatlite(fd, &stat_lite);
++
++ if (!error)
++ error = cp_new_statlite(&stat_lite, statlitebuf);
++
++ return error;
++}
++
+ asmlinkage long sys_readlinkat(int dfd, const char __user *path,
+ char __user *buf, int bufsiz)
+ {
+@@ -366,6 +580,60 @@
+ return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
+ }
+
++static long cp_new_stat64_lite(struct kstat_lite *stat_lite, struct stat64_lite __user *statlitebuf)
++{
++ struct stat64_lite tmp;
++
++ memset(&tmp, 0, sizeof(struct stat64_lite));
++#ifdef CONFIG_MIPS
++ /* mips has weird padding, so we don't get 64 bits there */
++ if (!new_valid_dev(stat_lite->dev) || !new_valid_dev(stat_lite->rdev))
++ return -EOVERFLOW;
++ tmp.st_dev = new_encode_dev(stat_lite->dev);
++ tmp.st_rdev = new_encode_dev(stat_lite->rdev);
++#else
++ tmp.st_dev = huge_encode_dev(stat_lite->dev);
++ tmp.st_rdev = huge_encode_dev(stat_lite->rdev);
++#endif
++ tmp.st_ino = stat_lite->ino;
++#ifdef STAT64_HAS_BROKEN_ST_INO
++ tmp.__st_ino = stat_lite->ino;
++#endif
++ tmp.st_mode = stat_lite->mode;
++ tmp.st_nlink = stat_lite->nlink;
++ tmp.st_uid = stat_lite->uid;
++ tmp.st_gid = stat_lite->gid;
++
++ if (SLITE_ATIME(stat_lite->lite_mask)) {
++ tmp.st_atime = stat_lite->atime.tv_sec;
++ tmp.st_atime_nsec = stat_lite->atime.tv_nsec;
++ tmp.st_litemask |= S_SLITE_ATIME;
++ }
++ if (SLITE_MTIME(stat_lite->lite_mask)) {
++ tmp.st_mtime = stat_lite->mtime.tv_sec;
++ tmp.st_mtime_nsec = stat_lite->mtime.tv_nsec;
++ tmp.st_litemask |= S_SLITE_MTIME;
++ }
++ if (SLITE_CTIME(stat_lite->lite_mask)) {
++ tmp.st_ctime = stat_lite->ctime.tv_sec;
++ tmp.st_ctime_nsec = stat_lite->ctime.tv_nsec;
++ tmp.st_litemask |= S_SLITE_CTIME;
++ }
++ if (SLITE_SIZET(stat_lite->lite_mask)) {
++ tmp.st_size = stat_lite->size;
++ tmp.st_litemask |= S_SLITE_SIZET;
++ }
++ if (SLITE_BLOCKS(stat_lite->lite_mask)) {
++ tmp.st_blocks = stat_lite->blocks;
++ tmp.st_litemask |= S_SLITE_BLOCKS;
++ }
++ if (SLITE_BLKSIZE(stat_lite->lite_mask)) {
++ tmp.st_blksize = stat_lite->blksize;
++ tmp.st_litemask |= S_SLITE_BLKSIZE;
++ }
++ return copy_to_user(statlitebuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
++}
++
+ asmlinkage long sys_stat64(char __user * filename, struct stat64 __user * statbuf)
+ {
+ struct kstat stat;
+@@ -376,6 +644,18 @@
+
+ return error;
+ }
++
++asmlinkage long sys_statlite64(char __user * filename, struct stat64_lite __user * statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_statlite(filename, &stat_lite);
++
++ if (!error)
++ error = cp_new_stat64_lite(&stat_lite, statlitebuf);
++
++ return error;
++}
++
+ asmlinkage long sys_lstat64(char __user * filename, struct stat64 __user * statbuf)
+ {
+ struct kstat stat;
+@@ -386,6 +666,18 @@
+
+ return error;
+ }
++
++asmlinkage long sys_lstatlite64(char __user * filename, struct stat64_lite __user * statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_lstatlite(filename, &stat_lite);
++
++ if (!error)
++ error = cp_new_stat64_lite(&stat_lite, statlitebuf);
++
++ return error;
++}
++
+ asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user * statbuf)
+ {
+ struct kstat stat;
+@@ -397,6 +689,17 @@
+ return error;
+ }
+
++asmlinkage long sys_fstatlite64(unsigned long fd, struct stat64_lite __user * statlitebuf)
++{
++ struct kstat_lite stat_lite;
++ int error = vfs_fstatlite(fd, &stat_lite);
++
++ if (!error)
++ error = cp_new_stat64_lite(&stat_lite, statlitebuf);
++
++ return error;
++}
++
+ asmlinkage long sys_fstatat64(int dfd, char __user *filename,
+ struct stat64 __user *statbuf, int flag)
+ {
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/stat.h vanilla-new/include/asm-i386/stat.h
+--- vanilla/include/asm-i386/stat.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-i386/stat.h 2006-05-05 16:58:22.000000000 -0500
+@@ -36,6 +36,28 @@
+ unsigned long __unused5;
+ };
+
++struct stat_lite {
++ unsigned long st_dev;
++ unsigned long st_ino;
++ unsigned short st_mode;
++ unsigned short st_nlink;
++ unsigned short st_uid;
++ unsigned short st_gid;
++ unsigned long st_rdev;
++ unsigned long st_litemask;
++ unsigned long st_size;
++ unsigned long st_blksize;
++ unsigned long st_blocks;
++ unsigned long st_atime;
++ unsigned long st_atime_nsec;
++ unsigned long st_mtime;
++ unsigned long st_mtime_nsec;
++ unsigned long st_ctime;
++ unsigned long st_ctime_nsec;
++ unsigned long __unused4;
++ unsigned long __unused5;
++};
++
+ /* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+@@ -75,4 +97,41 @@
+
+ #define STAT_HAVE_NSEC 1
+
++struct stat64_lite {
++ unsigned long long st_dev;
++ unsigned char __pad0[4];
++
++#define STAT64_HAS_BROKEN_ST_INO 1
++ unsigned long __st_ino;
++
++ unsigned int st_mode;
++ unsigned int st_nlink;
++
++ unsigned long st_uid;
++ unsigned long st_gid;
++
++ unsigned long long st_rdev;
++ unsigned char __pad3[4];
++
++ unsigned long st_litemask;
++ unsigned char __pad5[4];
++
++ long long st_size;
++ unsigned long st_blksize;
++
++ unsigned long st_blocks; /* Number 512-byte blocks allocated. */
++ unsigned long __pad4; /* future possible st_blocks high bits */
++
++ unsigned long st_atime;
++ unsigned long st_atime_nsec;
++
++ unsigned long st_mtime;
++ unsigned int st_mtime_nsec;
++
++ unsigned long st_ctime;
++ unsigned long st_ctime_nsec;
++
++ unsigned long long st_ino;
++};
++
+ #endif
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-i386/unistd.h vanilla-new/include/asm-i386/unistd.h
+--- vanilla/include/asm-i386/unistd.h 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/include/asm-i386/unistd.h 2006-05-05 15:22:38.000000000 -0500
+@@ -318,8 +318,14 @@
+ #define __NR_unshare 310
+ #define __NR_openg 311
+ #define __NR_openfh 312
++#define __NR_newstatlite 313
++#define __NR_newlstatlite 314
++#define __NR_newfstatlite 315
++#define __NR_statlite64 316
++#define __NR_lstatlite64 317
++#define __NR_fstatlite64 318
+
+-#define NR_syscalls 313
++#define NR_syscalls 319
+
+ /*
+ * user-visible error numbers are in the range -1 - -128: see
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-ia64/unistd.h vanilla-new/include/asm-ia64/unistd.h
+--- vanilla/include/asm-ia64/unistd.h 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/include/asm-ia64/unistd.h 2006-05-05 15:27:03.000000000 -0500
+@@ -287,12 +287,15 @@
+ #define __NR_unshare 1296
+ #define __NR_openg 1297
+ #define __NR_openfh 1298
++#define __NR_statlite 1299
++#define __NR_lstatlite 1300
++#define __NR_fstatlite 1301
+
+ #ifdef __KERNEL__
+
+ #include <linux/config.h>
+
+-#define NR_syscalls 275 /* length of syscall table */
++#define NR_syscalls 278 /* length of syscall table */
+
+ #define __ARCH_WANT_SYS_RT_SIGACTION
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-powerpc/stat.h vanilla-new/include/asm-powerpc/stat.h
+--- vanilla/include/asm-powerpc/stat.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-powerpc/stat.h 2006-05-05 11:48:16.000000000 -0500
+@@ -55,6 +55,37 @@
+ #endif
+ };
+
++struct stat_lite {
++ unsigned long st_dev;
++ ino_t st_ino;
++#ifdef __powerpc64__
++ nlink_t st_nlink;
++ mode_t st_mode;
++#else
++ mode_t st_mode;
++ nlink_t st_nlink;
++#endif
++ uid_t st_uid;
++ gid_t st_gid;
++ unsigned long st_rdev;
++ unsigned long st_litemask;
++ off_t st_size;
++ unsigned long st_blksize;
++ unsigned long st_blocks;
++ unsigned long st_atime;
++ unsigned long st_atime_nsec;
++ unsigned long st_mtime;
++ unsigned long st_mtime_nsec;
++ unsigned long st_ctime;
++ unsigned long st_ctime_nsec;
++ unsigned long __unused4;
++ unsigned long __unused5;
++#ifdef __powerpc64__
++ unsigned long __unused6;
++#endif
++};
++
++
+ /* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
+ struct stat64 {
+ unsigned long long st_dev; /* Device. */
+@@ -78,4 +109,28 @@
+ unsigned int __unused5;
+ };
+
++/* This matches struct stat64_lite in glibc2.1. Only used for 32 bit. */
++struct stat64_lite {
++ unsigned long long st_dev; /* Device. */
++ unsigned long long st_ino; /* File serial number. */
++ unsigned int st_mode; /* File mode. */
++ unsigned int st_nlink; /* Link count. */
++ unsigned int st_uid; /* User ID of the file's owner. */
++ unsigned int st_gid; /* Group ID of the file's group. */
++ unsigned long long st_rdev; /* Device number, if device. */
++ unsigned short __pad2;
++ unsigned long st_litemask;
++ long long st_size; /* Size of file, in bytes. */
++ int st_blksize; /* Optimal block size for I/O. */
++ long long st_blocks; /* Number 512-byte blocks allocated. */
++ int st_atime; /* Time of last access. */
++ unsigned int st_atime_nsec;
++ int st_mtime; /* Time of last modification. */
++ unsigned int st_mtime_nsec;
++ int st_ctime; /* Time of last status change. */
++ unsigned int st_ctime_nsec;
++ unsigned int __unused4;
++ unsigned int __unused5;
++};
++
+ #endif /* _ASM_POWERPC_STAT_H */
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/compat.h vanilla-new/include/asm-x86_64/compat.h
+--- vanilla/include/asm-x86_64/compat.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-x86_64/compat.h 2006-05-05 13:56:12.000000000 -0500
+@@ -69,6 +69,30 @@
+ u32 __unused5;
+ };
+
++struct compat_stat_lite {
++ compat_dev_t st_dev;
++ u16 __pad1;
++ compat_ino_t st_ino;
++ compat_mode_t st_mode;
++ compat_nlink_t st_nlink;
++ __compat_uid_t st_uid;
++ __compat_gid_t st_gid;
++ compat_dev_t st_rdev;
++ u16 __pad2;
++ u32 st_litemask;
++ u32 st_size;
++ u32 st_blksize;
++ u32 st_blocks;
++ u32 st_atime;
++ u32 st_atime_nsec;
++ u32 st_mtime;
++ u32 st_mtime_nsec;
++ u32 st_ctime;
++ u32 st_ctime_nsec;
++ u32 __unused4;
++ u32 __unused5;
++};
++
+ struct compat_flock {
+ short l_type;
+ short l_whence;
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/stat.h vanilla-new/include/asm-x86_64/stat.h
+--- vanilla/include/asm-x86_64/stat.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/asm-x86_64/stat.h 2006-05-05 17:05:54.000000000 -0500
+@@ -26,6 +26,30 @@
+ long __unused[3];
+ };
+
++struct stat_lite {
++ unsigned long st_dev;
++ unsigned long st_ino;
++ unsigned long st_nlink;
++
++ unsigned int st_mode;
++ unsigned int st_uid;
++ unsigned int st_gid;
++ unsigned int __pad0;
++ unsigned long st_rdev;
++ unsigned long st_litemask;
++ long st_size;
++ long st_blksize;
++ long st_blocks; /* Number 512-byte blocks allocated. */
++
++ unsigned long st_atime;
++ unsigned long st_atime_nsec;
++ unsigned long st_mtime;
++ unsigned long st_mtime_nsec;
++ unsigned long st_ctime;
++ unsigned long st_ctime_nsec;
++ long __unused[3];
++};
++
+ /* For 32bit emulation */
+ struct __old_kernel_stat {
+ unsigned short st_dev;
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/asm-x86_64/unistd.h vanilla-new/include/asm-x86_64/unistd.h
+--- vanilla/include/asm-x86_64/unistd.h 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/include/asm-x86_64/unistd.h 2006-05-05 15:18:33.000000000 -0500
+@@ -609,8 +609,14 @@
+ __SYSCALL(__NR_openg, sys_openg)
+ #define __NR_openfh 274
+ __SYSCALL(__NR_openfh, sys_openfh)
++#define __NR_newstatlite 275
++__SYSCALL(__NR_newstatlite, sys_newstatlite)
++#define __NR_newlstatlite 276
++__SYSCALL(__NR_newlstatlite, sys_newlstatlite)
++#define __NR_newfstatlite 277
++__SYSCALL(__NR_newfstatlite, sys_newfstatlite)
+
+-#define __NR_syscall_max __NR_openfh
++#define __NR_syscall_max __NR_newfstatlite
+
+ #ifndef __NO_STUBS
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/compat.h vanilla-new/include/linux/compat.h
+--- vanilla/include/linux/compat.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/compat.h 2006-05-05 16:19:58.000000000 -0500
+@@ -52,6 +52,7 @@
+ } compat_sigset_t;
+
+ extern int cp_compat_stat(struct kstat *, struct compat_stat __user *);
++extern int cp_compat_statlite(struct kstat_lite *, struct compat_stat_lite __user *);
+ extern int get_compat_timespec(struct timespec *, const struct compat_timespec __user *);
+ extern int put_compat_timespec(const struct timespec *, struct compat_timespec __user *);
+
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/fs.h vanilla-new/include/linux/fs.h
+--- vanilla/include/linux/fs.h 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/include/linux/fs.h 2006-05-05 16:55:19.000000000 -0500
+@@ -1065,6 +1065,7 @@
+ int (*permission) (struct inode *, int, struct nameidata *);
+ int (*setattr) (struct dentry *, struct iattr *);
+ int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
++ int (*getattr_lite) (struct vfsmount *mnt, struct dentry *, struct kstat_lite *);
+ int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
+ ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
+ ssize_t (*listxattr) (struct dentry *, char *, size_t);
+@@ -1702,7 +1703,9 @@
+ extern struct inode_operations page_symlink_inode_operations;
+ extern int generic_readlink(struct dentry *, char __user *, int);
+ extern void generic_fillattr(struct inode *, struct kstat *);
++extern void generic_fillattr_lite(struct inode *, struct kstat_lite *);
+ extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
++extern int vfs_getattr_lite(struct vfsmount *, struct dentry *, struct kstat_lite *);
+ void inode_add_bytes(struct inode *inode, loff_t bytes);
+ void inode_sub_bytes(struct inode *inode, loff_t bytes);
+ loff_t inode_get_bytes(struct inode *inode);
+@@ -1711,10 +1714,15 @@
+ extern int vfs_readdir(struct file *, filldir_t, void *);
+
+ extern int vfs_stat(char __user *, struct kstat *);
++extern int vfs_statlite(char __user *, struct kstat_lite *);
+ extern int vfs_lstat(char __user *, struct kstat *);
++extern int vfs_lstatlite(char __user *, struct kstat_lite *);
+ extern int vfs_stat_fd(int dfd, char __user *, struct kstat *);
++extern int vfs_statlite_fd(int dfd, char __user *, struct kstat_lite *);
+ extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *);
++extern int vfs_lstatlite_fd(int dfd, char __user *, struct kstat_lite *);
+ extern int vfs_fstat(unsigned int, struct kstat *);
++extern int vfs_fstatlite(unsigned int, struct kstat_lite *);
+
+ extern int vfs_ioctl(struct file *, unsigned int, unsigned int, unsigned long);
+
+@@ -1728,6 +1736,7 @@
+ extern loff_t dcache_dir_lseek(struct file *, loff_t, int);
+ extern int dcache_readdir(struct file *, void *, filldir_t);
+ extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *);
++extern int simple_getattr_lite(struct vfsmount *, struct dentry *, struct kstat_lite *);
+ extern int simple_statfs(struct super_block *, struct kstatfs *);
+ extern int simple_link(struct dentry *, struct inode *, struct dentry *);
+ extern int simple_unlink(struct inode *, struct dentry *);
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/stat.h vanilla-new/include/linux/stat.h
+--- vanilla/include/linux/stat.h 2006-03-19 23:53:29.000000000 -0600
++++ vanilla-new/include/linux/stat.h 2006-05-05 17:00:11.000000000 -0500
+@@ -44,6 +44,22 @@
+ #define S_IWOTH 00002
+ #define S_IXOTH 00001
+
++#define S_SLITE_SIZET 0x1
++#define S_SLITE_BLKSIZE 0x2
++#define S_SLITE_BLOCKS 0x4
++#define S_SLITE_ATIME 0x8
++#define S_SLITE_MTIME 0x10
++#define S_SLITE_CTIME 0x20
++#define S_SLITE_ALL (S_SLITE_SIZET | S_SLITE_BLKSIZE | S_SLITE_BLOCKS \
++ S_SLITE_ATIME | S_SLITE_MTIME | S_SLITE_CTIME)
++
++#define SLITE_SIZET(m) ((m) & S_SLITE_SIZET)
++#define SLITE_BLKSIZE(m) ((m) & S_SLITE_BLKSIZE)
++#define SLITE_BLOCKS(m) ((m) & S_SLITE_BLOCKS)
++#define SLITE_ATIME(m) ((m) & S_SLITE_ATIME)
++#define SLITE_MTIME(m) ((m) & S_SLITE_MTIME)
++#define SLITE_CTIME(m) ((m) & S_SLITE_CTIME)
++
+ #endif
+
+ #ifdef __KERNEL__
+@@ -72,6 +88,24 @@
+ unsigned long blocks;
+ };
+
++struct kstat_lite {
++ unsigned long ino;
++ dev_t dev;
++ umode_t mode;
++ unsigned int nlink;
++ uid_t uid;
++ gid_t gid;
++ dev_t rdev;
++ unsigned long lite_mask;
++ /* Fields below this are optional */
++ loff_t size;
++ struct timespec atime;
++ struct timespec mtime;
++ struct timespec ctime;
++ unsigned long blksize;
++ unsigned long blocks;
++};
++
+ #endif
+
+ #endif
+diff -Naur --exclude-from=/home/vilayann/redhat/BUILD/kernel-2.6.16/exclude vanilla/include/linux/syscalls.h vanilla-new/include/linux/syscalls.h
+--- vanilla/include/linux/syscalls.h 2006-05-05 13:59:14.000000000 -0500
++++ vanilla-new/include/linux/syscalls.h 2006-05-05 17:12:01.000000000 -0500
+@@ -38,7 +38,9 @@
+ struct shmid_ds;
+ struct sockaddr;
+ struct stat;
++struct stat_lite;
+ struct stat64;
++struct stat64_lite;
+ struct statfs;
+ struct statfs64;
+ struct __sysctl_args;
+@@ -226,16 +228,29 @@
+ struct __old_kernel_stat __user *statbuf);
+ asmlinkage long sys_newstat(char __user *filename,
+ struct stat __user *statbuf);
++asmlinkage long sys_newstatlite(char __user *filename,
++ struct stat_lite __user *statlitebuf);
+ asmlinkage long sys_newlstat(char __user *filename,
+ struct stat __user *statbuf);
++asmlinkage long sys_newlstatlite(char __user *filename,
++ struct stat_lite __user *statlitebuf);
+ asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf);
++asmlinkage long sys_newfstatlite(unsigned int fd,
++ struct stat_lite __user *statlitebuf);
+ asmlinkage long sys_ustat(unsigned dev, struct ustat __user *ubuf);
+ #if BITS_PER_LONG == 32
+ asmlinkage long sys_stat64(char __user *filename,
+ struct stat64 __user *statbuf);
+-asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf);
++asmlinkage long sys_statlite64(char __user *filename,
++ struct stat64_lite __user *statlitebuf);
++asmlinkage long sys_fstat64(unsigned long fd,
++ struct stat64 __user *statbuf);
++asmlinkage long sys_fstatlite64(unsigned long fd,
++ struct stat64_lite __user *statlitebuf);
+ asmlinkage long sys_lstat64(char __user *filename,
+ struct stat64 __user *statbuf);
++asmlinkage long sys_lstatlite64(char __user *filename,
++ struct stat64_lite __user *statlitebuf);
+ asmlinkage long sys_truncate64(const char __user *path, loff_t length);
+ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length);
+ #endif
More information about the Pvfs2-cvs
mailing list