diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 13:50:47 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-02 13:50:47 -0400 |
| commit | c0e8a139a5bb8add02b4111e9e1957d810d7285e (patch) | |
| tree | f5f0695c7553c0f651ea3c714191dedf76e06c78 /mm/shmem.c | |
| parent | 033d9959ed2dc1029217d4165f80a71702dc578e (diff) | |
| parent | a6f00298b2ceaf50b4ab00e6ee3eb0206ac72fac (diff) | |
Merge branch 'for-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
Pull cgroup updates from Tejun Heo:
- xattr support added. The implementation is shared with tmpfs. The
usage is restricted and intended to be used to manage per-cgroup
metadata by system software. tmpfs changes are routed through this
branch with Hugh's permission.
- cgroup subsystem ID handling simplified.
* 'for-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup:
cgroup: Define CGROUP_SUBSYS_COUNT according the configuration
cgroup: Assign subsystem IDs during compile time
cgroup: Do not depend on a given order when populating the subsys array
cgroup: Wrap subsystem selection macro
cgroup: Remove CGROUP_BUILTIN_SUBSYS_COUNT
cgroup: net_prio: Do not define task_netpioidx() when not selected
cgroup: net_cls: Do not define task_cls_classid() when not selected
cgroup: net_cls: Move sock_update_classid() declaration to cls_cgroup.h
cgroup: trivial fixes for Documentation/cgroups/cgroups.txt
xattr: mark variable as uninitialized to make both gcc and smatch happy
fs: add missing documentation to simple_xattr functions
cgroup: add documentation on extended attributes usage
cgroup: rename subsys_bits to subsys_mask
cgroup: add xattr support
cgroup: revise how we re-populate root directory
xattr: extract simple_xattr code from tmpfs
Diffstat (limited to 'mm/shmem.c')
| -rw-r--r-- | mm/shmem.c | 171 |
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 | ||
| 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 | ||
