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 b6ee3a6ee96d..17fab89f6358 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; |
@@ -239,20 +237,28 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev) | |||
239 | WARN_ON_ONCE(prev == req); | 237 | WARN_ON_ONCE(prev == req); |
240 | 238 | ||
241 | if (!prev) { | 239 | if (!prev) { |
240 | /* a head request */ | ||
242 | req->wb_head = req; | 241 | req->wb_head = req; |
243 | req->wb_this_page = req; | 242 | req->wb_this_page = req; |
244 | } else { | 243 | } else { |
244 | /* a subrequest */ | ||
245 | WARN_ON_ONCE(prev->wb_this_page != prev->wb_head); | 245 | WARN_ON_ONCE(prev->wb_this_page != prev->wb_head); |
246 | WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags)); | 246 | WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags)); |
247 | req->wb_head = prev->wb_head; | 247 | req->wb_head = prev->wb_head; |
248 | req->wb_this_page = prev->wb_this_page; | 248 | req->wb_this_page = prev->wb_this_page; |
249 | prev->wb_this_page = req; | 249 | prev->wb_this_page = req; |
250 | 250 | ||
251 | /* All subrequests take a ref on the head request until | ||
252 | * nfs_page_group_destroy is called */ | ||
253 | kref_get(&req->wb_head->wb_kref); | ||
254 | |||
251 | /* grab extra ref if head request has extra ref from | 255 | /* grab extra ref if head request has extra ref from |
252 | * the write/commit path to handle handoff between write | 256 | * the write/commit path to handle handoff between write |
253 | * and commit lists */ | 257 | * and commit lists */ |
254 | if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) | 258 | if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) { |
259 | set_bit(PG_INODE_REF, &req->wb_flags); | ||
255 | kref_get(&req->wb_kref); | 260 | kref_get(&req->wb_kref); |
261 | } | ||
256 | } | 262 | } |
257 | } | 263 | } |
258 | 264 | ||
@@ -269,6 +275,10 @@ nfs_page_group_destroy(struct kref *kref) | |||
269 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); | 275 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); |
270 | struct nfs_page *tmp, *next; | 276 | struct nfs_page *tmp, *next; |
271 | 277 | ||
278 | /* subrequests must release the ref on the head request */ | ||
279 | if (req->wb_head != req) | ||
280 | nfs_release_request(req->wb_head); | ||
281 | |||
272 | if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN)) | 282 | if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN)) |
273 | return; | 283 | return; |
274 | 284 | ||
@@ -394,7 +404,7 @@ static void nfs_clear_request(struct nfs_page *req) | |||
394 | * | 404 | * |
395 | * Note: Should never be called with the spinlock held! | 405 | * Note: Should never be called with the spinlock held! |
396 | */ | 406 | */ |
397 | static void nfs_free_request(struct nfs_page *req) | 407 | void nfs_free_request(struct nfs_page *req) |
398 | { | 408 | { |
399 | WARN_ON_ONCE(req->wb_this_page != req); | 409 | WARN_ON_ONCE(req->wb_this_page != req); |
400 | 410 | ||
@@ -925,7 +935,6 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
925 | nfs_pageio_doio(desc); | 935 | nfs_pageio_doio(desc); |
926 | if (desc->pg_error < 0) | 936 | if (desc->pg_error < 0) |
927 | return 0; | 937 | return 0; |
928 | desc->pg_moreio = 0; | ||
929 | if (desc->pg_recoalesce) | 938 | if (desc->pg_recoalesce) |
930 | return 0; | 939 | return 0; |
931 | /* retry add_request for this subreq */ | 940 | /* retry add_request for this subreq */ |
@@ -972,6 +981,7 @@ static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) | |||
972 | desc->pg_count = 0; | 981 | desc->pg_count = 0; |
973 | desc->pg_base = 0; | 982 | desc->pg_base = 0; |
974 | desc->pg_recoalesce = 0; | 983 | desc->pg_recoalesce = 0; |
984 | desc->pg_moreio = 0; | ||
975 | 985 | ||
976 | while (!list_empty(&head)) { | 986 | while (!list_empty(&head)) { |
977 | struct nfs_page *req; | 987 | struct nfs_page *req; |