diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/shmem.c | 31 |
1 files changed, 18 insertions, 13 deletions
diff --git a/mm/shmem.c b/mm/shmem.c index 0f094a258526..3a5be0feb6af 100644 --- a/mm/shmem.c +++ b/mm/shmem.c | |||
@@ -73,6 +73,9 @@ static struct vfsmount *shm_mnt; | |||
73 | /* Pretend that each entry is of this size in directory's i_size */ | 73 | /* Pretend that each entry is of this size in directory's i_size */ |
74 | #define BOGO_DIRENT_SIZE 20 | 74 | #define BOGO_DIRENT_SIZE 20 |
75 | 75 | ||
76 | /* Symlink up to this size is kmalloc'ed instead of using a swappable page */ | ||
77 | #define SHORT_SYMLINK_LEN 128 | ||
78 | |||
76 | struct shmem_xattr { | 79 | struct shmem_xattr { |
77 | struct list_head list; /* anchored by shmem_inode_info->xattr_list */ | 80 | struct list_head list; /* anchored by shmem_inode_info->xattr_list */ |
78 | char *name; /* xattr name */ | 81 | char *name; /* xattr name */ |
@@ -585,7 +588,8 @@ static void shmem_evict_inode(struct inode *inode) | |||
585 | list_del_init(&info->swaplist); | 588 | list_del_init(&info->swaplist); |
586 | mutex_unlock(&shmem_swaplist_mutex); | 589 | mutex_unlock(&shmem_swaplist_mutex); |
587 | } | 590 | } |
588 | } | 591 | } else |
592 | kfree(info->symlink); | ||
589 | 593 | ||
590 | list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) { | 594 | list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) { |
591 | kfree(xattr->name); | 595 | kfree(xattr->name); |
@@ -1173,7 +1177,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode | |||
1173 | 1177 | ||
1174 | #ifdef CONFIG_TMPFS | 1178 | #ifdef CONFIG_TMPFS |
1175 | static const struct inode_operations shmem_symlink_inode_operations; | 1179 | static const struct inode_operations shmem_symlink_inode_operations; |
1176 | static const struct inode_operations shmem_symlink_inline_operations; | 1180 | static const struct inode_operations shmem_short_symlink_operations; |
1177 | 1181 | ||
1178 | static int | 1182 | static int |
1179 | shmem_write_begin(struct file *file, struct address_space *mapping, | 1183 | shmem_write_begin(struct file *file, struct address_space *mapping, |
@@ -1638,10 +1642,13 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s | |||
1638 | 1642 | ||
1639 | info = SHMEM_I(inode); | 1643 | info = SHMEM_I(inode); |
1640 | inode->i_size = len-1; | 1644 | inode->i_size = len-1; |
1641 | if (len <= SHMEM_SYMLINK_INLINE_LEN) { | 1645 | if (len <= SHORT_SYMLINK_LEN) { |
1642 | /* do it inline */ | 1646 | info->symlink = kmemdup(symname, len, GFP_KERNEL); |
1643 | memcpy(info->inline_symlink, symname, len); | 1647 | if (!info->symlink) { |
1644 | inode->i_op = &shmem_symlink_inline_operations; | 1648 | iput(inode); |
1649 | return -ENOMEM; | ||
1650 | } | ||
1651 | inode->i_op = &shmem_short_symlink_operations; | ||
1645 | } else { | 1652 | } else { |
1646 | error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL); | 1653 | error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL); |
1647 | if (error) { | 1654 | if (error) { |
@@ -1664,9 +1671,9 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s | |||
1664 | return 0; | 1671 | return 0; |
1665 | } | 1672 | } |
1666 | 1673 | ||
1667 | static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd) | 1674 | static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd) |
1668 | { | 1675 | { |
1669 | nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink); | 1676 | nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink); |
1670 | return NULL; | 1677 | return NULL; |
1671 | } | 1678 | } |
1672 | 1679 | ||
@@ -1914,9 +1921,9 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
1914 | } | 1921 | } |
1915 | #endif /* CONFIG_TMPFS_XATTR */ | 1922 | #endif /* CONFIG_TMPFS_XATTR */ |
1916 | 1923 | ||
1917 | static const struct inode_operations shmem_symlink_inline_operations = { | 1924 | static const struct inode_operations shmem_short_symlink_operations = { |
1918 | .readlink = generic_readlink, | 1925 | .readlink = generic_readlink, |
1919 | .follow_link = shmem_follow_link_inline, | 1926 | .follow_link = shmem_follow_short_symlink, |
1920 | #ifdef CONFIG_TMPFS_XATTR | 1927 | #ifdef CONFIG_TMPFS_XATTR |
1921 | .setxattr = shmem_setxattr, | 1928 | .setxattr = shmem_setxattr, |
1922 | .getxattr = shmem_getxattr, | 1929 | .getxattr = shmem_getxattr, |
@@ -2259,10 +2266,8 @@ static void shmem_destroy_callback(struct rcu_head *head) | |||
2259 | 2266 | ||
2260 | static void shmem_destroy_inode(struct inode *inode) | 2267 | static void shmem_destroy_inode(struct inode *inode) |
2261 | { | 2268 | { |
2262 | if ((inode->i_mode & S_IFMT) == S_IFREG) { | 2269 | if ((inode->i_mode & S_IFMT) == S_IFREG) |
2263 | /* only struct inode is valid if it's an inline symlink */ | ||
2264 | mpol_free_shared_policy(&SHMEM_I(inode)->policy); | 2270 | mpol_free_shared_policy(&SHMEM_I(inode)->policy); |
2265 | } | ||
2266 | call_rcu(&inode->i_rcu, shmem_destroy_callback); | 2271 | call_rcu(&inode->i_rcu, shmem_destroy_callback); |
2267 | } | 2272 | } |
2268 | 2273 | ||