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 617073 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]
Another revision
xgetdents-try3-09242012.patch (text/plain), 28.14 KB, created by
Abhijith Das
on 2012-09-25 14:36:28 UTC
(
hide
)
Description:
Another revision
Filename:
MIME Type:
Creator:
Abhijith Das
Created:
2012-09-25 14:36:28 UTC
Size:
28.14 KB
patch
obsolete
>diff --git a/arch/x86/syscalls/syscall_32.tbl b/arch/x86/syscalls/syscall_32.tbl >index b4d1f1c..37cd8b9 100644 >--- a/arch/x86/syscalls/syscall_32.tbl >+++ b/arch/x86/syscalls/syscall_32.tbl >@@ -358,3 +358,4 @@ > 349 i386 kcmp sys_kcmp > 350 i386 xstat sys_xstat > 351 i386 fxstat sys_fxstat >+352 i386 xgetdents sys_xgetdents >diff --git a/arch/x86/syscalls/syscall_64.tbl b/arch/x86/syscalls/syscall_64.tbl >index 64a2f82..cc7ed65 100644 >--- a/arch/x86/syscalls/syscall_64.tbl >+++ b/arch/x86/syscalls/syscall_64.tbl >@@ -321,6 +321,7 @@ > 312 common 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/gfs2/dir.c b/fs/gfs2/dir.c >index 259b088..f74c3e3 100644 >--- a/fs/gfs2/dir.c >+++ b/fs/gfs2/dir.c >@@ -72,6 +72,7 @@ > #include "trans.h" > #include "bmap.h" > #include "util.h" >+#include "xattr.h" > > #define IS_LEAF 1 /* Hashed (leaf) directory */ > #define IS_DINODE 2 /* Linear (stuffed dinode block) directory */ >@@ -1196,7 +1197,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 >+ * @xinfo: Pointer to a xdirent_info struct. filldir = xinfo ? 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 +1212,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 xdirent_info *xinfo, > const struct gfs2_dirent **darr, u32 entries, > int *copied) > { >@@ -1251,10 +1253,53 @@ 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 (!xinfo) { >+ 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; >+ struct gfs2_inode *ip; >+ struct gfs2_holder gh; >+ int unlock = 0; >+ >+ 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; >+ >+ ip = GFS2_I(inode); >+ if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) { >+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh); >+ if (error) >+ goto iput; >+ unlock = 1; >+ } >+ >+ gfs2_getattr_i(inode, &xinfo->xi_st); >+ >+ xinfo->xi_xattr_count = 0; >+ xinfo->xi_xattr_bytes = 0; >+ error = gfs2_getxattr_list(GFS2_I(inode), xinfo); >+ if (error) >+ goto free_xattrs; >+ >+ 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), xinfo); >+ free_xattrs: >+ gfs2_freexattr_list(xinfo->xi_xattrs, xinfo->xi_xattr_count); >+ if (unlock) >+ gfs2_glock_dq_uninit(&gh); >+ iput: >+ iput(inode); >+ } > if (error) > return 1; > >@@ -1290,8 +1335,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 xdirent_info *xinfo, int *copied, >+ unsigned *depth, u64 leaf_no) > { > struct gfs2_inode *ip = GFS2_I(inode); > struct gfs2_sbd *sdp = GFS2_SB(inode); >@@ -1368,7 +1413,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, xinfo, darr, > entries, copied); > out_free: > for(i = 0; i < leaf; i++) >@@ -1435,8 +1480,8 @@ static void gfs2_dir_readahead(struct inode *inode, unsigned hsize, u32 index, > * Returns: errno > */ > >-static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, >- filldir_t filldir, struct file_ra_state *f_ra) >+static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, void *filldir, >+ struct xdirent_info *xinfo, struct file_ra_state *f_ra) > { > struct gfs2_inode *dip = GFS2_I(inode); > u32 hsize, len = 0; >@@ -1460,7 +1505,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, >+ xinfo, &copied, &depth, > be64_to_cpu(lp[index])); > if (error) > break; >@@ -1474,8 +1519,8 @@ static int dir_e_read(struct inode *inode, u64 *offset, void *opaque, > return error; > } > >-int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, >- filldir_t filldir, struct file_ra_state *f_ra) >+int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, void *filldir, >+ struct xdirent_info *xinfo, struct file_ra_state *f_ra) > { > struct gfs2_inode *dip = GFS2_I(inode); > struct gfs2_sbd *sdp = GFS2_SB(inode); >@@ -1489,7 +1534,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, xinfo, f_ra); > > if (!gfs2_is_stuffed(dip)) { > gfs2_consist_inode(dip); >@@ -1521,8 +1566,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, xinfo, >+ darr, dip->i_entries, &copied); > out: > kfree(darr); > } >diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h >index 98c960b..50039de 100644 >--- a/fs/gfs2/dir.h >+++ b/fs/gfs2/dir.h >@@ -24,8 +24,8 @@ extern int gfs2_dir_check(struct inode *dir, const struct qstr *filename, > 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); >+extern int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque, void *filldir, >+ struct xdirent_info *xinfo, 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..8250d84 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" >@@ -104,7 +105,8 @@ 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); > >@@ -114,6 +116,58 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir) > } > > /** >+ * 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 >+ * @flags: Flags pertaining to the xstat info >+ * @mask: Field mask for xstat and xattr info. >+ * >+ * 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 xdirent_info *xinfo; >+ u64 offset = file->f_pos; >+ int error; >+ >+ xinfo = kmalloc(sizeof(struct xdirent_info), GFP_NOFS); >+ if (xinfo == NULL) >+ return -ENOMEM; >+ memset(xinfo, 0, sizeof(struct xdirent_info)); >+ >+ error = xdirent_get_params(mask, xinfo); >+ if (error != 0) >+ goto free_xinfo; >+ >+ xinfo->xi_st.query_flags = flags & KSTAT_QUERY_FLAGS; >+ xinfo->xi_st.result_mask = 0; >+ xinfo->xi_st.information = 0; >+ xinfo->xi_st.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); >+ goto free_xinfo; >+ } >+ >+ error = gfs2_dir_read(dir, &offset, xdirent, (void *) xfilldir, xinfo, &file->f_ra); >+ gfs2_glock_dq_uninit(&d_gh); >+ >+ file->f_pos = offset; >+ >+free_xinfo: >+ kfree(xinfo); >+ return error; >+} >+ >+/** > * fsflags_cvt > * @table: A table of 32 u32 flags > * @val: a 32 bit value to convert >@@ -1043,6 +1097,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 +1128,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 381893c..2b9297a 100644 >--- a/fs/gfs2/inode.c >+++ b/fs/gfs2/inode.c >@@ -1665,6 +1665,11 @@ out: > return error; > } > >+inline void gfs2_getattr_i(struct inode *inode, struct kstat *stat) >+{ >+ generic_fillattr(inode, stat); >+} >+ > /** > * gfs2_getattr - Read out an inode's attributes > * @mnt: The vfsmount the inode is being accessed from >@@ -1696,7 +1701,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..a4a2027 100644 >--- a/fs/gfs2/inode.h >+++ b/fs/gfs2/inode.h >@@ -106,6 +106,7 @@ 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 void 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/gfs2/xattr.c b/fs/gfs2/xattr.c >index db330e5..a5b3368 100644 >--- a/fs/gfs2/xattr.c >+++ b/fs/gfs2/xattr.c >@@ -361,6 +361,82 @@ static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea) > } > } > >+static inline int xattr_requested(char type, unsigned int mask) >+{ >+ if ((type == GFS2_EATYPE_USR) && (mask & XSTAT_XATTR_USER)) >+ return 1; >+ if ((type == GFS2_EATYPE_SYS) && (mask & XSTAT_XATTR_SYSTEM)) >+ return 1; >+ if ((type == GFS2_EATYPE_SECURITY) && (mask & XSTAT_XATTR_SECURITY)) >+ return 1; >+ return 0; >+} >+ >+static int ea_getlist_i(struct gfs2_inode *ip, struct buffer_head *bh, >+ struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, >+ void *private) >+{ >+ struct xdirent_info *xinfo = private; >+ struct xattr *xattr = &xinfo->xi_xattrs[xinfo->xi_xattr_count]; >+ char *prefix = NULL; >+ unsigned int l = 0; >+ char c = 0; >+ >+ if (!xattr_requested(ea->ea_type, xinfo->xi_xattr_mask)) >+ return 0; >+ >+ if (ea->ea_type == GFS2_EATYPE_UNUSED) >+ return 0; >+ >+ switch (ea->ea_type) { >+ case GFS2_EATYPE_USR: >+ prefix = "user."; >+ l=5; >+ break; >+ case GFS2_EATYPE_SYS: >+ prefix = "system."; >+ l=7; >+ break; >+ case GFS2_EATYPE_SECURITY: >+ prefix = "security."; >+ l=9; >+ break; >+ } >+ BUG_ON(l == 0); >+ xattr->name = kmalloc(l + ea->ea_name_len + 1, GFP_NOFS); >+ if (xattr->name == NULL) >+ goto enomem; >+ xattr->value = kmalloc(GFS2_EA_DATA_LEN(ea), GFP_NOFS); >+ printk(KERN_WARNING "GFS2_EA_DATA_LEN(ea): %u\n", GFS2_EA_DATA_LEN(ea)); >+ if (xattr->value == NULL) { >+ kfree(xattr->name); >+ goto enomem; >+ } >+ >+ memcpy(xattr->name, prefix, l); >+ memcpy(xattr->name + l, GFS2_EA2NAME(ea), ea->ea_name_len); >+ memcpy(xattr->name + l + ea->ea_name_len, &c, 1); >+ memcpy(xattr->value, GFS2_EA2DATA(ea), GFS2_EA_DATA_LEN(ea)); >+ xattr->value_len = GFS2_EA_DATA_LEN(ea); >+ >+ xinfo->xi_xattr_bytes += sizeof(xattr->value_len) + strlen(xattr->name) >+ + 1 + xattr->value_len; >+ >+ xinfo->xi_xattr_count++; >+ return 0; >+enomem: >+ return -ENOMEM; >+} >+ >+void gfs2_freexattr_list(struct xattr *xattr_l, unsigned int count) >+{ >+ while (count) { >+ kfree(xattr_l[count -1].name); >+ kfree(xattr_l[count -1].value); >+ count--; >+ } >+} >+ > static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, > struct gfs2_ea_header *ea, struct gfs2_ea_header *prev, > void *private) >@@ -408,6 +484,13 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh, > return 0; > } > >+ssize_t gfs2_getxattr_list(struct gfs2_inode *ip, struct xdirent_info *xinfo) >+{ >+ if (ip->i_eattr) >+ return ea_foreach(ip, ea_getlist_i, xinfo); >+ return 0; >+} >+ > /** > * gfs2_listxattr - List gfs2 extended attributes > * @dentry: The dentry whose inode we are interested in >diff --git a/fs/gfs2/xattr.h b/fs/gfs2/xattr.h >index d392f83..cc26139 100644 >--- a/fs/gfs2/xattr.h >+++ b/fs/gfs2/xattr.h >@@ -57,6 +57,8 @@ extern int __gfs2_xattr_set(struct inode *inode, const char *name, > const void *value, size_t size, > int flags, int type); > extern ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size); >+extern ssize_t gfs2_getxattr_list(struct gfs2_inode *ip, struct xdirent_info *xinfo); >+extern void gfs2_freexattr_list(struct xattr *xattr_l, unsigned int count); > extern int gfs2_ea_dealloc(struct gfs2_inode *ip); > > /* Exported to acl.c */ >diff --git a/fs/readdir.c b/fs/readdir.c >index 39e3370..9518f27 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,19 @@ 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 +140,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 +147,117 @@ struct getdents_callback { > int error; > }; > >-static int filldir(void * __buf, const char * name, int namlen, loff_t offset, >- u64 ino, unsigned int d_type) >+int xattr_set_result(struct xdirent_info *xinfo, struct linux_xdirent __user *xdirent, >+ unsigned int dent_len) >+{ >+ int i, reclen, namlen; >+ size_t bytes = 0; >+ struct xdirent_xattr __user *xl; >+ struct xattr *xattr_l = xinfo->xi_xattrs; >+ >+ xl = (struct xdirent_xattr __user *) ((char*)xdirent >+ + offsetof(struct linux_xdirent, x_dent) >+ + dent_len); >+ >+ if (xinfo->xi_xattr_count == 0) { >+ __put_user(sizeof(struct xdirent_xattr), &xdirent->x_xattr_bytes); >+ goto out; >+ } >+ for (i=0; i<xinfo->xi_xattr_count; i++) { >+ char *buf = xl->xa_name_val; >+ reclen = 0; >+ if (__put_user(xattr_l[i].value_len, &xl->xa_value_len)) >+ goto err; >+ reclen += sizeof(xl->xa_value_len); >+ /* copy name */ >+ namlen = strlen(xattr_l[i].name); >+ if (copy_to_user(buf, xattr_l[i].name, namlen)) >+ goto err; >+ if (__put_user(0, buf + namlen)) >+ goto err; >+ reclen += namlen + 1; >+ /* copy value */ >+ if (copy_to_user((char*)(buf + namlen + 1), xattr_l[i].value, >+ xattr_l[i].value_len)) >+ goto err; >+ reclen += xattr_l[i].value_len; >+ /* goto next xattr */ >+ bytes += reclen; >+ >+ xl = (struct xdirent_xattr __user *) ((char *) xl + reclen); >+ } >+ if (bytes != xinfo->xi_xattr_bytes) { >+ printk(KERN_WARNING "bytes: %lu, xi_xattr_bytes: %lu - NOT EQUAL\n", >+ bytes, xinfo->xi_xattr_bytes); >+ goto err; >+ } >+ if (__put_user(xinfo->xi_xattr_count, &xdirent->x_xattr_count) || >+ __put_user(xinfo->xi_xattr_bytes, &xdirent->x_xattr_bytes)) >+ goto err; >+ >+out: >+ return 0; >+err: >+ return -EFAULT; >+} >+ >+long xdirent_set_result(struct xdirent_info *xinfo, >+ struct linux_xdirent __user *xdirent, >+ unsigned int dent_len) >+{ >+ int error = 0; >+ >+ error = xstat_set_result(&xinfo->xi_st, &xdirent->x_st); >+ if (error) >+ return error; >+ >+ return xattr_set_result(xinfo, xdirent, dent_len); >+} >+EXPORT_SYMBOL(xdirent_set_result); >+ >+/* >+ * Get the xstat parameters with a xdirent >+ */ >+int xdirent_get_params(unsigned int mask, struct xdirent_info *xinfo) >+{ >+ xstat_get_params_i(mask, &xinfo->xi_st); >+ xinfo->xi_xattr_mask = mask & XSTAT_ALL_XATTRS; >+ return 0; >+} >+EXPORT_SYMBOL(xdirent_get_params); >+ >+static int lx_base_size(void) >+{ >+ struct linux_xdirent lxd; >+ return (sizeof(lxd.x_st) + >+ sizeof(lxd.x_xattr_mask) + >+ sizeof(lxd.x_xattr_count) + >+ sizeof(lxd.x_xattr_bytes)); >+} >+ >+static int linux_xdirent_size(struct xdirent_info *xinfo) > { >- struct linux_dirent __user * dirent; >- struct getdents_callback * buf = (struct getdents_callback *) __buf; >+ if (xinfo) { >+ if (xinfo->xi_xattr_count) >+ return lx_base_size() + xinfo->xi_xattr_bytes; >+ else >+ return lx_base_size() + sizeof(struct xdirent_xattr); >+ } >+ return 0; >+} >+ >+static int xfilldir_i(void *__buf, const char *name, int namlen, loff_t offset, >+ u64 ino, unsigned int d_type, struct xdirent_info *xinfo) >+{ >+ struct linux_dirent __user *dirent; >+ struct getdents_callback *buf = (struct getdents_callback *) __buf; > unsigned long d_ino; >+ int xdirent_sz = linux_xdirent_size(xinfo); /* excludes x_dent size */ > 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) >+ if (reclen + xdirent_sz > buf->count) > return -EINVAL; > d_ino = ino; > if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { >@@ -178,38 +280,62 @@ 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 (xinfo) { >+ struct linux_xdirent __user *xdirent; >+ xdirent = container_of(dirent, struct linux_xdirent, x_dent); >+ if (xdirent_set_result(xinfo, xdirent, reclen)) >+ goto efault; >+ xdirent = (void __user *)xdirent + reclen + xdirent_sz; >+ dirent = &xdirent->x_dent; >+ } else { >+ dirent = (void __user *)dirent + reclen; >+ } >+ > buf->current_dir = dirent; >- buf->count -= reclen; >+ buf->count -= reclen + xdirent_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 xdirent_info *xinfo) >+{ >+ return xfilldir_i(__buf, name, namlen, offset, ino, d_type, xinfo); >+} >+ >+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 +349,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 d9316cb..9363f8f 100644 >--- a/fs/stat.c >+++ b/fs/stat.c >@@ -52,7 +52,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat) > stat->atime = inode->i_atime; > > if (S_ISREG(stat->mode) && stat->nlink == 0) >- stat->information |= XSTAT_INFO_TEMPORARTY; >+ stat->information |= XSTAT_INFO_TEMPORARY; > if (IS_AUTOMOUNT(inode)) > stat->information |= XSTAT_INFO_AUTOMOUNT; > if (IS_POSIXACL(inode)) >@@ -594,6 +594,14 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, > } > #endif /* __ARCH_WANT_STAT64 */ > >+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 > */ >@@ -605,8 +613,7 @@ static int xstat_get_params(unsigned int mask, struct xstat __user *buffer, > if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer))) > return -EFAULT; > >- stat->request_mask = mask & XSTAT_ALL_STATS; >- stat->result_mask = 0; >+ xstat_get_params_i(mask, stat); > return 0; > } > >@@ -622,7 +629,7 @@ static int xstat_get_params(unsigned int mask, struct xstat __user *buffer, > * Otherwise we copy the extended stats to userspace and return the amount of > * data written into the buffer (or -EFAULT). > */ >-static long xstat_set_result(struct kstat *stat, struct xstat __user *buffer) >+long xstat_set_result(struct kstat *stat, struct xstat __user *buffer) > { > u32 mask = stat->result_mask, gran = stat->tv_granularity; > >@@ -694,7 +701,7 @@ SYSCALL_DEFINE5(xstat, > /* > * System call to get extended stats by file descriptor > */ >-SYSCALL_DEFINE5(fxstat, unsigned int, fd, unsigned int, flags, >+SYSCALL_DEFINE4(fxstat, unsigned int, fd, unsigned int, flags, > unsigned int, mask, struct xstat __user *, buffer) > { > struct kstat stat; >diff --git a/include/linux/fs.h b/include/linux/fs.h >index 6ee34d7..9e5911c 100644 >--- a/include/linux/fs.h >+++ b/include/linux/fs.h >@@ -1767,6 +1767,11 @@ 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 extended info like stat and xattrs >+ */ >+typedef int (*xfilldir_t)(void *, const char *, int, loff_t, u64, unsigned, >+ struct xdirent_info *); > 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); >diff --git a/include/linux/stat.h b/include/linux/stat.h >index d882548..1acfcd4 100644 >--- a/include/linux/stat.h >+++ b/include/linux/stat.h >@@ -5,6 +5,7 @@ > > #include <linux/types.h> > #include <asm/stat.h> >+#include <linux/xattr.h> > > #endif > >@@ -96,6 +97,13 @@ > #define XSTAT_VOLUME_ID 0x00008000U /* want/got st_volume_id */ > #define XSTAT_ALL_STATS 0x0000ffffU /* all supported stats */ > >+/* xattr request flags */ >+#define XSTAT_XATTR_USER 0x00010000U /* user.* xattrs */ >+#define XSTAT_XATTR_SYSTEM 0x00020000U /* system.* xattrs */ >+#define XSTAT_XATTR_SECURITY 0x00040000U /* security.* xattrs */ >+#define XSTAT_XATTR_POSIX_ACL 0x00080000U /* posix acl xattrs */ >+#define XSTAT_ALL_XATTRS 0x00ff0000U /* all xattrs */ >+ > /* > * Extended stat structures > */ >@@ -199,5 +207,50 @@ struct kstat { > unsigned char volume_id[16]; /* volume identifier */ > }; > >+/* >+ * 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]; >+}; >+ >+#define MAX_ARR_XATTRS 256 >+ >+struct xdirent_info { >+ struct kstat xi_st; >+ unsigned int xi_xattr_mask; >+ unsigned int xi_xattr_count; >+ size_t xi_xattr_bytes; >+ struct xattr xi_xattrs[MAX_ARR_XATTRS]; >+}; >+ >+struct xdirent_xattr { >+ size_t xa_value_len; /* length of value field */ >+ char xa_name_val[1]; /* Name/Value pair, name is NULL terminated >+ + * and value is xa_value_len in length */ >+}; >+ >+/* >+ * Extended dirent. >+ */ >+struct linux_xdirent { >+ struct xstat x_st; >+ unsigned int x_xattr_mask; /* return mask */ >+ unsigned int x_xattr_count; /* total number of extended attributes */ >+ size_t x_xattr_bytes; /* total bytes used by the x_xattr[] array */ >+ struct linux_dirent x_dent; >+ struct xdirent_xattr x_xattr[1]; >+}; >+ >+void xstat_get_params_i(unsigned int mask, struct kstat *stat); >+long xstat_set_result(struct kstat *stat, struct xstat __user *buffer); >+long xdirent_set_result(struct xdirent_info *xinfo, >+ struct linux_xdirent __user *xdirent, >+ unsigned int dent_len); >+int xdirent_get_params(unsigned int mask, struct xdirent_info *xinfo); > #endif > #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