aboutsummaryrefslogtreecommitdiff
path: root/mm
diff options
context:
space:
mode:
authorAl Viro2015-11-17 01:07:57 -0500
committerAl Viro2015-12-08 22:41:36 -0500
commit21fc61c73c3903c4c312d0802da01ec2b323d174 (patch)
treea26c29e3fbb766f00b023724e9e5b8b9bba9b879 /mm
parentaa80deab33a8fb180e718f5e45514db19aade165 (diff)
don't put symlink bodies in pagecache into highmem
kmap() in page_follow_link_light() needed to go - allowing to hold an arbitrary number of kmaps for long is a great way to deadlocking the system. new helper (inode_nohighmem(inode)) needs to be used for pagecache symlinks inodes; done for all in-tree cases. page_follow_link_light() instrumented to yell about anything missed. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm')
-rw-r--r--mm/shmem.c9
1 files changed, 3 insertions, 6 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index 9187eee4128b..64bf5acb49fe 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2444,7 +2444,6 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
int len;
struct inode *inode;
struct page *page;
- char *kaddr;
struct shmem_inode_info *info;
len = strlen(symname) + 1;
@@ -2483,9 +2482,8 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
}
inode->i_mapping->a_ops = &shmem_aops;
inode->i_op = &shmem_symlink_inode_operations;
- kaddr = kmap_atomic(page);
- memcpy(kaddr, symname, len);
- kunmap_atomic(kaddr);
+ inode_nohighmem(inode);
+ memcpy(page_address(page), symname, len);
SetPageUptodate(page);
set_page_dirty(page);
unlock_page(page);
@@ -2506,13 +2504,12 @@ static const char *shmem_follow_link(struct dentry *dentry, void **cookie)
return ERR_PTR(error);
unlock_page(page);
*cookie = page;
- return kmap(page);
+ return page_address(page);
}
static void shmem_put_link(struct inode *unused, void *cookie)
{
struct page *page = cookie;
- kunmap(page);
mark_page_accessed(page);
page_cache_release(page);
}