diff options
author | Aristeu Rozanski <aris@redhat.com> | 2012-08-23 16:53:28 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-08-24 18:55:33 -0400 |
commit | 38f38657444d15e1a8574eae80ed3de9f501737a (patch) | |
tree | b39bf533c5acb4b3ee48b6602dea9d92c2e9f72f | |
parent | fea7a08acb13524b47711625eebea40a0ede69a0 (diff) |
xattr: extract simple_xattr code from tmpfs
Extract in-memory xattr APIs from tmpfs. Will be used by cgroup.
$ size vmlinux.o
text data bss dec hex filename
4658782 880729 5195032 10734543 a3cbcf vmlinux.o
$ size vmlinux.o
text data bss dec hex filename
4658957 880729 5195032 10734718 a3cc7e vmlinux.o
v7:
- checkpatch warnings fixed
- Implement the changes requested by Hugh Dickins:
- make simple_xattrs_init and simple_xattrs_free inline
- get rid of locking and list reinitialization in simple_xattrs_free,
they're not needed
v6:
- no changes
v5:
- no changes
v4:
- move simple_xattrs_free() to fs/xattr.c
v3:
- in kmem_xattrs_free(), reinitialize the list
- use simple_xattr_* prefix
- introduce simple_xattr_add() to prevent direct list usage
Original-patch-by: Li Zefan <lizefan@huawei.com>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Hillf Danton <dhillf@gmail.com>
Cc: Lennart Poettering <lpoetter@redhat.com>
Acked-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Li Zefan <lizefan@huawei.com>
Signed-off-by: Aristeu Rozanski <aris@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r-- | fs/xattr.c | 166 | ||||
-rw-r--r-- | include/linux/shmem_fs.h | 3 | ||||
-rw-r--r-- | include/linux/xattr.h | 48 | ||||
-rw-r--r-- | mm/shmem.c | 171 |
4 files changed, 229 insertions, 159 deletions
diff --git a/fs/xattr.c b/fs/xattr.c index 4d45b7189e7e..e17e773517ef 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -791,3 +791,169 @@ EXPORT_SYMBOL(generic_getxattr); | |||
791 | EXPORT_SYMBOL(generic_listxattr); | 791 | EXPORT_SYMBOL(generic_listxattr); |
792 | EXPORT_SYMBOL(generic_setxattr); | 792 | EXPORT_SYMBOL(generic_setxattr); |
793 | EXPORT_SYMBOL(generic_removexattr); | 793 | EXPORT_SYMBOL(generic_removexattr); |
794 | |||
795 | /* | ||
796 | * Allocate new xattr and copy in the value; but leave the name to callers. | ||
797 | */ | ||
798 | struct simple_xattr *simple_xattr_alloc(const void *value, size_t size) | ||
799 | { | ||
800 | struct simple_xattr *new_xattr; | ||
801 | size_t len; | ||
802 | |||
803 | /* wrap around? */ | ||
804 | len = sizeof(*new_xattr) + size; | ||
805 | if (len <= sizeof(*new_xattr)) | ||
806 | return NULL; | ||
807 | |||
808 | new_xattr = kmalloc(len, GFP_KERNEL); | ||
809 | if (!new_xattr) | ||
810 | return NULL; | ||
811 | |||
812 | new_xattr->size = size; | ||
813 | memcpy(new_xattr->value, value, size); | ||
814 | return new_xattr; | ||
815 | } | ||
816 | |||
817 | /* | ||
818 | * xattr GET operation for in-memory/pseudo filesystems | ||
819 | */ | ||
820 | int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, | ||
821 | void *buffer, size_t size) | ||
822 | { | ||
823 | struct simple_xattr *xattr; | ||
824 | int ret = -ENODATA; | ||
825 | |||
826 | spin_lock(&xattrs->lock); | ||
827 | list_for_each_entry(xattr, &xattrs->head, list) { | ||
828 | if (strcmp(name, xattr->name)) | ||
829 | continue; | ||
830 | |||
831 | ret = xattr->size; | ||
832 | if (buffer) { | ||
833 | if (size < xattr->size) | ||
834 | ret = -ERANGE; | ||
835 | else | ||
836 | memcpy(buffer, xattr->value, xattr->size); | ||
837 | } | ||
838 | break; | ||
839 | } | ||
840 | spin_unlock(&xattrs->lock); | ||
841 | return ret; | ||
842 | } | ||
843 | |||
844 | static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name, | ||
845 | const void *value, size_t size, int flags) | ||
846 | { | ||
847 | struct simple_xattr *xattr; | ||
848 | struct simple_xattr *new_xattr = NULL; | ||
849 | int err = 0; | ||
850 | |||
851 | /* value == NULL means remove */ | ||
852 | if (value) { | ||
853 | new_xattr = simple_xattr_alloc(value, size); | ||
854 | if (!new_xattr) | ||
855 | return -ENOMEM; | ||
856 | |||
857 | new_xattr->name = kstrdup(name, GFP_KERNEL); | ||
858 | if (!new_xattr->name) { | ||
859 | kfree(new_xattr); | ||
860 | return -ENOMEM; | ||
861 | } | ||
862 | } | ||
863 | |||
864 | spin_lock(&xattrs->lock); | ||
865 | list_for_each_entry(xattr, &xattrs->head, list) { | ||
866 | if (!strcmp(name, xattr->name)) { | ||
867 | if (flags & XATTR_CREATE) { | ||
868 | xattr = new_xattr; | ||
869 | err = -EEXIST; | ||
870 | } else if (new_xattr) { | ||
871 | list_replace(&xattr->list, &new_xattr->list); | ||
872 | } else { | ||
873 | list_del(&xattr->list); | ||
874 | } | ||
875 | goto out; | ||
876 | } | ||
877 | } | ||
878 | if (flags & XATTR_REPLACE) { | ||
879 | xattr = new_xattr; | ||
880 | err = -ENODATA; | ||
881 | } else { | ||
882 | list_add(&new_xattr->list, &xattrs->head); | ||
883 | xattr = NULL; | ||
884 | } | ||
885 | out: | ||
886 | spin_unlock(&xattrs->lock); | ||
887 | if (xattr) { | ||
888 | kfree(xattr->name); | ||
889 | kfree(xattr); | ||
890 | } | ||
891 | return err; | ||
892 | |||
893 | } | ||
894 | |||
895 | /* | ||
896 | * xattr SET operation for in-memory/pseudo filesystems | ||
897 | */ | ||
898 | int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, | ||
899 | const void *value, size_t size, int flags) | ||
900 | { | ||
901 | if (size == 0) | ||
902 | value = ""; /* empty EA, do not remove */ | ||
903 | return __simple_xattr_set(xattrs, name, value, size, flags); | ||
904 | } | ||
905 | |||
906 | /* | ||
907 | * xattr REMOVE operation for in-memory/pseudo filesystems | ||
908 | */ | ||
909 | int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name) | ||
910 | { | ||
911 | return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE); | ||
912 | } | ||
913 | |||
914 | static bool xattr_is_trusted(const char *name) | ||
915 | { | ||
916 | return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); | ||
917 | } | ||
918 | |||
919 | /* | ||
920 | * xattr LIST operation for in-memory/pseudo filesystems | ||
921 | */ | ||
922 | ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer, | ||
923 | size_t size) | ||
924 | { | ||
925 | bool trusted = capable(CAP_SYS_ADMIN); | ||
926 | struct simple_xattr *xattr; | ||
927 | size_t used = 0; | ||
928 | |||
929 | spin_lock(&xattrs->lock); | ||
930 | list_for_each_entry(xattr, &xattrs->head, list) { | ||
931 | size_t len; | ||
932 | |||
933 | /* skip "trusted." attributes for unprivileged callers */ | ||
934 | if (!trusted && xattr_is_trusted(xattr->name)) | ||
935 | continue; | ||
936 | |||
937 | len = strlen(xattr->name) + 1; | ||
938 | used += len; | ||
939 | if (buffer) { | ||
940 | if (size < used) { | ||
941 | used = -ERANGE; | ||
942 | break; | ||
943 | } | ||
944 | memcpy(buffer, xattr->name, len); | ||
945 | buffer += len; | ||
946 | } | ||
947 | } | ||
948 | spin_unlock(&xattrs->lock); | ||
949 | |||
950 | return used; | ||
951 | } | ||
952 | |||
953 | void simple_xattr_list_add(struct simple_xattrs *xattrs, | ||
954 | struct simple_xattr *new_xattr) | ||
955 | { | ||
956 | spin_lock(&xattrs->lock); | ||
957 | list_add(&new_xattr->list, &xattrs->head); | ||
958 | spin_unlock(&xattrs->lock); | ||
959 | } | ||
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h index bef2cf00b3be..30aa0dc60d75 100644 --- a/include/linux/shmem_fs.h +++ b/include/linux/shmem_fs.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/mempolicy.h> | 5 | #include <linux/mempolicy.h> |
6 | #include <linux/pagemap.h> | 6 | #include <linux/pagemap.h> |
7 | #include <linux/percpu_counter.h> | 7 | #include <linux/percpu_counter.h> |
8 | #include <linux/xattr.h> | ||
8 | 9 | ||
9 | /* inode in-kernel data */ | 10 | /* inode in-kernel data */ |
10 | 11 | ||
@@ -18,7 +19,7 @@ struct shmem_inode_info { | |||
18 | }; | 19 | }; |
19 | struct shared_policy policy; /* NUMA memory alloc policy */ | 20 | struct shared_policy policy; /* NUMA memory alloc policy */ |
20 | struct list_head swaplist; /* chain of maybes on swap */ | 21 | struct list_head swaplist; /* chain of maybes on swap */ |
21 | struct list_head xattr_list; /* list of shmem_xattr */ | 22 | struct simple_xattrs xattrs; /* list of xattrs */ |
22 | struct inode vfs_inode; | 23 | struct inode vfs_inode; |
23 | }; | 24 | }; |
24 | 25 | ||
diff --git a/include/linux/xattr.h b/include/linux/xattr.h index e5d122031542..2ace7a60316d 100644 --- a/include/linux/xattr.h +++ b/include/linux/xattr.h | |||
@@ -59,7 +59,9 @@ | |||
59 | 59 | ||
60 | #ifdef __KERNEL__ | 60 | #ifdef __KERNEL__ |
61 | 61 | ||
62 | #include <linux/slab.h> | ||
62 | #include <linux/types.h> | 63 | #include <linux/types.h> |
64 | #include <linux/spinlock.h> | ||
63 | 65 | ||
64 | struct inode; | 66 | struct inode; |
65 | struct dentry; | 67 | struct dentry; |
@@ -96,6 +98,52 @@ ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name, | |||
96 | char **xattr_value, size_t size, gfp_t flags); | 98 | char **xattr_value, size_t size, gfp_t flags); |
97 | int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name, | 99 | int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name, |
98 | const char *value, size_t size, gfp_t flags); | 100 | const char *value, size_t size, gfp_t flags); |
101 | |||
102 | struct simple_xattrs { | ||
103 | struct list_head head; | ||
104 | spinlock_t lock; | ||
105 | }; | ||
106 | |||
107 | struct simple_xattr { | ||
108 | struct list_head list; | ||
109 | char *name; | ||
110 | size_t size; | ||
111 | char value[0]; | ||
112 | }; | ||
113 | |||
114 | /* | ||
115 | * initialize the simple_xattrs structure | ||
116 | */ | ||
117 | static inline void simple_xattrs_init(struct simple_xattrs *xattrs) | ||
118 | { | ||
119 | INIT_LIST_HEAD(&xattrs->head); | ||
120 | spin_lock_init(&xattrs->lock); | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * free all the xattrs | ||
125 | */ | ||
126 | static inline void simple_xattrs_free(struct simple_xattrs *xattrs) | ||
127 | { | ||
128 | struct simple_xattr *xattr, *node; | ||
129 | |||
130 | list_for_each_entry_safe(xattr, node, &xattrs->head, list) { | ||
131 | kfree(xattr->name); | ||
132 | kfree(xattr); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | struct simple_xattr *simple_xattr_alloc(const void *value, size_t size); | ||
137 | int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, | ||
138 | void *buffer, size_t size); | ||
139 | int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, | ||
140 | const void *value, size_t size, int flags); | ||
141 | int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name); | ||
142 | ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer, | ||
143 | size_t size); | ||
144 | void simple_xattr_list_add(struct simple_xattrs *xattrs, | ||
145 | struct simple_xattr *new_xattr); | ||
146 | |||
99 | #endif /* __KERNEL__ */ | 147 | #endif /* __KERNEL__ */ |
100 | 148 | ||
101 | #endif /* _LINUX_XATTR_H */ | 149 | #endif /* _LINUX_XATTR_H */ |
diff --git a/mm/shmem.c b/mm/shmem.c index d4e184e2a38e..d3752110c8c7 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -77,13 +77,6 @@ static struct vfsmount *shm_mnt; | |||
77 | /* Symlink up to this size is kmalloc'ed instead of using a swappable page */ | 77 | /* Symlink up to this size is kmalloc'ed instead of using a swappable page */ |
78 | #define SHORT_SYMLINK_LEN 128 | 78 | #define SHORT_SYMLINK_LEN 128 |
79 | 79 | ||
80 | struct shmem_xattr { | ||
81 | struct list_head list; /* anchored by shmem_inode_info->xattr_list */ | ||
82 | char *name; /* xattr name */ | ||
83 | size_t size; | ||
84 | char value[0]; | ||
85 | }; | ||
86 | |||
87 | /* | 80 | /* |
88 | * shmem_fallocate and shmem_writepage communicate via inode->i_private | 81 | * shmem_fallocate and shmem_writepage communicate via inode->i_private |
89 | * (with i_mutex making sure that it has only one user at a time): | 82 | * (with i_mutex making sure that it has only one user at a time): |
@@ -636,7 +629,6 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr) | |||
636 | static void shmem_evict_inode(struct inode *inode) | 629 | static void shmem_evict_inode(struct inode *inode) |
637 | { | 630 | { |
638 | struct shmem_inode_info *info = SHMEM_I(inode); | 631 | struct shmem_inode_info *info = SHMEM_I(inode); |
639 | struct shmem_xattr *xattr, *nxattr; | ||
640 | 632 | ||
641 | if (inode->i_mapping->a_ops == &shmem_aops) { | 633 | if (inode->i_mapping->a_ops == &shmem_aops) { |
642 | shmem_unacct_size(info->flags, inode->i_size); | 634 | shmem_unacct_size(info->flags, inode->i_size); |
@@ -650,10 +642,7 @@ static void shmem_evict_inode(struct inode *inode) | |||
650 | } else | 642 | } else |
651 | kfree(info->symlink); | 643 | kfree(info->symlink); |
652 | 644 | ||
653 | list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) { | 645 | simple_xattrs_free(&info->xattrs); |
654 | kfree(xattr->name); | ||
655 | kfree(xattr); | ||
656 | } | ||
657 | BUG_ON(inode->i_blocks); | 646 | BUG_ON(inode->i_blocks); |
658 | shmem_free_inode(inode->i_sb); | 647 | shmem_free_inode(inode->i_sb); |
659 | clear_inode(inode); | 648 | clear_inode(inode); |
@@ -1377,7 +1366,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode | |||
1377 | spin_lock_init(&info->lock); | 1366 | spin_lock_init(&info->lock); |
1378 | info->flags = flags & VM_NORESERVE; | 1367 | info->flags = flags & VM_NORESERVE; |
1379 | INIT_LIST_HEAD(&info->swaplist); | 1368 | INIT_LIST_HEAD(&info->swaplist); |
1380 | INIT_LIST_HEAD(&info->xattr_list); | 1369 | simple_xattrs_init(&info->xattrs); |
1381 | cache_no_acl(inode); | 1370 | cache_no_acl(inode); |
1382 | 1371 | ||
1383 | switch (mode & S_IFMT) { | 1372 | switch (mode & S_IFMT) { |
@@ -2060,28 +2049,6 @@ static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *co | |||
2060 | */ | 2049 | */ |
2061 | 2050 | ||
2062 | /* | 2051 | /* |
2063 | * Allocate new xattr and copy in the value; but leave the name to callers. | ||
2064 | */ | ||
2065 | static struct shmem_xattr *shmem_xattr_alloc(const void *value, size_t size) | ||
2066 | { | ||
2067 | struct shmem_xattr *new_xattr; | ||
2068 | size_t len; | ||
2069 | |||
2070 | /* wrap around? */ | ||
2071 | len = sizeof(*new_xattr) + size; | ||
2072 | if (len <= sizeof(*new_xattr)) | ||
2073 | return NULL; | ||
2074 | |||
2075 | new_xattr = kmalloc(len, GFP_KERNEL); | ||
2076 | if (!new_xattr) | ||
2077 | return NULL; | ||
2078 | |||
2079 | new_xattr->size = size; | ||
2080 | memcpy(new_xattr->value, value, size); | ||
2081 | return new_xattr; | ||
2082 | } | ||
2083 | |||
2084 | /* | ||
2085 | * Callback for security_inode_init_security() for acquiring xattrs. | 2052 | * Callback for security_inode_init_security() for acquiring xattrs. |
2086 | */ | 2053 | */ |
2087 | static int shmem_initxattrs(struct inode *inode, | 2054 | static int shmem_initxattrs(struct inode *inode, |
@@ -2090,11 +2057,11 @@ static int shmem_initxattrs(struct inode *inode, | |||
2090 | { | 2057 | { |
2091 | struct shmem_inode_info *info = SHMEM_I(inode); | 2058 | struct shmem_inode_info *info = SHMEM_I(inode); |
2092 | const struct xattr *xattr; | 2059 | const struct xattr *xattr; |
2093 | struct shmem_xattr *new_xattr; | 2060 | struct simple_xattr *new_xattr; |
2094 | size_t len; | 2061 | size_t len; |
2095 | 2062 | ||
2096 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { | 2063 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { |
2097 | new_xattr = shmem_xattr_alloc(xattr->value, xattr->value_len); | 2064 | new_xattr = simple_xattr_alloc(xattr->value, xattr->value_len); |
2098 | if (!new_xattr) | 2065 | if (!new_xattr) |
2099 | return -ENOMEM; | 2066 | return -ENOMEM; |
2100 | 2067 | ||
@@ -2111,91 +2078,12 @@ static int shmem_initxattrs(struct inode *inode, | |||
2111 | memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN, | 2078 | memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN, |
2112 | xattr->name, len); | 2079 | xattr->name, len); |
2113 | 2080 | ||
2114 | spin_lock(&info->lock); | 2081 | simple_xattr_list_add(&info->xattrs, new_xattr); |
2115 | list_add(&new_xattr->list, &info->xattr_list); | ||
2116 | spin_unlock(&info->lock); | ||
2117 | } | 2082 | } |
2118 | 2083 | ||
2119 | return 0; | 2084 | return 0; |
2120 | } | 2085 | } |
2121 | 2086 | ||
2122 | static int shmem_xattr_get(struct dentry *dentry, const char *name, | ||
2123 | void *buffer, size_t size) | ||
2124 | { | ||
2125 | struct shmem_inode_info *info; | ||
2126 | struct shmem_xattr *xattr; | ||
2127 | int ret = -ENODATA; | ||
2128 | |||
2129 | info = SHMEM_I(dentry->d_inode); | ||
2130 | |||
2131 | spin_lock(&info->lock); | ||
2132 | list_for_each_entry(xattr, &info->xattr_list, list) { | ||
2133 | if (strcmp(name, xattr->name)) | ||
2134 | continue; | ||
2135 | |||
2136 | ret = xattr->size; | ||
2137 | if (buffer) { | ||
2138 | if (size < xattr->size) | ||
2139 | ret = -ERANGE; | ||
2140 | else | ||
2141 | memcpy(buffer, xattr->value, xattr->size); | ||
2142 | } | ||
2143 | break; | ||
2144 | } | ||
2145 | spin_unlock(&info->lock); | ||
2146 | return ret; | ||
2147 | } | ||
2148 | |||
2149 | static int shmem_xattr_set(struct inode *inode, const char *name, | ||
2150 | const void *value, size_t size, int flags) | ||
2151 | { | ||
2152 | struct shmem_inode_info *info = SHMEM_I(inode); | ||
2153 | struct shmem_xattr *xattr; | ||
2154 | struct shmem_xattr *new_xattr = NULL; | ||
2155 | int err = 0; | ||
2156 | |||
2157 | /* value == NULL means remove */ | ||
2158 | if (value) { | ||
2159 | new_xattr = shmem_xattr_alloc(value, size); | ||
2160 | if (!new_xattr) | ||
2161 | return -ENOMEM; | ||
2162 | |||
2163 | new_xattr->name = kstrdup(name, GFP_KERNEL); | ||
2164 | if (!new_xattr->name) { | ||
2165 | kfree(new_xattr); | ||
2166 | return -ENOMEM; | ||
2167 | } | ||
2168 | } | ||
2169 | |||
2170 | spin_lock(&info->lock); | ||
2171 | list_for_each_entry(xattr, &info->xattr_list, list) { | ||
2172 | if (!strcmp(name, xattr->name)) { | ||
2173 | if (flags & XATTR_CREATE) { | ||
2174 | xattr = new_xattr; | ||
2175 | err = -EEXIST; | ||
2176 | } else if (new_xattr) { | ||
2177 | list_replace(&xattr->list, &new_xattr->list); | ||
2178 | } else { | ||
2179 | list_del(&xattr->list); | ||
2180 | } | ||
2181 | goto out; | ||
2182 | } | ||
2183 | } | ||
2184 | if (flags & XATTR_REPLACE) { | ||
2185 | xattr = new_xattr; | ||
2186 | err = -ENODATA; | ||
2187 | } else { | ||
2188 | list_add(&new_xattr->list, &info->xattr_list); | ||
2189 | xattr = NULL; | ||
2190 | } | ||
2191 | out: | ||
2192 | spin_unlock(&info->lock); | ||
2193 | if (xattr) | ||
2194 | kfree(xattr->name); | ||
2195 | kfree(xattr); | ||
2196 | return err; | ||
2197 | } | ||
2198 | |||
2199 | static const struct xattr_handler *shmem_xattr_handlers[] = { | 2087 | static const struct xattr_handler *shmem_xattr_handlers[] = { |
2200 | #ifdef CONFIG_TMPFS_POSIX_ACL | 2088 | #ifdef CONFIG_TMPFS_POSIX_ACL |
2201 | &generic_acl_access_handler, | 2089 | &generic_acl_access_handler, |
@@ -2226,6 +2114,7 @@ static int shmem_xattr_validate(const char *name) | |||
2226 | static ssize_t shmem_getxattr(struct dentry *dentry, const char *name, | 2114 | static ssize_t shmem_getxattr(struct dentry *dentry, const char *name, |
2227 | void *buffer, size_t size) | 2115 | void *buffer, size_t size) |
2228 | { | 2116 | { |
2117 | struct shmem_inode_info *info = SHMEM_I(dentry->d_inode); | ||
2229 | int err; | 2118 | int err; |
2230 | 2119 | ||
2231 | /* | 2120 | /* |
@@ -2240,12 +2129,13 @@ static ssize_t shmem_getxattr(struct dentry *dentry, const char *name, | |||
2240 | if (err) | 2129 | if (err) |
2241 | return err; | 2130 | return err; |
2242 | 2131 | ||
2243 | return shmem_xattr_get(dentry, name, buffer, size); | 2132 | return simple_xattr_get(&info->xattrs, name, buffer, size); |
2244 | } | 2133 | } |
2245 | 2134 | ||
2246 | static int shmem_setxattr(struct dentry *dentry, const char *name, | 2135 | static int shmem_setxattr(struct dentry *dentry, const char *name, |
2247 | const void *value, size_t size, int flags) | 2136 | const void *value, size_t size, int flags) |
2248 | { | 2137 | { |
2138 | struct shmem_inode_info *info = SHMEM_I(dentry->d_inode); | ||
2249 | int err; | 2139 | int err; |
2250 | 2140 | ||
2251 | /* | 2141 | /* |
@@ -2260,15 +2150,12 @@ static int shmem_setxattr(struct dentry *dentry, const char *name, | |||
2260 | if (err) | 2150 | if (err) |
2261 | return err; | 2151 | return err; |
2262 | 2152 | ||
2263 | if (size == 0) | 2153 | return simple_xattr_set(&info->xattrs, name, value, size, flags); |
2264 | value = ""; /* empty EA, do not remove */ | ||
2265 | |||
2266 | return shmem_xattr_set(dentry->d_inode, name, value, size, flags); | ||
2267 | |||
2268 | } | 2154 | } |
2269 | 2155 | ||
2270 | static int shmem_removexattr(struct dentry *dentry, const char *name) | 2156 | static int shmem_removexattr(struct dentry *dentry, const char *name) |
2271 | { | 2157 | { |
2158 | struct shmem_inode_info *info = SHMEM_I(dentry->d_inode); | ||
2272 | int err; | 2159 | int err; |
2273 | 2160 | ||
2274 | /* | 2161 | /* |
@@ -2283,45 +2170,13 @@ static int shmem_removexattr(struct dentry *dentry, const char *name) | |||
2283 | if (err) | 2170 | if (err) |
2284 | return err; | 2171 | return err; |
2285 | 2172 | ||
2286 | return shmem_xattr_set(dentry->d_inode, name, NULL, 0, XATTR_REPLACE); | 2173 | return simple_xattr_remove(&info->xattrs, name); |
2287 | } | ||
2288 | |||
2289 | static bool xattr_is_trusted(const char *name) | ||
2290 | { | ||
2291 | return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); | ||
2292 | } | 2174 | } |
2293 | 2175 | ||
2294 | static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) | 2176 | static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) |
2295 | { | 2177 | { |
2296 | bool trusted = capable(CAP_SYS_ADMIN); | 2178 | struct shmem_inode_info *info = SHMEM_I(dentry->d_inode); |
2297 | struct shmem_xattr *xattr; | 2179 | return simple_xattr_list(&info->xattrs, buffer, size); |
2298 | struct shmem_inode_info *info; | ||
2299 | size_t used = 0; | ||
2300 | |||
2301 | info = SHMEM_I(dentry->d_inode); | ||
2302 | |||
2303 | spin_lock(&info->lock); | ||
2304 | list_for_each_entry(xattr, &info->xattr_list, list) { | ||
2305 | size_t len; | ||
2306 | |||
2307 | /* skip "trusted." attributes for unprivileged callers */ | ||
2308 | if (!trusted && xattr_is_trusted(xattr->name)) | ||
2309 | continue; | ||
2310 | |||
2311 | len = strlen(xattr->name) + 1; | ||
2312 | used += len; | ||
2313 | if (buffer) { | ||
2314 | if (size < used) { | ||
2315 | used = -ERANGE; | ||
2316 | break; | ||
2317 | } | ||
2318 | memcpy(buffer, xattr->name, len); | ||
2319 | buffer += len; | ||
2320 | } | ||
2321 | } | ||
2322 | spin_unlock(&info->lock); | ||
2323 | |||
2324 | return used; | ||
2325 | } | 2180 | } |
2326 | #endif /* CONFIG_TMPFS_XATTR */ | 2181 | #endif /* CONFIG_TMPFS_XATTR */ |
2327 | 2182 | ||