diff 2.4.19-xfs/Documentation/filesystems/Locking --- 2.4.19-xfs/Documentation/filesystems/Locking +++ 2.4.19-xfs/Documentation/filesystems/Locking @@ -45,6 +45,10 @@ int (*revalidate) (struct dentry *); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct dentry *, struct iattr *); + int (*setxattr) (struct dentry *, const char *, void *, size_t, int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); locking rules: all may block @@ -61,9 +65,13 @@ follow_link: no no no truncate: yes yes no (see below) setattr: yes if ATTR_SIZE no -permssion: yes no no +permission: yes no no getattr: (see below) revalidate: no (see below) +setxattr: yes yes no +getxattr: yes yes no +listxattr: yes yes no +removexattr: yes yes no Additionally, ->rmdir() has i_zombie on victim and so does ->rename() in case when target exists and is a directory. ->rename() on directories has (per-superblock) ->s_vfs_rename_sem. diff 2.4.19-xfs/arch/i386/kernel/entry.S --- 2.4.19-xfs/arch/i386/kernel/entry.S +++ 2.4.19-xfs/arch/i386/kernel/entry.S @@ -650,18 +650,18 @@ .long SYMBOL_NAME(sys_ni_syscall) /* Reserved for Security */ .long SYMBOL_NAME(sys_gettid) .long SYMBOL_NAME(sys_readahead) /* 225 */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for setxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for lsetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fsetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for getxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* 230 reserved for lgetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fgetxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for listxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for llistxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for flistxattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* 235 reserved for removexattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for lremovexattr */ - .long SYMBOL_NAME(sys_ni_syscall) /* reserved for fremovexattr */ + .long SYMBOL_NAME(sys_setxattr) + .long SYMBOL_NAME(sys_lsetxattr) + .long SYMBOL_NAME(sys_fsetxattr) + .long SYMBOL_NAME(sys_getxattr) + .long SYMBOL_NAME(sys_lgetxattr) /* 230 */ + .long SYMBOL_NAME(sys_fgetxattr) + .long SYMBOL_NAME(sys_listxattr) + .long SYMBOL_NAME(sys_llistxattr) + .long SYMBOL_NAME(sys_flistxattr) + .long SYMBOL_NAME(sys_removexattr) /* 235 */ + .long SYMBOL_NAME(sys_lremovexattr) + .long SYMBOL_NAME(sys_fremovexattr) .long SYMBOL_NAME(sys_tkill) .long SYMBOL_NAME(sys_ni_syscall) /* reserved for sendfile64 */ .long SYMBOL_NAME(sys_ni_syscall) /* 240 reserved for futex */ diff 2.4.19-xfs/fs/Makefile --- 2.4.19-xfs/fs/Makefile +++ 2.4.19-xfs/fs/Makefile @@ -14,7 +14,7 @@ super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \ fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \ dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \ - filesystems.o namespace.o seq_file.o quota.o + filesystems.o namespace.o seq_file.o quota.o xattr.o obj-$(CONFIG_QUOTA) += dquot.o obj-$(CONFIG_QFMT_V1) += quota_v1.o diff 2.4.19-xfs/fs/xattr.c --- 2.4.19-xfs/fs/xattr.c +++ 2.4.19-xfs/fs/xattr.c @@ -0,0 +1,355 @@ +/* + File: fs/xattr.c + + Extended attribute handling. + + Copyright (C) 2001 by Andreas Gruenbacher + Copyright (C) 2001 SGI - Silicon Graphics, Inc + */ +#include +#include +#include +#include +#include +#include +#include + +/* + * Extended attribute memory allocation wrappers, originally + * based on the Intermezzo PRESTO_ALLOC/PRESTO_FREE macros. + * The vmalloc use here is very uncommon - extended attributes + * are supposed to be small chunks of metadata, and it is quite + * unusual to have very many extended attributes, so lists tend + * to be quite short as well. The 64K upper limit is derived + * from the extended attribute size limit used by XFS. + * Intentionally allow zero @size for value/list size requests. + */ +static void * +xattr_alloc(size_t size, size_t limit) +{ + void *ptr; + + if (size > limit) + return ERR_PTR(-E2BIG); + + if (!size) /* size request, no buffer is needed */ + return NULL; + else if (size <= PAGE_SIZE) + ptr = kmalloc((unsigned long) size, GFP_KERNEL); + else + ptr = vmalloc((unsigned long) size); + if (!ptr) + return ERR_PTR(-ENOMEM); + return ptr; +} + +static void +xattr_free(void *ptr, size_t size) +{ + if (!size) /* size request, no buffer was needed */ + return; + else if (size <= PAGE_SIZE) + kfree(ptr); + else + vfree(ptr); +} + +/* + * Extended attribute SET operations + */ +static long +setxattr(struct dentry *d, char *name, void *value, size_t size, int flags) +{ + int error; + void *kvalue; + char kname[XATTR_NAME_MAX + 1]; + + if (flags & ~(XATTR_CREATE|XATTR_REPLACE)) + return -EINVAL; + + error = strncpy_from_user(kname, name, sizeof(kname)); + if (error == 0 || error == sizeof(kname)) + error = -ERANGE; + if (error < 0) + return error; + + kvalue = xattr_alloc(size, XATTR_SIZE_MAX); + if (IS_ERR(kvalue)) + return PTR_ERR(kvalue); + + if (size > 0 && copy_from_user(kvalue, value, size)) { + xattr_free(kvalue, size); + return -EFAULT; + } + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->setxattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + + xattr_free(kvalue, size); + return error; +} + +asmlinkage long +sys_setxattr(char *path, char *name, void *value, size_t size, int flags) +{ + struct nameidata nd; + int error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = setxattr(nd.dentry, name, value, size, flags); + path_release(&nd); + return error; +} + +asmlinkage long +sys_lsetxattr(char *path, char *name, void *value, size_t size, int flags) +{ + struct nameidata nd; + int error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = setxattr(nd.dentry, name, value, size, flags); + path_release(&nd); + return error; +} + +asmlinkage long +sys_fsetxattr(int fd, char *name, void *value, size_t size, int flags) +{ + struct file *f; + int error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = setxattr(f->f_dentry, name, value, size, flags); + fput(f); + return error; +} + +/* + * Extended attribute GET operations + */ +static ssize_t +getxattr(struct dentry *d, char *name, void *value, size_t size) +{ + ssize_t error; + void *kvalue; + char kname[XATTR_NAME_MAX + 1]; + + error = strncpy_from_user(kname, name, sizeof(kname)); + if (error == 0 || error == sizeof(kname)) + error = -ERANGE; + if (error < 0) + return error; + + kvalue = xattr_alloc(size, XATTR_SIZE_MAX); + if (IS_ERR(kvalue)) + return PTR_ERR(kvalue); + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->getxattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->getxattr(d, kname, kvalue, size); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + + if (kvalue && error > 0) + if (copy_to_user(value, kvalue, error)) + error = -EFAULT; + xattr_free(kvalue, size); + return error; +} + +asmlinkage ssize_t +sys_getxattr(char *path, char *name, void *value, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = getxattr(nd.dentry, name, value, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_lgetxattr(char *path, char *name, void *value, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = getxattr(nd.dentry, name, value, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_fgetxattr(int fd, char *name, void *value, size_t size) +{ + struct file *f; + ssize_t error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = getxattr(f->f_dentry, name, value, size); + fput(f); + return error; +} + +/* + * Extended attribute LIST operations + */ +static ssize_t +listxattr(struct dentry *d, char *list, size_t size) +{ + ssize_t error; + char *klist; + + klist = (char *)xattr_alloc(size, XATTR_LIST_MAX); + if (IS_ERR(klist)) + return PTR_ERR(klist); + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->listxattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->listxattr(d, klist, size); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + + if (klist && error > 0) + if (copy_to_user(list, klist, error)) + error = -EFAULT; + xattr_free(klist, size); + return error; +} + +asmlinkage ssize_t +sys_listxattr(char *path, char *list, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = listxattr(nd.dentry, list, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_llistxattr(char *path, char *list, size_t size) +{ + struct nameidata nd; + ssize_t error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = listxattr(nd.dentry, list, size); + path_release(&nd); + return error; +} + +asmlinkage ssize_t +sys_flistxattr(int fd, char *list, size_t size) +{ + struct file *f; + ssize_t error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = listxattr(f->f_dentry, list, size); + fput(f); + return error; +} + +/* + * Extended attribute REMOVE operations + */ +static long +removexattr(struct dentry *d, char *name) +{ + int error; + char kname[XATTR_NAME_MAX + 1]; + + error = strncpy_from_user(kname, name, sizeof(kname)); + if (error == 0 || error == sizeof(kname)) + error = -ERANGE; + if (error < 0) + return error; + + error = -EOPNOTSUPP; + if (d->d_inode->i_op && d->d_inode->i_op->removexattr) { + down(&d->d_inode->i_sem); + lock_kernel(); + error = d->d_inode->i_op->removexattr(d, kname); + unlock_kernel(); + up(&d->d_inode->i_sem); + } + return error; +} + +asmlinkage long +sys_removexattr(char *path, char *name) +{ + struct nameidata nd; + int error; + + error = user_path_walk(path, &nd); + if (error) + return error; + error = removexattr(nd.dentry, name); + path_release(&nd); + return error; +} + +asmlinkage long +sys_lremovexattr(char *path, char *name) +{ + struct nameidata nd; + int error; + + error = user_path_walk_link(path, &nd); + if (error) + return error; + error = removexattr(nd.dentry, name); + path_release(&nd); + return error; +} + +asmlinkage long +sys_fremovexattr(int fd, char *name) +{ + struct file *f; + int error = -EBADF; + + f = fget(fd); + if (!f) + return error; + error = removexattr(f->f_dentry, name); + fput(f); + return error; +} diff 2.4.19-xfs/include/linux/fs.h --- 2.4.19-xfs/include/linux/fs.h +++ 2.4.19-xfs/include/linux/fs.h @@ -864,6 +864,10 @@ int (*revalidate) (struct dentry *); int (*setattr) (struct dentry *, struct iattr *); int (*getattr) (struct dentry *, struct iattr *); + int (*setxattr) (struct dentry *, const char *, void *, size_t, int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); }; struct seq_file; diff 2.4.19-xfs/include/linux/limits.h --- 2.4.19-xfs/include/linux/limits.h +++ 2.4.19-xfs/include/linux/limits.h @@ -13,6 +13,9 @@ #define NAME_MAX 255 /* # chars in a file name */ #define PATH_MAX 4096 /* # chars in a path name including nul */ #define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */ +#define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */ +#define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */ +#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */ #define RTSIG_MAX 32 diff 2.4.19-xfs/include/linux/xattr.h --- 2.4.19-xfs/include/linux/xattr.h +++ 2.4.19-xfs/include/linux/xattr.h @@ -0,0 +1,15 @@ +/* + File: linux/xattr.h + + Extended attributes handling. + + Copyright (C) 2001 by Andreas Gruenbacher + Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. +*/ +#ifndef _LINUX_XATTR_H +#define _LINUX_XATTR_H + +#define XATTR_CREATE 0x1 /* set the value, fail if attr already exists */ +#define XATTR_REPLACE 0x2 /* set the value, fail if attr does not exist */ + +#endif /* _LINUX_XATTR_H */