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>
This commit is contained in:
parent
4403158ba2
commit
f6d335c08d
@ -189,13 +189,9 @@ static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
|
|||||||
struct key *key)
|
struct key *key)
|
||||||
{
|
{
|
||||||
struct page *page;
|
struct page *page;
|
||||||
struct file file = {
|
|
||||||
.private_data = key,
|
|
||||||
};
|
|
||||||
|
|
||||||
_enter("{%lu},%lu", dir->i_ino, index);
|
_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)) {
|
if (!IS_ERR(page)) {
|
||||||
kmap(page);
|
kmap(page);
|
||||||
if (!PageChecked(page))
|
if (!PageChecked(page))
|
||||||
|
@ -121,34 +121,19 @@ static void afs_file_readpage_read_complete(struct page *page,
|
|||||||
#endif
|
#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 = page->mapping->host;
|
||||||
struct inode *inode;
|
struct afs_vnode *vnode = AFS_FS_I(inode);
|
||||||
struct key *key;
|
struct key *key = data;
|
||||||
size_t len;
|
size_t len;
|
||||||
off_t offset;
|
off_t offset;
|
||||||
int ret;
|
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);
|
_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
|
||||||
|
|
||||||
vnode = AFS_FS_I(inode);
|
|
||||||
|
|
||||||
BUG_ON(!PageLocked(page));
|
BUG_ON(!PageLocked(page));
|
||||||
|
|
||||||
ret = -ESTALE;
|
ret = -ESTALE;
|
||||||
@ -214,31 +199,56 @@ static int afs_readpage(struct file *file, struct page *page)
|
|||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file)
|
|
||||||
key_put(key);
|
|
||||||
_leave(" = 0");
|
_leave(" = 0");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
SetPageError(page);
|
SetPageError(page);
|
||||||
unlock_page(page);
|
unlock_page(page);
|
||||||
if (!file)
|
|
||||||
key_put(key);
|
|
||||||
error_nokey:
|
|
||||||
_leave(" = %d", ret);
|
_leave(" = %d", ret);
|
||||||
return 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
|
* read a set of pages
|
||||||
*/
|
*/
|
||||||
static int afs_readpages(struct file *file, struct address_space *mapping,
|
static int afs_readpages(struct file *file, struct address_space *mapping,
|
||||||
struct list_head *pages, unsigned nr_pages)
|
struct list_head *pages, unsigned nr_pages)
|
||||||
{
|
{
|
||||||
|
struct key *key = file->private_data;
|
||||||
struct afs_vnode *vnode;
|
struct afs_vnode *vnode;
|
||||||
int ret = 0;
|
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);
|
vnode = AFS_FS_I(mapping->host);
|
||||||
if (vnode->flags & AFS_VNODE_DELETED) {
|
if (vnode->flags & AFS_VNODE_DELETED) {
|
||||||
@ -279,7 +289,7 @@ static int afs_readpages(struct file *file, struct address_space *mapping,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* load the missing pages from the network */
|
/* 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);
|
_leave(" = %d [netting]", ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -494,6 +494,7 @@ extern const struct file_operations afs_file_operations;
|
|||||||
|
|
||||||
extern int afs_open(struct inode *, struct file *);
|
extern int afs_open(struct inode *, struct file *);
|
||||||
extern int afs_release(struct inode *, struct file *);
|
extern int afs_release(struct inode *, struct file *);
|
||||||
|
extern int afs_page_filler(void *, struct page *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* flock.c
|
* flock.c
|
||||||
|
@ -49,9 +49,6 @@ static unsigned long afs_mntpt_expiry_timeout = 10 * 60;
|
|||||||
*/
|
*/
|
||||||
int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
|
int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
|
||||||
{
|
{
|
||||||
struct file file = {
|
|
||||||
.private_data = key,
|
|
||||||
};
|
|
||||||
struct page *page;
|
struct page *page;
|
||||||
size_t size;
|
size_t size;
|
||||||
char *buf;
|
char *buf;
|
||||||
@ -61,7 +58,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)
|
|||||||
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
|
vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique);
|
||||||
|
|
||||||
/* read the contents of the symlink into the pagecache */
|
/* 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)) {
|
if (IS_ERR(page)) {
|
||||||
ret = PTR_ERR(page);
|
ret = PTR_ERR(page);
|
||||||
goto out;
|
goto out;
|
||||||
|
Loading…
Reference in New Issue
Block a user