diff options
Diffstat (limited to 'mm/shmem.c')
-rw-r--r-- | mm/shmem.c | 117 |
1 files changed, 106 insertions, 11 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index eda907c3a86a..bb8ca7ef7094 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/init.h> | 27 | #include <linux/init.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/xattr.h> | ||
30 | #include <linux/generic_acl.h> | ||
29 | #include <linux/mm.h> | 31 | #include <linux/mm.h> |
30 | #include <linux/mman.h> | 32 | #include <linux/mman.h> |
31 | #include <linux/file.h> | 33 | #include <linux/file.h> |
@@ -177,6 +179,7 @@ static const struct address_space_operations shmem_aops; | |||
177 | static struct file_operations shmem_file_operations; | 179 | static struct file_operations shmem_file_operations; |
178 | static struct inode_operations shmem_inode_operations; | 180 | static struct inode_operations shmem_inode_operations; |
179 | 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; | ||
180 | static struct vm_operations_struct shmem_vm_ops; | 183 | static struct vm_operations_struct shmem_vm_ops; |
181 | 184 | ||
182 | static struct backing_dev_info shmem_backing_dev_info __read_mostly = { | 185 | static struct backing_dev_info shmem_backing_dev_info __read_mostly = { |
@@ -637,7 +640,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
637 | struct page *page = NULL; | 640 | struct page *page = NULL; |
638 | int error; | 641 | int error; |
639 | 642 | ||
640 | if (attr->ia_valid & ATTR_SIZE) { | 643 | if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { |
641 | if (attr->ia_size < inode->i_size) { | 644 | if (attr->ia_size < inode->i_size) { |
642 | /* | 645 | /* |
643 | * If truncating down to a partial page, then | 646 | * If truncating down to a partial page, then |
@@ -670,6 +673,10 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr) | |||
670 | error = inode_change_ok(inode, attr); | 673 | error = inode_change_ok(inode, attr); |
671 | if (!error) | 674 | if (!error) |
672 | 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 | ||
673 | if (page) | 680 | if (page) |
674 | page_cache_release(page); | 681 | page_cache_release(page); |
675 | return error; | 682 | return error; |
@@ -1362,6 +1369,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
1362 | 1369 | ||
1363 | switch (mode & S_IFMT) { | 1370 | switch (mode & S_IFMT) { |
1364 | default: | 1371 | default: |
1372 | inode->i_op = &shmem_special_inode_operations; | ||
1365 | init_special_inode(inode, mode, dev); | 1373 | init_special_inode(inode, mode, dev); |
1366 | break; | 1374 | break; |
1367 | case S_IFREG: | 1375 | case S_IFREG: |
@@ -1371,7 +1379,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev) | |||
1371 | &sbinfo->policy_nodes); | 1379 | &sbinfo->policy_nodes); |
1372 | break; | 1380 | break; |
1373 | case S_IFDIR: | 1381 | case S_IFDIR: |
1374 | inode->i_nlink++; | 1382 | inc_nlink(inode); |
1375 | /* Some things misbehave if size == 0 on a directory */ | 1383 | /* Some things misbehave if size == 0 on a directory */ |
1376 | inode->i_size = 2 * BOGO_DIRENT_SIZE; | 1384 | inode->i_size = 2 * BOGO_DIRENT_SIZE; |
1377 | inode->i_op = &shmem_dir_inode_operations; | 1385 | inode->i_op = &shmem_dir_inode_operations; |
@@ -1682,7 +1690,11 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
1682 | iput(inode); | 1690 | iput(inode); |
1683 | return error; | 1691 | return error; |
1684 | } | 1692 | } |
1685 | error = 0; | 1693 | } |
1694 | error = shmem_acl_init(inode, dir); | ||
1695 | if (error) { | ||
1696 | iput(inode); | ||
1697 | return error; | ||
1686 | } | 1698 | } |
1687 | if (dir->i_mode & S_ISGID) { | 1699 | if (dir->i_mode & S_ISGID) { |
1688 | inode->i_gid = dir->i_gid; | 1700 | inode->i_gid = dir->i_gid; |
@@ -1703,7 +1715,7 @@ static int shmem_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
1703 | 1715 | ||
1704 | if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0))) | 1716 | if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0))) |
1705 | return error; | 1717 | return error; |
1706 | dir->i_nlink++; | 1718 | inc_nlink(dir); |
1707 | return 0; | 1719 | return 0; |
1708 | } | 1720 | } |
1709 | 1721 | ||
@@ -1738,7 +1750,7 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr | |||
1738 | 1750 | ||
1739 | dir->i_size += BOGO_DIRENT_SIZE; | 1751 | dir->i_size += BOGO_DIRENT_SIZE; |
1740 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; | 1752 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; |
1741 | inode->i_nlink++; | 1753 | inc_nlink(inode); |
1742 | atomic_inc(&inode->i_count); /* New dentry reference */ | 1754 | atomic_inc(&inode->i_count); /* New dentry reference */ |
1743 | dget(dentry); /* Extra pinning count for the created dentry */ | 1755 | dget(dentry); /* Extra pinning count for the created dentry */ |
1744 | d_instantiate(dentry, inode); | 1756 | d_instantiate(dentry, inode); |
@@ -1760,7 +1772,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry) | |||
1760 | 1772 | ||
1761 | dir->i_size -= BOGO_DIRENT_SIZE; | 1773 | dir->i_size -= BOGO_DIRENT_SIZE; |
1762 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; | 1774 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; |
1763 | inode->i_nlink--; | 1775 | drop_nlink(inode); |
1764 | dput(dentry); /* Undo the count from "create" - this does all the work */ | 1776 | dput(dentry); /* Undo the count from "create" - this does all the work */ |
1765 | return 0; | 1777 | return 0; |
1766 | } | 1778 | } |
@@ -1770,8 +1782,8 @@ static int shmem_rmdir(struct inode *dir, struct dentry *dentry) | |||
1770 | if (!simple_empty(dentry)) | 1782 | if (!simple_empty(dentry)) |
1771 | return -ENOTEMPTY; | 1783 | return -ENOTEMPTY; |
1772 | 1784 | ||
1773 | dentry->d_inode->i_nlink--; | 1785 | drop_nlink(dentry->d_inode); |
1774 | dir->i_nlink--; | 1786 | drop_nlink(dir); |
1775 | return shmem_unlink(dir, dentry); | 1787 | return shmem_unlink(dir, dentry); |
1776 | } | 1788 | } |
1777 | 1789 | ||
@@ -1792,10 +1804,10 @@ static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct | |||
1792 | if (new_dentry->d_inode) { | 1804 | if (new_dentry->d_inode) { |
1793 | (void) shmem_unlink(new_dir, new_dentry); | 1805 | (void) shmem_unlink(new_dir, new_dentry); |
1794 | if (they_are_dirs) | 1806 | if (they_are_dirs) |
1795 | old_dir->i_nlink--; | 1807 | drop_nlink(old_dir); |
1796 | } else if (they_are_dirs) { | 1808 | } else if (they_are_dirs) { |
1797 | old_dir->i_nlink--; | 1809 | drop_nlink(old_dir); |
1798 | new_dir->i_nlink++; | 1810 | inc_nlink(new_dir); |
1799 | } | 1811 | } |
1800 | 1812 | ||
1801 | old_dir->i_size -= BOGO_DIRENT_SIZE; | 1813 | old_dir->i_size -= BOGO_DIRENT_SIZE; |
@@ -1897,6 +1909,53 @@ static struct inode_operations shmem_symlink_inode_operations = { | |||
1897 | .put_link = shmem_put_link, | 1909 | .put_link = shmem_put_link, |
1898 | }; | 1910 | }; |
1899 | 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 | |||
1900 | 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, |
1901 | gid_t *gid, unsigned long *blocks, unsigned long *inodes, | 1960 | gid_t *gid, unsigned long *blocks, unsigned long *inodes, |
1902 | int *policy, nodemask_t *policy_nodes) | 1961 | int *policy, nodemask_t *policy_nodes) |
@@ -2094,6 +2153,10 @@ static int shmem_fill_super(struct super_block *sb, | |||
2094 | sb->s_magic = TMPFS_MAGIC; | 2153 | sb->s_magic = TMPFS_MAGIC; |
2095 | sb->s_op = &shmem_ops; | 2154 | sb->s_op = &shmem_ops; |
2096 | 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 | ||
2097 | 2160 | ||
2098 | inode = shmem_get_inode(sb, S_IFDIR | mode, 0); | 2161 | inode = shmem_get_inode(sb, S_IFDIR | mode, 0); |
2099 | if (!inode) | 2162 | if (!inode) |
@@ -2130,6 +2193,7 @@ static void shmem_destroy_inode(struct inode *inode) | |||
2130 | /* only struct inode is valid if it's an inline symlink */ | 2193 | /* only struct inode is valid if it's an inline symlink */ |
2131 | mpol_free_shared_policy(&SHMEM_I(inode)->policy); | 2194 | mpol_free_shared_policy(&SHMEM_I(inode)->policy); |
2132 | } | 2195 | } |
2196 | shmem_acl_destroy_inode(inode); | ||
2133 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); | 2197 | kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); |
2134 | } | 2198 | } |
2135 | 2199 | ||
@@ -2141,6 +2205,10 @@ static void init_once(void *foo, struct kmem_cache *cachep, | |||
2141 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | 2205 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == |
2142 | SLAB_CTOR_CONSTRUCTOR) { | 2206 | SLAB_CTOR_CONSTRUCTOR) { |
2143 | 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 | ||
2144 | } | 2212 | } |
2145 | } | 2213 | } |
2146 | 2214 | ||
@@ -2184,6 +2252,14 @@ static struct inode_operations shmem_inode_operations = { | |||
2184 | .truncate = shmem_truncate, | 2252 | .truncate = shmem_truncate, |
2185 | .setattr = shmem_notify_change, | 2253 | .setattr = shmem_notify_change, |
2186 | .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 | |||
2187 | }; | 2263 | }; |
2188 | 2264 | ||
2189 | static struct inode_operations shmem_dir_inode_operations = { | 2265 | static struct inode_operations shmem_dir_inode_operations = { |
@@ -2198,6 +2274,25 @@ static struct inode_operations shmem_dir_inode_operations = { | |||
2198 | .mknod = shmem_mknod, | 2274 | .mknod = shmem_mknod, |
2199 | .rename = shmem_rename, | 2275 | .rename = shmem_rename, |
2200 | #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 | ||
2201 | }; | 2296 | }; |
2202 | 2297 | ||
2203 | static struct super_operations shmem_ops = { | 2298 | static struct super_operations shmem_ops = { |