diff options
author | Weston Andros Adamson <dros@primarydata.com> | 2014-07-11 10:20:46 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-07-12 16:51:41 -0400 |
commit | 85710a837c2026aae80b7c64187edf1f10027b0b (patch) | |
tree | 9b8ac697b4bc8aa635a6b97432bc76113703a85a /fs/nfs/pagelist.c | |
parent | 17089a29a25a3bfe8d14520cd866b7d635ffe5ba (diff) |
nfs: nfs_page should take a ref on the head req
nfs_pages that aren't the the head of a group must take a reference on the
head as long as ->wb_head is set to it. This stops the head from hitting
a refcount of 0 while there is still an active nfs_page for the page group.
This avoids kref warnings in the writeback code when the page group head
is found and referenced.
Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 7368b2130a41..05a63593a61f 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -239,15 +239,21 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev) | |||
239 | WARN_ON_ONCE(prev == req); | 239 | WARN_ON_ONCE(prev == req); |
240 | 240 | ||
241 | if (!prev) { | 241 | if (!prev) { |
242 | /* a head request */ | ||
242 | req->wb_head = req; | 243 | req->wb_head = req; |
243 | req->wb_this_page = req; | 244 | req->wb_this_page = req; |
244 | } else { | 245 | } else { |
246 | /* a subrequest */ | ||
245 | WARN_ON_ONCE(prev->wb_this_page != prev->wb_head); | 247 | WARN_ON_ONCE(prev->wb_this_page != prev->wb_head); |
246 | WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags)); | 248 | WARN_ON_ONCE(!test_bit(PG_HEADLOCK, &prev->wb_head->wb_flags)); |
247 | req->wb_head = prev->wb_head; | 249 | req->wb_head = prev->wb_head; |
248 | req->wb_this_page = prev->wb_this_page; | 250 | req->wb_this_page = prev->wb_this_page; |
249 | prev->wb_this_page = req; | 251 | prev->wb_this_page = req; |
250 | 252 | ||
253 | /* All subrequests take a ref on the head request until | ||
254 | * nfs_page_group_destroy is called */ | ||
255 | kref_get(&req->wb_head->wb_kref); | ||
256 | |||
251 | /* grab extra ref if head request has extra ref from | 257 | /* grab extra ref if head request has extra ref from |
252 | * the write/commit path to handle handoff between write | 258 | * the write/commit path to handle handoff between write |
253 | * and commit lists */ | 259 | * and commit lists */ |
@@ -271,6 +277,10 @@ nfs_page_group_destroy(struct kref *kref) | |||
271 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); | 277 | struct nfs_page *req = container_of(kref, struct nfs_page, wb_kref); |
272 | struct nfs_page *tmp, *next; | 278 | struct nfs_page *tmp, *next; |
273 | 279 | ||
280 | /* subrequests must release the ref on the head request */ | ||
281 | if (req->wb_head != req) | ||
282 | nfs_release_request(req->wb_head); | ||
283 | |||
274 | if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN)) | 284 | if (!nfs_page_group_sync_on_bit(req, PG_TEARDOWN)) |
275 | return; | 285 | return; |
276 | 286 | ||