diff options
author | Yan, Zheng <zyan@redhat.com> | 2016-08-24 11:33:46 +0800 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2016-10-03 16:13:49 +0200 |
commit | 1afe478569ba7414dde8a874dda9c1ea621c0c63 (patch) | |
tree | 1a4b24ecb88e64c8cb7d4870afd2a126655cdf6c | |
parent | 0dcc685e7dd7190dcaa5435e9c14150f1d405b7b (diff) |
ceph: fix error handling of start_read()
If start_page() fails to add a page to page cache or fails to send
OSD request. It should cal put_page() (instead of free_page()) for
relevant pages.
Besides, start_page() need to cancel fscache readpage if it fails
to send OSD request.
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Reported-by: Zhi Zhang <zhang.david2011@gmail.com>
-rw-r--r-- | fs/ceph/addr.c | 19 |
1 files changed, 9 insertions, 10 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index d5b6f959a3c3..f410a0cb57e3 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -298,14 +298,6 @@ unlock: kfree(osd_data->pages); } -static void ceph_unlock_page_vector(struct page **pages, int num_pages) -{ - int i; - - for (i = 0; i < num_pages; i++) - unlock_page(pages[i]); -} - /* * start an async read(ahead) operation. return nr_pages we submitted * a read for on success, or negative error code. @@ -370,6 +362,10 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) dout("start_read %p add_to_page_cache failed %p\n", inode, page); nr_pages = i; + if (nr_pages > 0) { + len = nr_pages << PAGE_SHIFT; + break; + } goto out_pages; } pages[i] = page; @@ -386,8 +382,11 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max) return nr_pages; out_pages: - ceph_unlock_page_vector(pages, nr_pages); - ceph_release_page_vector(pages, nr_pages); + for (i = 0; i < nr_pages; ++i) { + ceph_fscache_readpage_cancel(inode, pages[i]); + unlock_page(pages[i]); + } + ceph_put_page_vector(pages, nr_pages, false); out: ceph_osdc_put_request(req); return ret; |