diff options
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 745a612dbe22..0be5050638f7 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -29,8 +29,6 @@ | |||
29 | static struct kmem_cache *nfs_page_cachep; | 29 | static struct kmem_cache *nfs_page_cachep; |
30 | static const struct rpc_call_ops nfs_pgio_common_ops; | 30 | static const struct rpc_call_ops nfs_pgio_common_ops; |
31 | 31 | ||
32 | static void nfs_free_request(struct nfs_page *); | ||
33 | |||
34 | static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) | 32 | static bool nfs_pgarray_set(struct nfs_page_array *p, unsigned int pagecount) |
35 | { | 33 | { |
36 | p->npages = pagecount; | 34 | p->npages = pagecount; |
@@ -232,20 +230,28 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev) | |||
232 | WARN_ON_ONCE(prev == req); | 230 | WARN_ON_ONCE(prev == req); |
233 | 231 | ||
234 | if (!prev) { | 232 | if (!prev) { |
233 | /* a head request */ | ||
235 | req->wb_head = req; | 234 | req->wb_head = req; |
236 | req->wb_this_page = req; | 235 | req->wb_this_page = req; |
237 | } else { | 236 | } else { |
237 | /* a subrequest */ | ||
238 | WARN_ON_ONCE(prev->wb_this_page != prev->wb_head); | 238 | WARN_ON_ONCE(prev->wb_this_page != prev->wb_head); |
239 | WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags)); | 239 | WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags)); |
240 | req->wb_head = prev->wb_head; | 240 | req->wb_head = prev->wb_head; |
241 | req->wb_this_page = prev->wb_this_page; | 241 | req->wb_this_page = prev->wb_this_page; |
242 | prev->wb_this_page = req; | 242 | prev->wb_this_page = req; |
243 | 243 | ||
244 | /* All subrequests take a ref on the head request until | ||
245 | * nfs_page_group_destroy is called */ | ||
246 | kref_get(&req->wb_head->wb_kref); | ||
247 | |||
244 | /* grab extra ref if head request has extra ref from | 248 | /* grab extra ref if head request has extra ref from |
245 | * the write/commit path to handle handoff between write | 249 | * the write/commit path to handle handoff between write |
246 | * and commit lists */ | 250 | * and commit lists */ |
247 | if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) | 251 | if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) { |
252 | set_bit(PG_INODE_REF, &req->wb_flags); | ||
248 | kref_get(&req->wb_kref); | 253 | kref_get(&req->wb_kref); |
254 | } | ||
249 | } | 255 | } |
250 | } | 256 | } |
251 | 257 | ||
@@ -262,6 +268,10 @@ nfs_page_group_destroy(struct kref *kref) | |||
262 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); | 268 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); |
263 | struct nfs_page *tmp, *next; | 269 | struct nfs_page *tmp, *next; |
264 | 270 | ||
271 | /* subrequests must release the ref on the head request */ | ||
272 | if (req->wb_head != req) | ||
273 | nfs_release_request(req->wb_head); | ||
274 | |||
265 | if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN)) | 275 | if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN)) |
266 | return; | 276 | return; |
267 | 277 | ||
@@ -387,7 +397,7 @@ static void nfs_clear_request(struct nfs_page *req) | |||
387 | * | 397 | * |
388 | * Note: Should never be called with the spinlock held! | 398 | * Note: Should never be called with the spinlock held! |
389 | */ | 399 | */ |
390 | static void nfs_free_request(struct nfs_page *req) | 400 | void nfs_free_request(struct nfs_page *req) |
391 | { | 401 | { |
392 | WARN_ON_ONCE(req->wb_this_page != req); | 402 | WARN_ON_ONCE(req->wb_this_page != req); |
393 | 403 | ||
@@ -917,7 +927,6 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
917 | nfs_pageio_doio(desc); | 927 | nfs_pageio_doio(desc); |
918 | if (desc->pg_error < 0) | 928 | if (desc->pg_error < 0) |
919 | return 0; | 929 | return 0; |
920 | desc->pg_moreio = 0; | ||
921 | if (desc->pg_recoalesce) | 930 | if (desc->pg_recoalesce) |
922 | return 0; | 931 | return 0; |
923 | /* retry add_request for this subreq */ | 932 | /* retry add_request for this subreq */ |
@@ -964,6 +973,7 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) | |||
964 | desc->pg_count = 0; | 973 | desc->pg_count = 0; |
965 | desc->pg_base = 0; | 974 | desc->pg_base = 0; |
966 | desc->pg_recoalesce = 0; | 975 | desc->pg_recoalesce = 0; |
976 | desc->pg_moreio = 0; | ||
967 | 977 | ||
968 | while (!list_empty(&head)) { | 978 | while (!list_empty(&head)) { |
969 | struct nfs_page *req; | 979 | struct nfs_page *req; |