Message ID | 1449639295-20512-6-git-send-email-viro@ZenIV.linux.org.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 9 December 2015 at 06:34, Al Viro <viro@zeniv.linux.org.uk> wrote: > From: Al Viro <viro@zeniv.linux.org.uk> > > 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. Hi, starting with with this change, I get this oops when installing packages into a rootfs in NFS: [ 144.455632] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 144.463726] pgd = ee760000 [ 144.466441] [00000000] *pgd=7b83f831 [ 144.470036] Internal error: Oops: 17 [#1] SMP ARM [ 144.474732] Modules linked in: [ 144.477798] CPU: 2 PID: 1 Comm: systemd Not tainted 4.4.0-rc4-00006-g21fc61c73c39-dirty #3521 [ 144.486307] Hardware name: Rockchip (Device Tree) [ 144.491004] task: ee078000 ti: ee062000 task.ti: ee062000 [ 144.496399] PC is at strlen+0x0/0x2c [ 144.499972] LR is at readlink_copy+0x24/0x94 [ 144.504236] pc : [<c049019c>] lr : [<c031ae40>] psr: 00000013 [ 144.504236] sp : ee063f38 ip : 00000000 fp : ec8a66b0 [ 144.515694] r10: 001acf88 r9 : 00000063 r8 : ee063f74 [ 144.520909] r7 : 001acef8 r6 : 001acf88 r5 : 00000000 r4 : 00000063 [ 144.527424] r3 : c0ee8e94 r2 : 00000000 r1 : 00000063 r0 : 00000000 [ 144.533939] Flags: nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 144.541060] Control: 10c5387d Table: 2e76006a DAC: 00000051 [ 144.546794] Process systemd (pid: 1, stack limit = 0xee062220) [ 144.552614] Stack: (0xee063f38 to 0xee064000) [ 144.556962] 3f20: 001acf88 ec8a66b0 [ 144.565126] 3f40: 00000063 001acef8 ee063f74 c031aedc 001acf88 eff69f20 ffffffea 00004000 [ 144.573290] 3f60: ffffff9c c0315e94 00000000 00000000 00000025 00000000 ee5f89d0 ec8367f8 [ 144.581453] 3f80: 56978623 001acf88 00000064 00000063 0000014c c0210d44 ee062000 00000000 [ 144.589616] 3fa0: 001acef8 c0210b80 001acf88 00000064 ffffff9c 001acef8 001acf88 00000063 [ 144.597780] 3fc0: 001acf88 00000064 00000063 0000014c be8930b8 001bcc94 0018695b 001acef8 [ 144.605943] 3fe0: 0000014c be893094 b6f3bf7b b6ec98e6 20000030 ffffff9c ffffffff ffeffffe [ 144.614109] [<c049019c>] (strlen) from [<c031ae40>] (readlink_copy+0x24/0x94) [ 144.621234] [<c031ae40>] (readlink_copy) from [<c031aedc>] (generic_readlink+0x2c/0x78) [ 144.629224] [<c031aedc>] (generic_readlink) from [<c0315e94>] (SyS_readlinkat+0x98/0xe0) [ 144.637301] [<c0315e94>] (SyS_readlinkat) from [<c0210b80>] (ret_fast_syscall+0x0/0x3c) [ 144.645290] Code: e7d23003 e3130020 1afffffb e12fff1e (e5d02000) [ 144.651388] ---[ end trace 299126b4c29ad1e5 ]--- [ 144.658936] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b [ 144.658936] [ 144.668056] CPU1: stopping [ 144.670759] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G D 4.4.0-rc4-00006-g21fc61c73c39-dirty #3521 [ 144.680651] Hardware name: Rockchip (Device Tree) [ 144.685355] [<c02191a0>] (unwind_backtrace) from [<c0214898>] (show_stack+0x10/0x14) [ 144.693085] [<c0214898>] (show_stack) from [<c0489ac4>] (dump_stack+0x84/0x94) [ 144.700295] [<c0489ac4>] (dump_stack) from [<c0217950>] (handle_IPI+0x188/0x1a8) [ 144.707678] [<c0217950>] (handle_IPI) from [<c020a740>] (gic_handle_irq+0x90/0x94) [ 144.715233] [<c020a740>] (gic_handle_irq) from [<c02153d4>] (__irq_svc+0x54/0x70) [ 144.722698] Exception stack(0xee0a7f80 to 0xee0a7fc8) [ 144.727739] 7f80: 00000001 00000000 00000000 c0223ae0 ee0a6000 c0ef04a4 00000000 00000000 [ 144.735900] 7fa0: ee0a7fd8 c0ef0504 c09f7624 c0ef050c 2e0ca000 ee0a7fd0 c0211668 c021166c [ 144.744060] 7fc0: 60070013 ffffffff [ 144.747543] [<c02153d4>] (__irq_svc) from [<c021166c>] (arch_cpu_idle+0x38/0x3c) [ 144.754926] [<c021166c>] (arch_cpu_idle) from [<c028158c>] (cpu_startup_entry+0x1ec/0x248) [ 144.763175] [<c028158c>] (cpu_startup_entry) from [<0020ab4c>] (0x20ab4c) [ 144.769948] CPU0: stopping [ 144.772650] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G D 4.4.0-rc4-00006-g21fc61c73c39-dirty #3521 [ 144.782543] Hardware name: Rockchip (Device Tree) [ 144.787241] [<c02191a0>] (unwind_backtrace) from [<c0214898>] (show_stack+0x10/0x14) [ 144.794970] [<c0214898>] (show_stack) from [<c0489ac4>] (dump_stack+0x84/0x94) [ 144.802179] [<c0489ac4>] (dump_stack) from [<c0217950>] (handle_IPI+0x188/0x1a8) [ 144.809560] [<c0217950>] (handle_IPI) from [<c020a740>] (gic_handle_irq+0x90/0x94) [ 144.817114] [<c020a740>] (gic_handle_irq) from [<c02153d4>] (__irq_svc+0x54/0x70) [ 144.824579] Exception stack(0xc0eeff48 to 0xc0eeff90) [ 144.829620] ff40: 00000001 00000000 00000000 c0223ae0 c0eee000 c0ef04a4 [ 144.837782] ff60: 00000000 00000000 c0eeffa0 c0ef0504 c09f7624 c0ef050c 60000013 c0eeff98 [ 144.845942] ff80: c0211668 c021166c 60000013 ffffffff [ 144.850983] [<c02153d4>] (__irq_svc) from [<c021166c>] (arch_cpu_idle+0x38/0x3c) [ 144.858365] [<c021166c>] (arch_cpu_idle) from [<c028158c>] (cpu_startup_entry+0x1ec/0x248) [ 144.866614] [<c028158c>] (cpu_startup_entry) from [<c0de6c88>] (start_kernel+0x3a8/0x3b4) [ 144.874775] CPU3: stopping [ 144.877477] CPU: 3 PID: 8117 Comm: apt-get Tainted: G D 4.4.0-rc4-00006-g21fc61c73c39-dirty #3521 [ 144.887455] Hardware name: Rockchip (Device Tree) [ 144.892154] [<c02191a0>] (unwind_backtrace) from [<c0214898>] (show_stack+0x10/0x14) [ 144.899885] [<c0214898>] (show_stack) from [<c0489ac4>] (dump_stack+0x84/0x94) [ 144.907094] [<c0489ac4>] (dump_stack) from [<c0217950>] (handle_IPI+0x188/0x1a8) [ 144.914475] [<c0217950>] (handle_IPI) from [<c020a740>] (gic_handle_irq+0x90/0x94) [ 144.922028] [<c020a740>] (gic_handle_irq) from [<c02153d4>] (__irq_svc+0x54/0x70) [ 144.929494] Exception stack(0xed57da88 to 0xed57dad0) [ 144.934535] da80: c1020dc4 a0000013 c1020dc4 000079a8 00000000 ee273dd0 [ 144.942696] daa0: f0bbd000 ee5d2300 00000000 00000000 0000000c 00000000 00000000 ed57dad8 [ 144.950856] dac0: c059f2ec c09ef788 60000013 ffffffff [ 144.955899] [<c02153d4>] (__irq_svc) from [<c09ef788>] (_raw_spin_unlock_irqrestore+0x1c/0x20) [ 144.964496] [<c09ef788>] (_raw_spin_unlock_irqrestore) from [<c059f2ec>] (uart_chars_in_buffer+0x2c/0x34) [ 144.974046] [<c059f2ec>] (uart_chars_in_buffer) from [<c0588520>] (n_tty_poll+0x180/0x19c) [ 144.982294] [<c0588520>] (n_tty_poll) from [<c0585418>] (tty_poll+0x6c/0x80) [ 144.989329] [<c0585418>] (tty_poll) from [<c0322f08>] (do_select+0x2dc/0x618) [ 144.996451] [<c0322f08>] (do_select) from [<c0323378>] (core_sys_select+0x134/0x3f4) [ 145.004179] [<c0323378>] (core_sys_select) from [<c0323940>] (SyS_pselect6+0x1d8/0x31c) [ 145.012168] [<c0323940>] (SyS_pselect6) from [<c0210b80>] (ret_fast_syscall+0x0/0x3c) [ 145.019985] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b Without it, the symlink is read correctly and there's no oops. Regards, Tomeu > Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> > --- > Documentation/filesystems/porting | 5 +++++ > fs/affs/inode.c | 1 + > fs/affs/namei.c | 1 + > fs/affs/symlink.c | 4 +--- > fs/afs/inode.c | 1 + > fs/befs/linuxvfs.c | 5 ++--- > fs/btrfs/inode.c | 2 ++ > fs/coda/cnode.c | 2 ++ > fs/coda/symlink.c | 4 +--- > fs/cramfs/inode.c | 1 + > fs/efs/inode.c | 1 + > fs/efs/symlink.c | 4 +--- > fs/exofs/inode.c | 1 + > fs/exofs/namei.c | 1 + > fs/ext2/inode.c | 1 + > fs/ext2/namei.c | 1 + > fs/ext4/inode.c | 1 + > fs/ext4/namei.c | 1 + > fs/ext4/symlink.c | 10 +++------- > fs/f2fs/inode.c | 1 + > fs/f2fs/namei.c | 5 ++--- > fs/freevxfs/vxfs_inode.c | 1 + > fs/hfsplus/inode.c | 2 ++ > fs/hpfs/inode.c | 1 + > fs/hpfs/namei.c | 5 ++--- > fs/hugetlbfs/inode.c | 1 + > fs/inode.c | 6 ++++++ > fs/isofs/inode.c | 1 + > fs/isofs/rock.c | 4 +--- > fs/jfs/inode.c | 1 + > fs/jfs/namei.c | 1 + > fs/logfs/dir.c | 1 + > fs/logfs/inode.c | 1 + > fs/minix/inode.c | 1 + > fs/namei.c | 9 +++------ > fs/ncpfs/inode.c | 1 + > fs/nfs/inode.c | 5 +++-- > fs/nfs/symlink.c | 2 +- > fs/nilfs2/inode.c | 1 + > fs/nilfs2/namei.c | 1 + > fs/ocfs2/inode.c | 1 + > fs/ocfs2/namei.c | 1 + > fs/qnx4/inode.c | 1 + > fs/qnx6/inode.c | 1 + > fs/ramfs/inode.c | 1 + > fs/reiserfs/inode.c | 1 + > fs/reiserfs/namei.c | 1 + > fs/romfs/super.c | 1 + > fs/squashfs/inode.c | 2 ++ > fs/sysv/inode.c | 1 + > fs/udf/inode.c | 1 + > fs/udf/namei.c | 1 + > fs/udf/symlink.c | 4 +--- > fs/ufs/inode.c | 1 + > fs/ufs/namei.c | 1 + > include/linux/fs.h | 1 + > mm/shmem.c | 9 +++------ > 57 files changed, 81 insertions(+), 46 deletions(-) > > diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting > index f24d1b8..3eb7c35 100644 > --- a/Documentation/filesystems/porting > +++ b/Documentation/filesystems/porting > @@ -504,3 +504,8 @@ in your dentry operations instead. > [mandatory] > __fd_install() & fd_install() can now sleep. Callers should not > hold a spinlock or other resources that do not allow a schedule. > +-- > +[mandatory] > + any symlink that might use page_follow_link_light/page_put_link() must > + have inode_nohighmem(inode) called before anything might start playing with > + its pagecache. > diff --git a/fs/affs/inode.c b/fs/affs/inode.c > index 1734950..0fdb0f5 100644 > --- a/fs/affs/inode.c > +++ b/fs/affs/inode.c > @@ -140,6 +140,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) > break; > case ST_SOFTLINK: > inode->i_mode |= S_IFLNK; > + inode_nohighmem(inode); > inode->i_op = &affs_symlink_inode_operations; > inode->i_data.a_ops = &affs_symlink_aops; > break; > diff --git a/fs/affs/namei.c b/fs/affs/namei.c > index 181e05b..00d3002 100644 > --- a/fs/affs/namei.c > +++ b/fs/affs/namei.c > @@ -344,6 +344,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) > return -ENOSPC; > > inode->i_op = &affs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_data.a_ops = &affs_symlink_aops; > inode->i_mode = S_IFLNK | 0777; > mode_to_prot(inode); > diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c > index ea5b69a..e3f9dc3 100644 > --- a/fs/affs/symlink.c > +++ b/fs/affs/symlink.c > @@ -14,7 +14,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page) > { > struct buffer_head *bh; > struct inode *inode = page->mapping->host; > - char *link = kmap(page); > + char *link = page_address(page); > struct slink_front *lf; > int i, j; > char c; > @@ -57,12 +57,10 @@ static int affs_symlink_readpage(struct file *file, struct page *page) > link[i] = '\0'; > affs_brelse(bh); > SetPageUptodate(page); > - kunmap(page); > unlock_page(page); > return 0; > fail: > SetPageError(page); > - kunmap(page); > unlock_page(page); > return -EIO; > } > diff --git a/fs/afs/inode.c b/fs/afs/inode.c > index e06f5a2..86cc726 100644 > --- a/fs/afs/inode.c > +++ b/fs/afs/inode.c > @@ -56,6 +56,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) > case AFS_FTYPE_SYMLINK: > inode->i_mode = S_IFLNK | vnode->status.mode; > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > break; > default: > printk("kAFS: AFS vnode with undefined type\n"); > diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c > index 1c8b0dc..25250fa 100644 > --- a/fs/befs/linuxvfs.c > +++ b/fs/befs/linuxvfs.c > @@ -397,6 +397,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) > } else if (S_ISLNK(inode->i_mode)) { > if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &befs_symlink_aops; > } else { > inode->i_link = befs_ino->i_data.symlink; > @@ -469,7 +470,7 @@ static int befs_symlink_readpage(struct file *unused, struct page *page) > struct befs_inode_info *befs_ino = BEFS_I(inode); > befs_data_stream *data = &befs_ino->i_data.ds; > befs_off_t len = data->size; > - char *link = kmap(page); > + char *link = page_address(page); > > if (len == 0 || len > PAGE_SIZE) { > befs_error(sb, "Long symlink with illegal length"); > @@ -483,12 +484,10 @@ static int befs_symlink_readpage(struct file *unused, struct page *page) > } > link[len - 1] = '\0'; > SetPageUptodate(page); > - kunmap(page); > unlock_page(page); > return 0; > fail: > SetPageError(page); > - kunmap(page); > unlock_page(page); > return -EIO; > } > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c > index a70c579..70f98bf 100644 > --- a/fs/btrfs/inode.c > +++ b/fs/btrfs/inode.c > @@ -3774,6 +3774,7 @@ cache_acl: > break; > case S_IFLNK: > inode->i_op = &btrfs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &btrfs_symlink_aops; > break; > default: > @@ -9705,6 +9706,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, > btrfs_free_path(path); > > inode->i_op = &btrfs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &btrfs_symlink_aops; > inode_set_bytes(inode, name_len); > btrfs_i_size_write(inode, name_len); > diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c > index 7740b1c..dd6a79e 100644 > --- a/fs/coda/cnode.c > +++ b/fs/coda/cnode.c > @@ -8,6 +8,7 @@ > > #include <linux/coda.h> > #include <linux/coda_psdev.h> > +#include <linux/pagemap.h> > #include "coda_linux.h" > > static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) > @@ -35,6 +36,7 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr) > inode->i_fop = &coda_dir_operations; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &coda_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_data.a_ops = &coda_symlink_aops; > inode->i_mapping = &inode->i_data; > } else > diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c > index ab94ef6..03736e2 100644 > --- a/fs/coda/symlink.c > +++ b/fs/coda/symlink.c > @@ -26,7 +26,7 @@ static int coda_symlink_filler(struct file *file, struct page *page) > int error; > struct coda_inode_info *cii; > unsigned int len = PAGE_SIZE; > - char *p = kmap(page); > + char *p = page_address(page); > > cii = ITOC(inode); > > @@ -34,13 +34,11 @@ static int coda_symlink_filler(struct file *file, struct page *page) > if (error) > goto fail; > SetPageUptodate(page); > - kunmap(page); > unlock_page(page); > return 0; > > fail: > SetPageError(page); > - kunmap(page); > unlock_page(page); > return error; > } > diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c > index 355c522..b862bc2 100644 > --- a/fs/cramfs/inode.c > +++ b/fs/cramfs/inode.c > @@ -100,6 +100,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, > break; > case S_IFLNK: > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_data.a_ops = &cramfs_aops; > break; > default: > diff --git a/fs/efs/inode.c b/fs/efs/inode.c > index 079d203..cdf0872 100644 > --- a/fs/efs/inode.c > +++ b/fs/efs/inode.c > @@ -151,6 +151,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino) > break; > case S_IFLNK: > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_data.a_ops = &efs_symlink_aops; > break; > case S_IFCHR: > diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c > index 75117d0..4870cc8 100644 > --- a/fs/efs/symlink.c > +++ b/fs/efs/symlink.c > @@ -13,7 +13,7 @@ > > static int efs_symlink_readpage(struct file *file, struct page *page) > { > - char *link = kmap(page); > + char *link = page_address(page); > struct buffer_head * bh; > struct inode * inode = page->mapping->host; > efs_block_t size = inode->i_size; > @@ -39,12 +39,10 @@ static int efs_symlink_readpage(struct file *file, struct page *page) > } > link[size] = '\0'; > SetPageUptodate(page); > - kunmap(page); > unlock_page(page); > return 0; > fail: > SetPageError(page); > - kunmap(page); > unlock_page(page); > return err; > } > diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c > index 73c64da..d8e9c181 100644 > --- a/fs/exofs/inode.c > +++ b/fs/exofs/inode.c > @@ -1227,6 +1227,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino) > inode->i_link = (char *)oi->i_data; > } else { > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &exofs_aops; > } > } else { > diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c > index 994e078..c20d77d 100644 > --- a/fs/exofs/namei.c > +++ b/fs/exofs/namei.c > @@ -111,6 +111,7 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry, > if (l > sizeof(oi->i_data)) { > /* slow symlink */ > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &exofs_aops; > memset(oi->i_data, 0, sizeof(oi->i_data)); > > diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c > index 0aa9bf6..338eefd 100644 > --- a/fs/ext2/inode.c > +++ b/fs/ext2/inode.c > @@ -1420,6 +1420,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) > sizeof(ei->i_data) - 1); > } else { > inode->i_op = &ext2_symlink_inode_operations; > + inode_nohighmem(inode); > if (test_opt(inode->i_sb, NOBH)) > inode->i_mapping->a_ops = &ext2_nobh_aops; > else > diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c > index 3267a80d..7a2be8f 100644 > --- a/fs/ext2/namei.c > +++ b/fs/ext2/namei.c > @@ -183,6 +183,7 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry, > if (l > sizeof (EXT2_I(inode)->i_data)) { > /* slow symlink */ > inode->i_op = &ext2_symlink_inode_operations; > + inode_nohighmem(inode); > if (test_opt(inode->i_sb, NOBH)) > inode->i_mapping->a_ops = &ext2_nobh_aops; > else > diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c > index ea433a7..b3bd912 100644 > --- a/fs/ext4/inode.c > +++ b/fs/ext4/inode.c > @@ -4283,6 +4283,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 a969ab3..f27e0c2 100644 > --- a/fs/ext4/namei.c > +++ b/fs/ext4/namei.c > @@ -3132,6 +3132,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 abe2401..0e6dc44 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); > } > diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c > index 97e20de..5528801 100644 > --- a/fs/f2fs/inode.c > +++ b/fs/f2fs/inode.c > @@ -202,6 +202,7 @@ make_now: > inode->i_op = &f2fs_encrypted_symlink_inode_operations; > else > inode->i_op = &f2fs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &f2fs_dblock_aops; > } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || > S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { > diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c > index 2c32110..484df68 100644 > --- a/fs/f2fs/namei.c > +++ b/fs/f2fs/namei.c > @@ -351,6 +351,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, > inode->i_op = &f2fs_encrypted_symlink_inode_operations; > else > inode->i_op = &f2fs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &f2fs_dblock_aops; > > f2fs_lock_op(sbi); > @@ -942,7 +943,7 @@ static const char *f2fs_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; > > /* Symlink is encrypted */ > @@ -982,13 +983,11 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook > /* Null-terminate the name */ > paddr[res] = '\0'; > > - kunmap(cpage); > page_cache_release(cpage); > return *cookie = paddr; > errout: > kfree(cstr.name); > f2fs_fname_crypto_free_buffer(&pstr); > - kunmap(cpage); > page_cache_release(cpage); > return ERR_PTR(res); > } > diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c > index ef73ed6..3e2ccad 100644 > --- a/fs/freevxfs/vxfs_inode.c > +++ b/fs/freevxfs/vxfs_inode.c > @@ -326,6 +326,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino) > } else if (S_ISLNK(ip->i_mode)) { > if (!VXFS_ISIMMED(vip)) { > ip->i_op = &page_symlink_inode_operations; > + inode_nohighmem(ip); > ip->i_mapping->a_ops = &vxfs_aops; > } else { > ip->i_op = &simple_symlink_inode_operations; > diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c > index 6dd107d..19b33f8 100644 > --- a/fs/hfsplus/inode.c > +++ b/fs/hfsplus/inode.c > @@ -403,6 +403,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode) > } else if (S_ISLNK(inode->i_mode)) { > sbi->file_count++; > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &hfsplus_aops; > hip->clump_blocks = 1; > } else > @@ -526,6 +527,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) > inode->i_mapping->a_ops = &hfsplus_aops; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &hfsplus_aops; > } else { > init_special_inode(inode, inode->i_mode, > diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c > index 933c737..1f3c6d7 100644 > --- a/fs/hpfs/inode.c > +++ b/fs/hpfs/inode.c > @@ -77,6 +77,7 @@ void hpfs_read_inode(struct inode *i) > kfree(ea); > i->i_mode = S_IFLNK | 0777; > i->i_op = &page_symlink_inode_operations; > + inode_nohighmem(i); > i->i_data.a_ops = &hpfs_symlink_aops; > set_nlink(i, 1); > i->i_size = ea_size; > diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c > index ae4d5a1..506765a 100644 > --- a/fs/hpfs/namei.c > +++ b/fs/hpfs/namei.c > @@ -332,6 +332,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy > result->i_blocks = 1; > set_nlink(result, 1); > result->i_size = strlen(symlink); > + inode_nohighmem(result); > result->i_op = &page_symlink_inode_operations; > result->i_data.a_ops = &hpfs_symlink_aops; > > @@ -500,7 +501,7 @@ out: > > static int hpfs_symlink_readpage(struct file *file, struct page *page) > { > - char *link = kmap(page); > + char *link = page_address(page); > struct inode *i = page->mapping->host; > struct fnode *fnode; > struct buffer_head *bh; > @@ -516,14 +517,12 @@ static int hpfs_symlink_readpage(struct file *file, struct page *page) > goto fail; > hpfs_unlock(i->i_sb); > SetPageUptodate(page); > - kunmap(page); > unlock_page(page); > return 0; > > fail: > hpfs_unlock(i->i_sb); > SetPageError(page); > - kunmap(page); > unlock_page(page); > return err; > } > diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c > index de4bdfa..d8f51ee 100644 > --- a/fs/hugetlbfs/inode.c > +++ b/fs/hugetlbfs/inode.c > @@ -760,6 +760,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, > break; > case S_IFLNK: > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > break; > } > lockdep_annotate_inode_mutex_key(inode); > diff --git a/fs/inode.c b/fs/inode.c > index 1be5f90..5bb85a0 100644 > --- a/fs/inode.c > +++ b/fs/inode.c > @@ -2028,3 +2028,9 @@ void inode_set_flags(struct inode *inode, unsigned int flags, > new_flags) != old_flags)); > } > EXPORT_SYMBOL(inode_set_flags); > + > +void inode_nohighmem(struct inode *inode) > +{ > + mapping_set_gfp_mask(inode->i_mapping, GFP_USER); > +} > +EXPORT_SYMBOL(inode_nohighmem); > diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c > index d67a16f..61abdc4 100644 > --- a/fs/isofs/inode.c > +++ b/fs/isofs/inode.c > @@ -1417,6 +1417,7 @@ static int isofs_read_inode(struct inode *inode, int relocated) > inode->i_fop = &isofs_dir_operations; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_data.a_ops = &isofs_symlink_aops; > } else > /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ > diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c > index 735d752..5384ceb 100644 > --- a/fs/isofs/rock.c > +++ b/fs/isofs/rock.c > @@ -687,7 +687,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) > struct inode *inode = page->mapping->host; > struct iso_inode_info *ei = ISOFS_I(inode); > struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb); > - char *link = kmap(page); > + char *link = page_address(page); > unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); > struct buffer_head *bh; > char *rpnt = link; > @@ -774,7 +774,6 @@ repeat: > brelse(bh); > *rpnt = '\0'; > SetPageUptodate(page); > - kunmap(page); > unlock_page(page); > return 0; > > @@ -791,7 +790,6 @@ fail: > brelse(bh); > error: > SetPageError(page); > - kunmap(page); > unlock_page(page); > return -EIO; > } > diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c > index 41aa3ca..9d9bae6 100644 > --- a/fs/jfs/inode.c > +++ b/fs/jfs/inode.c > @@ -60,6 +60,7 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino) > } else if (S_ISLNK(inode->i_mode)) { > if (inode->i_size >= IDATASIZE) { > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &jfs_aops; > } else { > inode->i_op = &jfs_fast_symlink_inode_operations; > diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c > index 9d7551f..701f893 100644 > --- a/fs/jfs/namei.c > +++ b/fs/jfs/namei.c > @@ -983,6 +983,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, > jfs_info("jfs_symlink: allocate extent ip:0x%p", ip); > > ip->i_op = &jfs_symlink_inode_operations; > + inode_nohighmem(ip); > ip->i_mapping->a_ops = &jfs_aops; > > /* > diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c > index 99944a4..542468e 100644 > --- a/fs/logfs/dir.c > +++ b/fs/logfs/dir.c > @@ -529,6 +529,7 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry, > return PTR_ERR(inode); > > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &logfs_reg_aops; > > return __logfs_create(dir, dentry, inode, target, destlen); > diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c > index 06baa92..0fce46d 100644 > --- a/fs/logfs/inode.c > +++ b/fs/logfs/inode.c > @@ -65,6 +65,7 @@ static void logfs_inode_setops(struct inode *inode) > break; > case S_IFLNK: > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &logfs_reg_aops; > break; > case S_IFSOCK: /* fall through */ > diff --git a/fs/minix/inode.c b/fs/minix/inode.c > index 086cd0a..67a23bf 100644 > --- a/fs/minix/inode.c > +++ b/fs/minix/inode.c > @@ -452,6 +452,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev) > inode->i_mapping->a_ops = &minix_aops; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &minix_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &minix_aops; > } else > init_special_inode(inode, inode->i_mode, rdev); > diff --git a/fs/namei.c b/fs/namei.c > index 4bae5cb..2808958 100644 > --- a/fs/namei.c > +++ b/fs/namei.c > @@ -4527,7 +4527,8 @@ static const char *page_getlink(struct dentry * dentry, void **cookie) > if (IS_ERR(page)) > return (char*)page; > *cookie = page; > - kaddr = kmap(page); > + BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); > + kaddr = page_address(page); > nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1); > return kaddr; > } > @@ -4541,7 +4542,6 @@ EXPORT_SYMBOL(page_follow_link_light); > void page_put_link(struct inode *unused, void *cookie) > { > struct page *page = cookie; > - kunmap(page); > page_cache_release(page); > } > EXPORT_SYMBOL(page_put_link); > @@ -4565,7 +4565,6 @@ int __page_symlink(struct inode *inode, const char *symname, int len, int nofs) > struct page *page; > void *fsdata; > int err; > - char *kaddr; > unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE; > if (nofs) > flags |= AOP_FLAG_NOFS; > @@ -4576,9 +4575,7 @@ retry: > if (err) > goto fail; > > - kaddr = kmap_atomic(page); > - memcpy(kaddr, symname, len-1); > - kunmap_atomic(kaddr); > + memcpy(page_address(page), symname, len-1); > > err = pagecache_write_end(NULL, mapping, 0, len-1, len-1, > page, fsdata); > diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c > index 9605a2f..bb856f7 100644 > --- a/fs/ncpfs/inode.c > +++ b/fs/ncpfs/inode.c > @@ -283,6 +283,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info) > #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &ncp_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_data.a_ops = &ncp_symlink_aops; > #endif > } else { > diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c > index 31b0a52..ae9aa0b 100644 > --- a/fs/nfs/inode.c > +++ b/fs/nfs/inode.c > @@ -408,9 +408,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st > inode->i_fop = NULL; > inode->i_flags |= S_AUTOMOUNT; > } > - } else if (S_ISLNK(inode->i_mode)) > + } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &nfs_symlink_inode_operations; > - else > + inode_nohighmem(inode); > + } else > init_special_inode(inode, inode->i_mode, fattr->rdev); > > memset(&inode->i_atime, 0, sizeof(inode->i_atime)); > diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c > index b6de433..abd93bf 100644 > --- a/fs/nfs/symlink.c > +++ b/fs/nfs/symlink.c > @@ -56,7 +56,7 @@ static const char *nfs_follow_link(struct dentry *dentry, void **cookie) > if (IS_ERR(page)) > return ERR_CAST(page); > *cookie = page; > - return kmap(page); > + return page_address(page); > } > > /* > diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c > index ac2f649..10b2252 100644 > --- a/fs/nilfs2/inode.c > +++ b/fs/nilfs2/inode.c > @@ -510,6 +510,7 @@ static int __nilfs_read_inode(struct super_block *sb, > inode->i_mapping->a_ops = &nilfs_aops; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &nilfs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &nilfs_aops; > } else { > inode->i_op = &nilfs_special_inode_operations; > diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c > index c9a1a49..90b3ba9 100644 > --- a/fs/nilfs2/namei.c > +++ b/fs/nilfs2/namei.c > @@ -161,6 +161,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry, > > /* slow symlink */ > inode->i_op = &nilfs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &nilfs_aops; > err = page_symlink(inode, symname, l); > if (err) > diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c > index 8f87e05..97a563b 100644 > --- a/fs/ocfs2/inode.c > +++ b/fs/ocfs2/inode.c > @@ -361,6 +361,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, > break; > case S_IFLNK: > inode->i_op = &ocfs2_symlink_inode_operations; > + inode_nohighmem(inode); > i_size_write(inode, le64_to_cpu(fe->i_size)); > break; > default: > diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c > index a03f6f4..2efe8af 100644 > --- a/fs/ocfs2/namei.c > +++ b/fs/ocfs2/namei.c > @@ -1960,6 +1960,7 @@ static int ocfs2_symlink(struct inode *dir, > inode->i_rdev = 0; > newsize = l - 1; > inode->i_op = &ocfs2_symlink_inode_operations; > + inode_nohighmem(inode); > if (l > ocfs2_fast_symlink_chars(sb)) { > u32 offset = 0; > > diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c > index c4bcb77..f37b3de 100644 > --- a/fs/qnx4/inode.c > +++ b/fs/qnx4/inode.c > @@ -316,6 +316,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino) > inode->i_fop = &qnx4_dir_operations; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &qnx4_aops; > qnx4_i(inode)->mmu_private = inode->i_size; > } else { > diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c > index 32d2e1a..9728b54 100644 > --- a/fs/qnx6/inode.c > +++ b/fs/qnx6/inode.c > @@ -582,6 +582,7 @@ struct inode *qnx6_iget(struct super_block *sb, unsigned ino) > inode->i_mapping->a_ops = &qnx6_aops; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &qnx6_aops; > } else > init_special_inode(inode, inode->i_mode, 0); > diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c > index 889d558..38981b0 100644 > --- a/fs/ramfs/inode.c > +++ b/fs/ramfs/inode.c > @@ -79,6 +79,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, > break; > case S_IFLNK: > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > break; > } > } > diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c > index 3d8e7e6..ae9e5b3 100644 > --- a/fs/reiserfs/inode.c > +++ b/fs/reiserfs/inode.c > @@ -1361,6 +1361,7 @@ static void init_inode(struct inode *inode, struct treepath *path) > inode->i_fop = &reiserfs_dir_operations; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &reiserfs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &reiserfs_address_space_operations; > } else { > inode->i_blocks = 0; > diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c > index 47f9698..4fc2326 100644 > --- a/fs/reiserfs/namei.c > +++ b/fs/reiserfs/namei.c > @@ -1170,6 +1170,7 @@ static int reiserfs_symlink(struct inode *parent_dir, > reiserfs_update_inode_transaction(parent_dir); > > inode->i_op = &reiserfs_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &reiserfs_address_space_operations; > > retval = reiserfs_add_entry(&th, parent_dir, dentry->d_name.name, > diff --git a/fs/romfs/super.c b/fs/romfs/super.c > index 268733c..bb894e7 100644 > --- a/fs/romfs/super.c > +++ b/fs/romfs/super.c > @@ -360,6 +360,7 @@ static struct inode *romfs_iget(struct super_block *sb, unsigned long pos) > break; > case ROMFH_SYM: > i->i_op = &page_symlink_inode_operations; > + inode_nohighmem(i); > i->i_data.a_ops = &romfs_aops; > mode |= S_IRWXUGO; > break; > diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c > index a1ce5ce..0927b1e 100644 > --- a/fs/squashfs/inode.c > +++ b/fs/squashfs/inode.c > @@ -41,6 +41,7 @@ > #include <linux/fs.h> > #include <linux/vfs.h> > #include <linux/xattr.h> > +#include <linux/pagemap.h> > > #include "squashfs_fs.h" > #include "squashfs_fs_sb.h" > @@ -291,6 +292,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) > set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); > inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); > inode->i_op = &squashfs_symlink_inode_ops; > + inode_nohighmem(inode); > inode->i_data.a_ops = &squashfs_symlink_aops; > inode->i_mode |= S_IFLNK; > squashfs_i(inode)->start = block; > diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c > index 02fa1dc..ef8bcdb 100644 > --- a/fs/sysv/inode.c > +++ b/fs/sysv/inode.c > @@ -163,6 +163,7 @@ void sysv_set_inode(struct inode *inode, dev_t rdev) > inode->i_mapping->a_ops = &sysv_aops; > } else if (S_ISLNK(inode->i_mode)) { > inode->i_op = &sysv_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &sysv_aops; > } else > init_special_inode(inode, inode->i_mode, rdev); > diff --git a/fs/udf/inode.c b/fs/udf/inode.c > index 8675c2b..0557463 100644 > --- a/fs/udf/inode.c > +++ b/fs/udf/inode.c > @@ -1541,6 +1541,7 @@ reread: > case ICBTAG_FILE_TYPE_SYMLINK: > inode->i_data.a_ops = &udf_symlink_aops; > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mode = S_IFLNK | S_IRWXUGO; > break; > case ICBTAG_FILE_TYPE_MAIN: > diff --git a/fs/udf/namei.c b/fs/udf/namei.c > index d0e6de1..42eafb9 100644 > --- a/fs/udf/namei.c > +++ b/fs/udf/namei.c > @@ -922,6 +922,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, > > inode->i_data.a_ops = &udf_symlink_aops; > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > > if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { > struct kernel_lb_addr eloc; > diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c > index 862535b..8d61977 100644 > --- a/fs/udf/symlink.c > +++ b/fs/udf/symlink.c > @@ -107,7 +107,7 @@ static int udf_symlink_filler(struct file *file, struct page *page) > struct buffer_head *bh = NULL; > unsigned char *symlink; > int err; > - unsigned char *p = kmap(page); > + unsigned char *p = page_address(page); > struct udf_inode_info *iinfo; > uint32_t pos; > > @@ -141,7 +141,6 @@ static int udf_symlink_filler(struct file *file, struct page *page) > > up_read(&iinfo->i_data_sem); > SetPageUptodate(page); > - kunmap(page); > unlock_page(page); > return 0; > > @@ -149,7 +148,6 @@ out_unlock_inode: > up_read(&iinfo->i_data_sem); > SetPageError(page); > out_unmap: > - kunmap(page); > unlock_page(page); > return err; > } > diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c > index 737160a..d897e16 100644 > --- a/fs/ufs/inode.c > +++ b/fs/ufs/inode.c > @@ -533,6 +533,7 @@ static void ufs_set_inode_ops(struct inode *inode) > } else { > inode->i_mapping->a_ops = &ufs_aops; > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > } > } else > init_special_inode(inode, inode->i_mode, > diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c > index 24b0cbd..acf4a3b 100644 > --- a/fs/ufs/namei.c > +++ b/fs/ufs/namei.c > @@ -124,6 +124,7 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry, > if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) { > /* slow symlink */ > inode->i_op = &page_symlink_inode_operations; > + inode_nohighmem(inode); > inode->i_mapping->a_ops = &ufs_aops; > err = page_symlink(inode, symname, l); > if (err) > diff --git a/include/linux/fs.h b/include/linux/fs.h > index 3aa5142..dfeda44 100644 > --- a/include/linux/fs.h > +++ b/include/linux/fs.h > @@ -3025,5 +3025,6 @@ static inline bool dir_relax(struct inode *inode) > } > > extern bool path_noexec(const struct path *path); > +extern void inode_nohighmem(struct inode *inode); > > #endif /* _LINUX_FS_H */ > diff --git a/mm/shmem.c b/mm/shmem.c > index 9187eee..64bf5ac 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); > } > -- > 2.1.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > Please read the FAQ at http://www.tux.org/lkml/ -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Jan 14, 2016 at 02:22:51PM +0100, Tomeu Vizoso wrote: > On 9 December 2015 at 06:34, Al Viro <viro@zeniv.linux.org.uk> wrote: > > From: Al Viro <viro@zeniv.linux.org.uk> > > > > 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. > > Hi, starting with with this change, I get this oops when installing > packages into a rootfs in NFS: Lovely... So you somehow getting a highmem page out page = read_cache_page(&inode->i_data, 0, (filler_t *)nfs_symlink_filler, inode); if (IS_ERR(page)) return ERR_CAST(page); and that - after inode_nohighmem(inode); (otherwise you wouldn't get nfs_symlink_inode_operations on that inode). Could you add printk(KERN_ERR "i_data = %p, i_mapping = %p, flags: %lx\n", &inode->i_data, inode->i_mapping, (unsigned long)inode->i_data.flags); right before the return from nfs_get_link() and see what it prints? -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 14 January 2016 at 16:25, Al Viro <viro@zeniv.linux.org.uk> wrote: > On Thu, Jan 14, 2016 at 02:22:51PM +0100, Tomeu Vizoso wrote: >> On 9 December 2015 at 06:34, Al Viro <viro@zeniv.linux.org.uk> wrote: >> > From: Al Viro <viro@zeniv.linux.org.uk> >> > >> > 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. >> >> Hi, starting with with this change, I get this oops when installing >> packages into a rootfs in NFS: > > Lovely... So you somehow getting a highmem page out > page = read_cache_page(&inode->i_data, 0, > (filler_t *)nfs_symlink_filler, inode); > if (IS_ERR(page)) > return ERR_CAST(page); > and that - after > inode_nohighmem(inode); > (otherwise you wouldn't get nfs_symlink_inode_operations on that inode). > > Could you add > printk(KERN_ERR "i_data = %p, i_mapping = %p, flags: %lx\n", > &inode->i_data, > inode->i_mapping, > (unsigned long)inode->i_data.flags); > right before the return from nfs_get_link() and see what it prints? Here it is: [ 170.136956] i_data = ed9c1b04, i_mapping = ed9c1b04, flags: 24200c0 [ 170.144567] i_data = ed9de784, i_mapping = ed9de784, flags: 24200c0 [ 170.151457] i_data = ed9dec84, i_mapping = ed9dec84, flags: 24200c0 [ 170.158358] i_data = ed9c3b84, i_mapping = ed9c3b84, flags: 24200c0 [ 170.165253] i_data = ed9d4204, i_mapping = ed9d4204, flags: 24200c0 [ 170.172131] i_data = ed9df184, i_mapping = ed9df184, flags: 24200c0 [ 170.188804] i_data = eddbce84, i_mapping = eddbce84, flags: 24200c0 [ 170.196158] i_data = ec904984, i_mapping = ec904984, flags: 24200c0 [ 170.205133] i_data = ec906784, i_mapping = ec906784, flags: 24200c0 [ 170.211406] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 170.219490] pgd = ee7f0000 [ 170.222197] [00000000] *pgd=7b85b835 [ 170.225784] Internal error: Oops: 17 [#1] SMP ARM [ 170.230477] Modules linked in: [ 170.233537] CPU: 2 PID: 1 Comm: systemd Not tainted 4.4.0-next-20160114-00005-g6f86169c2250-dirty #3525 [ 170.242910] Hardware name: Rockchip (Device Tree) [ 170.247604] task: ee078000 ti: ee062000 task.ti: ee062000 [ 170.252996] PC is at strlen+0x0/0x2c [ 170.256565] LR is at readlink_copy+0x24/0x94 [ 170.260826] pc : [<c049b138>] lr : [<c0321160>] psr: 00000013 [ 170.260826] sp : ee063f38 ip : 00000000 fp : ec9066b0 [ 170.272281] r10: 001a49f8 r9 : 00000063 r8 : ee063f74 [ 170.277494] r7 : 001a4968 r6 : 001a49f8 r5 : 00000000 r4 : 00000063 [ 170.284008] r3 : 0000012c r2 : 00000000 r1 : 00000063 r0 : 00000000 [ 170.290522] Flags: nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 170.297642] Control: 10c5387d Table: 2e7f006a DAC: 00000051 [ 170.303375] Process systemd (pid: 1, stack limit = 0xee062220) [ 170.309196] Stack: (0xee063f38 to 0xee064000) [ 170.313542] 3f20: 001a49f8 00000063 [ 170.321705] 3f40: ffffff9c 001a4968 ee063f74 c0321208 c0321250 eff6b920 ffffffea ffffffea [ 170.329868] 3f60: 00004000 c031c234 00000000 00000000 00000025 00000000 ee102b50 ec874990 [ 170.338030] 3f80: 5697c41b 001a49f8 00000064 00000063 0000014c c0210e84 ee062000 00000000 [ 170.346193] 3fa0: 001a4968 c0210cc0 001a49f8 00000064 ffffff9c 001a4968 001a49f8 00000063 [ 170.354355] 3fc0: 001a49f8 00000064 00000063 0000014c bec450b8 001c1094 001d0933 001a4968 [ 170.362518] 3fe0: 0000014c bec45094 b6f2af7b b6eb88e6 20000030 ffffff9c ffffffff ffeffffe [ 170.370683] [<c049b138>] (strlen) from [<c0321160>] (readlink_copy+0x24/0x94) [ 170.377806] [<c0321160>] (readlink_copy) from [<c0321208>] (generic_readlink+0x38/0x80) [ 170.385796] [<c0321208>] (generic_readlink) from [<c031c234>] (SyS_readlinkat+0x98/0xe0) [ 170.393874] [<c031c234>] (SyS_readlinkat) from [<c0210cc0>] (ret_fast_syscall+0x0/0x3c) [ 170.401863] Code: e7d23003 e3130020 1afffffb e12fff1e (e5d02000) [ 170.407965] ---[ end trace 87f95166dedbabb0 ]--- Full log at https://lava.collabora.co.uk/scheduler/job/127626/log_file Regards, Tomeu -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Jan 14, 2016 at 04:58:48PM +0100, Tomeu Vizoso wrote: > > Could you add > > printk(KERN_ERR "i_data = %p, i_mapping = %p, flags: %lx\n", > > &inode->i_data, > > inode->i_mapping, > > (unsigned long)inode->i_data.flags); > > right before the return from nfs_get_link() and see what it prints? > > Here it is: > > [ 170.136956] i_data = ed9c1b04, i_mapping = ed9c1b04, flags: 24200c0 > [ 170.144567] i_data = ed9de784, i_mapping = ed9de784, flags: 24200c0 > [ 170.151457] i_data = ed9dec84, i_mapping = ed9dec84, flags: 24200c0 > [ 170.158358] i_data = ed9c3b84, i_mapping = ed9c3b84, flags: 24200c0 > [ 170.165253] i_data = ed9d4204, i_mapping = ed9d4204, flags: 24200c0 > [ 170.172131] i_data = ed9df184, i_mapping = ed9df184, flags: 24200c0 > [ 170.188804] i_data = eddbce84, i_mapping = eddbce84, flags: 24200c0 > [ 170.196158] i_data = ec904984, i_mapping = ec904984, flags: 24200c0 > [ 170.205133] i_data = ec906784, i_mapping = ec906784, flags: 24200c0 Aha. So ->i_data vs. ->i_mapping is irrelevant (as it ought to be here) and inode_nohighmem() should've acted on the address_space we are hitting here. What do we have in flags... ___GFP_IO | ___GFP_FS | ___GFP_HARDWALL | ___GFP_DIRECT_RECLAIM | ___GFP_KSWAPD_RECLAIM. IOW, normal GFP_USER, no __GFP_HIGHMEM in sight. So either we have a highmem page somehow ending up in i_data before we set the flags, or __page_cache_alloc() done by read_cache_page() returns us a highmem page on GFP_USER | __GFP_COLD (or I'm misreading the things completely)... Could you slap printk(KERN_ERR "inode: %p, pages: %ld\n", inode, inode->i_data.nrpages); before that read_cache_page() in nfs_get_link() and printk(KERN_ERR "page_address: %p\n", page_address(page)); right before the return? -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 14 January 2016 at 17:23, Al Viro <viro@zeniv.linux.org.uk> wrote: > On Thu, Jan 14, 2016 at 04:58:48PM +0100, Tomeu Vizoso wrote: >> > Could you add >> > printk(KERN_ERR "i_data = %p, i_mapping = %p, flags: %lx\n", >> > &inode->i_data, >> > inode->i_mapping, >> > (unsigned long)inode->i_data.flags); >> > right before the return from nfs_get_link() and see what it prints? >> >> Here it is: >> >> [ 170.136956] i_data = ed9c1b04, i_mapping = ed9c1b04, flags: 24200c0 >> [ 170.144567] i_data = ed9de784, i_mapping = ed9de784, flags: 24200c0 >> [ 170.151457] i_data = ed9dec84, i_mapping = ed9dec84, flags: 24200c0 >> [ 170.158358] i_data = ed9c3b84, i_mapping = ed9c3b84, flags: 24200c0 >> [ 170.165253] i_data = ed9d4204, i_mapping = ed9d4204, flags: 24200c0 >> [ 170.172131] i_data = ed9df184, i_mapping = ed9df184, flags: 24200c0 >> [ 170.188804] i_data = eddbce84, i_mapping = eddbce84, flags: 24200c0 >> [ 170.196158] i_data = ec904984, i_mapping = ec904984, flags: 24200c0 >> [ 170.205133] i_data = ec906784, i_mapping = ec906784, flags: 24200c0 > > Aha. So ->i_data vs. ->i_mapping is irrelevant (as it ought to be here) > and inode_nohighmem() should've acted on the address_space we are hitting > here. What do we have in flags... ___GFP_IO | ___GFP_FS | ___GFP_HARDWALL | > ___GFP_DIRECT_RECLAIM | ___GFP_KSWAPD_RECLAIM. IOW, normal GFP_USER, no > __GFP_HIGHMEM in sight. > > So either we have a highmem page somehow ending up in i_data before we > set the flags, or __page_cache_alloc() done by read_cache_page() returns > us a highmem page on GFP_USER | __GFP_COLD (or I'm misreading the things > completely)... > > Could you slap > printk(KERN_ERR "inode: %p, pages: %ld\n", > inode, inode->i_data.nrpages); > before that read_cache_page() in nfs_get_link() and > printk(KERN_ERR "page_address: %p\n", page_address(page)); > right before the return? Here it is: [ 170.715356] inode: ec8c30b0, pages: 1 [ 170.719014] page_address: (null) https://lava.collabora.co.uk/scheduler/job/127698/log_file Regards, Tomeu -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thu, Jan 14, 2016 at 05:57:42PM +0100, Tomeu Vizoso wrote: > Here it is: > > [ 170.715356] inode: ec8c30b0, pages: 1 > [ 170.719014] page_address: (null) > > https://lava.collabora.co.uk/scheduler/job/127698/log_file Lovely... And that looks like the first time that inode hits nfs_get_link(). Ho-hum... Could you add WARN_ON(inode->i_mapping.nrpages) in inode_nohighmem() and see if that triggers? It really shouldn't (we hit it after iget5_locked() in nfs_fhget() has returned us a new inode, and there shouldn't be a chance for any pages to get in there between struct inode allocation and that point), but then neither should highmem pages be added to address_space without __GFP_HIGHMEM in ->flags... -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index f24d1b8..3eb7c35 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -504,3 +504,8 @@ in your dentry operations instead. [mandatory] __fd_install() & fd_install() can now sleep. Callers should not hold a spinlock or other resources that do not allow a schedule. +-- +[mandatory] + any symlink that might use page_follow_link_light/page_put_link() must + have inode_nohighmem(inode) called before anything might start playing with + its pagecache. diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 1734950..0fdb0f5 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -140,6 +140,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino) break; case ST_SOFTLINK: inode->i_mode |= S_IFLNK; + inode_nohighmem(inode); inode->i_op = &affs_symlink_inode_operations; inode->i_data.a_ops = &affs_symlink_aops; break; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 181e05b..00d3002 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -344,6 +344,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) return -ENOSPC; inode->i_op = &affs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_data.a_ops = &affs_symlink_aops; inode->i_mode = S_IFLNK | 0777; mode_to_prot(inode); diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index ea5b69a..e3f9dc3 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -14,7 +14,7 @@ static int affs_symlink_readpage(struct file *file, struct page *page) { struct buffer_head *bh; struct inode *inode = page->mapping->host; - char *link = kmap(page); + char *link = page_address(page); struct slink_front *lf; int i, j; char c; @@ -57,12 +57,10 @@ static int affs_symlink_readpage(struct file *file, struct page *page) link[i] = '\0'; affs_brelse(bh); SetPageUptodate(page); - kunmap(page); unlock_page(page); return 0; fail: SetPageError(page); - kunmap(page); unlock_page(page); return -EIO; } diff --git a/fs/afs/inode.c b/fs/afs/inode.c index e06f5a2..86cc726 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -56,6 +56,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key) case AFS_FTYPE_SYMLINK: inode->i_mode = S_IFLNK | vnode->status.mode; inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); break; default: printk("kAFS: AFS vnode with undefined type\n"); diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 1c8b0dc..25250fa 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -397,6 +397,7 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino) } else if (S_ISLNK(inode->i_mode)) { if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &befs_symlink_aops; } else { inode->i_link = befs_ino->i_data.symlink; @@ -469,7 +470,7 @@ static int befs_symlink_readpage(struct file *unused, struct page *page) struct befs_inode_info *befs_ino = BEFS_I(inode); befs_data_stream *data = &befs_ino->i_data.ds; befs_off_t len = data->size; - char *link = kmap(page); + char *link = page_address(page); if (len == 0 || len > PAGE_SIZE) { befs_error(sb, "Long symlink with illegal length"); @@ -483,12 +484,10 @@ static int befs_symlink_readpage(struct file *unused, struct page *page) } link[len - 1] = '\0'; SetPageUptodate(page); - kunmap(page); unlock_page(page); return 0; fail: SetPageError(page); - kunmap(page); unlock_page(page); return -EIO; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a70c579..70f98bf 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -3774,6 +3774,7 @@ cache_acl: break; case S_IFLNK: inode->i_op = &btrfs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &btrfs_symlink_aops; break; default: @@ -9705,6 +9706,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, btrfs_free_path(path); inode->i_op = &btrfs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &btrfs_symlink_aops; inode_set_bytes(inode, name_len); btrfs_i_size_write(inode, name_len); diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 7740b1c..dd6a79e 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -8,6 +8,7 @@ #include <linux/coda.h> #include <linux/coda_psdev.h> +#include <linux/pagemap.h> #include "coda_linux.h" static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) @@ -35,6 +36,7 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr) inode->i_fop = &coda_dir_operations; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &coda_symlink_inode_operations; + inode_nohighmem(inode); inode->i_data.a_ops = &coda_symlink_aops; inode->i_mapping = &inode->i_data; } else diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c index ab94ef6..03736e2 100644 --- a/fs/coda/symlink.c +++ b/fs/coda/symlink.c @@ -26,7 +26,7 @@ static int coda_symlink_filler(struct file *file, struct page *page) int error; struct coda_inode_info *cii; unsigned int len = PAGE_SIZE; - char *p = kmap(page); + char *p = page_address(page); cii = ITOC(inode); @@ -34,13 +34,11 @@ static int coda_symlink_filler(struct file *file, struct page *page) if (error) goto fail; SetPageUptodate(page); - kunmap(page); unlock_page(page); return 0; fail: SetPageError(page); - kunmap(page); unlock_page(page); return error; } diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 355c522..b862bc2 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -100,6 +100,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb, break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_data.a_ops = &cramfs_aops; break; default: diff --git a/fs/efs/inode.c b/fs/efs/inode.c index 079d203..cdf0872 100644 --- a/fs/efs/inode.c +++ b/fs/efs/inode.c @@ -151,6 +151,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino) break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_data.a_ops = &efs_symlink_aops; break; case S_IFCHR: diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c index 75117d0..4870cc8 100644 --- a/fs/efs/symlink.c +++ b/fs/efs/symlink.c @@ -13,7 +13,7 @@ static int efs_symlink_readpage(struct file *file, struct page *page) { - char *link = kmap(page); + char *link = page_address(page); struct buffer_head * bh; struct inode * inode = page->mapping->host; efs_block_t size = inode->i_size; @@ -39,12 +39,10 @@ static int efs_symlink_readpage(struct file *file, struct page *page) } link[size] = '\0'; SetPageUptodate(page); - kunmap(page); unlock_page(page); return 0; fail: SetPageError(page); - kunmap(page); unlock_page(page); return err; } diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 73c64da..d8e9c181 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c @@ -1227,6 +1227,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino) inode->i_link = (char *)oi->i_data; } else { inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &exofs_aops; } } else { diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c index 994e078..c20d77d 100644 --- a/fs/exofs/namei.c +++ b/fs/exofs/namei.c @@ -111,6 +111,7 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry, if (l > sizeof(oi->i_data)) { /* slow symlink */ inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &exofs_aops; memset(oi->i_data, 0, sizeof(oi->i_data)); diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 0aa9bf6..338eefd 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1420,6 +1420,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino) sizeof(ei->i_data) - 1); } else { inode->i_op = &ext2_symlink_inode_operations; + inode_nohighmem(inode); if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 3267a80d..7a2be8f 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -183,6 +183,7 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry, if (l > sizeof (EXT2_I(inode)->i_data)) { /* slow symlink */ inode->i_op = &ext2_symlink_inode_operations; + inode_nohighmem(inode); if (test_opt(inode->i_sb, NOBH)) inode->i_mapping->a_ops = &ext2_nobh_aops; else diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ea433a7..b3bd912 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4283,6 +4283,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 a969ab3..f27e0c2 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3132,6 +3132,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 abe2401..0e6dc44 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); } diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 97e20de..5528801 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -202,6 +202,7 @@ make_now: inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &f2fs_dblock_aops; } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 2c32110..484df68 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -351,6 +351,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry, inode->i_op = &f2fs_encrypted_symlink_inode_operations; else inode->i_op = &f2fs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &f2fs_dblock_aops; f2fs_lock_op(sbi); @@ -942,7 +943,7 @@ static const char *f2fs_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; /* Symlink is encrypted */ @@ -982,13 +983,11 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook /* Null-terminate the name */ paddr[res] = '\0'; - kunmap(cpage); page_cache_release(cpage); return *cookie = paddr; errout: kfree(cstr.name); f2fs_fname_crypto_free_buffer(&pstr); - kunmap(cpage); page_cache_release(cpage); return ERR_PTR(res); } diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index ef73ed6..3e2ccad 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -326,6 +326,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino) } else if (S_ISLNK(ip->i_mode)) { if (!VXFS_ISIMMED(vip)) { ip->i_op = &page_symlink_inode_operations; + inode_nohighmem(ip); ip->i_mapping->a_ops = &vxfs_aops; } else { ip->i_op = &simple_symlink_inode_operations; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 6dd107d..19b33f8 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -403,6 +403,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode) } else if (S_ISLNK(inode->i_mode)) { sbi->file_count++; inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &hfsplus_aops; hip->clump_blocks = 1; } else @@ -526,6 +527,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) inode->i_mapping->a_ops = &hfsplus_aops; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &hfsplus_aops; } else { init_special_inode(inode, inode->i_mode, diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 933c737..1f3c6d7 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c @@ -77,6 +77,7 @@ void hpfs_read_inode(struct inode *i) kfree(ea); i->i_mode = S_IFLNK | 0777; i->i_op = &page_symlink_inode_operations; + inode_nohighmem(i); i->i_data.a_ops = &hpfs_symlink_aops; set_nlink(i, 1); i->i_size = ea_size; diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index ae4d5a1..506765a 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -332,6 +332,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy result->i_blocks = 1; set_nlink(result, 1); result->i_size = strlen(symlink); + inode_nohighmem(result); result->i_op = &page_symlink_inode_operations; result->i_data.a_ops = &hpfs_symlink_aops; @@ -500,7 +501,7 @@ out: static int hpfs_symlink_readpage(struct file *file, struct page *page) { - char *link = kmap(page); + char *link = page_address(page); struct inode *i = page->mapping->host; struct fnode *fnode; struct buffer_head *bh; @@ -516,14 +517,12 @@ static int hpfs_symlink_readpage(struct file *file, struct page *page) goto fail; hpfs_unlock(i->i_sb); SetPageUptodate(page); - kunmap(page); unlock_page(page); return 0; fail: hpfs_unlock(i->i_sb); SetPageError(page); - kunmap(page); unlock_page(page); return err; } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index de4bdfa..d8f51ee 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -760,6 +760,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); break; } lockdep_annotate_inode_mutex_key(inode); diff --git a/fs/inode.c b/fs/inode.c index 1be5f90..5bb85a0 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2028,3 +2028,9 @@ void inode_set_flags(struct inode *inode, unsigned int flags, new_flags) != old_flags)); } EXPORT_SYMBOL(inode_set_flags); + +void inode_nohighmem(struct inode *inode) +{ + mapping_set_gfp_mask(inode->i_mapping, GFP_USER); +} +EXPORT_SYMBOL(inode_nohighmem); diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index d67a16f..61abdc4 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -1417,6 +1417,7 @@ static int isofs_read_inode(struct inode *inode, int relocated) inode->i_fop = &isofs_dir_operations; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_data.a_ops = &isofs_symlink_aops; } else /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c index 735d752..5384ceb 100644 --- a/fs/isofs/rock.c +++ b/fs/isofs/rock.c @@ -687,7 +687,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page) struct inode *inode = page->mapping->host; struct iso_inode_info *ei = ISOFS_I(inode); struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb); - char *link = kmap(page); + char *link = page_address(page); unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); struct buffer_head *bh; char *rpnt = link; @@ -774,7 +774,6 @@ repeat: brelse(bh); *rpnt = '\0'; SetPageUptodate(page); - kunmap(page); unlock_page(page); return 0; @@ -791,7 +790,6 @@ fail: brelse(bh); error: SetPageError(page); - kunmap(page); unlock_page(page); return -EIO; } diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 41aa3ca..9d9bae6 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -60,6 +60,7 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino) } else if (S_ISLNK(inode->i_mode)) { if (inode->i_size >= IDATASIZE) { inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &jfs_aops; } else { inode->i_op = &jfs_fast_symlink_inode_operations; diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 9d7551f..701f893 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -983,6 +983,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, jfs_info("jfs_symlink: allocate extent ip:0x%p", ip); ip->i_op = &jfs_symlink_inode_operations; + inode_nohighmem(ip); ip->i_mapping->a_ops = &jfs_aops; /* diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 99944a4..542468e 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -529,6 +529,7 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry, return PTR_ERR(inode); inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &logfs_reg_aops; return __logfs_create(dir, dentry, inode, target, destlen); diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index 06baa92..0fce46d 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c @@ -65,6 +65,7 @@ static void logfs_inode_setops(struct inode *inode) break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &logfs_reg_aops; break; case S_IFSOCK: /* fall through */ diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 086cd0a..67a23bf 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -452,6 +452,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev) inode->i_mapping->a_ops = &minix_aops; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &minix_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &minix_aops; } else init_special_inode(inode, inode->i_mode, rdev); diff --git a/fs/namei.c b/fs/namei.c index 4bae5cb..2808958 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4527,7 +4527,8 @@ static const char *page_getlink(struct dentry * dentry, void **cookie) if (IS_ERR(page)) return (char*)page; *cookie = page; - kaddr = kmap(page); + BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); + kaddr = page_address(page); nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1); return kaddr; } @@ -4541,7 +4542,6 @@ EXPORT_SYMBOL(page_follow_link_light); void page_put_link(struct inode *unused, void *cookie) { struct page *page = cookie; - kunmap(page); page_cache_release(page); } EXPORT_SYMBOL(page_put_link); @@ -4565,7 +4565,6 @@ int __page_symlink(struct inode *inode, const char *symname, int len, int nofs) struct page *page; void *fsdata; int err; - char *kaddr; unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE; if (nofs) flags |= AOP_FLAG_NOFS; @@ -4576,9 +4575,7 @@ retry: if (err) goto fail; - kaddr = kmap_atomic(page); - memcpy(kaddr, symname, len-1); - kunmap_atomic(kaddr); + memcpy(page_address(page), symname, len-1); err = pagecache_write_end(NULL, mapping, 0, len-1, len-1, page, fsdata); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 9605a2f..bb856f7 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -283,6 +283,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info) #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &ncp_symlink_inode_operations; + inode_nohighmem(inode); inode->i_data.a_ops = &ncp_symlink_aops; #endif } else { diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 31b0a52..ae9aa0b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -408,9 +408,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st inode->i_fop = NULL; inode->i_flags |= S_AUTOMOUNT; } - } else if (S_ISLNK(inode->i_mode)) + } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &nfs_symlink_inode_operations; - else + inode_nohighmem(inode); + } else init_special_inode(inode, inode->i_mode, fattr->rdev); memset(&inode->i_atime, 0, sizeof(inode->i_atime)); diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index b6de433..abd93bf 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -56,7 +56,7 @@ static const char *nfs_follow_link(struct dentry *dentry, void **cookie) if (IS_ERR(page)) return ERR_CAST(page); *cookie = page; - return kmap(page); + return page_address(page); } /* diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index ac2f649..10b2252 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c @@ -510,6 +510,7 @@ static int __nilfs_read_inode(struct super_block *sb, inode->i_mapping->a_ops = &nilfs_aops; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &nilfs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &nilfs_aops; } else { inode->i_op = &nilfs_special_inode_operations; diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index c9a1a49..90b3ba9 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -161,6 +161,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry, /* slow symlink */ inode->i_op = &nilfs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &nilfs_aops; err = page_symlink(inode, symname, l); if (err) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 8f87e05..97a563b 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -361,6 +361,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe, break; case S_IFLNK: inode->i_op = &ocfs2_symlink_inode_operations; + inode_nohighmem(inode); i_size_write(inode, le64_to_cpu(fe->i_size)); break; default: diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index a03f6f4..2efe8af 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1960,6 +1960,7 @@ static int ocfs2_symlink(struct inode *dir, inode->i_rdev = 0; newsize = l - 1; inode->i_op = &ocfs2_symlink_inode_operations; + inode_nohighmem(inode); if (l > ocfs2_fast_symlink_chars(sb)) { u32 offset = 0; diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index c4bcb77..f37b3de 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -316,6 +316,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino) inode->i_fop = &qnx4_dir_operations; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &qnx4_aops; qnx4_i(inode)->mmu_private = inode->i_size; } else { diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c index 32d2e1a..9728b54 100644 --- a/fs/qnx6/inode.c +++ b/fs/qnx6/inode.c @@ -582,6 +582,7 @@ struct inode *qnx6_iget(struct super_block *sb, unsigned ino) inode->i_mapping->a_ops = &qnx6_aops; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &qnx6_aops; } else init_special_inode(inode, inode->i_mode, 0); diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 889d558..38981b0 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -79,6 +79,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); break; } } diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 3d8e7e6..ae9e5b3 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1361,6 +1361,7 @@ static void init_inode(struct inode *inode, struct treepath *path) inode->i_fop = &reiserfs_dir_operations; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &reiserfs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &reiserfs_address_space_operations; } else { inode->i_blocks = 0; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 47f9698..4fc2326 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1170,6 +1170,7 @@ static int reiserfs_symlink(struct inode *parent_dir, reiserfs_update_inode_transaction(parent_dir); inode->i_op = &reiserfs_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &reiserfs_address_space_operations; retval = reiserfs_add_entry(&th, parent_dir, dentry->d_name.name, diff --git a/fs/romfs/super.c b/fs/romfs/super.c index 268733c..bb894e7 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -360,6 +360,7 @@ static struct inode *romfs_iget(struct super_block *sb, unsigned long pos) break; case ROMFH_SYM: i->i_op = &page_symlink_inode_operations; + inode_nohighmem(i); i->i_data.a_ops = &romfs_aops; mode |= S_IRWXUGO; break; diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index a1ce5ce..0927b1e 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c @@ -41,6 +41,7 @@ #include <linux/fs.h> #include <linux/vfs.h> #include <linux/xattr.h> +#include <linux/pagemap.h> #include "squashfs_fs.h" #include "squashfs_fs_sb.h" @@ -291,6 +292,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) set_nlink(inode, le32_to_cpu(sqsh_ino->nlink)); inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); inode->i_op = &squashfs_symlink_inode_ops; + inode_nohighmem(inode); inode->i_data.a_ops = &squashfs_symlink_aops; inode->i_mode |= S_IFLNK; squashfs_i(inode)->start = block; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index 02fa1dc..ef8bcdb 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -163,6 +163,7 @@ void sysv_set_inode(struct inode *inode, dev_t rdev) inode->i_mapping->a_ops = &sysv_aops; } else if (S_ISLNK(inode->i_mode)) { inode->i_op = &sysv_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &sysv_aops; } else init_special_inode(inode, inode->i_mode, rdev); diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 8675c2b..0557463 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -1541,6 +1541,7 @@ reread: case ICBTAG_FILE_TYPE_SYMLINK: inode->i_data.a_ops = &udf_symlink_aops; inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mode = S_IFLNK | S_IRWXUGO; break; case ICBTAG_FILE_TYPE_MAIN: diff --git a/fs/udf/namei.c b/fs/udf/namei.c index d0e6de1..42eafb9 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -922,6 +922,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, inode->i_data.a_ops = &udf_symlink_aops; inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { struct kernel_lb_addr eloc; diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c index 862535b..8d61977 100644 --- a/fs/udf/symlink.c +++ b/fs/udf/symlink.c @@ -107,7 +107,7 @@ static int udf_symlink_filler(struct file *file, struct page *page) struct buffer_head *bh = NULL; unsigned char *symlink; int err; - unsigned char *p = kmap(page); + unsigned char *p = page_address(page); struct udf_inode_info *iinfo; uint32_t pos; @@ -141,7 +141,6 @@ static int udf_symlink_filler(struct file *file, struct page *page) up_read(&iinfo->i_data_sem); SetPageUptodate(page); - kunmap(page); unlock_page(page); return 0; @@ -149,7 +148,6 @@ out_unlock_inode: up_read(&iinfo->i_data_sem); SetPageError(page); out_unmap: - kunmap(page); unlock_page(page); return err; } diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 737160a..d897e16 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -533,6 +533,7 @@ static void ufs_set_inode_ops(struct inode *inode) } else { inode->i_mapping->a_ops = &ufs_aops; inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); } } else init_special_inode(inode, inode->i_mode, diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 24b0cbd..acf4a3b 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -124,6 +124,7 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry, if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) { /* slow symlink */ inode->i_op = &page_symlink_inode_operations; + inode_nohighmem(inode); inode->i_mapping->a_ops = &ufs_aops; err = page_symlink(inode, symname, l); if (err) diff --git a/include/linux/fs.h b/include/linux/fs.h index 3aa5142..dfeda44 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3025,5 +3025,6 @@ static inline bool dir_relax(struct inode *inode) } extern bool path_noexec(const struct path *path); +extern void inode_nohighmem(struct inode *inode); #endif /* _LINUX_FS_H */ diff --git a/mm/shmem.c b/mm/shmem.c index 9187eee..64bf5ac 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); }