diff options
Diffstat (limited to 'fs/ceph/xattr.c')
-rw-r--r-- | fs/ceph/xattr.c | 115 |
1 files changed, 89 insertions, 26 deletions
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index be661d8f532a..a55ec37378c6 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
@@ -6,16 +6,33 @@ | |||
6 | #include <linux/ceph/decode.h> | 6 | #include <linux/ceph/decode.h> |
7 | 7 | ||
8 | #include <linux/xattr.h> | 8 | #include <linux/xattr.h> |
9 | #include <linux/posix_acl_xattr.h> | ||
9 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
10 | 11 | ||
11 | #define XATTR_CEPH_PREFIX "ceph." | 12 | #define XATTR_CEPH_PREFIX "ceph." |
12 | #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) | 13 | #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) |
13 | 14 | ||
15 | static int __remove_xattr(struct ceph_inode_info *ci, | ||
16 | struct ceph_inode_xattr *xattr); | ||
17 | |||
18 | /* | ||
19 | * List of handlers for synthetic system.* attributes. Other | ||
20 | * attributes are handled directly. | ||
21 | */ | ||
22 | const struct xattr_handler *ceph_xattr_handlers[] = { | ||
23 | #ifdef CONFIG_CEPH_FS_POSIX_ACL | ||
24 | &posix_acl_access_xattr_handler, | ||
25 | &posix_acl_default_xattr_handler, | ||
26 | #endif | ||
27 | NULL, | ||
28 | }; | ||
29 | |||
14 | static bool ceph_is_valid_xattr(const char *name) | 30 | static bool ceph_is_valid_xattr(const char *name) |
15 | { | 31 | { |
16 | return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || | 32 | return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) || |
17 | !strncmp(name, XATTR_SECURITY_PREFIX, | 33 | !strncmp(name, XATTR_SECURITY_PREFIX, |
18 | XATTR_SECURITY_PREFIX_LEN) || | 34 | XATTR_SECURITY_PREFIX_LEN) || |
35 | !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) || | ||
19 | !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || | 36 | !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) || |
20 | !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); | 37 | !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); |
21 | } | 38 | } |
@@ -305,8 +322,7 @@ static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, | |||
305 | static int __set_xattr(struct ceph_inode_info *ci, | 322 | static int __set_xattr(struct ceph_inode_info *ci, |
306 | const char *name, int name_len, | 323 | const char *name, int name_len, |
307 | const char *val, int val_len, | 324 | const char *val, int val_len, |
308 | int dirty, | 325 | int flags, int update_xattr, |
309 | int should_free_name, int should_free_val, | ||
310 | struct ceph_inode_xattr **newxattr) | 326 | struct ceph_inode_xattr **newxattr) |
311 | { | 327 | { |
312 | struct rb_node **p; | 328 | struct rb_node **p; |
@@ -335,12 +351,31 @@ static int __set_xattr(struct ceph_inode_info *ci, | |||
335 | xattr = NULL; | 351 | xattr = NULL; |
336 | } | 352 | } |
337 | 353 | ||
354 | if (update_xattr) { | ||
355 | int err = 0; | ||
356 | if (xattr && (flags & XATTR_CREATE)) | ||
357 | err = -EEXIST; | ||
358 | else if (!xattr && (flags & XATTR_REPLACE)) | ||
359 | err = -ENODATA; | ||
360 | if (err) { | ||
361 | kfree(name); | ||
362 | kfree(val); | ||
363 | return err; | ||
364 | } | ||
365 | if (update_xattr < 0) { | ||
366 | if (xattr) | ||
367 | __remove_xattr(ci, xattr); | ||
368 | kfree(name); | ||
369 | return 0; | ||
370 | } | ||
371 | } | ||
372 | |||
338 | if (!xattr) { | 373 | if (!xattr) { |
339 | new = 1; | 374 | new = 1; |
340 | xattr = *newxattr; | 375 | xattr = *newxattr; |
341 | xattr->name = name; | 376 | xattr->name = name; |
342 | xattr->name_len = name_len; | 377 | xattr->name_len = name_len; |
343 | xattr->should_free_name = should_free_name; | 378 | xattr->should_free_name = update_xattr; |
344 | 379 | ||
345 | ci->i_xattrs.count++; | 380 | ci->i_xattrs.count++; |
346 | dout("__set_xattr count=%d\n", ci->i_xattrs.count); | 381 | dout("__set_xattr count=%d\n", ci->i_xattrs.count); |
@@ -350,7 +385,7 @@ static int __set_xattr(struct ceph_inode_info *ci, | |||
350 | if (xattr->should_free_val) | 385 | if (xattr->should_free_val) |
351 | kfree((void *)xattr->val); | 386 | kfree((void *)xattr->val); |
352 | 387 | ||
353 | if (should_free_name) { | 388 | if (update_xattr) { |
354 | kfree((void *)name); | 389 | kfree((void *)name); |
355 | name = xattr->name; | 390 | name = xattr->name; |
356 | } | 391 | } |
@@ -365,8 +400,8 @@ static int __set_xattr(struct ceph_inode_info *ci, | |||
365 | xattr->val = ""; | 400 | xattr->val = ""; |
366 | 401 | ||
367 | xattr->val_len = val_len; | 402 | xattr->val_len = val_len; |
368 | xattr->dirty = dirty; | 403 | xattr->dirty = update_xattr; |
369 | xattr->should_free_val = (val && should_free_val); | 404 | xattr->should_free_val = (val && update_xattr); |
370 | 405 | ||
371 | if (new) { | 406 | if (new) { |
372 | rb_link_node(&xattr->node, parent, p); | 407 | rb_link_node(&xattr->node, parent, p); |
@@ -428,7 +463,7 @@ static int __remove_xattr(struct ceph_inode_info *ci, | |||
428 | struct ceph_inode_xattr *xattr) | 463 | struct ceph_inode_xattr *xattr) |
429 | { | 464 | { |
430 | if (!xattr) | 465 | if (!xattr) |
431 | return -EOPNOTSUPP; | 466 | return -ENODATA; |
432 | 467 | ||
433 | rb_erase(&xattr->node, &ci->i_xattrs.index); | 468 | rb_erase(&xattr->node, &ci->i_xattrs.index); |
434 | 469 | ||
@@ -574,7 +609,7 @@ start: | |||
574 | p += len; | 609 | p += len; |
575 | 610 | ||
576 | err = __set_xattr(ci, name, namelen, val, len, | 611 | err = __set_xattr(ci, name, namelen, val, len, |
577 | 0, 0, 0, &xattrs[numattr]); | 612 | 0, 0, &xattrs[numattr]); |
578 | 613 | ||
579 | if (err < 0) | 614 | if (err < 0) |
580 | goto bad; | 615 | goto bad; |
@@ -663,10 +698,9 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci) | |||
663 | } | 698 | } |
664 | } | 699 | } |
665 | 700 | ||
666 | ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, | 701 | ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value, |
667 | size_t size) | 702 | size_t size) |
668 | { | 703 | { |
669 | struct inode *inode = dentry->d_inode; | ||
670 | struct ceph_inode_info *ci = ceph_inode(inode); | 704 | struct ceph_inode_info *ci = ceph_inode(inode); |
671 | int err; | 705 | int err; |
672 | struct ceph_inode_xattr *xattr; | 706 | struct ceph_inode_xattr *xattr; |
@@ -675,7 +709,6 @@ ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, | |||
675 | if (!ceph_is_valid_xattr(name)) | 709 | if (!ceph_is_valid_xattr(name)) |
676 | return -ENODATA; | 710 | return -ENODATA; |
677 | 711 | ||
678 | |||
679 | /* let's see if a virtual xattr was requested */ | 712 | /* let's see if a virtual xattr was requested */ |
680 | vxattr = ceph_match_vxattr(inode, name); | 713 | vxattr = ceph_match_vxattr(inode, name); |
681 | if (vxattr && !(vxattr->exists_cb && !vxattr->exists_cb(ci))) { | 714 | if (vxattr && !(vxattr->exists_cb && !vxattr->exists_cb(ci))) { |
@@ -725,6 +758,15 @@ out: | |||
725 | return err; | 758 | return err; |
726 | } | 759 | } |
727 | 760 | ||
761 | ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, | ||
762 | size_t size) | ||
763 | { | ||
764 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
765 | return generic_getxattr(dentry, name, value, size); | ||
766 | |||
767 | return __ceph_getxattr(dentry->d_inode, name, value, size); | ||
768 | } | ||
769 | |||
728 | ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) | 770 | ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) |
729 | { | 771 | { |
730 | struct inode *inode = dentry->d_inode; | 772 | struct inode *inode = dentry->d_inode; |
@@ -829,6 +871,9 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, | |||
829 | 871 | ||
830 | dout("setxattr value=%.*s\n", (int)size, value); | 872 | dout("setxattr value=%.*s\n", (int)size, value); |
831 | 873 | ||
874 | if (!value) | ||
875 | flags |= CEPH_XATTR_REMOVE; | ||
876 | |||
832 | /* do request */ | 877 | /* do request */ |
833 | req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR, | 878 | req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR, |
834 | USE_AUTH_MDS); | 879 | USE_AUTH_MDS); |
@@ -863,15 +908,15 @@ out: | |||
863 | return err; | 908 | return err; |
864 | } | 909 | } |
865 | 910 | ||
866 | int ceph_setxattr(struct dentry *dentry, const char *name, | 911 | int __ceph_setxattr(struct dentry *dentry, const char *name, |
867 | const void *value, size_t size, int flags) | 912 | const void *value, size_t size, int flags) |
868 | { | 913 | { |
869 | struct inode *inode = dentry->d_inode; | 914 | struct inode *inode = dentry->d_inode; |
870 | struct ceph_vxattr *vxattr; | 915 | struct ceph_vxattr *vxattr; |
871 | struct ceph_inode_info *ci = ceph_inode(inode); | 916 | struct ceph_inode_info *ci = ceph_inode(inode); |
872 | int issued; | 917 | int issued; |
873 | int err; | 918 | int err; |
874 | int dirty; | 919 | int dirty = 0; |
875 | int name_len = strlen(name); | 920 | int name_len = strlen(name); |
876 | int val_len = size; | 921 | int val_len = size; |
877 | char *newname = NULL; | 922 | char *newname = NULL; |
@@ -879,9 +924,6 @@ int ceph_setxattr(struct dentry *dentry, const char *name, | |||
879 | struct ceph_inode_xattr *xattr = NULL; | 924 | struct ceph_inode_xattr *xattr = NULL; |
880 | int required_blob_size; | 925 | int required_blob_size; |
881 | 926 | ||
882 | if (ceph_snap(inode) != CEPH_NOSNAP) | ||
883 | return -EROFS; | ||
884 | |||
885 | if (!ceph_is_valid_xattr(name)) | 927 | if (!ceph_is_valid_xattr(name)) |
886 | return -EOPNOTSUPP; | 928 | return -EOPNOTSUPP; |
887 | 929 | ||
@@ -935,12 +977,14 @@ retry: | |||
935 | goto retry; | 977 | goto retry; |
936 | } | 978 | } |
937 | 979 | ||
938 | err = __set_xattr(ci, newname, name_len, newval, | 980 | err = __set_xattr(ci, newname, name_len, newval, val_len, |
939 | val_len, 1, 1, 1, &xattr); | 981 | flags, value ? 1 : -1, &xattr); |
940 | 982 | ||
941 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); | 983 | if (!err) { |
942 | ci->i_xattrs.dirty = true; | 984 | dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); |
943 | inode->i_ctime = CURRENT_TIME; | 985 | ci->i_xattrs.dirty = true; |
986 | inode->i_ctime = CURRENT_TIME; | ||
987 | } | ||
944 | 988 | ||
945 | spin_unlock(&ci->i_ceph_lock); | 989 | spin_unlock(&ci->i_ceph_lock); |
946 | if (dirty) | 990 | if (dirty) |
@@ -958,6 +1002,18 @@ out: | |||
958 | return err; | 1002 | return err; |
959 | } | 1003 | } |
960 | 1004 | ||
1005 | int ceph_setxattr(struct dentry *dentry, const char *name, | ||
1006 | const void *value, size_t size, int flags) | ||
1007 | { | ||
1008 | if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) | ||
1009 | return -EROFS; | ||
1010 | |||
1011 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
1012 | return generic_setxattr(dentry, name, value, size, flags); | ||
1013 | |||
1014 | return __ceph_setxattr(dentry, name, value, size, flags); | ||
1015 | } | ||
1016 | |||
961 | static int ceph_send_removexattr(struct dentry *dentry, const char *name) | 1017 | static int ceph_send_removexattr(struct dentry *dentry, const char *name) |
962 | { | 1018 | { |
963 | struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); | 1019 | struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb); |
@@ -984,7 +1040,7 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name) | |||
984 | return err; | 1040 | return err; |
985 | } | 1041 | } |
986 | 1042 | ||
987 | int ceph_removexattr(struct dentry *dentry, const char *name) | 1043 | int __ceph_removexattr(struct dentry *dentry, const char *name) |
988 | { | 1044 | { |
989 | struct inode *inode = dentry->d_inode; | 1045 | struct inode *inode = dentry->d_inode; |
990 | struct ceph_vxattr *vxattr; | 1046 | struct ceph_vxattr *vxattr; |
@@ -994,9 +1050,6 @@ int ceph_removexattr(struct dentry *dentry, const char *name) | |||
994 | int required_blob_size; | 1050 | int required_blob_size; |
995 | int dirty; | 1051 | int dirty; |
996 | 1052 | ||
997 | if (ceph_snap(inode) != CEPH_NOSNAP) | ||
998 | return -EROFS; | ||
999 | |||
1000 | if (!ceph_is_valid_xattr(name)) | 1053 | if (!ceph_is_valid_xattr(name)) |
1001 | return -EOPNOTSUPP; | 1054 | return -EOPNOTSUPP; |
1002 | 1055 | ||
@@ -1053,3 +1106,13 @@ out: | |||
1053 | return err; | 1106 | return err; |
1054 | } | 1107 | } |
1055 | 1108 | ||
1109 | int ceph_removexattr(struct dentry *dentry, const char *name) | ||
1110 | { | ||
1111 | if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP) | ||
1112 | return -EROFS; | ||
1113 | |||
1114 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
1115 | return generic_removexattr(dentry, name); | ||
1116 | |||
1117 | return __ceph_removexattr(dentry, name); | ||
1118 | } | ||