make sure that freeing shmem fast symlinks is RCU-delayed

Cc: stable@vger.kernel.org # v4.2+
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2016-01-22 18:08:52 -05:00
parent 5955102c99
commit 3ed47db34f
2 changed files with 5 additions and 9 deletions

View File

@ -15,10 +15,7 @@ struct shmem_inode_info {
unsigned int seals; /* shmem seals */ unsigned int seals; /* shmem seals */
unsigned long flags; unsigned long flags;
unsigned long alloced; /* data pages alloced to file */ unsigned long alloced; /* data pages alloced to file */
union { unsigned long swapped; /* subtotal assigned to swap */
unsigned long swapped; /* subtotal assigned to swap */
char *symlink; /* unswappable short symlink */
};
struct shared_policy policy; /* NUMA memory alloc policy */ struct shared_policy policy; /* NUMA memory alloc policy */
struct list_head swaplist; /* chain of maybes on swap */ struct list_head swaplist; /* chain of maybes on swap */
struct simple_xattrs xattrs; /* list of xattrs */ struct simple_xattrs xattrs; /* list of xattrs */

View File

@ -701,8 +701,7 @@ static void shmem_evict_inode(struct inode *inode)
list_del_init(&info->swaplist); list_del_init(&info->swaplist);
mutex_unlock(&shmem_swaplist_mutex); mutex_unlock(&shmem_swaplist_mutex);
} }
} else }
kfree(info->symlink);
simple_xattrs_free(&info->xattrs); simple_xattrs_free(&info->xattrs);
WARN_ON(inode->i_blocks); WARN_ON(inode->i_blocks);
@ -2549,13 +2548,12 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
info = SHMEM_I(inode); info = SHMEM_I(inode);
inode->i_size = len-1; inode->i_size = len-1;
if (len <= SHORT_SYMLINK_LEN) { if (len <= SHORT_SYMLINK_LEN) {
info->symlink = kmemdup(symname, len, GFP_KERNEL); inode->i_link = kmemdup(symname, len, GFP_KERNEL);
if (!info->symlink) { if (!inode->i_link) {
iput(inode); iput(inode);
return -ENOMEM; return -ENOMEM;
} }
inode->i_op = &shmem_short_symlink_operations; inode->i_op = &shmem_short_symlink_operations;
inode->i_link = info->symlink;
} else { } else {
inode_nohighmem(inode); inode_nohighmem(inode);
error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL); error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
@ -3132,6 +3130,7 @@ static struct inode *shmem_alloc_inode(struct super_block *sb)
static void shmem_destroy_callback(struct rcu_head *head) static void shmem_destroy_callback(struct rcu_head *head)
{ {
struct inode *inode = container_of(head, struct inode, i_rcu); struct inode *inode = container_of(head, struct inode, i_rcu);
kfree(inode->i_link);
kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
} }