diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 120 |
1 files changed, 105 insertions, 15 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 84b5cf9b63c5..b96de69f236b 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -23,11 +23,11 @@ | |||
23 | * which makes it a completely usable filesystem. | 23 | * which makes it a completely usable filesystem. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/config.h> | ||
27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
28 | #include <linux/init.h> | 27 | #include <linux/init.h> |
29 | #include <linux/devfs_fs_kernel.h> | ||
30 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/xattr.h> | ||
30 | #include <linux/generic_acl.h> | ||
31 | #include <linux/mm.h> | 31 | #include <linux/mm.h> |
32 | #include <linux/mman.h> | 32 | #include <linux/mman.h> |
33 | #include <linux/file.h> | 33 | #include <linux/file.h> |
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/namei.h> | 47 | #include <linux/namei.h> |
48 | #include <linux/ctype.h> | 48 | #include <linux/ctype.h> |
49 | #include <linux/migrate.h> | 49 | #include <linux/migrate.h> |
50 | #include <linux/highmem.h> | ||
50 | 51 | ||
51 | #include <asm/uaccess.h> | 52 | #include <asm/uaccess.h> |
52 | #include <asm/div64.h> | 53 | #include <asm/div64.h> |
@@ -174,10 +175,11 @@ static inline void shmem_unacct_blocks(unsigned long flags, long pages) | |||
174 | } | 175 | } |
175 | 176 | ||
176 | static struct super_operations shmem_ops; | 177 | static struct super_operations shmem_ops; |
177 | static struct address_space_operations shmem_aops; | 178 | static const struct address_space_operations shmem_aops; |
178 | static struct file_operations shmem_file_operations; | 179 | static struct file_operations shmem_file_operations; |
179 | static struct inode_operations shmem_inode_operations; | 180 | static struct inode_operations shmem_inode_operations; |
180 | static struct inode_operations shmem_dir_inode_operations; | 181 | static struct inode_operations shmem_dir_inode_operations; |
182 | static struct inode_operations shmem_special_inode_operations; | ||
181 | static struct vm_operations_struct shmem_vm_ops; | 183 | static struct vm_operations_struct shmem_vm_ops; |
182 | 184 | ||
183 | static struct backing_dev_info shmem_backing_dev_info __read_mostly = { | 185 | static struct backing_dev_info shmem_backing_dev_info __read_mostly = { |
@@ -638,7 +640,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
638 | struct page *page = NULL; | 640 | struct page *page = NULL; |
639 | int error; | 641 | int error; |
640 | 642 | ||
641 | if (attr->ia_valid & ATTR_SIZE) { | 643 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { |
642 | if (attr->ia_size < inode->i_size) { | 644 | if (attr->ia_size < inode->i_size) { |
643 | /* | 645 | /* |
644 | * If truncating down to a partial page, then | 646 | * If truncating down to a partial page, then |
@@ -671,6 +673,10 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
671 | error = inode_change_ok(inode, attr); | 673 | error = inode_change_ok(inode, attr); |
672 | if (!error) | 674 | if (!error) |
673 | error = inode_setattr(inode, attr); | 675 | error = inode_setattr(inode, attr); |
676 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
677 | if (!error && (attr->ia_valid & ATTR_MODE)) | ||
678 | error = generic_acl_chmod(inode, &shmem_acl_ops); | ||
679 | #endif | ||
674 | if (page) | 680 | if (page) |
675 | page_cache_release(page); | 681 | page_cache_release(page); |
676 | return error; | 682 | return error; |
@@ -1046,12 +1052,12 @@ repeat: | |||
1046 | swappage = lookup_swap_cache(swap); | 1052 | swappage = lookup_swap_cache(swap); |
1047 | if (!swappage) { | 1053 | if (!swappage) { |
1048 | shmem_swp_unmap(entry); | 1054 | shmem_swp_unmap(entry); |
1049 | spin_unlock(&info->lock); | ||
1050 | /* here we actually do the io */ | 1055 | /* here we actually do the io */ |
1051 | if (type && *type == VM_FAULT_MINOR) { | 1056 | if (type && *type == VM_FAULT_MINOR) { |
1052 | inc_page_state(pgmajfault); | 1057 | __count_vm_event(PGMAJFAULT); |
1053 | *type = VM_FAULT_MAJOR; | 1058 | *type = VM_FAULT_MAJOR; |
1054 | } | 1059 | } |
1060 | spin_unlock(&info->lock); | ||
1055 | swappage = shmem_swapin(info, swap, idx); | 1061 | swappage = shmem_swapin(info, swap, idx); |
1056 | if (!swappage) { | 1062 | if (!swappage) { |
1057 | spin_lock(&info->lock); | 1063 | spin_lock(&info->lock); |
@@ -1352,7 +1358,6 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
1352 | inode->i_mode = mode; | 1358 | inode->i_mode = mode; |
1353 | inode->i_uid = current->fsuid; | 1359 | inode->i_uid = current->fsuid; |
1354 | inode->i_gid = current->fsgid; | 1360 | inode->i_gid = current->fsgid; |
1355 | inode->i_blksize = PAGE_CACHE_SIZE; | ||
1356 | inode->i_blocks = 0; | 1361 | inode->i_blocks = 0; |
1357 | inode->i_mapping->a_ops = &shmem_aops; | 1362 | inode->i_mapping->a_ops = &shmem_aops; |
1358 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; | 1363 | inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; |
@@ -1364,6 +1369,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
1364 | 1369 | ||
1365 | switch (mode & S_IFMT) { | 1370 | switch (mode & S_IFMT) { |
1366 | default: | 1371 | default: |
1372 | inode->i_op = &shmem_special_inode_operations; | ||
1367 | init_special_inode(inode, mode, dev); | 1373 | init_special_inode(inode, mode, dev); |
1368 | break; | 1374 | break; |
1369 | case S_IFREG: | 1375 | case S_IFREG: |
@@ -1684,7 +1690,11 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1684 | iput(inode); | 1690 | iput(inode); |
1685 | return error; | 1691 | return error; |
1686 | } | 1692 | } |
1687 | error = 0; | 1693 | } |
1694 | error = shmem_acl_init(inode, dir); | ||
1695 | if (error) { | ||
1696 | iput(inode); | ||
1697 | return error; | ||
1688 | } | 1698 | } |
1689 | if (dir->i_mode & S_ISGID) { | 1699 | if (dir->i_mode & S_ISGID) { |
1690 | inode->i_gid = dir->i_gid; | 1700 | inode->i_gid = dir->i_gid; |
@@ -1899,6 +1909,53 @@ static struct inode_operations shmem_symlink_inode_operations = { | |||
1899 | .put_link = shmem_put_link, | 1909 | .put_link = shmem_put_link, |
1900 | }; | 1910 | }; |
1901 | 1911 | ||
1912 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
1913 | /** | ||
1914 | * Superblocks without xattr inode operations will get security.* xattr | ||
1915 | * support from the VFS "for free". As soon as we have any other xattrs | ||
1916 | * like ACLs, we also need to implement the security.* handlers at | ||
1917 | * filesystem level, though. | ||
1918 | */ | ||
1919 | |||
1920 | static size_t shmem_xattr_security_list(struct inode *inode, char *list, | ||
1921 | size_t list_len, const char *name, | ||
1922 | size_t name_len) | ||
1923 | { | ||
1924 | return security_inode_listsecurity(inode, list, list_len); | ||
1925 | } | ||
1926 | |||
1927 | static int shmem_xattr_security_get(struct inode *inode, const char *name, | ||
1928 | void *buffer, size_t size) | ||
1929 | { | ||
1930 | if (strcmp(name, "") == 0) | ||
1931 | return -EINVAL; | ||
1932 | return security_inode_getsecurity(inode, name, buffer, size, | ||
1933 | -EOPNOTSUPP); | ||
1934 | } | ||
1935 | |||
1936 | static int shmem_xattr_security_set(struct inode *inode, const char *name, | ||
1937 | const void *value, size_t size, int flags) | ||
1938 | { | ||
1939 | if (strcmp(name, "") == 0) | ||
1940 | return -EINVAL; | ||
1941 | return security_inode_setsecurity(inode, name, value, size, flags); | ||
1942 | } | ||
1943 | |||
1944 | struct xattr_handler shmem_xattr_security_handler = { | ||
1945 | .prefix = XATTR_SECURITY_PREFIX, | ||
1946 | .list = shmem_xattr_security_list, | ||
1947 | .get = shmem_xattr_security_get, | ||
1948 | .set = shmem_xattr_security_set, | ||
1949 | }; | ||
1950 | |||
1951 | static struct xattr_handler *shmem_xattr_handlers[] = { | ||
1952 | &shmem_xattr_acl_access_handler, | ||
1953 | &shmem_xattr_acl_default_handler, | ||
1954 | &shmem_xattr_security_handler, | ||
1955 | NULL | ||
1956 | }; | ||
1957 | #endif | ||
1958 | |||
1902 | static int shmem_parse_options(char *options, int *mode, uid_t *uid, | 1959 | static int shmem_parse_options(char *options, int *mode, uid_t *uid, |
1903 | gid_t *gid, unsigned long *blocks, unsigned long *inodes, | 1960 | gid_t *gid, unsigned long *blocks, unsigned long *inodes, |
1904 | int *policy, nodemask_t *policy_nodes) | 1961 | int *policy, nodemask_t *policy_nodes) |
@@ -2096,6 +2153,10 @@ static int shmem_fill_super(struct super_block *sb, | |||
2096 | sb->s_magic = TMPFS_MAGIC; | 2153 | sb->s_magic = TMPFS_MAGIC; |
2097 | sb->s_op = &shmem_ops; | 2154 | sb->s_op = &shmem_ops; |
2098 | sb->s_time_gran = 1; | 2155 | sb->s_time_gran = 1; |
2156 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
2157 | sb->s_xattr = shmem_xattr_handlers; | ||
2158 | sb->s_flags |= MS_POSIXACL; | ||
2159 | #endif | ||
2099 | 2160 | ||
2100 | inode = shmem_get_inode(sb, S_IFDIR | mode, 0); | 2161 | inode = shmem_get_inode(sb, S_IFDIR | mode, 0); |
2101 | if (!inode) | 2162 | if (!inode) |
@@ -2132,6 +2193,7 @@ static void shmem_destroy_inode(struct inode *inode) | |||
2132 | /* only struct inode is valid if it's an inline symlink */ | 2193 | /* only struct inode is valid if it's an inline symlink */ |
2133 | mpol_free_shared_policy(&SHMEM_I(inode)->policy); | 2194 | mpol_free_shared_policy(&SHMEM_I(inode)->policy); |
2134 | } | 2195 | } |
2196 | shmem_acl_destroy_inode(inode); | ||
2135 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); | 2197 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); |
2136 | } | 2198 | } |
2137 | 2199 | ||
@@ -2143,6 +2205,10 @@ static void init_once(void *foo, struct kmem_cache *cachep, | |||
2143 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | 2205 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == |
2144 | SLAB_CTOR_CONSTRUCTOR) { | 2206 | SLAB_CTOR_CONSTRUCTOR) { |
2145 | inode_init_once(&p->vfs_inode); | 2207 | inode_init_once(&p->vfs_inode); |
2208 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
2209 | p->i_acl = NULL; | ||
2210 | p->i_default_acl = NULL; | ||
2211 | #endif | ||
2146 | } | 2212 | } |
2147 | } | 2213 | } |
2148 | 2214 | ||
@@ -2158,11 +2224,10 @@ static int init_inodecache(void) | |||
2158 | 2224 | ||
2159 | static void destroy_inodecache(void) | 2225 | static void destroy_inodecache(void) |
2160 | { | 2226 | { |
2161 | if (kmem_cache_destroy(shmem_inode_cachep)) | 2227 | kmem_cache_destroy(shmem_inode_cachep); |
2162 | printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n"); | ||
2163 | } | 2228 | } |
2164 | 2229 | ||
2165 | static struct address_space_operations shmem_aops = { | 2230 | static const struct address_space_operations shmem_aops = { |
2166 | .writepage = shmem_writepage, | 2231 | .writepage = shmem_writepage, |
2167 | .set_page_dirty = __set_page_dirty_nobuffers, | 2232 | .set_page_dirty = __set_page_dirty_nobuffers, |
2168 | #ifdef CONFIG_TMPFS | 2233 | #ifdef CONFIG_TMPFS |
@@ -2187,6 +2252,14 @@ static struct inode_operations shmem_inode_operations = { | |||
2187 | .truncate = shmem_truncate, | 2252 | .truncate = shmem_truncate, |
2188 | .setattr = shmem_notify_change, | 2253 | .setattr = shmem_notify_change, |
2189 | .truncate_range = shmem_truncate_range, | 2254 | .truncate_range = shmem_truncate_range, |
2255 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
2256 | .setxattr = generic_setxattr, | ||
2257 | .getxattr = generic_getxattr, | ||
2258 | .listxattr = generic_listxattr, | ||
2259 | .removexattr = generic_removexattr, | ||
2260 | .permission = shmem_permission, | ||
2261 | #endif | ||
2262 | |||
2190 | }; | 2263 | }; |
2191 | 2264 | ||
2192 | static struct inode_operations shmem_dir_inode_operations = { | 2265 | static struct inode_operations shmem_dir_inode_operations = { |
@@ -2201,6 +2274,25 @@ static struct inode_operations shmem_dir_inode_operations = { | |||
2201 | .mknod = shmem_mknod, | 2274 | .mknod = shmem_mknod, |
2202 | .rename = shmem_rename, | 2275 | .rename = shmem_rename, |
2203 | #endif | 2276 | #endif |
2277 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
2278 | .setattr = shmem_notify_change, | ||
2279 | .setxattr = generic_setxattr, | ||
2280 | .getxattr = generic_getxattr, | ||
2281 | .listxattr = generic_listxattr, | ||
2282 | .removexattr = generic_removexattr, | ||
2283 | .permission = shmem_permission, | ||
2284 | #endif | ||
2285 | }; | ||
2286 | |||
2287 | static struct inode_operations shmem_special_inode_operations = { | ||
2288 | #ifdef CONFIG_TMPFS_POSIX_ACL | ||
2289 | .setattr = shmem_notify_change, | ||
2290 | .setxattr = generic_setxattr, | ||
2291 | .getxattr = generic_getxattr, | ||
2292 | .listxattr = generic_listxattr, | ||
2293 | .removexattr = generic_removexattr, | ||
2294 | .permission = shmem_permission, | ||
2295 | #endif | ||
2204 | }; | 2296 | }; |
2205 | 2297 | ||
2206 | static struct super_operations shmem_ops = { | 2298 | static struct super_operations shmem_ops = { |
@@ -2252,10 +2344,8 @@ static int __init init_tmpfs(void) | |||
2252 | printk(KERN_ERR "Could not register tmpfs\n"); | 2344 | printk(KERN_ERR "Could not register tmpfs\n"); |
2253 | goto out2; | 2345 | goto out2; |
2254 | } | 2346 | } |
2255 | #ifdef CONFIG_TMPFS | 2347 | |
2256 | devfs_mk_dir("shm"); | 2348 | shm_mnt = vfs_kern_mount(&tmpfs_fs_type, MS_NOUSER, |
2257 | #endif | ||
2258 | shm_mnt = do_kern_mount(tmpfs_fs_type.name, MS_NOUSER, | ||
2259 | tmpfs_fs_type.name, NULL); | 2349 | tmpfs_fs_type.name, NULL); |
2260 | if (IS_ERR(shm_mnt)) { | 2350 | if (IS_ERR(shm_mnt)) { |
2261 | error = PTR_ERR(shm_mnt); | 2351 | error = PTR_ERR(shm_mnt); |