aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
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 /mm/shmem.c
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>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c171
1 files changed, 13 insertions, 158 deletions
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