xgetdents system call
Subsystems (5)
cover xgetdents system call
This system call takes 5 arguments:
fd - file descriptor of the directory
flags - flags used by xstat
mask - field mask used to request stat/xattr info
buf - user buf to return collected info
count - size of user buffer in bytes
xgetdents() should read the directory entries, collect stat and xattr information for each entry as requested and return all the data back to the user in a container structure (linux_xdirent) as part of the supplied user buffer.
Abhi Das (5):
fs: xstat system call VFS bits
fs: Add xgetdents system call and xreaddir file operation
gfs2: Add a dynamic buffer backed by a vector of pages
gfs2: Add sort functionality with extra parameter
gfs2: Add xreaddir file operation and supporting functions
arch/x86/syscalls/syscall_32.tbl | 3 + arch/x86/syscalls/syscall_64.tbl | 3 + fs/gfs2/Makefile | 3 +- fs/gfs2/dir.c | 80 +-- fs/gfs2/dir.h | 13 +- fs/gfs2/export.c | 2 +- fs/gfs2/file.c | 17 +- fs/gfs2/incore.h | 6 + fs/gfs2/inode.c | 3 +- fs/gfs2/inode.h | 5 + fs/gfs2/ops_fstype.c | 4 + fs/gfs2/sys.c | 26 +- fs/gfs2/util.c | 363 ++++++++++++++ fs/gfs2/util.h | 47 ++ fs/gfs2/xattr.c | 27 +- fs/gfs2/xattr.h | 23 + fs/gfs2/xreaddir.c | 1024 ++++++++++++++++++++++++++++++++++++++ fs/gfs2/xreaddir.h | 84 ++++ fs/readdir.c | 42 ++ fs/stat.c | 340 ++++++++++++- include/linux/fs.h | 5 + include/linux/stat.h | 16 +- include/linux/syscalls.h | 5 + include/uapi/linux/fcntl.h | 1 + include/uapi/linux/stat.h | 143 ++++++ 25 files changed, 2196 insertions(+), 89 deletions(-) create mode 100644 fs/gfs2/xreaddir.c create mode 100644 fs/gfs2/xreaddir.h
Signature · 1 line
1.8.1.4
RFC PATCH 1/5 fs: xstat system call VFS bits
This patch adds the VFS bits of the xstat patchset by David Howells. The xgetdents syscall uses this to obtain stat information for directory entries.
--- arch/x86/syscalls/syscall_32.tbl | 2 + arch/x86/syscalls/syscall_64.tbl | 2 + fs/stat.c | 338 ++++++++++++++++++++++++++++++++++++--- include/linux/fs.h | 4 + include/linux/stat.h | 14 +- include/linux/syscalls.h | 5 + include/uapi/linux/fcntl.h | 1 + include/uapi/linux/stat.h | 110 +++++++++++++ 8 files changed, 453 insertions(+), 23 deletions(-)
arch/x86/syscalls/syscall_32.tbl +2 -0
@@ -360,3 +360,5 @@ 351 i386 sched_setattr sys_sched_setattr 352 i386 sched_getattr sys_sched_getattr 353 i386 renameat2 sys_renameat2 +354 i386 xstat sys_xstat +355 i386 fxstat sys_fxstat
arch/x86/syscalls/syscall_64.tbl +2 -0
@@ -323,6 +323,8 @@ 314 common sched_setattr sys_sched_setattr 315 common sched_getattr sys_sched_getattr 316 common renameat2 sys_renameat2 +317 common xstat sys_xstat +318 common fxstat sys_fxstat # # x32-specific system call numbers start at 512 to avoid cache impact
fs/stat.c +316 -22
430 lines not on this page · raw message
include/linux/fs.h +4 -0
@@ -1207,6 +1207,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;
@@ -2519,6 +2520,7 @@ extern int generic_readlink(struct dentry *, char __user *, int);extern void generic_fillattr (struct inode *,struct kstat *);int vfs_getattr_nosec (struct path *path,struct kstat *stat);extern int vfs_getattr (struct path *,struct kstat *); +extern int vfs_xgetattr (struct path *,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);
@@ -2533,6 +2535,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);
include/linux/stat.h +13 -1
@@ -2,6 +2,7 @@#define _LINUX_STAT_H +#include <linux/types.h> #include <asm/stat.h> #include <uapi/linux/stat.h>
@@ -19,6 +20,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;
@@ -26,12 +33,17 @@ 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
include/linux/syscalls.h +5 -0
@@ -866,4 +866,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_finit_module (int fd,const char __user *uargs,int flags); + +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
include/uapi/linux/fcntl.h +1 -0
@@ -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 */ #endif /* _UAPI_LINUX_FCNTL_H */
include/uapi/linux/stat.h +110 -0
115 lines not on this page · raw message
Signature · 1 line
1.8.1.4
Re: [Cluster-devel] [RFC PATCH 1/5] fs: xstat system call VFS bits
----- Original Message -----
Quoted 16 lines
This patch adds the VFS bits of the xstat patchset by David Howells. The xgetdents syscall uses this to obtain stat information for directory entries.
Signed-off-by Abhi Das <[email protected]>--- arch/x86/syscalls/syscall_32.tbl | 2 + arch/x86/syscalls/syscall_64.tbl | 2 + fs/stat.c | 338 ++++++++++++++++++++++++++++++++++++--- include/linux/fs.h | 4 + include/linux/stat.h | 14 +- include/linux/syscalls.h | 5 + include/uapi/linux/fcntl.h | 1 + include/uapi/linux/stat.h | 110 +++++++++++++ 8 files changed, 453 insertions(+), 23 deletions(-)
(snip)
fs/stat.c SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, · line 632
Quoted 4 lines
fs/stat.c +4
-0+static int xstat_get_params (unsigned int mask,struct xstat __user *buffer, +struct kstat *stat) +{ +memset (stat,0xde ,sizeof (*stat));// DEBUGGING
Did you forget to remove this DEBUGGING statement? In either case, the c++ comment should be /* */.
Regards,
Bob Peterson
Red Hat File Systems
RFC PATCH 2/5 fs: Add xgetdents system call and xreaddir file operation
In reply to Abhi DasAlso add linux_xdirent structure that will be the container for dirent, stat and xattr info.
--- arch/x86/syscalls/syscall_32.tbl | 1 + arch/x86/syscalls/syscall_64.tbl | 1 + fs/readdir.c | 42 ++++++++++++++++++++++++++++++++++++++++ fs/stat.c | 4 +++- include/linux/fs.h | 1 + include/linux/stat.h | 2 ++ include/uapi/linux/stat.h | 33 +++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 1 deletion(-)
arch/x86/syscalls/syscall_32.tbl +1 -0
@@ -362,3 +362,4 @@ 353 i386 renameat2 sys_renameat2 354 i386 xstat sys_xstat 355 i386 fxstat sys_fxstat +356 i386 xgetdents sys_xgetdents
arch/x86/syscalls/syscall_64.tbl +1 -0
@@ -325,6 +325,7 @@ 316 common renameat2 sys_renameat2 317 common xstat sys_xstat 318 common fxstat sys_fxstat +319 common xgetdents sys_xgetdents # # x32-specific system call numbers start at 512 to avoid cache impact
fs/readdir.c +42 -0
48 lines not on this page · raw message
fs/stat.c +3 -1
@@ -651,7 +651,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;
@@ -701,6 +701,8 @@ static long xstat_set_result(struct kstat *stat, struct xstat __user *buffer)return 0 ; } +EXPORT_SYMBOL (xstat_set_result); +/* * System call to get extended stats by path */
include/linux/fs.h +1 -0
@@ -1464,6 +1464,7 @@ struct file_operations {ssize_t (*read_iter) (struct kiocb *,struct iov_iter *);ssize_t (*write_iter) (struct kiocb *,struct iov_iter *);int (*iterate) (struct file *,struct dir_context *); +size_t (*xreaddir) (struct file *,unsigned int ,unsigned int ,void __user *,size_t );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 );
include/linux/stat.h +2 -0
@@ -46,4 +46,6 @@ struct kstat { unsigned char volume_id[16]; /* volume identifier */ }; +long xstat_set_result (struct kstat *stat,struct xstat __user *buffer); +#endif
include/uapi/linux/stat.h +33 -0
@@ -90,6 +90,14 @@#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_XATTR_ALL 0x00ff0000U/* all xattrs */ +#define XSTAT_XATTR_VALUES 0x01000000U/* retrieve values along with keys */ +/* * Extended stat structures */
@@ -152,4 +160,29 @@ struct xstat {#define XSTAT_INFO_SYSTEM 0x00001000U/* File is marked system (DOS+) */ #define XSTAT_INFO_ARCHIVE 0x00002000U/* File is marked archive (DOS+) */ +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 */ +}; + +/* +* xb_blob: first contains NULL terminated name, followed by struct xdirent_xattr +* objects packed together. +*/ +struct xdirent_blob { +unsigned int xb_xattr_count; +char xb_blob[1 ];/* contains variable length data like +* NULL-terminated name, xattrs etc */ +}; + +struct linux_xdirent { +unsigned long xd_ino; +char xd_type; +unsigned long xd_off; +struct xstat xd_stat; +unsigned long xd_reclen; +struct xdirent_blob xd_blob; +}; +#endif /* _UAPI_LINUX_STAT_H */
Signature · 1 line
1.8.1.4
Re: [RFC PATCH 2/5] fs: Add xgetdents system call and xreaddir file operation
[CC += linux-api]
Quoted 190 lines · Abhi Das
Also add
linux_xdirentstructure that will be the container for dirent, stat and xattr info.Signed-off-by Abhi Das <[email protected]>--- arch/x86/syscalls/syscall_32.tbl | 1 + arch/x86/syscalls/syscall_64.tbl | 1 + fs/readdir.c | 42 ++++++++++++++++++++++++++++++++++++++++ fs/stat.c | 4 +++- include/linux/fs.h | 1 + include/linux/stat.h | 2 ++ include/uapi/linux/stat.h | 33 +++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 1 deletion(-)arch/x86/syscalls/syscall_32.tbl +1
-0@@ -362,3 +362,4 @@ 353 i386 renameat2 sys_renameat2 354 i386 xstat sys_xstat 355 i386 fxstat sys_fxstat +356 i386 xgetdents sys_xgetdentsarch/x86/syscalls/syscall_64.tbl +1
-0@@ -325,6 +325,7 @@ 316 common renameat2 sys_renameat2 317 common xstat sys_xstat 318 common fxstat sys_fxstat +319 common xgetdents sys_xgetdents # # x32-specific system call numbers start at 512 to avoid cache impactfs/readdir.c +42
-0@@ -224,6 +224,48 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,return error; } +SYSCALL_DEFINE5(xgetdents, unsigned int, fd, unsigned, flags, unsigned int, mask, + void __user *, buf, unsigned int, count) +{ +struct fd f; +struct inode *inode; +int error = -ENOTDIR ; + +if (!count) +return -EINVAL ; + +if (!access_ok (VERIFY_WRITE , buf, count)) +return -EFAULT ; + + f =fdget (fd); +if (!f.file) +return -EBADF ; + + inode = f.file->f_path.dentry->d_inode; + + error = -ENOTSUPP ; +if (!f.file->f_op || !f.file->f_op->xreaddir) + goto out; + + error =security_file_permission (f.file,MAY_READ ); +if (error) + goto out; + + error =mutex_lock_killable (&inode->i_mutex); +if (error) + goto out; + + error = -ENOENT ; +if (!IS_DEADDIR (inode)) { + error = f.file->f_op->xreaddir (f.file, flags, mask, buf, count); +file_accessed (f.file); + } +mutex_unlock (&inode->i_mutex); +out: +fdput (f); +return error; +} +struct getdents_callback64 {struct dir_context ctx;struct linux_dirent64 __user * current_dir;fs/stat.c +3
-1@@ -651,7 +651,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;@@ -701,6 +701,8 @@ static long xstat_set_result(struct kstat *stat, struct xstat __user *buffer)return 0 ; } +EXPORT_SYMBOL (xstat_set_result); +/* * System call to get extended stats by path */ include/linux/fs.h +1
-0@@ -1464,6 +1464,7 @@ struct file_operations {ssize_t (*read_iter) (struct kiocb *,struct iov_iter *);ssize_t (*write_iter) (struct kiocb *,struct iov_iter *);int (*iterate) (struct file *,struct dir_context *); +size_t (*xreaddir) (struct file *,unsigned int ,unsigned int ,void __user *,size_t );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 );include/linux/stat.h +2
-0@@ -46,4 +46,6 @@ struct kstat { unsigned char volume_id[16]; /* volume identifier */ }; +long xstat_set_result (struct kstat *stat,struct xstat __user *buffer); +#endif include/uapi/linux/stat.h +33
-1@@ -90,6 +90,14 @@#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_XATTR_ALL 0x00ff0000U/* all xattrs */ +#define XSTAT_XATTR_VALUES 0x01000000U/* retrieve values along with keys */ +/* * Extended stat structures */ @@ -152,4 +160,29 @@ struct xstat {#define XSTAT_INFO_SYSTEM 0x00001000U/* File is marked system (DOS+) */ #define XSTAT_INFO_ARCHIVE 0x00002000U/* File is marked archive (DOS+) */ +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 */ +}; + +/* +* xb_blob: first contains NULL terminated name, followed by struct xdirent_xattr +* objects packed together. +*/ +struct xdirent_blob { +unsigned int xb_xattr_count; +char xb_blob[1 ];/* contains variable length data like +* NULL-terminated name, xattrs etc */ +}; + +struct linux_xdirent { +unsigned long xd_ino; +char xd_type; +unsigned long xd_off; +struct xstat xd_stat; +unsigned long xd_reclen; +struct xdirent_blob xd_blob; +}; +#endif /* _UAPI_LINUX_STAT_H */ --1.8.1.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Signature · 3 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Author of "The Linux Programming Interface", http://blog.man7.org/
RFC PATCH 3/5 gfs2: Add a dynamic buffer backed by a vector of pages
In reply to Abhi DasThis patch adds a new buffer called 'vbuf' that is backed by a vector of pages. It is dynamic and can be expanded as needed with low overhead.
--- fs/gfs2/util.c | 299 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/gfs2/util.h | 43 +++++++++ 2 files changed, 342 insertions(+)
fs/gfs2/util.c +299 -0
@@ -263,3 +263,302 @@ int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,return rv; } +/* +* Fast vector-of-pages backed buffer +*/ + +static int vp_alloc_pages (struct vp_ctx *vpx,int start,int end) +{ +int i; + +for (i = start; i < end; i++) { + vpx->vp_pages[i] =alloc_page (GFP_KERNEL |GFP_NOFS ); +if (vpx->vp_pages[i] ==NULL ) + goto free; + } +return 0 ; +free: +for (i = start; i < end; i++) +if (vpx->vp_pages[i]) { +__free_page (vpx->vp_pages[i]); + vpx->vp_pages[i] =NULL ; + } +return -ENOMEM ; +} + +static void vp_free_pages (struct vp_ctx *vpx) +{ +int i; + +for (i =0 ; i < vpx->vp_size; i++) +if (vpx->vp_pages[i]) { +__free_page (vpx->vp_pages[i]); + vpx->vp_pages[i] =NULL ; + } +} + +static int vp_extend (struct vp_ctx *vpx,int size) +{ +struct gfs2_sbd *sdp = vpx->vp_sdp; + +/* first make room for more pointers */ +if (size <=0 ) +return -EINVAL ; + + vpx->vp_pages =krealloc (vpx->vp_pages, +sizeof (struct page *) * (vpx->vp_size + size), +GFP_KERNEL ); +if (vpx->vp_pages ==NULL ) + goto out; + +/* Zero out the new pointers and allocate pages*/ +memset (&vpx->vp_pages[vpx->vp_size],0 ,sizeof (struct page *) * size); +if (vp_alloc_pages (vpx, vpx->vp_size, vpx->vp_size + size)) + goto out; + + vpx->vp_size += size; +return 0 ; +out: +return -ENOMEM ; +} + +int vp_init (struct gfs2_sbd *sdp,struct vbuf *vb,int init_cap) +{ +int cap, err = -ENOMEM ; +struct vp_ctx *vpx; + + cap =DIV_ROUND_UP (init_cap,PAGE_SIZE ); + + vpx =kmalloc (sizeof (struct vp_ctx ),GFP_KERNEL ); +if (vpx ==NULL ) + goto out; + + vpx->vp_magic =VP_MAGIC ; + vpx->vp_size = cap; + vpx->vp_pages =kzalloc (sizeof (struct page *) * cap,GFP_KERNEL ); +if (vpx->vp_pages ==NULL ) + goto free; + +if (vp_alloc_pages (vpx,0 , cap)) + goto free_all; + + vpx->vp_baseptr = vpx->vp_top =page_address (vpx->vp_pages[0 ]); + vpx->vp_sdp = sdp; + vb->v_ptr = vpx->vp_baseptr; + vb->v_opaque = vpx; + + err =0 ; + goto out; + +free_all: +vp_free_pages (vpx); +kfree (vpx->vp_pages); +free: +kfree (vpx); + vpx =NULL ; +out: +return err; +} + +void vp_uninit (struct vbuf *vb) +{ +struct vp_ctx *vpx; + +if (!vb || !vb->v_opaque) +return ; + + vpx = vb->v_opaque; +if (vpx->vp_magic !=VP_MAGIC ) +return ; + +vp_free_pages (vpx); +kfree (vpx->vp_pages); +kfree (vpx); + vb->v_ptr = vb->v_opaque =NULL ; +} + +static int vp_rw_pages (struct vp_ctx *vpx,void *to,const void *from, +size_t count,int what) +{ +int pg_ind, pg_off, bytes, rw =0 ; + +while (count >0 ) { + pg_ind = what ==VP_READ ?VP_PAGE_INDEX (vpx, from) + :VP_PAGE_INDEX (vpx, to); + pg_off = what ==VP_READ ?VP_PAGE_OFFSET (vpx, from) + :VP_PAGE_OFFSET (vpx, to); + bytes = what ==VP_READ ?VP_PAGE_BYTES_LEFT (vpx, from) + :VP_PAGE_BYTES_LEFT (vpx, to); + bytes =min (count, (size_t ) bytes); + +if (what ==VP_READ ) +memcpy (to,VP_PAGE_PTR (vpx, pg_ind, pg_off), bytes); +else { +if (what ==VP_WRITE ) +memcpy (VP_PAGE_PTR (vpx, pg_ind, pg_off), + from, bytes); +else if (what ==VP_MEMSET ) +memset (VP_PAGE_PTR (vpx, pg_ind, pg_off), + (*(const int *)from), bytes); +if ((to + count) > vpx->vp_top) + vpx->vp_top = to + count; + } + to += bytes; +if (what !=VP_MEMSET ) + from += bytes; + rw += bytes; + count -= bytes; + } +return rw; +} + +struct vp_ctx *vp_get_vpx (struct vbuf *vb) +{ +struct vp_ctx *vpx =NULL ; + +if (!vb || !vb->v_opaque) + goto out; + + vpx = vb->v_opaque; +if (vpx->vp_magic !=VP_MAGIC ) { + vpx =NULL ; + goto out; + } +out: +return vpx; +} + +int vp_read (struct vbuf *vb,void *to,const void *from,size_t count) +{ +struct vp_ctx *vpx; +void *buf_end =NULL ; +int err = -EINVAL ; + + vpx =vp_get_vpx (vb); +if (!vpx) +return err; + + buf_end = vpx->vp_baseptr +PAGE_SIZE * vpx->vp_size; +if (count <=0 || (from + count > buf_end)) +return err; + +return vp_rw_pages (vpx, to, from, count,VP_READ ); +} + +int vp_write_i (struct vp_ctx *vpx,void *to,const void *from, +size_t count,int what) +{ +int err = -EINVAL ; +void *buf_end =NULL ; + +/* Check to see if the write will fall within limits */ + buf_end = vpx->vp_baseptr +PAGE_SIZE * vpx->vp_size; +if (to < vpx->vp_baseptr || + (to + count) > (buf_end +PAGE_SIZE *VP_MAX_ALLOC_STEP )) +return err; + +if ((to + count) > buf_end) { + err =vp_extend (vpx,DIV_ROUND_UP (to + count - buf_end, +PAGE_SIZE )); +if (err) +return err; + } +return vp_rw_pages (vpx, to, from, count, what); +} + +int vp_write (struct vbuf *vb,void *to,const void *from,size_t count) +{ +struct vp_ctx *vpx; +int err = -EINVAL ; + +if (count <=0 || count >VP_MAX_WRITE ) +return err; + + vpx =vp_get_vpx (vb); +if (!vpx) +return err; + +return vp_write_i (vpx, to, from, count,VP_WRITE ); +} + +int vp_append (struct vbuf *vb,const void *from,size_t count) +{ +struct vp_ctx *vpx; +int err = -EINVAL ; + +if (count <=0 || count >VP_MAX_WRITE ) +return err; + + vpx =vp_get_vpx (vb); +if (!vpx) +return err; + +return vp_write_i (vpx, vpx->vp_top, from, count,VP_WRITE ); +} + +int vp_memset (struct vbuf *vb,void *to,int c,size_t count) +{ +struct vp_ctx *vpx; +int err = -EINVAL ; + +if (count <=0 || count >VP_MAX_WRITE ) +return err; + + vpx =vp_get_vpx (vb); +if (!vpx) +return err; + + err =vp_write_i (vpx, to, &c, count,VP_MEMSET ); + +return err; +} + +/* +* Returns the linear ptr to the top of this buffer +*/ +void *vp_get_top (struct vbuf *vb) +{ +struct vp_ctx *vpx; + vpx =vp_get_vpx (vb); +if (!vpx) +return NULL ; +else +return vpx->vp_top; +} + +/* +* vp_get_page_count: Returns # of pages allocated to this buffer +*/ +size_t vp_get_page_count (struct vbuf *vb) +{ +struct vp_ctx *vpx; + vpx =vp_get_vpx (vb); +if (!vpx) +return -EINVAL ; +return vpx->vp_size; +} + +/* +* vp_get_size: Returns number of bytes used in this buffer +*/ +size_t vp_get_size (struct vbuf *vb) +{ +struct vp_ctx *vpx; + vpx =vp_get_vpx (vb); +if (!vpx) +return -EINVAL ; +return vpx->vp_top - vpx->vp_baseptr; +} + +/* +* vp_reset: Doesn't deallocate, simply moves +* vp_top to vp_baseptr, making the entire buffer +* available for writing. +*/ +void vp_reset (struct vbuf *vb) +{ +struct vp_ctx *vpx; + vpx =vp_get_vpx (vb); +if (vpx) + vpx->vp_top = vpx->vp_baseptr; +}
fs/gfs2/util.h +43 -0
53 lines not on this page · raw message
Signature · 1 line
1.8.1.4
Re: [Cluster-devel] [RFC PATCH 3/5] gfs2: Add a dynamic buffer backed by a vector of pages
----- Original Message -----
Quoted 8 lines
fs/gfs2/util.c +8
-0+static int vp_alloc_pages (struct vp_ctx *vpx,int start,int end) +{ +int i; + +for (i = start; i < end; i++) { + vpx->vp_pages[i] =alloc_page (GFP_KERNEL |GFP_NOFS ); +if (vpx->vp_pages[i] ==NULL ) + goto free;
fs/gfs2/util.c int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, · line 287
Quoted 10 lines
fs/gfs2/util.c +10
-0+ } +return 0 ; +free: +for (i = start; i < end; i++) +if (vpx->vp_pages[i]) { +__free_page (vpx->vp_pages[i]); + vpx->vp_pages[i] =NULL ; + } +return -ENOMEM ; +}
I'm concerned that if we have a value for vpx->vp_pages[i] that is nonzero (uninitialized) _after_ an element in which we couldn't allocate a page, we could try to free the nonzero value. For that reason, I always prefer to do something like this instead:
free:
while (i > start) {
i--;
__free_page(vpx->vp_pages[i]);
vpx->vp_pages[i] = NULL;
}
return -ENOMEM;(snip)
fs/gfs2/util.c int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, · line 425
Quoted 11 lines
fs/gfs2/util.c +11
-0+struct vp_ctx *vp_get_vpx (struct vbuf *vb) +{ +struct vp_ctx *vpx =NULL ; + +if (!vb || !vb->v_opaque) + goto out; + + vpx = vb->v_opaque; +if (vpx->vp_magic !=VP_MAGIC ) { + vpx =NULL ; + goto out;
This goto is unnecessary, and if you eliminate it, you don't need the brackets.
fs/gfs2/util.c int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh, · line 429
Quoted 4 lines
fs/gfs2/util.c +4
-0+ } +out: +return vpx; +}
Regards,
Bob Peterson
Red Hat File Systems
RFC PATCH 4/5 gfs2: Add sort functionality with extra parameter
In reply to Abhi DasThis is essentially a copy of the sort function and its helpers from lib/sort.c with the exception of an additional 'void *opaque' parameter added here.
custom cmp_func and swap_func functions can make use of the opaque field for relevant context
--- fs/gfs2/util.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/gfs2/util.h | 4 ++++ 2 files changed, 59 insertions(+)
fs/gfs2/util.c +55 -0
@@ -562,3 +562,58 @@ void vp_reset(struct vbuf *vb)if (vpx) vpx->vp_top = vpx->vp_baseptr; } + +/* heap sort that takes an opaque context - directly copied from lib/sort.c */ +static void u32_swap (void *opaque,void *a,void *b,int size) +{ +u32 t = *(u32 *)a; + *(u32 *)a = *(u32 *)b; + *(u32 *)b = t; +} + +static void generic_swap (void *opaque,void *a,void *b,int size) +{ +char t; +do { + t = *(char *)a; + *(char *)a++ = *(char *)b; + *(char *)b++ = t; + }while (--size >0 ); +} + +void ctx_sort (void *opaque,void *base,size_t num,size_t size, +int (*cmp_func)(void *,const void *,const void *), +void (*swap_func)(void *,void *,void *,int size)) +{ +int i = (num/2 -1 ) * size, n = num * size, c, r; + +if (!swap_func) + swap_func = (size ==4 ? u32_swap : generic_swap); + +/* heapify */ +for ( ; i >=0 ; i -= size) { +for (r = i; r *2 + size < n; r = c) { + c = r *2 + size; +if (c < n - size && +cmp_func (opaque, base + c, base + c + size) <0 ) + c += size; +if (cmp_func (opaque, base + r, base + c) >=0 ) +break ; +swap_func (opaque, base + r, base + c, size); + } + } + +/* sort */ +for (i = n - size; i >0 ; i -= size) { +swap_func (opaque, base, base + i, size); +for (r =0 ; r *2 + size < i; r = c) { + c = r *2 + size; +if (c < i - size && +cmp_func (opaque, base + c, base + c + size) <0 ) + c += size; +if (cmp_func (opaque, base + r, base + c) >=0 ) +break ; +swap_func (opaque, base + r, base + c, size); + } + } +}
fs/gfs2/util.h +4 -0
@@ -210,5 +210,9 @@ int vp_read(struct vbuf *vb, void *to, const void *from, size_t count);int vp_write (struct vbuf *vb,void *to,const void *from,size_t count);int vp_append (struct vbuf *vb,const void *from,size_t count);int vp_memset (struct vbuf *vb,void *to,int c,size_t count); + +void ctx_sort (void *opaque,void *base,size_t num,size_t size, +int (*cmp_func)(void *,const void *,const void *), +void (*swap_func)(void *,void *,void *,int size));#endif /* __UTIL_DOT_H__ */
Signature · 1 line
1.8.1.4
RFC PATCH 5/5 gfs2: Add xreaddir file operation and supporting functions
In reply to Abhi DasThis patch adds support in GFS2 for the xgetdents syscall by implementing the xreaddir file operation.
GFS2 uses vbufs (buffer backed by a vector of pages) to store intermediate data like dirents, stat info and extended attribute keys/values to eventually bundle them into a container structure to return to the user.
--- fs/gfs2/Makefile | 3 +- fs/gfs2/dir.c | 80 ++-- fs/gfs2/dir.h | 13 +- fs/gfs2/export.c | 2 +- fs/gfs2/file.c | 17 +- fs/gfs2/incore.h | 6 + fs/gfs2/inode.c | 3 +- fs/gfs2/inode.h | 5 + fs/gfs2/ops_fstype.c | 4 + fs/gfs2/sys.c | 26 +- fs/gfs2/util.c | 9 + fs/gfs2/xattr.c | 27 +- fs/gfs2/xattr.h | 23 ++ fs/gfs2/xreaddir.c | 1024 ++++++++++++++++++++++++++++++++++++++++++++++++++ fs/gfs2/xreaddir.h | 84 +++++ 15 files changed, 1260 insertions(+), 66 deletions(-) create mode 100644 fs/gfs2/xreaddir.c create mode 100644 fs/gfs2/xreaddir.h
fs/gfs2/Makefile +2 -1
@@ -4,7 +4,8 @@ gfs2-y := acl.o bmap.o dir.o xattr.o glock.o \ glops.o log.o lops.o main.o meta_io.o \ aops.o dentry.o export.o file.o \ ops_fstype.o inode.o quota.o \ - recovery.o rgrp.o super.o sys.o trans.o util.o + recovery.o rgrp.o super.o sys.o \ + trans.o util.o xreaddir.o gfs2-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
fs/gfs2/dir.c +45 -35
190 lines not on this page · raw message
fs/gfs2/dir.h +12 -1
@@ -12,6 +12,10 @@#include <linux/dcache.h> #include <linux/crc32.h> +#include "util.h" + +#define gfs2_disk_hash2offset (h) (((u64)(h)) >> 1) +#define gfs2_dir_offset2hash (p) ((u32)(((u64)(p)) << 1))struct inode ;struct gfs2_inode ;
@@ -25,6 +29,13 @@ struct gfs2_diradd {struct buffer_head *bh; }; +typedef int (*process_dent_t )(const struct gfs2_dirent *,loff_t ,void *,filldir_t ); +extern int compare_dents_i (const struct gfs2_dirent *dent_a, +const struct gfs2_dirent *dent_b); +extern int foreach_dent (u64 *offset,void *opaque,filldir_t filldir, +const struct gfs2_dirent **darr,u32 entries, +int *copied,process_dent_t pd_fn); +extern struct inode *gfs2_dir_search (struct inode *dir,const struct qstr *filename,bool fail_on_exist);
@@ -40,7 +51,7 @@ static inline void gfs2_dir_no_add(struct gfs2_diradd *da) }extern int gfs2_dir_del (struct gfs2_inode *dip,const struct dentry *dentry);extern int gfs2_dir_read (struct inode *inode,struct dir_context *ctx, -struct file_ra_state *f_ra); +struct gfs2_xrdir_ctx *xc,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);
fs/gfs2/export.c +1 -1
@@ -114,7 +114,7 @@ static int gfs2_get_name(struct dentry *parent, char *name,if (error)return error; - error =gfs2_dir_read (dir, &gnfd.ctx, &f_ra); + error =gfs2_dir_read (dir, &gnfd.ctx,NULL , &f_ra);gfs2_glock_dq_uninit (&gh);
fs/gfs2/file.c +15 -2
@@ -16,6 +16,8 @@#include <linux/blkdev.h> #include <linux/mm.h> #include <linux/mount.h> +#include <linux/stat.h> +#include <linux/sort.h> #include <linux/fs.h> #include <linux/gfs2_ondisk.h> #include <linux/falloc.h>
@@ -40,6 +42,7 @@#include "rgrp.h" #include "trans.h" #include "util.h" +#include "xreaddir.h" /** * gfs2_llseek - seek to a location in a file
@@ -100,7 +103,7 @@ static int gfs2_readdir(struct file *file, struct dir_context *ctx)if (error)return error; - error =gfs2_dir_read (dir, ctx, &file->f_ra); + error =gfs2_dir_read (dir, ctx,NULL , &file->f_ra);gfs2_glock_dq_uninit (&d_gh);
@@ -562,8 +565,13 @@ int gfs2_open_common(struct inode *inode, struct file *file)return -ENOMEM ;mutex_init (&fp->f_fl_mutex); -gfs2_assert_warn (GFS2_SB (inode), !file->private_data); + +if (S_ISDIR (inode->i_mode)) { + ret =gfs2_xrdir_ctx_init (fp,GFS2_SB (inode)); +if (ret) +return ret; + } file->private_data = fp;return 0 ; }
@@ -617,6 +625,9 @@ static int gfs2_release(struct inode *inode, struct file *file) {struct gfs2_inode *ip =GFS2_I (inode); +if (S_ISDIR (ip->i_inode.i_mode)) +gfs2_xrdir_ctx_uninit ((struct gfs2_file *)file->private_data); +kfree (file->private_data); file->private_data =NULL ;
@@ -1075,6 +1086,7 @@ const struct file_operations gfs2_file_fops = {const struct file_operations gfs2_dir_fops = { .iterate = gfs2_readdir, + .xreaddir = gfs2_xreaddir, .unlocked_ioctl = gfs2_ioctl, .open = gfs2_open, .release = gfs2_release,
@@ -1105,6 +1117,7 @@ const struct file_operations gfs2_file_fops_nolock = {const struct file_operations gfs2_dir_fops_nolock = { .iterate = gfs2_readdir, + .xreaddir = gfs2_xreaddir, .unlocked_ioctl = gfs2_ioctl, .open = gfs2_open, .release = gfs2_release,
fs/gfs2/incore.h +6 -0
@@ -414,6 +414,7 @@ static inline struct gfs2_sbd *GFS2_SB(const struct inode *inode)struct gfs2_file {struct mutex f_fl_mutex;struct gfs2_holder f_fl_gh; +struct gfs2_xrdir_ctx *f_xrctx; };struct gfs2_revoke_replay {
@@ -570,6 +571,8 @@ struct gfs2_tune {unsigned int gt_complain_secs;unsigned int gt_statfs_quantum;unsigned int gt_statfs_slow; +unsigned int gt_max_vb_pages;/* Max pages to utilize for vector-page buffers */ +unsigned int gt_max_xrdir_dents;/* Maximum dents to process per collect cycle (conserves memory) */ };enum {
@@ -812,6 +815,9 @@ struct gfs2_sbd {struct dentry *debugfs_dentry_glocks;struct dentry *debugfs_dentry_glstats;struct dentry *debugfs_dentry_sbstats; + +/* Vector Pages accounting */ +atomic_t sd_vb_page_count; };static inline void gfs2_glstats_inc (struct gfs2_glock *gl,int which)
fs/gfs2/inode.c +2 -1
@@ -1833,7 +1833,8 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, } } -generic_fillattr (inode, stat); +gfs2_getattr_i (ip, stat); +if (unlock)gfs2_glock_dq_uninit (&gh);else if (frozen_root &&atomic_dec_and_test (&sdp->sd_frozen_root))
fs/gfs2/inode.h +5 -0
@@ -93,6 +93,11 @@ err:return -EIO ; } +static inline void gfs2_getattr_i (struct gfs2_inode *ip,struct kstat *stat) +{ +generic_fillattr (&ip->i_inode, stat); +} +extern struct inode *gfs2_inode_lookup (struct super_block *sb,unsigned type,u64 no_addr,u64 no_formal_ino,int non_block);
fs/gfs2/ops_fstype.c +4 -0
@@ -60,6 +60,8 @@ static void gfs2_tune_init(struct gfs2_tune *gt) gt->gt_new_files_jdata =0 ; gt->gt_max_readahead =1 <<18 ; gt->gt_complain_secs =10 ; + gt->gt_max_vb_pages =65536 ; + gt->gt_max_xrdir_dents =25000 ; }static struct gfs2_sbd *init_sbd (struct super_block *sb)
@@ -135,6 +137,8 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)atomic_set (&sdp->sd_frozen_root,0 );init_waitqueue_head (&sdp->sd_frozen_root_wait); +atomic_set (&sdp->sd_vb_page_count,0 ); +return sdp; }
fs/gfs2/sys.c +22 -4
@@ -548,8 +548,8 @@ static ssize_t quota_scale_store(struct gfs2_sbd *sdp, const char *buf,return len; } -static ssize_t tune_set (struct gfs2_sbd *sdp,unsigned int *field, -int check_zero,const char *buf,size_t len) +static ssize_t tune_set (struct gfs2_sbd *sdp,unsigned int *field,int check_zero, +unsigned int min,unsigned int max,const char *buf,size_t len) {struct gfs2_tune *gt = &sdp->sd_tune;unsigned int x;
@@ -562,6 +562,12 @@ static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,if (check_zero && !x)return -EINVAL ; +if (min && x < min) +return -EINVAL ; + +if (max && x > max) +return -EINVAL ; +spin_lock (>->gt_spin); *field = x;spin_unlock (>->gt_spin);
@@ -578,13 +584,21 @@ static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \ } \ TUNE_ATTR_3(name, name##_show, store) -#define TUNE_ATTR (name, check_zero) \ +#define TUNE_ATTR (name, check_zero) \ +static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len) \ +{ \ + return tune_set(sdp, &sdp->sd_tune.gt_##name, check_zero, 0, 0, buf, len); \ +} \ +TUNE_ATTR_2(name, name##_store) + +#define TUNE_ATTR_B (name, min, max) \ static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\ { \ - return tune_set(sdp, &sdp->sd_tune.gt_##name, check_zero, buf, len); \ + return tune_set(sdp, &sdp->sd_tune.gt_##name, 0, min, max, buf, len); \ } \ TUNE_ATTR_2(name, name##_store) +TUNE_ATTR (quota_warn_period,0 );TUNE_ATTR (quota_quantum,0 );TUNE_ATTR (max_readahead,0 );
@@ -593,6 +607,8 @@ TUNE_ATTR(statfs_slow, 0);TUNE_ATTR (new_files_jdata,0 );TUNE_ATTR (statfs_quantum,1 );TUNE_ATTR_3 (quota_scale, quota_scale_show, quota_scale_store); +TUNE_ATTR_B (max_vb_pages,32 ,8388608 );/* total capacity can be 128K to 32G bytes */ +TUNE_ATTR (max_xrdir_dents,0 );static struct attribute *tune_attrs[] = { &tune_attr_quota_warn_period.attr,
@@ -603,6 +619,8 @@ static struct attribute *tune_attrs[] = { &tune_attr_statfs_quantum.attr, &tune_attr_quota_scale.attr, &tune_attr_new_files_jdata.attr, + &tune_attr_max_vb_pages.attr, + &tune_attr_max_xrdir_dents.attr, NULL, };
fs/gfs2/util.c +9 -0
@@ -301,6 +301,9 @@ static int vp_extend(struct vp_ctx *vpx, int size) {struct gfs2_sbd *sdp = vpx->vp_sdp; +if ((gfs2_tune_get (sdp, gt_max_vb_pages) + -atomic_read (&sdp->sd_vb_page_count)) < size) + goto out;/* first make room for more pointers */ if (size <=0 )return -EINVAL ;
@@ -317,6 +320,7 @@ static int vp_extend(struct vp_ctx *vpx, int size) goto out; vpx->vp_size += size; +atomic_add (size, &sdp->sd_vb_page_count);return 0 ; out:return -ENOMEM ;
@@ -328,6 +332,9 @@ int vp_init(struct gfs2_sbd *sdp, struct vbuf *vb, int init_cap)struct vp_ctx *vpx; cap =DIV_ROUND_UP (init_cap,PAGE_SIZE ); +if ((gfs2_tune_get (sdp, gt_max_vb_pages) + -atomic_read (&sdp->sd_vb_page_count)) < cap) + goto out; vpx =kmalloc (sizeof (struct vp_ctx ),GFP_KERNEL );if (vpx ==NULL )
@@ -344,6 +351,7 @@ int vp_init(struct gfs2_sbd *sdp, struct vbuf *vb, int init_cap) vpx->vp_baseptr = vpx->vp_top =page_address (vpx->vp_pages[0 ]); vpx->vp_sdp = sdp; +atomic_add (cap, &sdp->sd_vb_page_count); vb->v_ptr = vpx->vp_baseptr; vb->v_opaque = vpx;
@@ -373,6 +381,7 @@ void vp_uninit(struct vbuf *vb)vp_free_pages (vpx);kfree (vpx->vp_pages); +atomic_sub (vpx->vp_size, &vpx->vp_sdp->sd_vb_page_count);kfree (vpx); vb->v_ptr = vb->v_opaque =NULL ; }
fs/gfs2/xattr.c +6 -21
@@ -11,6 +11,7 @@#include <linux/spinlock.h> #include <linux/completion.h> #include <linux/buffer_head.h> +#include <linux/sort.h> #include <linux/xattr.h> #include <linux/gfs2_ondisk.h> #include <linux/posix_acl_xattr.h>
@@ -19,6 +20,7 @@#include "gfs2.h" #include "incore.h" #include "acl.h" +#include "dir.h" #include "xattr.h" #include "glock.h" #include "inode.h"
@@ -27,6 +29,7 @@#include "rgrp.h" #include "trans.h" #include "util.h" +#include "xreaddir.h" /** * ea_calc_size - returns the acutal number of bytes the request will take up
@@ -72,10 +75,6 @@ static int ea_check_size(struct gfs2_sbd *sdp, unsigned int nsize, size_t dsize)return 0 ; } -typedef int (*ea_call_t ) (struct gfs2_inode *ip,struct buffer_head *bh, -struct gfs2_ea_header *ea, -struct gfs2_ea_header *prev,void *private); -static int ea_foreach_i (struct gfs2_inode *ip,struct buffer_head *bh,ea_call_t ea_call,void *data) {
@@ -113,7 +112,7 @@ fail:return -EIO ; } -static int ea_foreach (struct gfs2_inode *ip,ea_call_t ea_call,void *data) +int ea_foreach (struct gfs2_inode *ip,ea_call_t ea_call,void *data) {struct buffer_head *bh, *eabh;__be64 *eablk, *end;
@@ -374,28 +373,14 @@ static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,return 0 ;if (er->er_data_len) { -char *prefix =NULL ; +char prefix[9 ];unsigned int l =0 ;char c =0 ;if (ei->ei_size + ea_size > er->er_data_len)return -ERANGE ; -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 ; - } - + l =ea_prefix (ea, prefix,9 );BUG_ON (l ==0 );memcpy (er->er_data + ei->ei_size, prefix, l);
fs/gfs2/xattr.h +23 -0
@@ -10,6 +10,8 @@#ifndef __EATTR_DOT_H__#define __EATTR_DOT_H__ +#include "dir.h" +struct gfs2_inode ;struct iattr ;
@@ -53,9 +55,30 @@ struct gfs2_ea_location {struct gfs2_ea_header *el_prev; }; +static __inline__int ea_prefix (struct gfs2_ea_header *ea,char *buf,int size) +{ +BUG_ON (size <9 ); +switch (ea->ea_type) { +case GFS2_EATYPE_USR : +strncpy (buf,"user." ,5 ); +return 5 ; +case GFS2_EATYPE_SYS : +strncpy (buf,"system." ,7 ); +return 7 ; +case GFS2_EATYPE_SECURITY : +strncpy (buf,"security." ,9 ); +return 9 ; + } +return 0 ; +} +extern int __gfs2_xattr_set (struct inode *inode,const char *name,const void *value,size_t size,int flags,int type); +typedef int (*ea_call_t ) (struct gfs2_inode *ip,struct buffer_head *bh, +struct gfs2_ea_header *ea, +struct gfs2_ea_header *prev,void *private); +extern int ea_foreach (struct gfs2_inode *ip,ea_call_t ea_call,void *data);extern ssize_t gfs2_listxattr (struct dentry *dentry,char *buffer,size_t size);extern int gfs2_ea_dealloc (struct gfs2_inode *ip);
fs/gfs2/xreaddir.c new file +1024 -0
1,024 lines not on this page · raw message
fs/gfs2/xreaddir.h new file +84 -0
84 lines not on this page · raw message
Signature · 1 line
1.8.1.4
Re: [RFC PATCH 5/5] gfs2: Add xreaddir file operation and supporting functions
Quoted 2 lines · On Fri, 25 Jul 2014 12:38:08 -0500 Abhi Das <[email protected]> wrote:
This patch adds support in GFS2 for the xgetdents syscall by implementing the xreaddir file operation.
So I was trying to make sense of this, and ran into one little thing that jumped out at me:
fs/gfs2/xreaddir.c line 755
Quoted 5 lines
fs/gfs2/xreaddir.c new file +5
-0+static int gfs2_xrdir_to_user_vars (struct gfs2_xrdir_ctx *xc, +struct gfs2_xdirent *x, +struct gfs2_xdirent *x_vb_p, +struct linux_xdirent __user *lxd, +size_t count,size_t *bytes)
Now, I'll readily admit that I could be overly confused by this function. When the variables are named "x", "xx", "xc", "x_vb_p", "xblob", and "lxd", it all starts to run together. But still...
fs/gfs2/xreaddir.c line 788
Quoted 2 lines
fs/gfs2/xreaddir.c new file +2
-0+if ((xc->xc_xattr_mask &XSTAT_XATTR_ALL ) && + lxd->xd_blob.xb_xattr_count) {
How can that be right? lxd is __user, it doesn't seem right to be dereferencing it directly...?
Thanks,
jon
Re: [RFC PATCH 5/5] gfs2: Add xreaddir file operation and supporting functions
----- Original Message -----
Quoted 15 lines
From: "Jonathan Corbet" <[email protected]>
To: "Abhi Das" <[email protected]>
Cc: linux-kernel at vger.kernel.org, linux-fsdevel at vger.kernel.org, cluster-devel at redhat.com
Sent: Tuesday, July 29, 2014 1:58:08 PM
Subject: Re: [RFC PATCH 5/5] gfs2: Add xreaddir file operation and supporting functionsQuoted 2 lines · On Fri, 25 Jul 2014 12:38:08 -0500 Abhi Das <[email protected]> wrote:
This patch adds support in GFS2 for the xgetdents syscall by implementing the xreaddir file operation.
So I was trying to make sense of this, and ran into one little thing that jumped out at me:
Quoted 10 lines
fs/gfs2/xreaddir.c line 755
Quoted 5 lines
fs/gfs2/xreaddir.c new file +5
-0+static int gfs2_xrdir_to_user_vars (struct gfs2_xrdir_ctx *xc, +struct gfs2_xdirent *x, +struct gfs2_xdirent *x_vb_p, +struct linux_xdirent __user *lxd, +size_t count,size_t *bytes)Now, I'll readily admit that I could be overly confused by this function. When the variables are named "x", "xx", "xc", "
x_vb_p", "xblob", and "lxd", it all starts to run together. But still...
As I went along writing this patch, I ended up needing more structs and names and this is the ugly result :(. I guess some of these structs/names can be reviewed and changed as needed. This is just a proof of concept patch to illustrate how such a syscall can be implemented.
Quoted 5 lines
fs/gfs2/xreaddir.c line 788
Quoted 2 lines
fs/gfs2/xreaddir.c new file +2
-0+if ((xc->xc_xattr_mask &XSTAT_XATTR_ALL ) && + lxd->xd_blob.xb_xattr_count) {How can that be right? lxd is
__user, it doesn't seem right to be dereferencing it directly...?
Wouldn't the call to access_ok() at the start of the syscall take care of this? All the __user pointers point to areas within the user supplied buffer buf and overflow past the end of the buffer for the last lxd is checked for.
The 2/5 patch in this series adds the following in fs/readdir.c:
+SYSCALL_DEFINE5(xgetdents, unsigned int, fd, unsigned, flags, unsigned int, mask,
+ void __user *, buf, unsigned int, count)
...
...
...
+ if (!access_ok(VERIFY_WRITE, buf, count))
+ return -EFAULT;
Quoted 5 lines
Thanks,
jon
Cheers!
--Abhi
RFC PATCH 5/5 gfs2: Add xreaddir file operation and supporting functions
Quoted 7 lines · Abhijith Das
----- Original Message -----
Quoted 5 lines
From: "Jonathan Corbet" <[email protected]>
To: "Abhi Das" <[email protected]>
Cc: linux-kernel at vger.kernel.org, linux-fsdevel at vger.kernel.org, cluster-devel at redhat.com
Sent: Tuesday, July 29, 2014 1:58:08 PM
Subject: Re: [RFC PATCH 5/5] gfs2: Add xreaddir file operation and supporting functions
[snip]
Quoted 11 lines
Quoted 4 lines
fs/gfs2/xreaddir.c line 788
Quoted 2 lines
fs/gfs2/xreaddir.c new file +2
-0+if ((xc->xc_xattr_mask &XSTAT_XATTR_ALL ) && + lxd->xd_blob.xb_xattr_count) {How can that be right? lxd is
__user, it doesn't seem right to be dereferencing it directly...?Wouldn't the call to
access_ok()at the start of the syscall take care of this? All the__userpointers point to areas within the user supplied buffer buf and overflow past the end of the buffer for the last lxd is checked for.The 2/5 patch in this series adds the following in
fs/readdir.c:
Review
Quoted 7 lines
(quoted diff) +4
-0+SYSCALL_DEFINE5(xgetdents, unsigned int, fd, unsigned, flags, unsigned int, mask, + void __user *, buf, unsigned int, count) + if (!access_ok(VERIFY_WRITE, buf, count)) + return -EFAULT;
The access_ok() call only checks the source memory at the time of the call, it is possible for the page to become invalid for reading or writing to at any subsequent time. So that the kernel's accessor functions are required here. I think sparse should warn about this too.
However, the intention was to show that the xreaddir approach is not ideal due to its complexity, and also due to it being very much single purpose compared with the readahead approach, and from that point of view it shouldn't affect the performance measurements in this case,
Steve.
Re: [RFC PATCH 5/5] gfs2: Add xreaddir file operation and supporting functions
In reply to Abhijith DasQuoted 9 lines · On Tue, 29 Jul 2014 18:25:57 -0400 (EDT) Abhijith Das <[email protected]> wrote:
Quoted 5 lines
fs/gfs2/xreaddir.c line 788
Quoted 2 lines
fs/gfs2/xreaddir.c new file +2
-0+if ((xc->xc_xattr_mask &XSTAT_XATTR_ALL ) && + lxd->xd_blob.xb_xattr_count) {How can that be right? lxd is
__user, it doesn't seem right to be dereferencing it directly...?Wouldn't the call to
access_ok()at the start of the syscall take care of this? All the__userpointers point to areas within the user supplied buffer buf and overflow past the end of the buffer for the last lxd is checked for.
No, dereferencing user-space pointers in the kernel is never OK. What if user space remapped that page after the access_ok() call? You need to use copy_*_user() to get at user-space structures from the kernel.
jon
Quoted 11 lines · Abhi Das
This system call takes 5 arguments:
fd - file descriptor of the directory
flags - flags used by xstat
mask - field mask used to request stat/xattr info
buf - user buf to return collected info
count - size of user buffer in bytes
xgetdents()should read the directory entries, collect stat and xattr information for each entry as requested and return all the data back to the user in a container structure (linux_xdirent) as part of the supplied user buffer.
Hello Abhi,
As per Documentation/SubmitChecklist, please CC linux-api on patches that change the kerne-user-space API/ABI. (See
https://www.kernel.org/doc/man-pages/linux-api-ml.html for more details.)
Cheers,
Michael
Quoted 43 lines
Abhi Das (5):
fs: xstat system call VFS bits
fs: Add xgetdents system call and xreaddir file operation
gfs2: Add a dynamic buffer backed by a vector of pages
gfs2: Add sort functionality with extra parameter
gfs2: Add xreaddir file operation and supporting functionsarch/x86/syscalls/syscall_32.tbl | 3 + arch/x86/syscalls/syscall_64.tbl | 3 + fs/gfs2/Makefile | 3 +- fs/gfs2/dir.c | 80 +-- fs/gfs2/dir.h | 13 +- fs/gfs2/export.c | 2 +- fs/gfs2/file.c | 17 +- fs/gfs2/incore.h | 6 + fs/gfs2/inode.c | 3 +- fs/gfs2/inode.h | 5 + fs/gfs2/ops_fstype.c | 4 + fs/gfs2/sys.c | 26 +- fs/gfs2/util.c | 363 ++++++++++++++ fs/gfs2/util.h | 47 ++ fs/gfs2/xattr.c | 27 +- fs/gfs2/xattr.h | 23 + fs/gfs2/xreaddir.c | 1024 ++++++++++++++++++++++++++++++++++++++ fs/gfs2/xreaddir.h | 84 ++++ fs/readdir.c | 42 ++ fs/stat.c | 340 ++++++++++++- include/linux/fs.h | 5 + include/linux/stat.h | 16 +- include/linux/syscalls.h | 5 + include/uapi/linux/fcntl.h | 1 + include/uapi/linux/stat.h | 143 ++++++ 25 files changed, 2196 insertions(+), 89 deletions(-) create mode 100644 fs/gfs2/xreaddir.c create mode 100644 fs/gfs2/xreaddir.h--
1.8.1.4--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Signature · 3 lines
Michael Kerrisk Linux man-pages maintainer; http://www.kernel.org/doc/man-pages/ Author of "The Linux Programming Interface", http://blog.man7.org/