From: Andreas Gruenbacher That's better, yes. Attached is a version that incorporates the feedback so far. Signed-off-by: Andreas Gruenbacher Cc: Hugh Dickins Signed-off-by: Andrew Morton --- include/linux/shmem_fs.h | 3 + mm/shmem.c | 9 +++ mm/shmem_acl.c | 84 +++++++++++++++++++++++++------------ 3 files changed, 69 insertions(+), 27 deletions(-) diff -puN fs/Kconfig~access-control-lists-for-tmpfs-cleanup fs/Kconfig diff -puN include/linux/shmem_fs.h~access-control-lists-for-tmpfs-cleanup include/linux/shmem_fs.h --- a/include/linux/shmem_fs.h~access-control-lists-for-tmpfs-cleanup +++ a/include/linux/shmem_fs.h @@ -47,6 +47,9 @@ void shmem_acl_destroy_inode(struct inod extern struct xattr_handler shmem_xattr_acl_access_handler; extern struct xattr_handler shmem_xattr_acl_default_handler; + +extern struct generic_acl_operations shmem_acl_ops; + #else static inline int shmem_acl_init(struct inode *inode, struct inode *dir) { diff -puN mm/Makefile~access-control-lists-for-tmpfs-cleanup mm/Makefile diff -puN mm/shmem.c~access-control-lists-for-tmpfs-cleanup mm/shmem.c --- a/mm/shmem.c~access-control-lists-for-tmpfs-cleanup +++ a/mm/shmem.c @@ -634,8 +634,6 @@ static void shmem_truncate(struct inode shmem_truncate_range(inode, inode->i_size, (loff_t)-1); } -extern struct generic_acl_operations shmem_acl_ops; - static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; @@ -1912,6 +1910,13 @@ static struct inode_operations shmem_sym }; #ifdef CONFIG_TMPFS_POSIX_ACL +/** + * Superblocks without xattr inode operations will get security.* xattr + * support from the VFS "for free". As soon as we have any other xattrs + * like ACLs, we also need to implement the security.* handlers at + * filesystem level, though. + */ + static size_t shmem_xattr_security_list(struct inode *inode, char *list, size_t list_len, const char *name, size_t name_len) diff -puN mm/shmem_acl.c~access-control-lists-for-tmpfs-cleanup mm/shmem_acl.c --- a/mm/shmem_acl.c~access-control-lists-for-tmpfs-cleanup +++ a/mm/shmem_acl.c @@ -11,6 +11,9 @@ #include #include +/** + * shmem_get_acl - generic_acl_operations->getacl() operation + */ static struct posix_acl * shmem_get_acl(struct inode *inode, int type) { @@ -31,24 +34,28 @@ shmem_get_acl(struct inode *inode, int t return acl; } +/** + * shmem_get_acl - generic_acl_operations->setacl() operation + */ static void shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl) { + struct posix_acl *free = NULL; + spin_lock(&inode->i_lock); switch(type) { case ACL_TYPE_ACCESS: - if (SHMEM_I(inode)->i_acl) - posix_acl_release(SHMEM_I(inode)->i_acl); + free = SHMEM_I(inode)->i_acl; SHMEM_I(inode)->i_acl = posix_acl_dup(acl); break; case ACL_TYPE_DEFAULT: - if (SHMEM_I(inode)->i_default_acl) - posix_acl_release(SHMEM_I(inode)->i_default_acl); + free = SHMEM_I(inode)->i_default_acl; SHMEM_I(inode)->i_default_acl = posix_acl_dup(acl); break; } spin_unlock(&inode->i_lock); + posix_acl_release(free); } struct generic_acl_operations shmem_acl_ops = { @@ -56,6 +63,12 @@ struct generic_acl_operations shmem_acl_ .setacl = shmem_set_acl, }; +/** + * shmem_list_acl_access, shmem_get_acl_access, shmem_set_acl_access, + * shmem_xattr_acl_access_handler - plumbing code to implement the + * system.posix_acl_access xattr using the generic acl functions. + */ + static size_t shmem_list_acl_access(struct inode *inode, char *list, size_t list_size, const char *name, size_t name_len) @@ -64,14 +77,6 @@ shmem_list_acl_access(struct inode *inod list, list_size); } -static size_t -shmem_list_acl_default(struct inode *inode, char *list, size_t list_size, - const char *name, size_t name_len) -{ - return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, - list, list_size); -} - static int shmem_get_acl_access(struct inode *inode, const char *name, void *buffer, size_t size) @@ -83,22 +88,43 @@ shmem_get_acl_access(struct inode *inode } static int -shmem_get_acl_default(struct inode *inode, const char *name, void *buffer, - size_t size) +shmem_set_acl_access(struct inode *inode, const char *name, const void *value, + size_t size, int flags) { if (strcmp(name, "") != 0) return -EINVAL; - return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, buffer, + return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, value, size); } +struct xattr_handler shmem_xattr_acl_access_handler = { + .prefix = POSIX_ACL_XATTR_ACCESS, + .list = shmem_list_acl_access, + .get = shmem_get_acl_access, + .set = shmem_set_acl_access, +}; + +/** + * shmem_list_acl_default, shmem_get_acl_default, shmem_set_acl_default, + * shmem_xattr_acl_default_handler - plumbing code to implement the + * system.posix_acl_default xattr using the generic acl functions. + */ + +static size_t +shmem_list_acl_default(struct inode *inode, char *list, size_t list_size, + const char *name, size_t name_len) +{ + return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, + list, list_size); +} + static int -shmem_set_acl_access(struct inode *inode, const char *name, const void *value, - size_t size, int flags) +shmem_get_acl_default(struct inode *inode, const char *name, void *buffer, + size_t size) { if (strcmp(name, "") != 0) return -EINVAL; - return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, value, + return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, buffer, size); } @@ -112,13 +138,6 @@ shmem_set_acl_default(struct inode *inod size); } -struct xattr_handler shmem_xattr_acl_access_handler = { - .prefix = POSIX_ACL_XATTR_ACCESS, - .list = shmem_list_acl_access, - .get = shmem_get_acl_access, - .set = shmem_set_acl_access, -}; - struct xattr_handler shmem_xattr_acl_default_handler = { .prefix = POSIX_ACL_XATTR_DEFAULT, .list = shmem_list_acl_default, @@ -126,12 +145,21 @@ struct xattr_handler shmem_xattr_acl_def .set = shmem_set_acl_default, }; +/** + * shmem_acl_init - Inizialize the acl(s) of a new inode + */ int shmem_acl_init(struct inode *inode, struct inode *dir) { return generic_acl_init(inode, dir, &shmem_acl_ops); } +/** + * shmem_acl_destroy_inode - destroy acls hanging off the in-memory inode + * + * This is done before destroying the actual inode. + */ + void shmem_acl_destroy_inode(struct inode *inode) { @@ -143,6 +171,9 @@ shmem_acl_destroy_inode(struct inode *in SHMEM_I(inode)->i_default_acl = NULL; } +/** + * shmem_check_acl - check_acl() callback for generic_permission() + */ static int shmem_check_acl(struct inode *inode, int mask) { @@ -156,6 +187,9 @@ shmem_check_acl(struct inode *inode, int return -EAGAIN; } +/** + * shmem_permission - permission() inode operation + */ int shmem_permission(struct inode *inode, int mask, struct nameidata *nd) { _