Skip to content
Permalink
1139b72d5e
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
441 lines (419 sloc) 13.5 KB
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);