diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-11-17 01:07:57 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-12-08 22:41:36 -0500 |
commit | 21fc61c73c3903c4c312d0802da01ec2b323d174 (patch) | |
tree | a26c29e3fbb766f00b023724e9e5b8b9bba9b879 /fs/namei.c | |
parent | aa80deab33a8fb180e718f5e45514db19aade165 (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 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 9 |
1 files changed, 3 insertions, 6 deletions
diff --git a/fs/namei.c b/fs/namei.c index 4bae5cbfaa85..2808958e6c67 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -4527,7 +4527,8 @@ static const char *page_getlink(struct dentry * dentry, void **cookie) | |||
4527 | if (IS_ERR(page)) | 4527 | if (IS_ERR(page)) |
4528 | return (char*)page; | 4528 | return (char*)page; |
4529 | *cookie = page; | 4529 | *cookie = page; |
4530 | kaddr = kmap(page); | 4530 | BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); |
4531 | kaddr = page_address(page); | ||
4531 | nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1); | 4532 | nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1); |
4532 | return kaddr; | 4533 | return kaddr; |
4533 | } | 4534 | } |
@@ -4541,7 +4542,6 @@ EXPORT_SYMBOL(page_follow_link_light); | |||
4541 | void page_put_link(struct inode *unused, void *cookie) | 4542 | void page_put_link(struct inode *unused, void *cookie) |
4542 | { | 4543 | { |
4543 | struct page *page = cookie; | 4544 | struct page *page = cookie; |
4544 | kunmap(page); | ||
4545 | page_cache_release(page); | 4545 | page_cache_release(page); |
4546 | } | 4546 | } |
4547 | EXPORT_SYMBOL(page_put_link); | 4547 | EXPORT_SYMBOL(page_put_link); |
@@ -4565,7 +4565,6 @@ int __page_symlink(struct inode *inode, const char *symname, int len, int nofs) | |||
4565 | struct page *page; | 4565 | struct page *page; |
4566 | void *fsdata; | 4566 | void *fsdata; |
4567 | int err; | 4567 | int err; |
4568 | char *kaddr; | ||
4569 | unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE; | 4568 | unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE; |
4570 | if (nofs) | 4569 | if (nofs) |
4571 | flags |= AOP_FLAG_NOFS; | 4570 | flags |= AOP_FLAG_NOFS; |
@@ -4576,9 +4575,7 @@ retry: | |||
4576 | if (err) | 4575 | if (err) |
4577 | goto fail; | 4576 | goto fail; |
4578 | 4577 | ||
4579 | kaddr = kmap_atomic(page); | 4578 | memcpy(page_address(page), symname, len-1); |
4580 | memcpy(kaddr, symname, len-1); | ||
4581 | kunmap_atomic(kaddr); | ||
4582 | 4579 | ||
4583 | err = pagecache_write_end(NULL, mapping, 0, len-1, len-1, | 4580 | err = pagecache_write_end(NULL, mapping, 0, len-1, len-1, |
4584 | page, fsdata); | 4581 | page, fsdata); |