Skip to content

Commit 69f07ec

Browse files
Hugh Dickinstorvalds
authored andcommitted
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 <[email protected]> Acked-by: Rik van Riel <[email protected]> Reviewed-by: Pekka Enberg <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 6922c0c commit 69f07ec

File tree

2 files changed

+21
-21
lines changed

2 files changed

+21
-21
lines changed

include/linux/shmem_fs.h

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,15 @@
88

99
/* inode in-kernel data */
1010

11-
#define SHMEM_NR_DIRECT 16
12-
13-
#define SHMEM_SYMLINK_INLINE_LEN (SHMEM_NR_DIRECT * sizeof(swp_entry_t))
14-
1511
struct shmem_inode_info {
1612
spinlock_t lock;
1713
unsigned long flags;
1814
unsigned long alloced; /* data pages alloced to file */
19-
unsigned long swapped; /* subtotal assigned to swap */
20-
struct shared_policy policy; /* NUMA memory alloc policy */
2115
union {
22-
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
23-
char inline_symlink[SHMEM_SYMLINK_INLINE_LEN];
16+
unsigned long swapped; /* subtotal assigned to swap */
17+
char *symlink; /* unswappable short symlink */
2418
};
19+
struct shared_policy policy; /* NUMA memory alloc policy */
2520
struct list_head swaplist; /* chain of maybes on swap */
2621
struct list_head xattr_list; /* list of shmem_xattr */
2722
struct inode vfs_inode;

mm/shmem.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ static struct vfsmount *shm_mnt;
7373
/* Pretend that each entry is of this size in directory's i_size */
7474
#define BOGO_DIRENT_SIZE 20
7575

76+
/* Symlink up to this size is kmalloc'ed instead of using a swappable page */
77+
#define SHORT_SYMLINK_LEN 128
78+
7679
struct shmem_xattr {
7780
struct list_head list; /* anchored by shmem_inode_info->xattr_list */
7881
char *name; /* xattr name */
@@ -585,7 +588,8 @@ static void shmem_evict_inode(struct inode *inode)
585588
list_del_init(&info->swaplist);
586589
mutex_unlock(&shmem_swaplist_mutex);
587590
}
588-
}
591+
} else
592+
kfree(info->symlink);
589593

590594
list_for_each_entry_safe(xattr, nxattr, &info->xattr_list, list) {
591595
kfree(xattr->name);
@@ -1173,7 +1177,7 @@ static struct inode *shmem_get_inode(struct super_block *sb, const struct inode
11731177

11741178
#ifdef CONFIG_TMPFS
11751179
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;
11771181

11781182
static int
11791183
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
16381642

16391643
info = SHMEM_I(inode);
16401644
inode->i_size = len-1;
1641-
if (len <= SHMEM_SYMLINK_INLINE_LEN) {
1642-
/* do it inline */
1643-
memcpy(info->inline_symlink, symname, len);
1644-
inode->i_op = &shmem_symlink_inline_operations;
1645+
if (len <= SHORT_SYMLINK_LEN) {
1646+
info->symlink = kmemdup(symname, len, GFP_KERNEL);
1647+
if (!info->symlink) {
1648+
iput(inode);
1649+
return -ENOMEM;
1650+
}
1651+
inode->i_op = &shmem_short_symlink_operations;
16451652
} else {
16461653
error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
16471654
if (error) {
@@ -1664,9 +1671,9 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
16641671
return 0;
16651672
}
16661673

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)
16681675
{
1669-
nd_set_link(nd, SHMEM_I(dentry->d_inode)->inline_symlink);
1676+
nd_set_link(nd, SHMEM_I(dentry->d_inode)->symlink);
16701677
return NULL;
16711678
}
16721679

@@ -1914,9 +1921,9 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
19141921
}
19151922
#endif /* CONFIG_TMPFS_XATTR */
19161923

1917-
static const struct inode_operations shmem_symlink_inline_operations = {
1924+
static const struct inode_operations shmem_short_symlink_operations = {
19181925
.readlink = generic_readlink,
1919-
.follow_link = shmem_follow_link_inline,
1926+
.follow_link = shmem_follow_short_symlink,
19201927
#ifdef CONFIG_TMPFS_XATTR
19211928
.setxattr = shmem_setxattr,
19221929
.getxattr = shmem_getxattr,
@@ -2259,10 +2266,8 @@ static void shmem_destroy_callback(struct rcu_head *head)
22592266

22602267
static void shmem_destroy_inode(struct inode *inode)
22612268
{
2262-
if ((inode->i_mode & S_IFMT) == S_IFREG) {
2263-
/* only struct inode is valid if it's an inline symlink */
2269+
if ((inode->i_mode & S_IFMT) == S_IFREG)
22642270
mpol_free_shared_policy(&SHMEM_I(inode)->policy);
2265-
}
22662271
call_rcu(&inode->i_rcu, shmem_destroy_callback);
22672272
}
22682273

0 commit comments

Comments
 (0)