Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 605960 Details for
Bug 850426
gfs2: Add xgetdents syscall to the kernel
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
First bash at a patch
xgetdents-try1-08202012.patch (text/plain), 47.08 KB, created by
Abhijith Das
on 2012-08-21 14:55:36 UTC
(
hide
)
Description:
First bash at a patch
Filename:
MIME Type:
Creator:
Abhijith Das
Created:
2012-08-21 14:55:36 UTC
Size:
47.08 KB
patch
obsolete
>diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl >index 7a35a6e..fe54552 100644 >--- a/arch/x86/syscalls/syscall_32.tbl >+++ b/arch/x86/syscalls/syscall_32.tbl >@@ -356,3 +356,6 @@ > 347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv > 348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev > 349 i386 kcmp sys_kcmp >+350 i386 xstat sys_xstat >+351 i386 fxstat sys_fxstat >+352 i386 xgetdents sys_xgetdents >\ No newline at end of file >diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl >index 51171ae..f17413b 100644 >--- a/arch/x86/syscalls/syscall_64.tbl >+++ b/arch/x86/syscalls/syscall_64.tbl >@@ -319,6 +319,9 @@ > 310 64 process_vm_readv sys_process_vm_readv > 311 64 process_vm_writev sys_process_vm_writev > 312 64 kcmp sys_kcmp >+313 common xstat sys_xstat >+314 common fxstat sys_fxstat >+315 common xgetdents sys_xgetdents > > # > # x32-specific system call numbers start at 512 to avoid cache impact >diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h >index c3411d4..f1d24b3 100644 >--- a/fs/ext4/ext4.h >+++ b/fs/ext4/ext4.h >@@ -1987,6 +1987,8 @@ extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, > struct kstat *stat); > extern void ext4_evict_inode(struct inode *); > extern void ext4_clear_inode(struct inode *); >+extern int ext4_file_getattr(struct vfsmount *mnt, struct dentry *dentry, >+ struct kstat *stat); > extern int ext4_sync_inode(handle_t *, struct inode *); > extern void ext4_dirty_inode(struct inode *, int); > extern int ext4_change_inode_journal_flag(struct inode *, int); >diff --git a/fs/ext4/file.c b/fs/ext4/file.c >index 3b0e3bd..9992273 100644 >--- a/fs/ext4/file.c >+++ b/fs/ext4/file.c >@@ -325,7 +325,7 @@ const struct file_operations ext4_file_operations = { > > const struct inode_operations ext4_file_inode_operations = { > .setattr = ext4_setattr, >- .getattr = ext4_getattr, >+ .getattr = ext4_file_getattr, > #ifdef CONFIG_EXT4_FS_XATTR > .setxattr = generic_setxattr, > .getxattr = generic_getxattr, >diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c >index 6324f74..2c5a427 100644 >--- a/fs/ext4/inode.c >+++ b/fs/ext4/inode.c >@@ -4377,11 +4377,37 @@ err_out: > int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, > struct kstat *stat) > { >- struct inode *inode; >- unsigned long delalloc_blocks; >+ struct inode *inode = dentry->d_inode; >+ struct ext4_inode_info *ei = EXT4_I(inode); >+ >+ stat->result_mask |= XSTAT_BTIME; >+ stat->btime.tv_sec = ei->i_crtime.tv_sec; >+ stat->btime.tv_nsec = ei->i_crtime.tv_nsec; >+ >+ if (inode->i_ino != EXT4_ROOT_INO) { >+ stat->result_mask |= XSTAT_GEN; >+ stat->gen = inode->i_generation; >+ } >+ if (S_ISDIR(inode->i_mode) || IS_I_VERSION(inode)) { >+ stat->result_mask |= XSTAT_VERSION; >+ stat->version = inode->i_version; >+ } >+ >+ ext4_get_inode_flags(ei); >+ stat->ioc_flags |= ei->i_flags & EXT4_FL_USER_VISIBLE; >+ stat->result_mask |= XSTAT_IOC_FLAGS; > >- inode = dentry->d_inode; > generic_fillattr(inode, stat); >+ return 0; >+} >+ >+int ext4_file_getattr(struct vfsmount *mnt, struct dentry *dentry, >+ struct kstat *stat) >+{ >+ struct inode *inode = dentry->d_inode; >+ u64 delalloc_blocks; >+ >+ ext4_getattr(mnt, dentry, stat); > > /* > * We can't update i_blocks if the block allocation is delayed >diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c >index 2a42cc0..dad9f7e 100644 >--- a/fs/ext4/namei.c >+++ b/fs/ext4/namei.c >@@ -2976,6 +2976,7 @@ const struct inode_operations ext4_dir_inode_operations = { > .mknod = ext4_mknod, > .rename = ext4_rename, > .setattr = ext4_setattr, >+ .getattr = ext4_getattr, > #ifdef CONFIG_EXT4_FS_XATTR > .setxattr = generic_setxattr, > .getxattr = generic_getxattr, >@@ -2988,6 +2989,7 @@ const struct inode_operations ext4_dir_inode_operations = { > > const struct inode_operations ext4_special_inode_operations = { > .setattr = ext4_setattr, >+ .getattr = ext4_getattr, > #ifdef CONFIG_EXT4_FS_XATTR > .setxattr = generic_setxattr, > .getxattr = generic_getxattr, >diff --git a/fs/ext4/super.c b/fs/ext4/super.c >index d76ec82..64ee59c 100644 >--- a/fs/ext4/super.c >+++ b/fs/ext4/super.c >@@ -3285,6 +3285,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) > if (sb->s_magic != EXT4_SUPER_MAGIC) > goto cantfind_ext4; > sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); >+ memcpy(sb->s_volume_id, es->s_uuid, sizeof(sb->s_volume_id)); > > /* Warn if metadata_csum and gdt_csum are both set. */ > if (EXT4_HAS_RO_COMPAT_FEATURE(sb, >diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c >index ed9354a..7c5184a 100644 >--- a/fs/ext4/symlink.c >+++ b/fs/ext4/symlink.c >@@ -35,6 +35,7 @@ const struct inode_operations ext4_symlink_inode_operations = { > .follow_link = page_follow_link_light, > .put_link = page_put_link, > .setattr = ext4_setattr, >+ .getattr = ext4_getattr, > #ifdef CONFIG_EXT4_FS_XATTR > .setxattr = generic_setxattr, > .getxattr = generic_getxattr, >@@ -47,6 +48,7 @@ const struct inode_operations ext4_fast_symlink_inode_operations = { > .readlink = generic_readlink, > .follow_link = ext4_follow_link, > .setattr = ext4_setattr, >+ .getattr = ext4_getattr, > #ifdef CONFIG_EXT4_FS_XATTR > .setxattr = generic_setxattr, > .getxattr = generic_getxattr, >diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c >index 259b088..05dc7af 100644 >--- a/fs/gfs2/dir.c >+++ b/fs/gfs2/dir.c >@@ -1196,7 +1196,8 @@ static int compare_dents(const void *a, const void *b) > * @dip: The GFS2 inode > * @offset: The offset in the file to read from > * @opaque: opaque data to pass to filldir >- * @filldir: The function to pass entries to >+ * @filldir: The function to pass entries to. Could be filldir_t or xfilldir_t >+ * @stat: Pointer to a kstat buffer. filldir = kstat ? xfilldir_t : filldir_t > * @darr: an array of struct gfs2_dirent pointers to read > * @entries: the number of entries in darr > * @copied: pointer to int that's non-zero if a entry has been copied out >@@ -1210,7 +1211,7 @@ static int compare_dents(const void *a, const void *b) > */ > > static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, >- void *opaque, filldir_t filldir, >+ void *opaque, void *filldir, struct kstat *stat, > const struct gfs2_dirent **darr, u32 entries, > int *copied) > { >@@ -1251,10 +1252,33 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset, > *offset = off; > } > >- error = filldir(opaque, (const char *)(dent + 1), >- be16_to_cpu(dent->de_name_len), >- off, be64_to_cpu(dent->de_inum.no_addr), >- be16_to_cpu(dent->de_type)); >+ if (!stat) { >+ filldir_t fdir = (filldir_t) filldir; >+ error = fdir(opaque, (const char *)(dent + 1), >+ be16_to_cpu(dent->de_name_len), >+ off, be64_to_cpu(dent->de_inum.no_addr), >+ be16_to_cpu(dent->de_type)); >+ } else { /* xfilldir */ >+ xfilldir_t fdir = (xfilldir_t) filldir; >+ struct inode *inode; >+ inode = gfs2_inode_lookup(dip->i_inode.i_sb, >+ be16_to_cpu(dent->de_type), >+ be64_to_cpu(dent->de_inum.no_addr), >+ be64_to_cpu(dent->de_inum.no_formal_ino), 0); >+ if (IS_ERR(inode)) >+ return 1; >+ >+ error = gfs2_getattr_i(inode, stat); >+ if (error) >+ goto iput; >+ >+ error = fdir(opaque, (const char *)(dent + 1), >+ be16_to_cpu(dent->de_name_len), >+ off, be64_to_cpu(dent->de_inum.no_addr), >+ be16_to_cpu(dent->de_type), stat); >+ iput: >+ iput(inode); >+ } > if (error) > return 1; > >@@ -1290,8 +1314,8 @@ static void gfs2_free_sort_buffer(void *ptr) > } > > static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, >- filldir_t filldir, int *copied, unsigned *depth, >- u64 leaf_no) >+ void *filldir, struct kstat *stat, int *copied, >+ unsigned *depth, u64 leaf_no) > { > struct gfs2_inode *ip = GFS2_I(inode); > struct gfs2_sbd *sdp = GFS2_SB(inode); >@@ -1368,7 +1392,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque, > } while(lfn); > > BUG_ON(entries2 != entries); >- error = do_filldir_main(ip, offset, opaque, filldir, darr, >+ error = do_filldir_main(ip, offset, opaque, filldir, stat, darr, > entries, copied); > out_free: > for(i = 0; i < leaf; i++) >@@ -1436,7 +1460,7 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index, > */ > > static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, >- filldir_t filldir, struct file_ra_state *f_ra) >+ void *filldir, struct kstat *stat, struct file_ra_state *f_ra) > { > struct gfs2_inode *dip = GFS2_I(inode); > u32 hsize, len = 0; >@@ -1460,7 +1484,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, > > while (index < hsize) { > error = gfs2_dir_read_leaf(inode, offset, opaque, filldir, >- &copied, &depth, >+ stat, &copied, &depth, > be64_to_cpu(lp[index])); > if (error) > break; >@@ -1475,7 +1499,7 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, > } > > int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, >- filldir_t filldir, struct file_ra_state *f_ra) >+ void *filldir, struct kstat *stat, struct file_ra_state *f_ra) > { > struct gfs2_inode *dip = GFS2_I(inode); > struct gfs2_sbd *sdp = GFS2_SB(inode); >@@ -1489,7 +1513,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, > return 0; > > if (dip->i_diskflags & GFS2_DIF_EXHASH) >- return dir_e_read(inode, offset, opaque, filldir, f_ra); >+ return dir_e_read(inode, offset, opaque, filldir, stat, f_ra); > > if (!gfs2_is_stuffed(dip)) { > gfs2_consist_inode(dip); >@@ -1521,8 +1545,8 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, > error = -EIO; > goto out; > } >- error = do_filldir_main(dip, offset, opaque, filldir, darr, >- dip->i_entries, &copied); >+ error = do_filldir_main(dip, offset, opaque, filldir, stat, >+ darr, dip->i_entries, &copied); > out: > kfree(darr); > } >diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h >index 98c960b..8846757 100644 >--- a/fs/gfs2/dir.h >+++ b/fs/gfs2/dir.h >@@ -25,7 +25,7 @@ extern int gfs2_dir_add(struct inode *inode, const struct qstr *filename, > const struct gfs2_inode *ip); > extern int gfs2_dir_del(struct gfs2_inode *dip, const struct dentry *dentry); > extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, >- filldir_t filldir, struct file_ra_state *f_ra); >+ void *filldir, struct kstat *stat, struct file_ra_state *f_ra); > extern int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename, > const struct gfs2_inode *nip, unsigned int new_type); > >diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c >index e8ed6d4..f0bba59 100644 >--- a/fs/gfs2/export.c >+++ b/fs/gfs2/export.c >@@ -112,7 +112,7 @@ static int gfs2_get_name(struct dentry *parent, char *name, > if (error) > return error; > >- error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir, &f_ra); >+ error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir, NULL, &f_ra); > > gfs2_glock_dq_uninit(&gh); > >diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c >index 30e2199..fb83218 100644 >--- a/fs/gfs2/file.c >+++ b/fs/gfs2/file.c >@@ -25,6 +25,7 @@ > #include <asm/uaccess.h> > #include <linux/dlm.h> > #include <linux/dlm_plock.h> >+#include <linux/stat.h> > > #include "gfs2.h" > #include "incore.h" >@@ -88,7 +89,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin) > * > * Returns: errno > */ >- > static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) > { > struct inode *dir = file->f_mapping->host; >@@ -104,7 +104,51 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) > return error; > } > >- error = gfs2_dir_read(dir, &offset, dirent, filldir, &file->f_ra); >+ error = gfs2_dir_read(dir, &offset, dirent, (void *) filldir, NULL, >+ &file->f_ra); >+ >+ gfs2_glock_dq_uninit(&d_gh); >+ >+ file->f_pos = offset; >+ >+ return error; >+} >+ >+/** >+ * gfs2_xreaddir - Read directory entries with xstat info >+ * @file: The directory to read from >+ * @xdirent: Buffer for xdirents >+ * @xfilldir: Function used to do the copying >+ * >+ * Returns: errno >+ */ >+static int gfs2_xreaddir(struct file *file, void *xdirent, xfilldir_t xfilldir, >+ unsigned flags, unsigned int mask) >+{ >+ struct inode *dir = file->f_mapping->host; >+ struct gfs2_inode *dip = GFS2_I(dir); >+ struct gfs2_holder d_gh; >+ struct kstat stat; >+ u64 offset = file->f_pos; >+ int error; >+ >+ error = xdirent_get_params(mask, &stat); >+ if (error != 0) >+ return error; >+ >+ stat.query_flags = flags & KSTAT_QUERY_FLAGS; >+ stat.result_mask = 0; >+ stat.information = 0; >+ stat.ioc_flags = 0; >+ >+ gfs2_holder_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh); >+ error = gfs2_glock_nq(&d_gh); >+ if (error) { >+ gfs2_holder_uninit(&d_gh); >+ return error; >+ } >+ >+ error = gfs2_dir_read(dir, &offset, xdirent, (void *) xfilldir, &stat, &file->f_ra); > > gfs2_glock_dq_uninit(&d_gh); > >@@ -1043,6 +1087,7 @@ const struct file_operations gfs2_file_fops = { > > const struct file_operations gfs2_dir_fops = { > .readdir = gfs2_readdir, >+ .xreaddir = gfs2_xreaddir, > .unlocked_ioctl = gfs2_ioctl, > .open = gfs2_open, > .release = gfs2_release, >@@ -1073,6 +1118,7 @@ const struct file_operations gfs2_file_fops_nolock = { > > const struct file_operations gfs2_dir_fops_nolock = { > .readdir = gfs2_readdir, >+ .xreaddir = gfs2_xreaddir, > .unlocked_ioctl = gfs2_ioctl, > .open = gfs2_open, > .release = gfs2_release, >diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c >index f2709ea..7d18fda 100644 >--- a/fs/gfs2/inode.c >+++ b/fs/gfs2/inode.c >@@ -1670,6 +1670,15 @@ out: > return error; > } > >+inline int gfs2_getattr_i(struct inode *inode, struct kstat *stat) >+{ >+ int error = 0; >+ >+ generic_fillattr(inode, stat); >+ >+ return error; >+} >+ > /** > * gfs2_getattr - Read out an inode's attributes > * @mnt: The vfsmount the inode is being accessed from >@@ -1701,7 +1710,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, > unlock = 1; > } > >- generic_fillattr(inode, stat); >+ gfs2_getattr_i(inode, stat); > if (unlock) > gfs2_glock_dq_uninit(&gh); > >diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h >index c53c747..79775fa 100644 >--- a/fs/gfs2/inode.h >+++ b/fs/gfs2/inode.h >@@ -106,6 +106,8 @@ extern int gfs2_inode_refresh(struct gfs2_inode *ip); > extern struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name, > int is_root); > extern int gfs2_permission(struct inode *inode, int mask); >+extern int gfs2_getattr_i(struct inode *inode, struct kstat *stat); >+ > extern int gfs2_setattr_simple(struct inode *inode, struct iattr *attr); > extern struct inode *gfs2_lookup_simple(struct inode *dip, const char *name); > extern void gfs2_dinode_out(const struct gfs2_inode *ip, void *buf); >diff --git a/fs/readdir.c b/fs/readdir.c >index 39e3370..dd53207 100644 >--- a/fs/readdir.c >+++ b/fs/readdir.c >@@ -20,11 +20,12 @@ > > #include <asm/uaccess.h> > >-int vfs_readdir(struct file *file, filldir_t filler, void *buf) >+static int vfs_xreaddir_i(struct file *file, filldir_t filler, xfilldir_t xfiller, >+ void *buf, unsigned flags, unsigned int mask) > { > struct inode *inode = file->f_path.dentry->d_inode; > int res = -ENOTDIR; >- if (!file->f_op || !file->f_op->readdir) >+ if (!file->f_op || (filler ? !file->f_op->readdir : !file->f_op->xreaddir)) > goto out; > > res = security_file_permission(file, MAY_READ); >@@ -37,7 +38,8 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf) > > res = -ENOENT; > if (!IS_DEADDIR(inode)) { >- res = file->f_op->readdir(file, buf, filler); >+ res = filler ? file->f_op->readdir(file, buf, filler) : >+ file->f_op->xreaddir(file, buf, xfiller, flags, mask); > file_accessed(file); > } > mutex_unlock(&inode->i_mutex); >@@ -45,8 +47,20 @@ out: > return res; > } > >+int vfs_readdir(struct file *file, filldir_t filler, void *buf) >+{ >+ return vfs_xreaddir_i(file, filler, NULL, buf, 0, 0); >+} >+ > EXPORT_SYMBOL(vfs_readdir); > >+int vfs_xreaddir(struct file *file, xfilldir_t xfiller, void *buf, unsigned flags, >+ unsigned int mask) >+{ >+ return vfs_xreaddir_i(file, NULL, xfiller, buf, flags, mask); >+} >+EXPORT_SYMBOL(vfs_xreaddir); >+ > /* > * Traditional linux readdir() handling.. > * >@@ -127,17 +141,6 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, > > #endif /* __ARCH_WANT_OLD_READDIR */ > >-/* >- * New, all-improved, singing, dancing, iBCS2-compliant getdents() >- * interface. >- */ >-struct linux_dirent { >- unsigned long d_ino; >- unsigned long d_off; >- unsigned short d_reclen; >- char d_name[1]; >-}; >- > struct getdents_callback { > struct linux_dirent __user * current_dir; > struct linux_dirent __user * previous; >@@ -145,17 +148,18 @@ struct getdents_callback { > int error; > }; > >-static int filldir(void * __buf, const char * name, int namlen, loff_t offset, >- u64 ino, unsigned int d_type) >+static int xfilldir_i(void *__buf, const char *name, int namlen, loff_t offset, >+ u64 ino, unsigned int d_type, struct kstat *stat) > { >- struct linux_dirent __user * dirent; >- struct getdents_callback * buf = (struct getdents_callback *) __buf; >+ struct linux_dirent __user *dirent; >+ struct getdents_callback *buf = (struct getdents_callback *) __buf; > unsigned long d_ino; >+ int stat_sz = stat ? sizeof(struct xstat) : 0; > int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, >- sizeof(long)); >+ sizeof(long)); > >- buf->error = -EINVAL; /* only used if we fail.. */ >- if (reclen > buf->count) >+ buf->error = -EINVAL; /* only used if we fail */ >+ if (reclen + stat_sz > buf->count) > return -EINVAL; > d_ino = ino; > if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { >@@ -178,38 +182,63 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, > goto efault; > if (__put_user(d_type, (char __user *) dirent + reclen - 1)) > goto efault; >+ > buf->previous = dirent; >- dirent = (void __user *)dirent + reclen; >+ >+ if (stat) { >+ /* Copy the kstat struct here */ >+ struct linux_xdirent __user *xdirent; >+ xdirent = container_of(dirent, struct linux_xdirent, x_dent); >+ if (xstat_set_result(stat, &xdirent->x_st)) >+ goto efault; >+ xdirent = (void __user *)xdirent + reclen + stat_sz; >+ dirent = &xdirent->x_dent; >+ } else { >+ dirent = (void __user *)dirent + reclen; >+ } >+ > buf->current_dir = dirent; >- buf->count -= reclen; >+ buf->count -= reclen + stat_sz; >+ > return 0; > efault: > buf->error = -EFAULT; > return -EFAULT; > } > >-SYSCALL_DEFINE3(getdents, unsigned int, fd, >- struct linux_dirent __user *, dirent, unsigned int, count) >+static int filldir(void * __buf, const char * name, int namlen, loff_t offset, >+ u64 ino, unsigned int d_type) > { >- struct file * file; >- struct linux_dirent __user * lastdirent; >+ return xfilldir_i(__buf, name, namlen, offset, ino, d_type, NULL); >+} >+ >+static int xfilldir(void *__buf, const char *name, int namlen, loff_t offset, >+ u64 ino, unsigned int d_type, struct kstat *stat) >+{ >+ return xfilldir_i(__buf, name, namlen, offset, ino, d_type, stat); >+} >+ >+static int xgetdents_i(unsigned int fd, struct linux_dirent __user *dirent, >+ struct linux_xdirent __user *xdirent, unsigned int count, >+ unsigned int flags, unsigned int mask) >+{ >+ struct file *file; > struct getdents_callback buf; >+ struct linux_dirent __user *lastdirent; > int fput_needed; > int error; >- >- if (!access_ok(VERIFY_WRITE, dirent, count)) >- return -EFAULT; >- >+ > file = fget_light(fd, &fput_needed); > if (!file) > return -EBADF; > >- buf.current_dir = dirent; >+ buf.current_dir = dirent ? dirent : &xdirent->x_dent; > buf.previous = NULL; > buf.count = count; > buf.error = 0; > >- error = vfs_readdir(file, filldir, &buf); >+ error = dirent ? vfs_readdir(file, filldir, &buf) : >+ vfs_xreaddir(file, xfilldir, &buf, flags, mask); > if (error >= 0) > error = buf.error; > lastdirent = buf.previous; >@@ -223,6 +252,25 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, > return error; > } > >+SYSCALL_DEFINE3(getdents, unsigned int, fd, >+ struct linux_dirent __user *, dirent, unsigned int, count) >+{ >+ if (!access_ok(VERIFY_WRITE, dirent, count)) >+ return -EFAULT; >+ >+ return xgetdents_i(fd, dirent, NULL, count, 0, 0); >+} >+ >+SYSCALL_DEFINE5(xgetdents, unsigned int, fd, >+ struct linux_xdirent __user *, xdirent, unsigned int, count, >+ unsigned, flags, unsigned int, mask) >+{ >+ if (!access_ok(VERIFY_WRITE, xdirent, count)) >+ return -EFAULT; >+ >+ return xgetdents_i(fd, NULL, xdirent, count, flags, mask); >+} >+ > struct getdents_callback64 { > struct linux_dirent64 __user * current_dir; > struct linux_dirent64 __user * previous; >diff --git a/fs/stat.c b/fs/stat.c >index b6ff118..db38c89 100644 >--- a/fs/stat.c >+++ b/fs/stat.c >@@ -18,8 +18,20 @@ > #include <asm/uaccess.h> > #include <asm/unistd.h> > >+/** >+ * generic_fillattr - Fill in the basic attributes from the inode struct >+ * @inode: Inode to use as the source >+ * @stat: Where to fill in the attributes >+ * >+ * Fill in the basic attributes in the kstat structure from data that's to be >+ * found on the VFS inode structure. This is the default if no getattr inode >+ * operation is supplied. >+ */ > void generic_fillattr(struct inode *inode, struct kstat *stat) > { >+ struct super_block *sb = inode->i_sb; >+ u32 x; >+ > stat->dev = inode->i_sb->s_dev; > stat->ino = inode->i_ino; > stat->mode = inode->i_mode; >@@ -27,17 +39,61 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) > stat->uid = inode->i_uid; > stat->gid = inode->i_gid; > stat->rdev = inode->i_rdev; >- stat->size = i_size_read(inode); >- stat->atime = inode->i_atime; > stat->mtime = inode->i_mtime; > stat->ctime = inode->i_ctime; >- stat->blksize = (1 << inode->i_blkbits); >+ stat->size = i_size_read(inode); > stat->blocks = inode->i_blocks; >-} >+ stat->blksize = (1 << inode->i_blkbits); > >+ stat->result_mask |= XSTAT_BASIC_STATS & ~XSTAT_RDEV; >+ if (IS_NOATIME(inode)) >+ stat->result_mask &= ~XSTAT_ATIME; >+ else >+ stat->atime = inode->i_atime; >+ >+ if (S_ISREG(stat->mode) && stat->nlink == 0) >+ stat->information |= XSTAT_INFO_TEMPORARY; >+ if (IS_AUTOMOUNT(inode)) >+ stat->information |= XSTAT_INFO_AUTOMOUNT; >+ if (IS_POSIXACL(inode)) >+ stat->information |= XSTAT_INFO_HAS_ACL; >+ >+ /* if unset, assume 1s granularity */ >+ stat->tv_granularity = sb->s_time_gran ?: 1000000000U; >+ >+ if (unlikely(S_ISBLK(stat->mode) || S_ISCHR(stat->mode))) >+ stat->result_mask |= XSTAT_RDEV; >+ >+ x = ((u32*)&stat->volume_id)[0] = ((u32*)&sb->s_volume_id)[0]; >+ x |= ((u32*)&stat->volume_id)[1] = ((u32*)&sb->s_volume_id)[1]; >+ x |= ((u32*)&stat->volume_id)[2] = ((u32*)&sb->s_volume_id)[2]; >+ x |= ((u32*)&stat->volume_id)[3] = ((u32*)&sb->s_volume_id)[3]; >+ if (x) >+ stat->result_mask |= XSTAT_VOLUME_ID; >+} > EXPORT_SYMBOL(generic_fillattr); > >-int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) >+/** >+ * vfs_xgetattr - Get the basic and extra attributes of a file >+ * @mnt: The mountpoint to which the dentry belongs >+ * @dentry: The file of interest >+ * @stat: Where to return the statistics >+ * >+ * Ask the filesystem for a file's attributes. The caller must have preset >+ * stat->request_mask and stat->query_flags to indicate what they want. >+ * >+ * If the file is remote, the filesystem can be forced to update the attributes >+ * from the backing store by passing AT_FORCE_ATTR_SYNC in query_flags. >+ * >+ * Bits must have been set in stat->request_mask to indicate which attributes >+ * the caller wants retrieving. Any such attribute not requested may be >+ * returned anyway, but the value may be approximate, and, if remote, may not >+ * have been synchronised with the server. >+ * >+ * 0 will be returned on success, and a -ve error code if unsuccessful. >+ */ >+int vfs_xgetattr(struct vfsmount *mnt, struct dentry *dentry, >+ struct kstat *stat) > { > struct inode *inode = dentry->d_inode; > int retval; >@@ -46,65 +102,186 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) > if (retval) > return retval; > >+ stat->result_mask = 0; >+ stat->information = 0; >+ stat->ioc_flags = 0; > if (inode->i_op->getattr) > return inode->i_op->getattr(mnt, dentry, stat); > > generic_fillattr(inode, stat); > return 0; > } >+EXPORT_SYMBOL(vfs_xgetattr); > >+/** >+ * vfs_getattr - Get the basic attributes of a file >+ * @mnt: The mountpoint to which the dentry belongs >+ * @dentry: The file of interest >+ * @stat: Where to return the statistics >+ * >+ * Ask the filesystem for a file's attributes. If remote, the filesystem isn't >+ * forced to update its files from the backing store. Only the basic set of >+ * attributes will be retrieved; anyone wanting more must use vfs_getxattr(), >+ * as must anyone who wants to force attributes to be sync'd with the server. >+ * >+ * 0 will be returned on success, and a -ve error code if unsuccessful. >+ */ >+int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) >+{ >+ stat->query_flags = 0; >+ stat->request_mask = XSTAT_BASIC_STATS; >+ return vfs_xgetattr(mnt, dentry, stat); >+} > EXPORT_SYMBOL(vfs_getattr); > >-int vfs_fstat(unsigned int fd, struct kstat *stat) >+/** >+ * vfs_fxstat - Get basic and extra attributes by file descriptor >+ * @fd: The file descriptor refering to the file of interest >+ * @stat: The result structure to fill in. >+ * >+ * This function is a wrapper around vfs_xgetattr(). The main difference is >+ * that is uses a file descriptor to determine the file location. >+ * >+ * The caller must have preset stat->query_flags and stat->request_mask as for >+ * vfs_xgetattr(). >+ * >+ * 0 will be returned on success, and a -ve error code if unsuccessful. >+ */ >+int vfs_fxstat(unsigned int fd, struct kstat *stat) > { > int fput_needed; > struct file *f = fget_light(fd, &fput_needed); > int error = -EBADF; > >+ if (stat->query_flags & ~KSTAT_QUERY_FLAGS) >+ return -EINVAL; > if (f) { >- error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat); >+ error = vfs_xgetattr(f->f_path.mnt, f->f_path.dentry, stat); > fput_light(f, fput_needed); > } > return error; > } >+EXPORT_SYMBOL(vfs_fxstat); >+ >+/** >+ * vfs_fstat - Get basic attributes by file descriptor >+ * @fd: The file descriptor refering to the file of interest >+ * @stat: The result structure to fill in. >+ * >+ * This function is a wrapper around vfs_getattr(). The main difference is >+ * that it uses a file descriptor to determine the file location. >+ * >+ * 0 will be returned on success, and a -ve error code if unsuccessful. >+ */ >+int vfs_fstat(unsigned int fd, struct kstat *stat) >+{ >+ stat->query_flags = 0; >+ stat->request_mask = XSTAT_BASIC_STATS; >+ return vfs_fxstat(fd, stat); >+} > EXPORT_SYMBOL(vfs_fstat); > >-int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, >- int flag) >+/** >+ * vfs_xstat - Get basic and extra attributes by filename >+ * @dfd: A file descriptor respresenting the base dir for a relative filename >+ * @filename: The name of the file of interest >+ * @flags: Flags to control the query >+ * @stat: The result structure to fill in. >+ * >+ * This function is a wrapper around vfs_xgetattr(). The main difference is >+ * that it uses a filename and base directory to determine the file location. >+ * Additionally, the addition of AT_SYMLINK_NOFOLLOW to flags will prevent a >+ * symlink at the given name from being referenced. >+ * >+ * The caller must have preset stat->request_mask as for vfs_xgetattr(). The >+ * flags are also used to load up stat->query_flags. >+ * >+ * 0 will be returned on success, and a -ve error code if unsuccessful. >+ */ >+int vfs_xstat(int dfd, const char __user *filename, int flags, >+ struct kstat *stat) > { > struct path path; >- int error = -EINVAL; >- int lookup_flags = 0; >+ int error, lookup_flags = LOOKUP_FOLLOW | LOOKUP_AUTOMOUNT; > >- if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | >- AT_EMPTY_PATH)) != 0) >- goto out; >+ if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | >+ AT_EMPTY_PATH | KSTAT_QUERY_FLAGS)) != 0) >+ return -EINVAL; > >- if (!(flag & AT_SYMLINK_NOFOLLOW)) >- lookup_flags |= LOOKUP_FOLLOW; >- if (flag & AT_EMPTY_PATH) >+ if (flags & AT_SYMLINK_NOFOLLOW) >+ lookup_flags &= ~LOOKUP_FOLLOW; >+ if (flags & AT_NO_AUTOMOUNT) >+ lookup_flags &= ~LOOKUP_AUTOMOUNT; >+ if (flags & AT_EMPTY_PATH) > lookup_flags |= LOOKUP_EMPTY; > >+ stat->query_flags = flags & KSTAT_QUERY_FLAGS; > error = user_path_at(dfd, filename, lookup_flags, &path); >- if (error) >- goto out; >- >- error = vfs_getattr(path.mnt, path.dentry, stat); >- path_put(&path); >-out: >+ if (!error) { >+ error = vfs_xgetattr(path.mnt, path.dentry, stat); >+ path_put(&path); >+ } > return error; > } >+EXPORT_SYMBOL(vfs_xstat); >+ >+/** >+ * vfs_fstatat - Get basic attributes by filename >+ * @dfd: A file descriptor representing the base dir for a relative filename >+ * @filename: The name of the file of interest >+ * @flags: Flags to control the query >+ * @stat: The result structure to fill in. >+ * >+ * This function is a wrapper around vfs_xstat(). The difference is that it >+ * preselects basic stats only. The flags are used to load up >+ * stat->query_flags in addition to indicating symlink handling during path >+ * resolution. >+ * >+ * 0 will be returned on success, and a -ve error code if unsuccessful. >+ */ >+int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, >+ int flags) >+{ >+ stat->request_mask = XSTAT_BASIC_STATS; >+ return vfs_xstat(dfd, filename, flags, stat); >+} > EXPORT_SYMBOL(vfs_fstatat); > >-int vfs_stat(const char __user *name, struct kstat *stat) >+/** >+ * vfs_stat - Get basic attributes by filename >+ * @filename: The name of the file of interest >+ * @stat: The result structure to fill in. >+ * >+ * This function is a wrapper around vfs_xstat(). The difference is that it >+ * preselects basic stats only, terminal symlinks are followed regardless and a >+ * remote filesystem can't be forced to query the server. If such is desired, >+ * vfs_xstat() should be used instead. >+ * >+ * 0 will be returned on success, and a -ve error code if unsuccessful. >+ */ >+int vfs_stat(const char __user *filename, struct kstat *stat) > { >- return vfs_fstatat(AT_FDCWD, name, stat, 0); >+ stat->request_mask = XSTAT_BASIC_STATS; >+ return vfs_xstat(AT_FDCWD, filename, 0, stat); > } > EXPORT_SYMBOL(vfs_stat); > >+/** >+ * vfs_lstat - Get basic attributes by filename, without following terminal symlink >+ * @filename: The name of the file of interest >+ * @stat: The result structure to fill in. >+ * >+ * This function is a wrapper around vfs_xstat(). The difference is that it >+ * preselects basic stats only, terminal symlinks are not followed regardless >+ * and a remote filesystem can't be forced to query the server. If such is >+ * desired, vfs_xstat() should be used instead. >+ * >+ * 0 is returned on success, and a -ve error code if unsuccessful. >+ */ > int vfs_lstat(const char __user *name, struct kstat *stat) > { >- return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW); >+ stat->request_mask = XSTAT_BASIC_STATS; >+ return vfs_xstat(AT_FDCWD, name, AT_SYMLINK_NOFOLLOW, stat); > } > EXPORT_SYMBOL(vfs_lstat); > >@@ -119,7 +296,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta > { > static int warncount = 5; > struct __old_kernel_stat tmp; >- >+ > if (warncount > 0) { > warncount--; > printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", >@@ -144,7 +321,7 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta > #if BITS_PER_LONG == 32 > if (stat->size > MAX_NON_LFS) > return -EOVERFLOW; >-#endif >+#endif > tmp.st_size = stat->size; > tmp.st_atime = stat->atime.tv_sec; > tmp.st_mtime = stat->mtime.tv_sec; >@@ -417,6 +594,143 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, > } > #endif /* __ARCH_WANT_STAT64 */ > >+static inline void xstat_get_params_i(unsigned int mask, struct kstat *stat) >+{ >+ memset(stat, 0xde, sizeof(*stat)); // DEBUGGING >+ >+ stat->request_mask = mask & XSTAT_ALL_STATS; >+ stat->result_mask = 0; >+} >+/* >+ * Get the xstat parameters if supplied >+ */ >+static int xstat_get_params(unsigned int mask, struct xstat __user *buffer, >+ struct kstat *stat) >+{ >+ if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer))) >+ return -EFAULT; >+ >+ xstat_get_params_i(mask, stat); >+ return 0; >+} >+ >+/* >+ * Get the xstat parameters with a xdirent >+ */ >+int xdirent_get_params(unsigned int mask, struct kstat *stat) >+{ >+ xstat_get_params_i(mask, stat); >+ return 0; >+} >+EXPORT_SYMBOL(xdirent_get_params); >+ >+/* >+ * Set the xstat results >+ * >+ * If the buffer size was 0, we just return the size of the buffer needed to >+ * return the full result. >+ * >+ * If bufsize indicates a buffer of insufficient size to hold the full result, >+ * we return -E2BIG. >+ * >+ * Otherwise we copy the extended stats to userspace and return the amount of >+ * data written into the buffer (or -EFAULT). >+ */ >+long xstat_set_result(struct kstat *stat, struct xstat __user *buffer) >+{ >+ u32 mask = stat->result_mask, gran = stat->tv_granularity; >+ >+#define __put_timestamp(kts, uts) ( \ >+ __put_user(kts.tv_sec, uts.tv_sec ) || \ >+ __put_user(kts.tv_nsec, uts.tv_nsec ) || \ >+ __put_user(gran, uts.tv_granularity )) >+ >+ /* clear out anything we're not returning */ >+ if (!(mask & XSTAT_IOC_FLAGS)) >+ stat->ioc_flags = 0; >+ if (!(mask & XSTAT_BTIME)) >+ memset(&stat->btime, 0, sizeof(stat->btime)); >+ if (!(mask & XSTAT_GEN)) >+ stat->gen = 0; >+ if (!(mask & XSTAT_VERSION)) >+ stat->version = 0; >+ if (!(mask & XSTAT_VOLUME_ID)) >+ memset(&stat->volume_id, 0, sizeof(stat->volume_id)); >+ >+ /* transfer the results */ >+ if (__put_user(mask, &buffer->st_mask ) || >+ __put_user(stat->mode, &buffer->st_mode ) || >+ __put_user(stat->nlink, &buffer->st_nlink ) || >+ __put_user(stat->uid, &buffer->st_uid ) || >+ __put_user(stat->gid, &buffer->st_gid ) || >+ __put_user(stat->information, &buffer->st_information ) || >+ __put_user(stat->ioc_flags, &buffer->st_ioc_flags ) || >+ __put_user(stat->blksize, &buffer->st_blksize ) || >+ __put_user(MAJOR(stat->rdev), &buffer->st_rdev.major ) || >+ __put_user(MINOR(stat->rdev), &buffer->st_rdev.minor ) || >+ __put_user(MAJOR(stat->dev), &buffer->st_dev.major ) || >+ __put_user(MINOR(stat->dev), &buffer->st_dev.minor ) || >+ __put_timestamp(stat->atime, &buffer->st_atime ) || >+ __put_timestamp(stat->btime, &buffer->st_btime ) || >+ __put_timestamp(stat->ctime, &buffer->st_ctime ) || >+ __put_timestamp(stat->mtime, &buffer->st_mtime ) || >+ __put_user(stat->ino, &buffer->st_ino ) || >+ __put_user(stat->size, &buffer->st_size ) || >+ __put_user(stat->blocks, &buffer->st_blocks ) || >+ __put_user(stat->gen, &buffer->st_gen ) || >+ __put_user(stat->version, &buffer->st_version ) || >+ __copy_to_user(&buffer->st_volume_id, &stat->volume_id, >+ sizeof(buffer->st_volume_id) ) || >+ __clear_user(&buffer->__spares, sizeof(buffer->__spares))) >+ return -EFAULT; >+ return 0; >+} >+ >+long xdirent_set_result(struct kstat *stat, void __user *buffer) >+{ >+ struct linux_xdirent __user *xdirent = (struct linux_xdirent *) buffer; >+ return xstat_set_result(stat, &xdirent->x_st); >+} >+ >+/* >+ * System call to get extended stats by path >+ */ >+SYSCALL_DEFINE5(xstat, >+ int, dfd, const char __user *, filename, unsigned, flags, >+ unsigned int, mask, struct xstat __user *, buffer) >+{ >+ struct kstat stat; >+ int error; >+ >+ error = xstat_get_params(mask, buffer, &stat); >+ if (error != 0) >+ return error; >+ error = vfs_xstat(dfd, filename, flags, &stat); >+ if (error) >+ return error; >+ return xstat_set_result(&stat, buffer); >+} >+ >+/* >+ * System call to get extended stats by file descriptor >+ */ >+SYSCALL_DEFINE4(fxstat, >+ unsigned int, fd, unsigned int, flags, >+ unsigned int, mask, struct xstat __user *, buffer) >+{ >+ struct kstat stat; >+ int error; >+ >+ error = xstat_get_params(mask, buffer, &stat); >+ if (error < 0) >+ return error; >+ stat.query_flags = flags; >+ error = vfs_fxstat(fd, &stat); >+ if (error) >+ return error; >+ return xstat_set_result(&stat, buffer); >+} >+ > /* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ > void __inode_add_bytes(struct inode *inode, loff_t bytes) > { >diff --git a/include/linux/fcntl.h b/include/linux/fcntl.h >index f550f89..9c84e23 100644 >--- a/include/linux/fcntl.h >+++ b/include/linux/fcntl.h >@@ -47,6 +47,7 @@ > #define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ > #define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ > #define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ >+#define AT_FORCE_ATTR_SYNC 0x2000 /* Force the attributes to be sync'd with the server */ > > #ifdef __KERNEL__ > >diff --git a/include/linux/fs.h b/include/linux/fs.h >index 38dba16..b3974df 100644 >--- a/include/linux/fs.h >+++ b/include/linux/fs.h >@@ -1539,6 +1539,7 @@ struct super_block { > > char s_id[32]; /* Informational name */ > u8 s_uuid[16]; /* UUID */ >+ unsigned char s_volume_id[16]; /* Volume identifier */ > > void *s_fs_info; /* Filesystem private info */ > unsigned int s_max_links; >@@ -1767,6 +1768,10 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); > * to have different dirent layouts depending on the binary type. > */ > typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned); >+/* >+ * Extended filldir function to return kstat as well >+ */ >+typedef int (*xfilldir_t)(void *, const char *, int, loff_t, u64, unsigned, struct kstat *); > struct block_device_operations; > > /* These macros are for out of kernel modules to test that >@@ -1783,6 +1788,7 @@ struct file_operations { > ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); > ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); > int (*readdir) (struct file *, void *, filldir_t); >+ int (*xreaddir) (struct file *, void *, xfilldir_t, unsigned flags, unsigned int mask); > unsigned int (*poll) (struct file *, struct poll_table_struct *); > long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); > long (*compat_ioctl) (struct file *, unsigned int, unsigned long); >@@ -2657,6 +2663,7 @@ 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_xgetattr(struct vfsmount *, struct dentry *, struct kstat *); > void __inode_add_bytes(struct inode *inode, loff_t bytes); > void inode_add_bytes(struct inode *inode, loff_t bytes); > void inode_sub_bytes(struct inode *inode, loff_t bytes); >@@ -2669,6 +2676,8 @@ extern int vfs_stat(const char __user *, struct kstat *); > extern int vfs_lstat(const char __user *, struct kstat *); > extern int vfs_fstat(unsigned int, struct kstat *); > extern int vfs_fstatat(int , const char __user *, struct kstat *, int); >+extern int vfs_xstat(int, const char __user *, int, struct kstat *); >+extern int vfs_fxstat(unsigned int, struct kstat *); > > extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, > unsigned long arg); >diff --git a/include/linux/stat.h b/include/linux/stat.h >index 4613240..cc9535a 100644 >--- a/include/linux/stat.h >+++ b/include/linux/stat.h >@@ -3,6 +3,7 @@ > > #ifdef __KERNEL__ > >+#include <linux/types.h> > #include <asm/stat.h> > > #endif >@@ -46,6 +47,117 @@ > > #endif > >+/* >+ * Query request/result mask >+ * >+ * Bits should be set in request_mask to request particular items when calling >+ * xstat() or fxstat(). >+ * >+ * The bits in st_mask may or may not be set upon return, in part depending on >+ * what was set in the mask argument: >+ * >+ * - if not available at all, the bit will be cleared before returning and the >+ * field will be cleared; otherise, >+ * >+ * - if AT_FORCE_ATTR_SYNC is set, then the datum will be synchronised to the >+ * server and the field and bit will be set on return; otherwise, >+ * >+ * - if explicitly requested, the datum will be synchronised to a serer or >+ * other medium if out of date before being returned, and the bit will be set >+ * on return; otherwise, >+ * >+ * - if not requested, but available in approximate form without any effort, it >+ * will be filled in anyway, and the bit will be set upon return (it might >+ * not be up to date, however, and no attempt will be made to synchronise the >+ * internal state first); otherwise, >+ * >+ * - the field and the bit will be cleared before returning. >+ * >+ * Items in XSTAT_BASIC_STATS may be marked unavailable on return, but they >+ * will have a value installed for compatibility purposes so that stat() and >+ * co. can be emulated in userspace. >+ */ >+#define XSTAT_MODE 0x00000001U /* want/got st_mode */ >+#define XSTAT_NLINK 0x00000002U /* want/got st_nlink */ >+#define XSTAT_UID 0x00000004U /* want/got st_uid */ >+#define XSTAT_GID 0x00000008U /* want/got st_gid */ >+#define XSTAT_RDEV 0x00000010U /* want/got st_rdev */ >+#define XSTAT_ATIME 0x00000020U /* want/got st_atime */ >+#define XSTAT_MTIME 0x00000040U /* want/got st_mtime */ >+#define XSTAT_CTIME 0x00000080U /* want/got st_ctime */ >+#define XSTAT_INO 0x00000100U /* want/got st_ino */ >+#define XSTAT_SIZE 0x00000200U /* want/got st_size */ >+#define XSTAT_BLOCKS 0x00000400U /* want/got st_blocks */ >+#define XSTAT_BASIC_STATS 0x000007ffU /* the stuff in the normal stat struct */ >+#define XSTAT_IOC_FLAGS 0x00000800U /* want/got FS_IOC_GETFLAGS */ >+#define XSTAT_BTIME 0x00001000U /* want/got st_btime */ >+#define XSTAT_GEN 0x00002000U /* want/got st_gen */ >+#define XSTAT_VERSION 0x00004000U /* want/got st_version */ >+#define XSTAT_VOLUME_ID 0x00008000U /* want/got st_volume_id */ >+#define XSTAT_ALL_STATS 0x0000ffffU /* all supported stats */ >+ >+/* >+ * Extended stat structures >+ */ >+struct xstat_dev { >+ uint32_t major, minor; >+}; >+ >+struct xstat_time { >+ int64_t tv_sec; >+ uint32_t tv_nsec; >+ uint32_t tv_granularity; /* time granularity (in nS) */ >+}; >+ >+struct xstat { >+ uint32_t st_mask; /* what results were written */ >+ uint32_t st_mode; /* file mode */ >+ uint32_t st_nlink; /* number of hard links */ >+ uint32_t st_uid; /* user ID of owner */ >+ uint32_t st_gid; /* group ID of owner */ >+ uint32_t st_information; /* information about the file */ >+ uint32_t st_ioc_flags; /* as FS_IOC_GETFLAGS */ >+ uint32_t st_blksize; /* optimal size for filesystem I/O */ >+ struct xstat_dev st_rdev; /* device ID of special file */ >+ struct xstat_dev st_dev; /* ID of device containing file */ >+ struct xstat_time st_atime; /* last access time */ >+ struct xstat_time st_btime; /* file creation time */ >+ struct xstat_time st_ctime; /* last attribute change time */ >+ struct xstat_time st_mtime; /* last data modification time */ >+ uint64_t st_ino; /* inode number */ >+ uint64_t st_size; /* file size */ >+ uint64_t st_blocks; /* number of 512-byte blocks allocated */ >+ uint64_t st_gen; /* inode generation number */ >+ uint64_t st_version; /* data version number */ >+ uint8_t st_volume_id[16]; /* volume identifier */ >+ uint64_t __spares[11]; /* spare space for future expansion */ >+}; >+ >+/* >+ * Flags to be found in st_information >+ * >+ * These give information about the features or the state of a file that might >+ * be of use to ordinary userspace programs such as GUIs or ls rather than >+ * specialised tools. >+ * >+ * Additional information may be found in st_ioc_flags and we try not to >+ * overlap with it. >+ */ >+#define XSTAT_INFO_ENCRYPTED 0x00000001U /* File is encrypted */ >+#define XSTAT_INFO_TEMPORARY 0x00000002U /* File is temporary (NTFS/CIFS) */ >+#define XSTAT_INFO_FABRICATED 0x00000004U /* File was made up by filesystem */ >+#define XSTAT_INFO_KERNEL_API 0x00000008U /* File is kernel API (eg: procfs/sysfs) */ >+#define XSTAT_INFO_REMOTE 0x00000010U /* File is remote */ >+#define XSTAT_INFO_OFFLINE 0x00000020U /* File is offline (CIFS) */ >+#define XSTAT_INFO_AUTOMOUNT 0x00000040U /* Dir is automount trigger */ >+#define XSTAT_INFO_AUTODIR 0x00000080U /* Dir provides unlisted automounts */ >+#define XSTAT_INFO_NONSYSTEM_OWNERSHIP 0x00000100U /* File has non-system ownership details */ >+#define XSTAT_INFO_HAS_ACL 0x00000200U /* File has an ACL of some sort */ >+#define XSTAT_INFO_REPARSE_POINT 0x00000400U /* File is reparse point (NTFS/CIFS) */ >+#define XSTAT_INFO_HIDDEN 0x00000800U /* File is marked hidden (DOS+) */ >+#define XSTAT_INFO_SYSTEM 0x00001000U /* File is marked system (DOS+) */ >+#define XSTAT_INFO_ARCHIVE 0x00002000U /* File is marked archive (DOS+) */ >+ > #ifdef __KERNEL__ > #define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) > #define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) >@@ -61,6 +173,12 @@ > #include <linux/uidgid.h> > > struct kstat { >+ u32 query_flags; /* operational flags */ >+#define KSTAT_QUERY_FLAGS (AT_FORCE_ATTR_SYNC) >+ u32 request_mask; /* what fields the user asked for */ >+ u32 result_mask; /* what fields the user got */ >+ u32 information; >+ u32 ioc_flags; /* inode flags (FS_IOC_GETFLAGS) */ > u64 ino; > dev_t dev; > umode_t mode; >@@ -68,14 +186,40 @@ struct kstat { > kuid_t uid; > kgid_t gid; > dev_t rdev; >+ unsigned int tv_granularity; /* granularity of times (in nS) */ > loff_t size; >- struct timespec atime; >+ struct timespec atime; > struct timespec mtime; > struct timespec ctime; >+ struct timespec btime; /* file creation time */ > unsigned long blksize; > unsigned long long blocks; >+ u64 gen; /* inode generation */ >+ u64 version; /* data version */ >+ unsigned char volume_id[16]; /* volume identifier */ > }; > >-#endif >+/* >+ * New, all-improved, singing, dancing, iBCS2-compliant getdents() >+ * interface. >+ */ >+struct linux_dirent { >+ unsigned long d_ino; >+ unsigned long d_off; >+ unsigned short d_reclen; >+ char d_name[1]; >+}; > >+/* >+ * Extended dirent. x_dent.d_reclen contains the combined length of x_dent and x_st >+ */ >+struct linux_xdirent { >+ struct xstat x_st; >+ struct linux_dirent x_dent; >+}; >+ >+long xstat_set_result(struct kstat *stat, struct xstat __user *buffer); >+long xdirent_set_result(struct kstat *stat, void __user *buffer); >+int xdirent_get_params(unsigned int mask, struct kstat *stat); >+#endif > #endif >diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h >index 19439c7..36ce855 100644 >--- a/include/linux/syscalls.h >+++ b/include/linux/syscalls.h >@@ -860,4 +860,9 @@ asmlinkage long sys_process_vm_writev(pid_t pid, > > asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, > unsigned long idx1, unsigned long idx2); >+ >+asmlinkage long sys_xstat(int dfd, const char __user *path, unsigned flags, >+ unsigned mask, struct xstat __user *buffer); >+asmlinkage long sys_fxstat(unsigned fd, unsigned flags, >+ unsigned mask, struct xstat __user *buffer); > #endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 850426
:
605960
|
617073
|
625592
|
678841
|
680222
|
680282
|
708389
|
731269
|
731270
|
731272
|
731273
|
731274
|
731278
|
731279
|
732739
|
732740
|
732845
|
834840
|
853502
|
909528
|
909529
|
909534
|
912745
|
917238
|
917239
|
920895
|
920896
|
920897
|
920898
|
920899
|
920902
|
920903
|
947987