Hello! Just as we discussed earlier today, here is a simple version that should do everything we need. I have separated stat fields into arbitrary categories based on my idea of how this needs to be done, that could of course be refined in other ways if desired. Only x86* syscall tables updated for now and no 64bit syscalls (probably we don't need them anyway, just need to always return 64 bit structure). I quickly realized that perhaps we can use just one extra syscall for fstat, and stat/lstat could be implemented as statat with just current cwd, though I do not know how desirable that is. Also I though that it would be kind of useful to allow the bitmask to be compatible with existing statat flags usage so that we do not need a new statat. Also perhaps the ->getattr just needs a prototype change to accept the flags argument and if the FS cares about it - to use it, but I did not want to do this huge patch touching every FS right now if only to save my time should this approach to be determined as undesirable for one reason or another, so for now I add a ->getattr_light Any comments? Bye, Oleg
--- ./arch/x86/ia32/ia32entry.S.orig 2009-04-07 01:49:27.000000000 -0400 +++ ./arch/x86/ia32/ia32entry.S 2009-04-07 01:52:44.000000000 -0400 @@ -828,4 +828,7 @@ .quad sys_dup3 /* 330 */ .quad sys_pipe2 .quad sys_inotify_init1 + .quad sys_fstatlight + .quad sys_lstatlight + .quad sys_statlight ia32_syscall_end: --- ./arch/x86/include/asm/unistd_32.h.orig 2009-04-07 01:26:02.000000000 -0400 +++ ./arch/x86/include/asm/unistd_32.h 2009-04-07 01:38:39.000000000 -0400 @@ -338,6 +338,9 @@ #define __NR_dup3 330 #define __NR_pipe2 331 #define __NR_inotify_init1 332 +#define __NR_fstat_light 333 +#define __NR_lstat_light 334 +#define __NR_stat_light 335 #ifdef __KERNEL__ --- ./arch/x86/include/asm/unistd_64.h.orig 2009-04-07 01:26:12.000000000 -0400 +++ ./arch/x86/include/asm/unistd_64.h 2009-04-07 01:53:40.000000000 -0400 @@ -653,7 +653,12 @@ __SYSCALL(__NR_pipe2, sys_pipe2) #define __NR_inotify_init1 294 __SYSCALL(__NR_inotify_init1, sys_inotify_init1) - +#define __NR_fstat_light 295 +__SYSCALL(__NR_fstat_light, sys_fstatlight) +#define __NR_lstat_light 296 +__SYSCALL(__NR_lstat_light, sys_lstatlight) +#define __NR_stat_light 297 +__SYSCALL(__NR_inotify_init1, sys_statlight) #ifndef __NO_STUBS #define __ARCH_WANT_OLD_READDIR --- ./fs/stat.c.orig 2009-04-07 00:23:22.000000000 -0400 +++ ./fs/stat.c 2009-04-07 01:51:49.000000000 -0400 @@ -37,7 +37,8 @@ EXPORT_SYMBOL(generic_fillattr); -int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) +int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat, + unsigned int flags) { struct inode *inode = dentry->d_inode; int retval; @@ -46,6 +47,9 @@ if (retval) return retval; + if (inode->i_op->getattr_light) + return inode->i_op->getattr_light(mnt, dentry, stat, flags); + if (inode->i_op->getattr) return inode->i_op->getattr(mnt, dentry, stat); @@ -55,53 +59,56 @@ EXPORT_SYMBOL(vfs_getattr); -int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) +int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat, + unsigned int flags) { struct path path; int error; error = user_path_at(dfd, name, LOOKUP_FOLLOW, &path); if (!error) { - error = vfs_getattr(path.mnt, path.dentry, stat); + error = vfs_getattr(path.mnt, path.dentry, stat, flags); path_put(&path); } return error; } -int vfs_stat(char __user *name, struct kstat *stat) +int vfs_stat(char __user *name, struct kstat *stat, unsigned int flags) { - return vfs_stat_fd(AT_FDCWD, name, stat); + return vfs_stat_fd(AT_FDCWD, name, stat, flags); } EXPORT_SYMBOL(vfs_stat); -int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) +int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat, + unsigned int flags) { struct path path; int error; error = user_path_at(dfd, name, 0, &path); if (!error) { - error = vfs_getattr(path.mnt, path.dentry, stat); + error = vfs_getattr(path.mnt, path.dentry, stat, flags); path_put(&path); } return error; } -int vfs_lstat(char __user *name, struct kstat *stat) +int vfs_lstat(char __user *name, struct kstat *stat, unsigned int flags) { - return vfs_lstat_fd(AT_FDCWD, name, stat); + return vfs_lstat_fd(AT_FDCWD, name, stat, flags); } EXPORT_SYMBOL(vfs_lstat); -int vfs_fstat(unsigned int fd, struct kstat *stat) +int vfs_fstat(unsigned int fd, struct kstat *stat, unsigned int flags) { struct file *f = fget(fd); int error = -EBADF; if (f) { - error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat); + error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat, + flags); fput(f); } return error; @@ -155,7 +162,7 @@ SYSCALL_DEFINE2(stat, char __user *, filename, struct __old_kernel_stat __user *, statbuf) { struct kstat stat; - int error = vfs_stat_fd(AT_FDCWD, filename, &stat); + int error = vfs_stat_fd(AT_FDCWD, filename, &stat, STAT_EVERYTHING); if (!error) error = cp_old_stat(&stat, statbuf); @@ -166,7 +173,7 @@ SYSCALL_DEFINE2(lstat, char __user *, filename, struct __old_kernel_stat __user *, statbuf) { struct kstat stat; - int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); + int error = vfs_lstat_fd(AT_FDCWD, filename, &stat, STAT_EVERYTHING); if (!error) error = cp_old_stat(&stat, statbuf); @@ -177,7 +184,7 @@ SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf) { struct kstat stat; - int error = vfs_fstat(fd, &stat); + int error = vfs_fstat(fd, &stat, STAT_EVERYTHING); if (!error) error = cp_old_stat(&stat, statbuf); @@ -240,7 +247,7 @@ SYSCALL_DEFINE2(newstat, char __user *, filename, struct stat __user *, statbuf) { struct kstat stat; - int error = vfs_stat_fd(AT_FDCWD, filename, &stat); + int error = vfs_stat_fd(AT_FDCWD, filename, &stat, STAT_EVERYTHING); if (!error) error = cp_new_stat(&stat, statbuf); @@ -251,7 +258,7 @@ SYSCALL_DEFINE2(newlstat, char __user *, filename, struct stat __user *, statbuf) { struct kstat stat; - int error = vfs_lstat_fd(AT_FDCWD, filename, &stat); + int error = vfs_lstat_fd(AT_FDCWD, filename, &stat, STAT_EVERYTHING); if (!error) error = cp_new_stat(&stat, statbuf); @@ -270,9 +277,9 @@ goto out; if (flag & AT_SYMLINK_NOFOLLOW) - error = vfs_lstat_fd(dfd, filename, &stat); + error = vfs_lstat_fd(dfd, filename, &stat, STAT_EVERYTHING); else - error = vfs_stat_fd(dfd, filename, &stat); + error = vfs_stat_fd(dfd, filename, &stat, STAT_EVERYTHING); if (!error) error = cp_new_stat(&stat, statbuf); @@ -285,7 +292,43 @@ SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf) { struct kstat stat; - int error = vfs_fstat(fd, &stat); + int error = vfs_fstat(fd, &stat, STAT_EVERYTHING); + + if (!error) + error = cp_new_stat(&stat, statbuf); + + return error; +} + +SYSCALL_DEFINE3(statlight, char __user *, filename, + struct stat __user *, statbuf, unsigned int, flags) +{ + struct kstat stat; + int error = vfs_stat_fd(AT_FDCWD, filename, &stat, flags); + + if (!error) + error = cp_new_stat(&stat, statbuf); + + return error; +} + +SYSCALL_DEFINE3(lstatlight, char __user *, filename, + struct stat __user *, statbuf, unsigned int, flags) +{ + struct kstat stat; + int error = vfs_lstat_fd(AT_FDCWD, filename, &stat, flags); + + if (!error) + error = cp_new_stat(&stat, statbuf); + + return error; +} + +SYSCALL_DEFINE3(fstatlight, unsigned int, fd, struct stat __user *, statbuf, + unsigned int, flags) +{ + struct kstat stat; + int error = vfs_fstat(fd, &stat, flags); if (!error) error = cp_new_stat(&stat, statbuf); @@ -370,7 +413,7 @@ SYSCALL_DEFINE2(stat64, char __user *, filename, struct stat64 __user *, statbuf) { struct kstat stat; - int error = vfs_stat(filename, &stat); + int error = vfs_stat(filename, &stat, STAT_EVERYTHING); if (!error) error = cp_new_stat64(&stat, statbuf); @@ -381,7 +424,7 @@ SYSCALL_DEFINE2(lstat64, char __user *, filename, struct stat64 __user *, statbuf) { struct kstat stat; - int error = vfs_lstat(filename, &stat); + int error = vfs_lstat(filename, &stat, STAT_EVERYTHING); if (!error) error = cp_new_stat64(&stat, statbuf); @@ -392,7 +435,7 @@ SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf) { struct kstat stat; - int error = vfs_fstat(fd, &stat); + int error = vfs_fstat(fd, &stat, STAT_EVERYTHING); if (!error) error = cp_new_stat64(&stat, statbuf); @@ -410,9 +453,9 @@ goto out; if (flag & AT_SYMLINK_NOFOLLOW) - error = vfs_lstat_fd(dfd, filename, &stat); + error = vfs_lstat_fd(dfd, filename, &stat, STAT_EVERYTHING); else - error = vfs_stat_fd(dfd, filename, &stat); + error = vfs_stat_fd(dfd, filename, &stat, STAT_EVERYTHING); if (!error) error = cp_new_stat64(&stat, statbuf); --- ./include/linux/fcntl.h.orig 2009-04-07 00:31:36.000000000 -0400 +++ ./include/linux/fcntl.h 2009-04-07 00:44:41.000000000 -0400 @@ -40,6 +40,14 @@ unlinking file. */ #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ +/* Bits to define what fields the "stat light" syscall must fill in struct stat, + * should not intersect with abovr AT_* bits */ +#define STAT_NLINK 0x01000 /* nlink */ +#define STAT_TIMES 0x02000 /* atime, mtime, ctime */ +#define STAT_SIZE 0x04000 /* File size and blocks */ +#define STAT_ACCESS 0x08000 /* mode, user, group */ +#define STAT_EVERYTHING 0x0f000 /* Just a normal stat */ + #ifdef __KERNEL__ #ifndef force_o_largefile --- ./include/linux/fs.h.orig 2009-04-07 00:30:52.000000000 -0400 +++ ./include/linux/fs.h 2009-04-07 01:03:58.000000000 -0400 @@ -1354,6 +1354,8 @@ int (*permission) (struct inode *, int); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); + int (*getattr_light) (struct vfsmount *mnt, struct dentry *, + struct kstat *, unsigned int); 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); @@ -2062,7 +2064,8 @@ extern const 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 int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); +extern int vfs_getattr(struct vfsmount *, struct dentry *, struct kstat *, + unsigned int); 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); @@ -2070,11 +2073,11 @@ extern int vfs_readdir(struct file *, filldir_t, void *); -extern int vfs_stat(char __user *, struct kstat *); -extern int vfs_lstat(char __user *, struct kstat *); -extern int vfs_stat_fd(int dfd, char __user *, struct kstat *); -extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *); -extern int vfs_fstat(unsigned int, struct kstat *); +extern int vfs_stat(char __user *, struct kstat *, unsigned int); +extern int vfs_lstat(char __user *, struct kstat *, unsigned int); +extern int vfs_stat_fd(int dfd, char __user *, struct kstat *, unsigned int); +extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *, unsigned int); +extern int vfs_fstat(unsigned int, struct kstat *, unsigned int); extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, unsigned long arg); --- ./include/linux/syscalls.h.orig 2009-04-07 01:18:06.000000000 -0400 +++ ./include/linux/syscalls.h 2009-04-07 01:57:34.000000000 -0400 @@ -304,6 +304,13 @@ struct stat __user *statbuf); asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf); asmlinkage long sys_ustat(unsigned dev, struct ustat __user *ubuf); +asmlinkage long sys_fstatlight(unsigned int fd, + struct stat __user *statbuf, + unsigned int); +asmlinkage long sys_statlight(char __user *filename, + struct stat __user *statbuf, unsigned int); +asmlinkage long sys_lstatlight(char __user *filename, + struct stat __user *statbuf, unsigned int); #if BITS_PER_LONG == 32 asmlinkage long sys_stat64(char __user *filename, struct stat64 __user *statbuf);