aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/pagelist.c5
-rw-r--r--fs/nfs/pnfs.h73
-rw-r--r--fs/nfs/write.c41
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfs_page.h6
5 files changed, 108 insertions, 18 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)
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 4179c368844b..eddda6ce7c42 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -226,6 +226,7 @@ struct nfs_inode {
226#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ 226#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */
227#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ 227#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */
228#define NFS_INO_COMMIT (7) /* inode is committing unstable writes */ 228#define NFS_INO_COMMIT (7) /* inode is committing unstable writes */
229#define NFS_INO_PNFS_COMMIT (8) /* use pnfs code for commit */
229 230
230static inline struct nfs_inode *NFS_I(const struct inode *inode) 231static inline struct nfs_inode *NFS_I(const struct inode *inode)
231{ 232{
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h
index 92d54c81f51e..8023e4e25133 100644
--- a/include/linux/nfs_page.h
+++ b/include/linux/nfs_page.h
@@ -33,11 +33,15 @@ enum {
33 PG_CLEAN, 33 PG_CLEAN,
34 PG_NEED_COMMIT, 34 PG_NEED_COMMIT,
35 PG_NEED_RESCHED, 35 PG_NEED_RESCHED,
36 PG_PNFS_COMMIT,
36}; 37};
37 38
38struct nfs_inode; 39struct nfs_inode;
39struct nfs_page { 40struct nfs_page {
40 struct list_head wb_list; /* Defines state of page: */ 41 union {
42 struct list_head wb_list; /* Defines state of page: */
43 struct pnfs_layout_segment *wb_commit_lseg; /* Used when PG_PNFS_COMMIT set */
44 };
41 struct page *wb_page; /* page to read in/write out */ 45 struct page *wb_page; /* page to read in/write out */
42 struct nfs_open_context *wb_context; /* File state context info */ 46 struct nfs_open_context *wb_context; /* File state context info */
43 struct nfs_lock_context *wb_lock_context; /* lock context info */ 47 struct nfs_lock_context *wb_lock_context; /* lock context info */