aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorHugh Dickins <hughd@google.com>2011-08-03 19:21:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-08-03 20:25:24 -0400
commit69f07ec938712b58755add82dd3d0b35f01317cc (patch)
tree7a0a704ed4bc79dbba50454093469d0ce31ef1a4 /mm
parent6922c0c7abd387374255801f7739624867e8acad (diff)
tmpfs: use kmemdup for short symlinks
But we've not yet removed the old swp_entry_t i_direct[16] from shmem_inode_info. That's because it was still being shared with the inline symlink. Remove it now (saving 64 or 128 bytes from shmem inode size), and use kmemdup() for short symlinks, say, those up to 128 bytes. I wonder why mpol_free_shared_policy() is done in shmem_destroy_inode() rather than shmem_evict_inode(), where we usually do such freeing? I guess it doesn't matter, and I'm not into NUMA mpol testing right now. Signed-off-by: Hugh Dickins <hughd@google.com> Acked-by: Rik van Riel <riel@redhat.com> Reviewed-by: Pekka Enberg <penberg@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/shmem.c31
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
76struct shmem_xattr { 79struct 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
1175static const struct inode_operations shmem_symlink_inode_operations; 1179static const struct inode_operations shmem_symlink_inode_operations;
1176static const struct inode_operations shmem_symlink_inline_operations; 1180static const struct inode_operations shmem_short_symlink_operations;
1177 1181
1178static int 1182static int
1179shmem_write_begin(struct file *file, struct address_space *mapping, 1183shmem_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
1667static void *shmem_follow_link_inline(struct dentry *dentry, struct nameidata *nd) 1674static 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
1917static const struct inode_operations shmem_symlink_inline_operations = { 1924static 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
2260static void shmem_destroy_inode(struct inode *inode) 2267static 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