diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-11-17 01:07:57 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2018-02-16 20:09:38 +0100 |
commit | 076e4ab3279eb3ddb206de44d04df7aeb2428e09 (patch) | |
tree | 9c68c20e8d2241455fb03c68868c1da639a15afb /fs/ext4 | |
parent | 33813d43dd593e1c32c567c75483233212b825ae (diff) |
don't put symlink bodies in pagecache into highmem
commit 21fc61c73c3903c4c312d0802da01ec2b323d174 upstream.
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>
Signed-off-by: Jin Qian <jinqian@google.com>
Signed-off-by: Jin Qian <jinqian@android.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/inode.c | 1 | ||||
-rw-r--r-- | fs/ext4/namei.c | 1 | ||||
-rw-r--r-- | fs/ext4/symlink.c | 10 |
3 files changed, 5 insertions, 7 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 4df1cb19a243..f0cabc8c96cb 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4417,6 +4417,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) inode->i_op = &ext4_symlink_inode_operations; ext4_set_aops(inode); } + inode_nohighmem(inode); } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { inode->i_op = &ext4_special_inode_operations; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 4c36dca486cc..32960b3ecd4f 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3151,6 +3151,7 @@ static int ext4_symlink(struct inode *dir, if ((disk_link.len > EXT4_N_BLOCKS * 4)) { if (!encryption_required) inode->i_op = &ext4_symlink_inode_operations; + inode_nohighmem(inode); ext4_set_aops(inode); /* * We cannot call page_symlink() with transaction started diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index e8e7af62ac95..287c3980fa0b 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -45,7 +45,7 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook cpage = read_mapping_page(inode->i_mapping, 0, NULL); if (IS_ERR(cpage)) return ERR_CAST(cpage); - caddr = kmap(cpage); + caddr = page_address(cpage); caddr[size] = 0; } @@ -75,16 +75,12 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook /* Null-terminate the name */ if (res <= plen) paddr[res] = '\0'; - if (cpage) { - kunmap(cpage); + if (cpage) page_cache_release(cpage); - } return *cookie = paddr; errout: - if (cpage) { - kunmap(cpage); + if (cpage) page_cache_release(cpage); - } kfree(paddr); return ERR_PTR(res); } |