aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorWeston Andros Adamson <dros@primarydata.com>2014-07-11 10:20:46 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-07-12 16:51:41 -0400
commit85710a837c2026aae80b7c64187edf1f10027b0b (patch)
tree9b8ac697b4bc8aa635a6b97432bc76113703a85a /fs
parent17089a29a25a3bfe8d14520cd866b7d635ffe5ba (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')
-rw-r--r--fs/nfs/pagelist.c10
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