aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorFred Isaman <iisaman@netapp.com>2011-03-23 09:27:51 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2011-03-23 15:29:03 -0400
commita861a1e1c398fe34701569fd8ac9225dfe0a9a7e (patch)
treefe28b8cfa4b8a6066ee6f2feeaa2b61e9bfaa0c0 /fs
parent425eb736cd905181a4dd4dc8d66342a7c7ab2f27 (diff)
NFSv4.1: add generic layer hooks for pnfs COMMIT
We create three major hooks for the pnfs code. pnfs_mark_request_commit() is called during writeback_done from nfs_mark_request_commit, which gives the driver an opportunity to claim it wants control over commiting a particular req. pnfs_choose_commit_list() is called from nfs_scan_list to choose which list a given req should be added to, based on where we intend to send it for COMMIT. It is up to the driver to have preallocated list headers for each destination it may need. pnfs_commit_list() is how the driver actually takes control, it is used instead of nfs_commit_list(). In order to pass information between the above functions, we create a union in nfs_page to hold a lseg (which is possible because the req is not on any list while in transition), and add some flags to indicate if we need to use the pnfs code. Signed-off-by: Fred Isaman <iisaman@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/pagelist.c5
-rw-r--r--fs/nfs/pnfs.h73
-rw-r--r--fs/nfs/write.c41
3 files changed, 102 insertions, 17 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index fd85618149a1..87a593c2b055 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -398,6 +398,7 @@ int nfs_scan_list(struct nfs_inode *nfsi,
398 pgoff_t idx_end; 398 pgoff_t idx_end;
399 int found, i; 399 int found, i;
400 int res; 400 int res;
401 struct list_head *list;
401 402
402 res = 0; 403 res = 0;
403 if (npages == 0) 404 if (npages == 0)
@@ -418,10 +419,10 @@ int nfs_scan_list(struct nfs_inode *nfsi,
418 idx_start = req->wb_index + 1; 419 idx_start = req->wb_index + 1;
419 if (nfs_set_page_tag_locked(req)) { 420 if (nfs_set_page_tag_locked(req)) {
420 kref_get(&req->wb_kref); 421 kref_get(&req->wb_kref);
421 nfs_list_remove_request(req);
422 radix_tree_tag_clear(&nfsi->nfs_page_tree, 422 radix_tree_tag_clear(&nfsi->nfs_page_tree,
423 req->wb_index, tag); 423 req->wb_index, tag);
424 nfs_list_add_request(req, dst); 424 list = pnfs_choose_commit_list(req, dst);
425 nfs_list_add_request(req, list);
425 res++; 426 res++;
426 if (res == INT_MAX) 427 if (res == INT_MAX)
427 goto out; 428 goto out;
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 6380b9405bcd..5370f1b9aa43 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -74,6 +74,13 @@ struct pnfs_layoutdriver_type {
74 /* test for nfs page cache coalescing */ 74 /* test for nfs page cache coalescing */
75 int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); 75 int (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *);
76 76
77 /* Returns true if layoutdriver wants to divert this request to
78 * driver's commit routine.
79 */
80 bool (*mark_pnfs_commit)(struct pnfs_layout_segment *lseg);
81 struct list_head * (*choose_commit_list) (struct nfs_page *req);
82 int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
83
77 /* 84 /*
78 * Return PNFS_ATTEMPTED to indicate the layout code has attempted 85 * Return PNFS_ATTEMPTED to indicate the layout code has attempted
79 * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS 86 * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS
@@ -169,6 +176,51 @@ static inline int pnfs_enabled_sb(struct nfs_server *nfss)
169 return nfss->pnfs_curr_ld != NULL; 176 return nfss->pnfs_curr_ld != NULL;
170} 177}
171 178
179static inline void
180pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
181{
182 if (lseg) {
183 struct pnfs_layoutdriver_type *ld;
184
185 ld = NFS_SERVER(req->wb_page->mapping->host)->pnfs_curr_ld;
186 if (ld->mark_pnfs_commit && ld->mark_pnfs_commit(lseg)) {
187 set_bit(PG_PNFS_COMMIT, &req->wb_flags);
188 req->wb_commit_lseg = get_lseg(lseg);
189 }
190 }
191}
192
193static inline int
194pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
195{
196 if (!test_and_clear_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags))
197 return PNFS_NOT_ATTEMPTED;
198 return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
199}
200
201static inline struct list_head *
202pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
203{
204 struct list_head *rv;
205
206 if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags)) {
207 struct inode *inode = req->wb_commit_lseg->pls_layout->plh_inode;
208
209 set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
210 rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req);
211 /* matched by ref taken when PG_PNFS_COMMIT is set */
212 put_lseg(req->wb_commit_lseg);
213 } else
214 rv = mds;
215 return rv;
216}
217
218static inline void pnfs_clear_request_commit(struct nfs_page *req)
219{
220 if (test_and_clear_bit(PG_PNFS_COMMIT, &req->wb_flags))
221 put_lseg(req->wb_commit_lseg);
222}
223
172#else /* CONFIG_NFS_V4_1 */ 224#else /* CONFIG_NFS_V4_1 */
173 225
174static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) 226static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -252,6 +304,27 @@ pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *ino)
252 pgio->pg_test = NULL; 304 pgio->pg_test = NULL;
253} 305}
254 306
307static inline void
308pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
309{
310}
311
312static inline int
313pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
314{
315 return PNFS_NOT_ATTEMPTED;
316}
317
318static inline struct list_head *
319pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds)
320{
321 return mds;
322}
323
324static inline void pnfs_clear_request_commit(struct nfs_page *req)
325{
326}
327
255#endif /* CONFIG_NFS_V4_1 */ 328#endif /* CONFIG_NFS_V4_1 */
256 329
257#endif /* FS_NFS_PNFS_H */ 330#endif /* FS_NFS_PNFS_H */
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index f5f005e9db48..6927a18b6891 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -441,7 +441,7 @@ nfs_mark_request_dirty(struct nfs_page *req)
441 * Add a request to the inode's commit list. 441 * Add a request to the inode's commit list.
442 */ 442 */
443static void 443static void
444nfs_mark_request_commit(struct nfs_page *req) 444nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
445{ 445{
446 struct inode *inode = req->wb_context->path.dentry->d_inode; 446 struct inode *inode = req->wb_context->path.dentry->d_inode;
447 struct nfs_inode *nfsi = NFS_I(inode); 447 struct nfs_inode *nfsi = NFS_I(inode);
@@ -453,6 +453,7 @@ nfs_mark_request_commit(struct nfs_page *req)
453 NFS_PAGE_TAG_COMMIT); 453 NFS_PAGE_TAG_COMMIT);
454 nfsi->ncommit++; 454 nfsi->ncommit++;
455 spin_unlock(&inode->i_lock); 455 spin_unlock(&inode->i_lock);
456 pnfs_mark_request_commit(req, lseg);
456 inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); 457 inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
457 inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); 458 inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
458 __mark_inode_dirty(inode, I_DIRTY_DATASYNC); 459 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
@@ -481,10 +482,11 @@ int nfs_write_need_commit(struct nfs_write_data *data)
481} 482}
482 483
483static inline 484static inline
484int nfs_reschedule_unstable_write(struct nfs_page *req) 485int nfs_reschedule_unstable_write(struct nfs_page *req,
486 struct nfs_write_data *data)
485{ 487{
486 if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { 488 if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) {
487 nfs_mark_request_commit(req); 489 nfs_mark_request_commit(req, data->lseg);
488 return 1; 490 return 1;
489 } 491 }
490 if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { 492 if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) {
@@ -495,7 +497,7 @@ int nfs_reschedule_unstable_write(struct nfs_page *req)
495} 497}
496#else 498#else
497static inline void 499static inline void
498nfs_mark_request_commit(struct nfs_page *req) 500nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
499{ 501{
500} 502}
501 503
@@ -512,7 +514,8 @@ int nfs_write_need_commit(struct nfs_write_data *data)
512} 514}
513 515
514static inline 516static inline
515int nfs_reschedule_unstable_write(struct nfs_page *req) 517int nfs_reschedule_unstable_write(struct nfs_page *req,
518 struct nfs_write_data *data)
516{ 519{
517 return 0; 520 return 0;
518} 521}
@@ -615,9 +618,11 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
615 } 618 }
616 619
617 if (nfs_clear_request_commit(req) && 620 if (nfs_clear_request_commit(req) &&
618 radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree, 621 radix_tree_tag_clear(&NFS_I(inode)->nfs_page_tree,
619 req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) 622 req->wb_index, NFS_PAGE_TAG_COMMIT) != NULL) {
620 NFS_I(inode)->ncommit--; 623 NFS_I(inode)->ncommit--;
624 pnfs_clear_request_commit(req);
625 }
621 626
622 /* Okay, the request matches. Update the region */ 627 /* Okay, the request matches. Update the region */
623 if (offset < req->wb_offset) { 628 if (offset < req->wb_offset) {
@@ -765,11 +770,12 @@ int nfs_updatepage(struct file *file, struct page *page,
765 return status; 770 return status;
766} 771}
767 772
768static void nfs_writepage_release(struct nfs_page *req) 773static void nfs_writepage_release(struct nfs_page *req,
774 struct nfs_write_data *data)
769{ 775{
770 struct page *page = req->wb_page; 776 struct page *page = req->wb_page;
771 777
772 if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) 778 if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req, data))
773 nfs_inode_remove_request(req); 779 nfs_inode_remove_request(req);
774 nfs_clear_page_tag_locked(req); 780 nfs_clear_page_tag_locked(req);
775 nfs_end_page_writeback(page); 781 nfs_end_page_writeback(page);
@@ -1087,7 +1093,7 @@ static void nfs_writeback_release_partial(void *calldata)
1087 1093
1088out: 1094out:
1089 if (atomic_dec_and_test(&req->wb_complete)) 1095 if (atomic_dec_and_test(&req->wb_complete))
1090 nfs_writepage_release(req); 1096 nfs_writepage_release(req, data);
1091 nfs_writedata_release(calldata); 1097 nfs_writedata_release(calldata);
1092} 1098}
1093 1099
@@ -1154,7 +1160,7 @@ static void nfs_writeback_release_full(void *calldata)
1154 1160
1155 if (nfs_write_need_commit(data)) { 1161 if (nfs_write_need_commit(data)) {
1156 memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); 1162 memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
1157 nfs_mark_request_commit(req); 1163 nfs_mark_request_commit(req, data->lseg);
1158 dprintk(" marked for commit\n"); 1164 dprintk(" marked for commit\n");
1159 goto next; 1165 goto next;
1160 } 1166 }
@@ -1357,14 +1363,15 @@ static void nfs_init_commit(struct nfs_write_data *data,
1357 nfs_fattr_init(&data->fattr); 1363 nfs_fattr_init(&data->fattr);
1358} 1364}
1359 1365
1360static void nfs_retry_commit(struct list_head *page_list) 1366static void nfs_retry_commit(struct list_head *page_list,
1367 struct pnfs_layout_segment *lseg)
1361{ 1368{
1362 struct nfs_page *req; 1369 struct nfs_page *req;
1363 1370
1364 while (!list_empty(page_list)) { 1371 while (!list_empty(page_list)) {
1365 req = nfs_list_entry(page_list->next); 1372 req = nfs_list_entry(page_list->next);
1366 nfs_list_remove_request(req); 1373 nfs_list_remove_request(req);
1367 nfs_mark_request_commit(req); 1374 nfs_mark_request_commit(req, lseg);
1368 dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); 1375 dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
1369 dec_bdi_stat(req->wb_page->mapping->backing_dev_info, 1376 dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
1370 BDI_RECLAIMABLE); 1377 BDI_RECLAIMABLE);
@@ -1389,7 +1396,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
1389 nfs_init_commit(data, head); 1396 nfs_init_commit(data, head);
1390 return nfs_initiate_commit(data, NFS_CLIENT(inode), data->mds_ops, how); 1397 return nfs_initiate_commit(data, NFS_CLIENT(inode), data->mds_ops, how);
1391 out_bad: 1398 out_bad:
1392 nfs_retry_commit(head); 1399 nfs_retry_commit(head, NULL);
1393 nfs_commit_clear_lock(NFS_I(inode)); 1400 nfs_commit_clear_lock(NFS_I(inode));
1394 return -ENOMEM; 1401 return -ENOMEM;
1395} 1402}
@@ -1477,7 +1484,11 @@ int nfs_commit_inode(struct inode *inode, int how)
1477 res = nfs_scan_commit(inode, &head, 0, 0); 1484 res = nfs_scan_commit(inode, &head, 0, 0);
1478 spin_unlock(&inode->i_lock); 1485 spin_unlock(&inode->i_lock);
1479 if (res) { 1486 if (res) {
1480 int error = nfs_commit_list(inode, &head, how); 1487 int error;
1488
1489 error = pnfs_commit_list(inode, &head, how);
1490 if (error == PNFS_NOT_ATTEMPTED)
1491 error = nfs_commit_list(inode, &head, how);
1481 if (error < 0) 1492 if (error < 0)
1482 return error; 1493 return error;
1483 if (!may_wait) 1494 if (!may_wait)