Commit 21fc61c7 authored by Al Viro's avatar Al Viro
Browse files

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent aa80deab
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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.
+1 −0
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −3
Original line number Diff line number Diff line
@@ -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;
}
+1 −0
Original line number Diff line number Diff line
@@ -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");
Loading