AFS: Don't put struct file on the stack

Don't put struct file on the stack as it takes up quite a lot of space
and violates lifetime rules for struct file.

Rather than calling afs_readpage() indirectly from the directory routines by
way of read_mapping_page(), split afs_readpage() to have afs_page_filler()
that's given a key instead of a file and call read_cache_page(), specifying the
new function directly.  Use it in afs_readpages() as well.

Also make use of this in afs_mntpt_check_symlink() too for the same reason.

Reported-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: David Howells <dhowells@redhat.com>
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index adc1cb7..b42d5cc 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -189,13 +189,9 @@
 				     struct key *key)
 {
 	struct page *page;
-	struct file file = {
-		.private_data = key,
-	};
-
 	_enter("{%lu},%lu", dir->i_ino, index);
 
-	page = read_mapping_page(dir->i_mapping, index, &file);
+	page = read_cache_page(dir->i_mapping, index, afs_page_filler, key);
 	if (!IS_ERR(page)) {
 		kmap(page);
 		if (!PageChecked(page))
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 0df9bc2..14d89fa 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -121,34 +121,19 @@
 #endif
 
 /*
- * AFS read page from file, directory or symlink
+ * read page from file, directory or symlink, given a key to use
  */
-static int afs_readpage(struct file *file, struct page *page)
+int afs_page_filler(void *data, struct page *page)
 {
-	struct afs_vnode *vnode;
-	struct inode *inode;
-	struct key *key;
+	struct inode *inode = page->mapping->host;
+	struct afs_vnode *vnode = AFS_FS_I(inode);
+	struct key *key = data;
 	size_t len;
 	off_t offset;
 	int ret;
 
-	inode = page->mapping->host;
-
-	if (file) {
-		key = file->private_data;
-		ASSERT(key != NULL);
-	} else {
-		key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell);
-		if (IS_ERR(key)) {
-			ret = PTR_ERR(key);
-			goto error_nokey;
-		}
-	}
-
 	_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
 
-	vnode = AFS_FS_I(inode);
-
 	BUG_ON(!PageLocked(page));
 
 	ret = -ESTALE;
@@ -214,31 +199,56 @@
 		unlock_page(page);
 	}
 
-	if (!file)
-		key_put(key);
 	_leave(" = 0");
 	return 0;
 
 error:
 	SetPageError(page);
 	unlock_page(page);
-	if (!file)
-		key_put(key);
-error_nokey:
 	_leave(" = %d", ret);
 	return ret;
 }
 
 /*
+ * read page from file, directory or symlink, given a file to nominate the key
+ * to be used
+ */
+static int afs_readpage(struct file *file, struct page *page)
+{
+	struct key *key;
+	int ret;
+
+	if (file) {
+		key = file->private_data;
+		ASSERT(key != NULL);
+		ret = afs_page_filler(key, page);
+	} else {
+		struct inode *inode = page->mapping->host;
+		key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell);
+		if (IS_ERR(key)) {
+			ret = PTR_ERR(key);
+		} else {
+			ret = afs_page_filler(key, page);
+			key_put(key);
+		}
+	}
+	return ret;
+}
+
+/*
  * read a set of pages
  */
 static int afs_readpages(struct file *file, struct address_space *mapping,
 			 struct list_head *pages, unsigned nr_pages)
 {
+	struct key *key = file->private_data;
 	struct afs_vnode *vnode;
 	int ret = 0;
 
-	_enter(",{%lu},,%d", mapping->host->i_ino, nr_pages);
+	_enter("{%d},{%lu},,%d",
+	       key_serial(key), mapping->host->i_ino, nr_pages);
+
+	ASSERT(key != NULL);
 
 	vnode = AFS_FS_I(mapping->host);
 	if (vnode->flags & AFS_VNODE_DELETED) {
@@ -279,7 +289,7 @@
 	}
 
 	/* load the missing pages from the network */
-	ret = read_cache_pages(mapping, pages, (void *) afs_readpage, file);
+	ret = read_cache_pages(mapping, pages, afs_page_filler, key);
 
 	_leave(" = %d [netting]", ret);
 	return ret;
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index a10f258..807f284 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -494,6 +494,7 @@
 
 extern int afs_open(struct inode *, struct file *);
 extern int afs_release(struct inode *, struct file *);
+extern int afs_page_filler(void *, struct page *);
 
 /*
  * flock.c
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index b3feddc..a9e2303 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -49,9 +49,6 @@
  */
 int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
 {
-	struct file file = {
-		.private_data = key,
-	};
 	struct page *page;
 	size_t size;
 	char *buf;
@@ -61,7 +58,8 @@
 	       vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
 
 	/* read the contents of the symlink into the pagecache */
-	page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file);
+	page = read_cache_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0,
+			       afs_page_filler, key);
 	if (IS_ERR(page)) {
 		ret = PTR_ERR(page);
 		goto out;