From: Alexander Zarochentsev Don't let fuse_readpages leave the @pages list not empty when exiting on error. Signed-off-by: Alexander Zarochentsev Signed-off-by: Miklos Szeredi Signed-off-by: Andrew Morton --- fs/fuse/file.c | 10 ++++++++-- include/linux/mm.h | 1 + mm/swap.c | 18 ++++++++++++++++++ 3 files changed, 27 insertions(+), 2 deletions(-) diff -puN fs/fuse/file.c~fuse-fix-error-case-in-fuse_readpages fs/fuse/file.c --- a/fs/fuse/file.c~fuse-fix-error-case-in-fuse_readpages +++ a/fs/fuse/file.c @@ -395,14 +395,16 @@ static int fuse_readpages(struct file *f struct fuse_readpages_data data; int err; + err = -EIO; if (is_bad_inode(inode)) - return -EIO; + goto clean_pages_up; data.file = file; data.inode = inode; data.req = fuse_get_req(fc); + err = PTR_ERR(data.req); if (IS_ERR(data.req)) - return PTR_ERR(data.req); + goto clean_pages_up; err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); if (!err) { @@ -412,6 +414,10 @@ static int fuse_readpages(struct file *f fuse_put_request(fc, data.req); } return err; + +clean_pages_up: + put_pages_list(pages); + return err; } static size_t fuse_send_write(struct fuse_req *req, struct file *file, diff -puN include/linux/mm.h~fuse-fix-error-case-in-fuse_readpages include/linux/mm.h --- a/include/linux/mm.h~fuse-fix-error-case-in-fuse_readpages +++ a/include/linux/mm.h @@ -336,6 +336,7 @@ static inline void init_page_count(struc } void put_page(struct page *page); +void put_pages_list(struct list_head *pages); void split_page(struct page *page, unsigned int order); diff -puN mm/swap.c~fuse-fix-error-case-in-fuse_readpages mm/swap.c --- a/mm/swap.c~fuse-fix-error-case-in-fuse_readpages +++ a/mm/swap.c @@ -54,6 +54,24 @@ void put_page(struct page *page) } EXPORT_SYMBOL(put_page); +/** + * Release page list. Currently used by read_cache_pages() and related + * cleanup code. + * + * @pages: list of pages threaded on page->lru + */ +void put_pages_list(struct list_head *pages) +{ + while (!list_empty(pages)) { + struct page *victim; + + victim = list_entry(pages->prev, struct page, lru); + list_del(&victim->lru); + page_cache_release(victim); + } +} +EXPORT_SYMBOL(put_pages_list); + /* * Writeback is about to end against a page which has been marked for immediate * reclaim. If it still appears to be reclaimable, move it to the tail of the _