aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAristeu Rozanski <aris@redhat.com>2012-08-23 16:53:28 -0400
committerTejun Heo <tj@kernel.org>2012-08-24 18:55:33 -0400
commit38f38657444d15e1a8574eae80ed3de9f501737a (patch)
treeb39bf533c5acb4b3ee48b6602dea9d92c2e9f72f
parentfea7a08acb13524b47711625eebea40a0ede69a0 (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.c166
-rw-r--r--include/linux/shmem_fs.h3
-rw-r--r--include/linux/xattr.h48
-rw-r--r--mm/shmem.c171
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);
791EXPORT_SYMBOL(generic_listxattr); 791EXPORT_SYMBOL(generic_listxattr);
792EXPORT_SYMBOL(generic_setxattr); 792EXPORT_SYMBOL(generic_setxattr);
793EXPORT_SYMBOL(generic_removexattr); 793EXPORT_SYMBOL(generic_removexattr);
794
795/*
796 * Allocate new xattr and copy in the value; but leave the name to callers.
797 */
798struct 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 */
820int 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
844static 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 }
885out:
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 */
898int 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 */
909int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
910{
911 return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
912}
913
914static 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 */
922ssize_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
953void 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
64struct inode; 66struct inode;
65struct dentry; 67struct 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);
97int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name, 99int 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
102struct simple_xattrs {
103 struct list_head head;
104 spinlock_t lock;
105};
106
107struct 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 */
117static 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 */
126static 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
136struct simple_xattr *simple_xattr_alloc(const void *value, size_t size);
137int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
138 void *buffer, size_t size);
139int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
140 const void *value, size_t size, int flags);
141int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name);
142ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
143 size_t size);
144void 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
80struct 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)
636static void shmem_evict_inode(struct inode *inode) 629static 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 */
2065static 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 */
2087static int shmem_initxattrs(struct inode *inode, 2054static 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
2122static 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
2149static 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 }
2191out:
2192 spin_unlock(&info->lock);
2193 if (xattr)
2194 kfree(xattr->name);
2195 kfree(xattr);
2196 return err;
2197}
2198
2199static const struct xattr_handler *shmem_xattr_handlers[] = { 2087static 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)
2226static ssize_t shmem_getxattr(struct dentry *dentry, const char *name, 2114static 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
2246static int shmem_setxattr(struct dentry *dentry, const char *name, 2135static 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
2270static int shmem_removexattr(struct dentry *dentry, const char *name) 2156static 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
2289static bool xattr_is_trusted(const char *name)
2290{
2291 return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
2292} 2174}
2293 2175
2294static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) 2176static 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