Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ceph: add acl for cephfs

Signed-off-by: Guangliang Zhao <lucienchao@gmail.com>
Reviewed-by: Li Wang <li.wang@ubuntykylin.com>
Reviewed-by: Zheng Yan <zheng.z.yan@intel.com>

authored by

Guangliang Zhao and committed by
Ilya Dryomov
7221fe4c 61f68816

+451 -13
+13
fs/ceph/Kconfig
··· 25 25 caching support for Ceph clients using FS-Cache 26 26 27 27 endif 28 + 29 + config CEPH_FS_POSIX_ACL 30 + bool "Ceph POSIX Access Control Lists" 31 + depends on CEPH_FS 32 + select FS_POSIX_ACL 33 + help 34 + POSIX Access Control Lists (ACLs) support permissions for users and 35 + groups beyond the owner/group/world scheme. 36 + 37 + To learn more about Access Control Lists, visit the POSIX ACLs for 38 + Linux website <http://acl.bestbits.at/>. 39 + 40 + If you don't know what Access Control Lists are, say N
+1
fs/ceph/Makefile
··· 10 10 debugfs.o 11 11 12 12 ceph-$(CONFIG_CEPH_FSCACHE) += cache.o 13 + ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o
+332
fs/ceph/acl.c
··· 1 + /* 2 + * linux/fs/ceph/acl.c 3 + * 4 + * Copyright (C) 2013 Guangliang Zhao, <lucienchao@gmail.com> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public 8 + * License v2 as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope that it will be useful, 11 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public 16 + * License along with this program; if not, write to the 17 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 18 + * Boston, MA 021110-1307, USA. 19 + */ 20 + 21 + #include <linux/ceph/ceph_debug.h> 22 + #include <linux/fs.h> 23 + #include <linux/string.h> 24 + #include <linux/xattr.h> 25 + #include <linux/posix_acl_xattr.h> 26 + #include <linux/posix_acl.h> 27 + #include <linux/sched.h> 28 + #include <linux/slab.h> 29 + 30 + #include "super.h" 31 + 32 + static inline void ceph_set_cached_acl(struct inode *inode, 33 + int type, struct posix_acl *acl) 34 + { 35 + struct ceph_inode_info *ci = ceph_inode(inode); 36 + 37 + spin_lock(&ci->i_ceph_lock); 38 + if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) 39 + set_cached_acl(inode, type, acl); 40 + spin_unlock(&ci->i_ceph_lock); 41 + } 42 + 43 + static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode, 44 + int type) 45 + { 46 + struct ceph_inode_info *ci = ceph_inode(inode); 47 + struct posix_acl *acl = ACL_NOT_CACHED; 48 + 49 + spin_lock(&ci->i_ceph_lock); 50 + if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0)) 51 + acl = get_cached_acl(inode, type); 52 + spin_unlock(&ci->i_ceph_lock); 53 + 54 + return acl; 55 + } 56 + 57 + void ceph_forget_all_cached_acls(struct inode *inode) 58 + { 59 + forget_all_cached_acls(inode); 60 + } 61 + 62 + struct posix_acl *ceph_get_acl(struct inode *inode, int type) 63 + { 64 + int size; 65 + const char *name; 66 + char *value = NULL; 67 + struct posix_acl *acl; 68 + 69 + if (!IS_POSIXACL(inode)) 70 + return NULL; 71 + 72 + acl = ceph_get_cached_acl(inode, type); 73 + if (acl != ACL_NOT_CACHED) 74 + return acl; 75 + 76 + switch (type) { 77 + case ACL_TYPE_ACCESS: 78 + name = POSIX_ACL_XATTR_ACCESS; 79 + break; 80 + case ACL_TYPE_DEFAULT: 81 + name = POSIX_ACL_XATTR_DEFAULT; 82 + break; 83 + default: 84 + BUG(); 85 + } 86 + 87 + size = __ceph_getxattr(inode, name, "", 0); 88 + if (size > 0) { 89 + value = kzalloc(size, GFP_NOFS); 90 + if (!value) 91 + return ERR_PTR(-ENOMEM); 92 + size = __ceph_getxattr(inode, name, value, size); 93 + } 94 + 95 + if (size > 0) 96 + acl = posix_acl_from_xattr(&init_user_ns, value, size); 97 + else if (size == -ERANGE || size == -ENODATA || size == 0) 98 + acl = NULL; 99 + else 100 + acl = ERR_PTR(-EIO); 101 + 102 + kfree(value); 103 + 104 + if (!IS_ERR(acl)) 105 + ceph_set_cached_acl(inode, type, acl); 106 + 107 + return acl; 108 + } 109 + 110 + static int ceph_set_acl(struct dentry *dentry, struct inode *inode, 111 + struct posix_acl *acl, int type) 112 + { 113 + int ret = 0, size = 0; 114 + const char *name = NULL; 115 + char *value = NULL; 116 + struct iattr newattrs; 117 + umode_t new_mode = inode->i_mode, old_mode = inode->i_mode; 118 + 119 + if (acl) { 120 + ret = posix_acl_valid(acl); 121 + if (ret < 0) 122 + goto out; 123 + } 124 + 125 + switch (type) { 126 + case ACL_TYPE_ACCESS: 127 + name = POSIX_ACL_XATTR_ACCESS; 128 + if (acl) { 129 + ret = posix_acl_equiv_mode(acl, &new_mode); 130 + if (ret < 0) 131 + goto out; 132 + if (ret == 0) 133 + acl = NULL; 134 + } 135 + break; 136 + case ACL_TYPE_DEFAULT: 137 + if (!S_ISDIR(inode->i_mode)) { 138 + ret = acl ? -EINVAL : 0; 139 + goto out; 140 + } 141 + name = POSIX_ACL_XATTR_DEFAULT; 142 + break; 143 + default: 144 + ret = -EINVAL; 145 + goto out; 146 + } 147 + 148 + if (acl) { 149 + size = posix_acl_xattr_size(acl->a_count); 150 + value = kmalloc(size, GFP_NOFS); 151 + if (!value) { 152 + ret = -ENOMEM; 153 + goto out; 154 + } 155 + 156 + ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 157 + if (ret < 0) 158 + goto out_free; 159 + } 160 + 161 + if (new_mode != old_mode) { 162 + newattrs.ia_mode = new_mode; 163 + newattrs.ia_valid = ATTR_MODE; 164 + ret = ceph_setattr(dentry, &newattrs); 165 + if (ret) 166 + goto out_free; 167 + } 168 + 169 + if (value) 170 + ret = __ceph_setxattr(dentry, name, value, size, 0); 171 + else 172 + ret = __ceph_removexattr(dentry, name); 173 + 174 + if (ret) { 175 + if (new_mode != old_mode) { 176 + newattrs.ia_mode = old_mode; 177 + newattrs.ia_valid = ATTR_MODE; 178 + ceph_setattr(dentry, &newattrs); 179 + } 180 + goto out_free; 181 + } 182 + 183 + ceph_set_cached_acl(inode, type, acl); 184 + 185 + out_free: 186 + kfree(value); 187 + out: 188 + return ret; 189 + } 190 + 191 + int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir) 192 + { 193 + struct posix_acl *acl = NULL; 194 + int ret = 0; 195 + 196 + if (!S_ISLNK(inode->i_mode)) { 197 + if (IS_POSIXACL(dir)) { 198 + acl = ceph_get_acl(dir, ACL_TYPE_DEFAULT); 199 + if (IS_ERR(acl)) { 200 + ret = PTR_ERR(acl); 201 + goto out; 202 + } 203 + } 204 + 205 + if (!acl) 206 + inode->i_mode &= ~current_umask(); 207 + } 208 + 209 + if (IS_POSIXACL(dir) && acl) { 210 + if (S_ISDIR(inode->i_mode)) { 211 + ret = ceph_set_acl(dentry, inode, acl, 212 + ACL_TYPE_DEFAULT); 213 + if (ret) 214 + goto out_release; 215 + } 216 + ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode); 217 + if (ret < 0) 218 + goto out; 219 + else if (ret > 0) 220 + ret = ceph_set_acl(dentry, inode, acl, ACL_TYPE_ACCESS); 221 + else 222 + cache_no_acl(inode); 223 + } else { 224 + cache_no_acl(inode); 225 + } 226 + 227 + out_release: 228 + posix_acl_release(acl); 229 + out: 230 + return ret; 231 + } 232 + 233 + int ceph_acl_chmod(struct dentry *dentry, struct inode *inode) 234 + { 235 + struct posix_acl *acl; 236 + int ret = 0; 237 + 238 + if (S_ISLNK(inode->i_mode)) { 239 + ret = -EOPNOTSUPP; 240 + goto out; 241 + } 242 + 243 + if (!IS_POSIXACL(inode)) 244 + goto out; 245 + 246 + acl = ceph_get_acl(inode, ACL_TYPE_ACCESS); 247 + if (IS_ERR_OR_NULL(acl)) { 248 + ret = PTR_ERR(acl); 249 + goto out; 250 + } 251 + 252 + ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode); 253 + if (ret) 254 + goto out; 255 + ret = ceph_set_acl(dentry, inode, acl, ACL_TYPE_ACCESS); 256 + posix_acl_release(acl); 257 + out: 258 + return ret; 259 + } 260 + 261 + static int ceph_xattr_acl_get(struct dentry *dentry, const char *name, 262 + void *value, size_t size, int type) 263 + { 264 + struct posix_acl *acl; 265 + int ret = 0; 266 + 267 + if (!IS_POSIXACL(dentry->d_inode)) 268 + return -EOPNOTSUPP; 269 + 270 + acl = ceph_get_acl(dentry->d_inode, type); 271 + if (IS_ERR(acl)) 272 + return PTR_ERR(acl); 273 + if (acl == NULL) 274 + return -ENODATA; 275 + 276 + ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); 277 + posix_acl_release(acl); 278 + 279 + return ret; 280 + } 281 + 282 + static int ceph_xattr_acl_set(struct dentry *dentry, const char *name, 283 + const void *value, size_t size, int flags, int type) 284 + { 285 + int ret = 0; 286 + struct posix_acl *acl = NULL; 287 + 288 + if (!inode_owner_or_capable(dentry->d_inode)) { 289 + ret = -EPERM; 290 + goto out; 291 + } 292 + 293 + if (!IS_POSIXACL(dentry->d_inode)) { 294 + ret = -EOPNOTSUPP; 295 + goto out; 296 + } 297 + 298 + if (value) { 299 + acl = posix_acl_from_xattr(&init_user_ns, value, size); 300 + if (IS_ERR(acl)) { 301 + ret = PTR_ERR(acl); 302 + goto out; 303 + } 304 + 305 + if (acl) { 306 + ret = posix_acl_valid(acl); 307 + if (ret) 308 + goto out_release; 309 + } 310 + } 311 + 312 + ret = ceph_set_acl(dentry, dentry->d_inode, acl, type); 313 + 314 + out_release: 315 + posix_acl_release(acl); 316 + out: 317 + return ret; 318 + } 319 + 320 + const struct xattr_handler ceph_xattr_acl_default_handler = { 321 + .prefix = POSIX_ACL_XATTR_DEFAULT, 322 + .flags = ACL_TYPE_DEFAULT, 323 + .get = ceph_xattr_acl_get, 324 + .set = ceph_xattr_acl_set, 325 + }; 326 + 327 + const struct xattr_handler ceph_xattr_acl_access_handler = { 328 + .prefix = POSIX_ACL_XATTR_ACCESS, 329 + .flags = ACL_TYPE_ACCESS, 330 + .get = ceph_xattr_acl_get, 331 + .set = ceph_xattr_acl_set, 332 + };
+1
fs/ceph/caps.c
··· 2464 2464 ceph_buffer_put(ci->i_xattrs.blob); 2465 2465 ci->i_xattrs.blob = ceph_buffer_get(xattr_buf); 2466 2466 ci->i_xattrs.version = version; 2467 + ceph_forget_all_cached_acls(inode); 2467 2468 } 2468 2469 } 2469 2470
+5
fs/ceph/dir.c
··· 693 693 if (!err && !req->r_reply_info.head->is_dentry) 694 694 err = ceph_handle_notrace_create(dir, dentry); 695 695 ceph_mdsc_put_request(req); 696 + 697 + if (!err) 698 + err = ceph_init_acl(dentry, dentry->d_inode, dir); 699 + 696 700 if (err) 697 701 d_drop(dentry); 698 702 return err; ··· 1297 1293 .getxattr = ceph_getxattr, 1298 1294 .listxattr = ceph_listxattr, 1299 1295 .removexattr = ceph_removexattr, 1296 + .get_acl = ceph_get_acl, 1300 1297 .mknod = ceph_mknod, 1301 1298 .symlink = ceph_symlink, 1302 1299 .mkdir = ceph_mkdir,
+11
fs/ceph/inode.c
··· 95 95 .getxattr = ceph_getxattr, 96 96 .listxattr = ceph_listxattr, 97 97 .removexattr = ceph_removexattr, 98 + .get_acl = ceph_get_acl, 98 99 }; 99 100 100 101 ··· 681 680 memcpy(ci->i_xattrs.blob->vec.iov_base, 682 681 iinfo->xattr_data, iinfo->xattr_len); 683 682 ci->i_xattrs.version = le64_to_cpu(info->xattr_version); 683 + ceph_forget_all_cached_acls(inode); 684 684 xattr_blob = NULL; 685 685 } 686 686 ··· 1614 1612 .getxattr = ceph_getxattr, 1615 1613 .listxattr = ceph_listxattr, 1616 1614 .removexattr = ceph_removexattr, 1615 + .get_acl = ceph_get_acl, 1617 1616 }; 1618 1617 1619 1618 /* ··· 1688 1685 dirtied |= CEPH_CAP_AUTH_EXCL; 1689 1686 } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 || 1690 1687 attr->ia_mode != inode->i_mode) { 1688 + inode->i_mode = attr->ia_mode; 1691 1689 req->r_args.setattr.mode = cpu_to_le32(attr->ia_mode); 1692 1690 mask |= CEPH_SETATTR_MODE; 1693 1691 release |= CEPH_CAP_AUTH_SHARED; ··· 1804 1800 if (inode_dirty_flags) 1805 1801 __mark_inode_dirty(inode, inode_dirty_flags); 1806 1802 1803 + if (ia_valid & ATTR_MODE) { 1804 + err = ceph_acl_chmod(dentry, inode); 1805 + if (err) 1806 + goto out_put; 1807 + } 1808 + 1807 1809 if (mask) { 1808 1810 req->r_inode = inode; 1809 1811 ihold(inode); ··· 1829 1819 return err; 1830 1820 out: 1831 1821 spin_unlock(&ci->i_ceph_lock); 1822 + out_put: 1832 1823 ceph_mdsc_put_request(req); 1833 1824 return err; 1834 1825 }
+4
fs/ceph/super.c
··· 819 819 820 820 s->s_flags = fsc->mount_options->sb_flags; 821 821 s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */ 822 + #ifdef CONFIG_CEPH_FS_POSIX_ACL 823 + s->s_flags |= MS_POSIXACL; 824 + #endif 822 825 826 + s->s_xattr = ceph_xattr_handlers; 823 827 s->s_fs_info = fsc; 824 828 fsc->sb = s; 825 829
+36 -1
fs/ceph/super.h
··· 335 335 u32 i_fscache_gen; /* sequence, for delayed fscache validate */ 336 336 struct work_struct i_revalidate_work; 337 337 #endif 338 - 339 338 struct inode vfs_inode; /* at end */ 340 339 }; 341 340 ··· 724 725 /* xattr.c */ 725 726 extern int ceph_setxattr(struct dentry *, const char *, const void *, 726 727 size_t, int); 728 + int __ceph_setxattr(struct dentry *, const char *, const void *, size_t, int); 729 + ssize_t __ceph_getxattr(struct inode *, const char *, void *, size_t); 730 + int __ceph_removexattr(struct dentry *, const char *); 727 731 extern ssize_t ceph_getxattr(struct dentry *, const char *, void *, size_t); 728 732 extern ssize_t ceph_listxattr(struct dentry *, char *, size_t); 729 733 extern int ceph_removexattr(struct dentry *, const char *); ··· 734 732 extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci); 735 733 extern void __init ceph_xattr_init(void); 736 734 extern void ceph_xattr_exit(void); 735 + 736 + /* acl.c */ 737 + extern const struct xattr_handler ceph_xattr_acl_access_handler; 738 + extern const struct xattr_handler ceph_xattr_acl_default_handler; 739 + extern const struct xattr_handler *ceph_xattr_handlers[]; 740 + 741 + #ifdef CONFIG_CEPH_FS_POSIX_ACL 742 + 743 + struct posix_acl *ceph_get_acl(struct inode *, int); 744 + int ceph_init_acl(struct dentry *, struct inode *, struct inode *); 745 + int ceph_acl_chmod(struct dentry *, struct inode *); 746 + void ceph_forget_all_cached_acls(struct inode *inode); 747 + 748 + #else 749 + 750 + #define ceph_get_acl NULL 751 + 752 + static inline int ceph_init_acl(struct dentry *dentry, struct inode *inode, 753 + struct inode *dir) 754 + { 755 + return 0; 756 + } 757 + 758 + static inline int ceph_acl_chmod(struct dentry *dentry, struct inode *inode) 759 + { 760 + return 0; 761 + } 762 + 763 + static inline void ceph_forget_all_cached_acls(struct inode *inode) 764 + { 765 + } 766 + 767 + #endif 737 768 738 769 /* caps.c */ 739 770 extern const char *ceph_cap_string(int c);
+48 -12
fs/ceph/xattr.c
··· 11 11 #define XATTR_CEPH_PREFIX "ceph." 12 12 #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) 13 13 14 + /* 15 + * List of handlers for synthetic system.* attributes. Other 16 + * attributes are handled directly. 17 + */ 18 + const struct xattr_handler *ceph_xattr_handlers[] = { 19 + #ifdef CONFIG_CEPH_FS_POSIX_ACL 20 + &ceph_xattr_acl_access_handler, 21 + &ceph_xattr_acl_default_handler, 22 + #endif 23 + NULL, 24 + }; 25 + 14 26 static bool ceph_is_valid_xattr(const char *name) 15 27 { 16 28 return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || 17 29 !strncmp(name, XATTR_SECURITY_PREFIX, 18 30 XATTR_SECURITY_PREFIX_LEN) || 31 + !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) || 19 32 !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || 20 33 !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); 21 34 } ··· 676 663 } 677 664 } 678 665 679 - ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, 666 + ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, 680 667 size_t size) 681 668 { 682 - struct inode *inode = dentry->d_inode; 683 669 struct ceph_inode_info *ci = ceph_inode(inode); 684 670 int err; 685 671 struct ceph_inode_xattr *xattr; ··· 686 674 687 675 if (!ceph_is_valid_xattr(name)) 688 676 return -ENODATA; 689 - 690 677 691 678 /* let's see if a virtual xattr was requested */ 692 679 vxattr = ceph_match_vxattr(inode, name); ··· 734 723 out: 735 724 spin_unlock(&ci->i_ceph_lock); 736 725 return err; 726 + } 727 + 728 + ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, 729 + size_t size) 730 + { 731 + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) 732 + return generic_getxattr(dentry, name, value, size); 733 + 734 + return __ceph_getxattr(dentry->d_inode, name, value, size); 737 735 } 738 736 739 737 ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) ··· 883 863 return err; 884 864 } 885 865 886 - int ceph_setxattr(struct dentry *dentry, const char *name, 887 - const void *value, size_t size, int flags) 866 + int __ceph_setxattr(struct dentry *dentry, const char *name, 867 + const void *value, size_t size, int flags) 888 868 { 889 869 struct inode *inode = dentry->d_inode; 890 870 struct ceph_vxattr *vxattr; ··· 898 878 char *newval = NULL; 899 879 struct ceph_inode_xattr *xattr = NULL; 900 880 int required_blob_size; 901 - 902 - if (ceph_snap(inode) != CEPH_NOSNAP) 903 - return -EROFS; 904 881 905 882 if (!ceph_is_valid_xattr(name)) 906 883 return -EOPNOTSUPP; ··· 975 958 return err; 976 959 } 977 960 961 + int ceph_setxattr(struct dentry *dentry, const char *name, 962 + const void *value, size_t size, int flags) 963 + { 964 + if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) 965 + return -EROFS; 966 + 967 + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) 968 + return generic_setxattr(dentry, name, value, size, flags); 969 + 970 + return __ceph_setxattr(dentry, name, value, size, flags); 971 + } 972 + 978 973 static int ceph_send_removexattr(struct dentry *dentry, const char *name) 979 974 { 980 975 struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); ··· 1013 984 return err; 1014 985 } 1015 986 1016 - int ceph_removexattr(struct dentry *dentry, const char *name) 987 + int __ceph_removexattr(struct dentry *dentry, const char *name) 1017 988 { 1018 989 struct inode *inode = dentry->d_inode; 1019 990 struct ceph_vxattr *vxattr; ··· 1022 993 int err; 1023 994 int required_blob_size; 1024 995 int dirty; 1025 - 1026 - if (ceph_snap(inode) != CEPH_NOSNAP) 1027 - return -EROFS; 1028 996 1029 997 if (!ceph_is_valid_xattr(name)) 1030 998 return -EOPNOTSUPP; ··· 1079 1053 return err; 1080 1054 } 1081 1055 1056 + int ceph_removexattr(struct dentry *dentry, const char *name) 1057 + { 1058 + if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) 1059 + return -EROFS; 1060 + 1061 + if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) 1062 + return generic_removexattr(dentry, name); 1063 + 1064 + return __ceph_removexattr(dentry, name); 1065 + }