diff options
-rw-r--r-- | fs/nfs/pagelist.c | 5 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 73 | ||||
-rw-r--r-- | fs/nfs/write.c | 41 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 1 | ||||
-rw-r--r-- | include/linux/nfs_page.h | 6 |
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 | ||
179 | static inline void | ||
180 | pnfs_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 | |||
193 | static inline int | ||
194 | pnfs_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 | |||
201 | static inline struct list_head * | ||
202 | pnfs_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 | |||
218 | static 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 | ||
174 | static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) | 226 | static 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 | ||
307 | static inline void | ||
308 | pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | ||
309 | { | ||
310 | } | ||
311 | |||
312 | static inline int | ||
313 | pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how) | ||
314 | { | ||
315 | return PNFS_NOT_ATTEMPTED; | ||
316 | } | ||
317 | |||
318 | static inline struct list_head * | ||
319 | pnfs_choose_commit_list(struct nfs_page *req, struct list_head *mds) | ||
320 | { | ||
321 | return mds; | ||
322 | } | ||
323 | |||
324 | static 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 | */ |
443 | static void | 443 | static void |
444 | nfs_mark_request_commit(struct nfs_page *req) | 444 | nfs_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 | ||
483 | static inline | 484 | static inline |
484 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 485 | int 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 |
497 | static inline void | 499 | static inline void |
498 | nfs_mark_request_commit(struct nfs_page *req) | 500 | nfs_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 | ||
514 | static inline | 516 | static inline |
515 | int nfs_reschedule_unstable_write(struct nfs_page *req) | 517 | int 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 | ||
768 | static void nfs_writepage_release(struct nfs_page *req) | 773 | static 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 | ||
1088 | out: | 1094 | out: |
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 | ||
1360 | static void nfs_retry_commit(struct list_head *page_list) | 1366 | static 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 | ||
230 | static inline struct nfs_inode *NFS_I(const struct inode *inode) | 231 | static 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 | ||
38 | struct nfs_inode; | 39 | struct nfs_inode; |
39 | struct nfs_page { | 40 | struct 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 */ |