diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 258 |
1 files changed, 82 insertions, 176 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 797558941745..5d44b8bd1070 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -38,7 +38,8 @@ | |||
38 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, | 38 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, |
39 | struct page *, | 39 | struct page *, |
40 | unsigned int, unsigned int); | 40 | unsigned int, unsigned int); |
41 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how); | 41 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc, |
42 | struct inode *inode, int ioflags); | ||
42 | static const struct rpc_call_ops nfs_write_partial_ops; | 43 | static const struct rpc_call_ops nfs_write_partial_ops; |
43 | static const struct rpc_call_ops nfs_write_full_ops; | 44 | static const struct rpc_call_ops nfs_write_full_ops; |
44 | static const struct rpc_call_ops nfs_commit_ops; | 45 | static const struct rpc_call_ops nfs_commit_ops; |
@@ -71,9 +72,8 @@ void nfs_commit_free(struct nfs_write_data *wdata) | |||
71 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); | 72 | call_rcu_bh(&wdata->task.u.tk_rcu, nfs_commit_rcu_free); |
72 | } | 73 | } |
73 | 74 | ||
74 | struct nfs_write_data *nfs_writedata_alloc(size_t len) | 75 | struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount) |
75 | { | 76 | { |
76 | unsigned int pagecount = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
77 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); | 77 | struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS); |
78 | 78 | ||
79 | if (p) { | 79 | if (p) { |
@@ -139,7 +139,7 @@ static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int c | |||
139 | { | 139 | { |
140 | struct inode *inode = page->mapping->host; | 140 | struct inode *inode = page->mapping->host; |
141 | loff_t end, i_size = i_size_read(inode); | 141 | loff_t end, i_size = i_size_read(inode); |
142 | unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; | 142 | pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT; |
143 | 143 | ||
144 | if (i_size > 0 && page->index < end_index) | 144 | if (i_size > 0 && page->index < end_index) |
145 | return; | 145 | return; |
@@ -201,7 +201,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
201 | static int wb_priority(struct writeback_control *wbc) | 201 | static int wb_priority(struct writeback_control *wbc) |
202 | { | 202 | { |
203 | if (wbc->for_reclaim) | 203 | if (wbc->for_reclaim) |
204 | return FLUSH_HIGHPRI; | 204 | return FLUSH_HIGHPRI | FLUSH_STABLE; |
205 | if (wbc->for_kupdate) | 205 | if (wbc->for_kupdate) |
206 | return FLUSH_LOWPRI; | 206 | return FLUSH_LOWPRI; |
207 | return 0; | 207 | return 0; |
@@ -251,7 +251,8 @@ static void nfs_end_page_writeback(struct page *page) | |||
251 | * was not tagged. | 251 | * was not tagged. |
252 | * May also return an error if the user signalled nfs_wait_on_request(). | 252 | * May also return an error if the user signalled nfs_wait_on_request(). |
253 | */ | 253 | */ |
254 | static int nfs_page_mark_flush(struct page *page) | 254 | static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio, |
255 | struct page *page) | ||
255 | { | 256 | { |
256 | struct nfs_page *req; | 257 | struct nfs_page *req; |
257 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); | 258 | struct nfs_inode *nfsi = NFS_I(page->mapping->host); |
@@ -273,6 +274,8 @@ static int nfs_page_mark_flush(struct page *page) | |||
273 | * request as dirty (in which case we don't care). | 274 | * request as dirty (in which case we don't care). |
274 | */ | 275 | */ |
275 | spin_unlock(req_lock); | 276 | spin_unlock(req_lock); |
277 | /* Prevent deadlock! */ | ||
278 | nfs_pageio_complete(pgio); | ||
276 | ret = nfs_wait_on_request(req); | 279 | ret = nfs_wait_on_request(req); |
277 | nfs_release_request(req); | 280 | nfs_release_request(req); |
278 | if (ret != 0) | 281 | if (ret != 0) |
@@ -283,21 +286,18 @@ static int nfs_page_mark_flush(struct page *page) | |||
283 | /* This request is marked for commit */ | 286 | /* This request is marked for commit */ |
284 | spin_unlock(req_lock); | 287 | spin_unlock(req_lock); |
285 | nfs_unlock_request(req); | 288 | nfs_unlock_request(req); |
289 | nfs_pageio_complete(pgio); | ||
286 | return 1; | 290 | return 1; |
287 | } | 291 | } |
288 | if (nfs_set_page_writeback(page) == 0) { | 292 | if (nfs_set_page_writeback(page) != 0) { |
289 | nfs_list_remove_request(req); | ||
290 | /* add the request to the inode's dirty list. */ | ||
291 | radix_tree_tag_set(&nfsi->nfs_page_tree, | ||
292 | req->wb_index, NFS_PAGE_TAG_DIRTY); | ||
293 | nfs_list_add_request(req, &nfsi->dirty); | ||
294 | nfsi->ndirty++; | ||
295 | spin_unlock(req_lock); | ||
296 | __mark_inode_dirty(page->mapping->host, I_DIRTY_PAGES); | ||
297 | } else | ||
298 | spin_unlock(req_lock); | 293 | spin_unlock(req_lock); |
294 | BUG(); | ||
295 | } | ||
296 | radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index, | ||
297 | NFS_PAGE_TAG_WRITEBACK); | ||
299 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); | 298 | ret = test_bit(PG_NEED_FLUSH, &req->wb_flags); |
300 | nfs_unlock_request(req); | 299 | spin_unlock(req_lock); |
300 | nfs_pageio_add_request(pgio, req); | ||
301 | return ret; | 301 | return ret; |
302 | } | 302 | } |
303 | 303 | ||
@@ -306,6 +306,7 @@ static int nfs_page_mark_flush(struct page *page) | |||
306 | */ | 306 | */ |
307 | static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) | 307 | static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc) |
308 | { | 308 | { |
309 | struct nfs_pageio_descriptor mypgio, *pgio; | ||
309 | struct nfs_open_context *ctx; | 310 | struct nfs_open_context *ctx; |
310 | struct inode *inode = page->mapping->host; | 311 | struct inode *inode = page->mapping->host; |
311 | unsigned offset; | 312 | unsigned offset; |
@@ -314,7 +315,14 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc | |||
314 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 315 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
315 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 316 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
316 | 317 | ||
317 | err = nfs_page_mark_flush(page); | 318 | if (wbc->for_writepages) |
319 | pgio = wbc->fs_private; | ||
320 | else { | ||
321 | nfs_pageio_init_write(&mypgio, inode, wb_priority(wbc)); | ||
322 | pgio = &mypgio; | ||
323 | } | ||
324 | |||
325 | err = nfs_page_async_flush(pgio, page); | ||
318 | if (err <= 0) | 326 | if (err <= 0) |
319 | goto out; | 327 | goto out; |
320 | err = 0; | 328 | err = 0; |
@@ -331,12 +339,12 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc | |||
331 | put_nfs_open_context(ctx); | 339 | put_nfs_open_context(ctx); |
332 | if (err != 0) | 340 | if (err != 0) |
333 | goto out; | 341 | goto out; |
334 | err = nfs_page_mark_flush(page); | 342 | err = nfs_page_async_flush(pgio, page); |
335 | if (err > 0) | 343 | if (err > 0) |
336 | err = 0; | 344 | err = 0; |
337 | out: | 345 | out: |
338 | if (!wbc->for_writepages) | 346 | if (!wbc->for_writepages) |
339 | nfs_flush_mapping(page->mapping, wbc, FLUSH_STABLE|wb_priority(wbc)); | 347 | nfs_pageio_complete(pgio); |
340 | return err; | 348 | return err; |
341 | } | 349 | } |
342 | 350 | ||
@@ -352,20 +360,20 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) | |||
352 | int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | 360 | int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) |
353 | { | 361 | { |
354 | struct inode *inode = mapping->host; | 362 | struct inode *inode = mapping->host; |
363 | struct nfs_pageio_descriptor pgio; | ||
355 | int err; | 364 | int err; |
356 | 365 | ||
357 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); | 366 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); |
358 | 367 | ||
368 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc)); | ||
369 | wbc->fs_private = &pgio; | ||
359 | err = generic_writepages(mapping, wbc); | 370 | err = generic_writepages(mapping, wbc); |
371 | nfs_pageio_complete(&pgio); | ||
360 | if (err) | 372 | if (err) |
361 | return err; | 373 | return err; |
362 | err = nfs_flush_mapping(mapping, wbc, wb_priority(wbc)); | 374 | if (pgio.pg_error) |
363 | if (err < 0) | 375 | return pgio.pg_error; |
364 | goto out; | 376 | return 0; |
365 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, err); | ||
366 | err = 0; | ||
367 | out: | ||
368 | return err; | ||
369 | } | 377 | } |
370 | 378 | ||
371 | /* | 379 | /* |
@@ -503,11 +511,11 @@ int nfs_reschedule_unstable_write(struct nfs_page *req) | |||
503 | * | 511 | * |
504 | * Interruptible by signals only if mounted with intr flag. | 512 | * Interruptible by signals only if mounted with intr flag. |
505 | */ | 513 | */ |
506 | static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_start, unsigned int npages) | 514 | static int nfs_wait_on_requests_locked(struct inode *inode, pgoff_t idx_start, unsigned int npages) |
507 | { | 515 | { |
508 | struct nfs_inode *nfsi = NFS_I(inode); | 516 | struct nfs_inode *nfsi = NFS_I(inode); |
509 | struct nfs_page *req; | 517 | struct nfs_page *req; |
510 | unsigned long idx_end, next; | 518 | pgoff_t idx_end, next; |
511 | unsigned int res = 0; | 519 | unsigned int res = 0; |
512 | int error; | 520 | int error; |
513 | 521 | ||
@@ -536,18 +544,6 @@ static int nfs_wait_on_requests_locked(struct inode *inode, unsigned long idx_st | |||
536 | return res; | 544 | return res; |
537 | } | 545 | } |
538 | 546 | ||
539 | static void nfs_cancel_dirty_list(struct list_head *head) | ||
540 | { | ||
541 | struct nfs_page *req; | ||
542 | while(!list_empty(head)) { | ||
543 | req = nfs_list_entry(head->next); | ||
544 | nfs_list_remove_request(req); | ||
545 | nfs_end_page_writeback(req->wb_page); | ||
546 | nfs_inode_remove_request(req); | ||
547 | nfs_clear_page_writeback(req); | ||
548 | } | ||
549 | } | ||
550 | |||
551 | static void nfs_cancel_commit_list(struct list_head *head) | 547 | static void nfs_cancel_commit_list(struct list_head *head) |
552 | { | 548 | { |
553 | struct nfs_page *req; | 549 | struct nfs_page *req; |
@@ -574,7 +570,7 @@ static void nfs_cancel_commit_list(struct list_head *head) | |||
574 | * The requests are *not* checked to ensure that they form a contiguous set. | 570 | * The requests are *not* checked to ensure that they form a contiguous set. |
575 | */ | 571 | */ |
576 | static int | 572 | static int |
577 | nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 573 | nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
578 | { | 574 | { |
579 | struct nfs_inode *nfsi = NFS_I(inode); | 575 | struct nfs_inode *nfsi = NFS_I(inode); |
580 | int res = 0; | 576 | int res = 0; |
@@ -588,40 +584,12 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_st | |||
588 | return res; | 584 | return res; |
589 | } | 585 | } |
590 | #else | 586 | #else |
591 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages) | 587 | static inline int nfs_scan_commit(struct inode *inode, struct list_head *dst, pgoff_t idx_start, unsigned int npages) |
592 | { | 588 | { |
593 | return 0; | 589 | return 0; |
594 | } | 590 | } |
595 | #endif | 591 | #endif |
596 | 592 | ||
597 | static int nfs_wait_on_write_congestion(struct address_space *mapping) | ||
598 | { | ||
599 | struct inode *inode = mapping->host; | ||
600 | struct backing_dev_info *bdi = mapping->backing_dev_info; | ||
601 | int ret = 0; | ||
602 | |||
603 | might_sleep(); | ||
604 | |||
605 | if (!bdi_write_congested(bdi)) | ||
606 | return 0; | ||
607 | |||
608 | nfs_inc_stats(inode, NFSIOS_CONGESTIONWAIT); | ||
609 | |||
610 | do { | ||
611 | struct rpc_clnt *clnt = NFS_CLIENT(inode); | ||
612 | sigset_t oldset; | ||
613 | |||
614 | rpc_clnt_sigmask(clnt, &oldset); | ||
615 | ret = congestion_wait_interruptible(WRITE, HZ/10); | ||
616 | rpc_clnt_sigunmask(clnt, &oldset); | ||
617 | if (ret == -ERESTARTSYS) | ||
618 | break; | ||
619 | ret = 0; | ||
620 | } while (bdi_write_congested(bdi)); | ||
621 | |||
622 | return ret; | ||
623 | } | ||
624 | |||
625 | /* | 593 | /* |
626 | * Try to update any existing write request, or create one if there is none. | 594 | * Try to update any existing write request, or create one if there is none. |
627 | * In order to match, the request's credentials must match those of | 595 | * In order to match, the request's credentials must match those of |
@@ -636,12 +604,10 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | |||
636 | struct inode *inode = mapping->host; | 604 | struct inode *inode = mapping->host; |
637 | struct nfs_inode *nfsi = NFS_I(inode); | 605 | struct nfs_inode *nfsi = NFS_I(inode); |
638 | struct nfs_page *req, *new = NULL; | 606 | struct nfs_page *req, *new = NULL; |
639 | unsigned long rqend, end; | 607 | pgoff_t rqend, end; |
640 | 608 | ||
641 | end = offset + bytes; | 609 | end = offset + bytes; |
642 | 610 | ||
643 | if (nfs_wait_on_write_congestion(mapping)) | ||
644 | return ERR_PTR(-ERESTARTSYS); | ||
645 | for (;;) { | 611 | for (;;) { |
646 | /* Loop over all inode entries and see if we find | 612 | /* Loop over all inode entries and see if we find |
647 | * A request for the page we wish to update | 613 | * A request for the page we wish to update |
@@ -865,7 +831,7 @@ static void nfs_execute_write(struct nfs_write_data *data) | |||
865 | * Generate multiple small requests to write out a single | 831 | * Generate multiple small requests to write out a single |
866 | * contiguous dirty area on one page. | 832 | * contiguous dirty area on one page. |
867 | */ | 833 | */ |
868 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | 834 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) |
869 | { | 835 | { |
870 | struct nfs_page *req = nfs_list_entry(head->next); | 836 | struct nfs_page *req = nfs_list_entry(head->next); |
871 | struct page *page = req->wb_page; | 837 | struct page *page = req->wb_page; |
@@ -877,11 +843,11 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | |||
877 | 843 | ||
878 | nfs_list_remove_request(req); | 844 | nfs_list_remove_request(req); |
879 | 845 | ||
880 | nbytes = req->wb_bytes; | 846 | nbytes = count; |
881 | do { | 847 | do { |
882 | size_t len = min(nbytes, wsize); | 848 | size_t len = min(nbytes, wsize); |
883 | 849 | ||
884 | data = nfs_writedata_alloc(len); | 850 | data = nfs_writedata_alloc(1); |
885 | if (!data) | 851 | if (!data) |
886 | goto out_bad; | 852 | goto out_bad; |
887 | list_add(&data->pages, &list); | 853 | list_add(&data->pages, &list); |
@@ -892,23 +858,19 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, int how) | |||
892 | 858 | ||
893 | ClearPageError(page); | 859 | ClearPageError(page); |
894 | offset = 0; | 860 | offset = 0; |
895 | nbytes = req->wb_bytes; | 861 | nbytes = count; |
896 | do { | 862 | do { |
897 | data = list_entry(list.next, struct nfs_write_data, pages); | 863 | data = list_entry(list.next, struct nfs_write_data, pages); |
898 | list_del_init(&data->pages); | 864 | list_del_init(&data->pages); |
899 | 865 | ||
900 | data->pagevec[0] = page; | 866 | data->pagevec[0] = page; |
901 | 867 | ||
902 | if (nbytes > wsize) { | 868 | if (nbytes < wsize) |
903 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 869 | wsize = nbytes; |
904 | wsize, offset, how); | 870 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
905 | offset += wsize; | 871 | wsize, offset, how); |
906 | nbytes -= wsize; | 872 | offset += wsize; |
907 | } else { | 873 | nbytes -= wsize; |
908 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | ||
909 | nbytes, offset, how); | ||
910 | nbytes = 0; | ||
911 | } | ||
912 | nfs_execute_write(data); | 874 | nfs_execute_write(data); |
913 | } while (nbytes != 0); | 875 | } while (nbytes != 0); |
914 | 876 | ||
@@ -934,26 +896,23 @@ out_bad: | |||
934 | * This is the case if nfs_updatepage detects a conflicting request | 896 | * This is the case if nfs_updatepage detects a conflicting request |
935 | * that has been written but not committed. | 897 | * that has been written but not committed. |
936 | */ | 898 | */ |
937 | static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | 899 | static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) |
938 | { | 900 | { |
939 | struct nfs_page *req; | 901 | struct nfs_page *req; |
940 | struct page **pages; | 902 | struct page **pages; |
941 | struct nfs_write_data *data; | 903 | struct nfs_write_data *data; |
942 | unsigned int count; | ||
943 | 904 | ||
944 | data = nfs_writedata_alloc(NFS_SERVER(inode)->wsize); | 905 | data = nfs_writedata_alloc(npages); |
945 | if (!data) | 906 | if (!data) |
946 | goto out_bad; | 907 | goto out_bad; |
947 | 908 | ||
948 | pages = data->pagevec; | 909 | pages = data->pagevec; |
949 | count = 0; | ||
950 | while (!list_empty(head)) { | 910 | while (!list_empty(head)) { |
951 | req = nfs_list_entry(head->next); | 911 | req = nfs_list_entry(head->next); |
952 | nfs_list_remove_request(req); | 912 | nfs_list_remove_request(req); |
953 | nfs_list_add_request(req, &data->pages); | 913 | nfs_list_add_request(req, &data->pages); |
954 | ClearPageError(req->wb_page); | 914 | ClearPageError(req->wb_page); |
955 | *pages++ = req->wb_page; | 915 | *pages++ = req->wb_page; |
956 | count += req->wb_bytes; | ||
957 | } | 916 | } |
958 | req = nfs_list_entry(data->pages.next); | 917 | req = nfs_list_entry(data->pages.next); |
959 | 918 | ||
@@ -973,40 +932,15 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, int how) | |||
973 | return -ENOMEM; | 932 | return -ENOMEM; |
974 | } | 933 | } |
975 | 934 | ||
976 | static int nfs_flush_list(struct inode *inode, struct list_head *head, int npages, int how) | 935 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
936 | struct inode *inode, int ioflags) | ||
977 | { | 937 | { |
978 | LIST_HEAD(one_request); | ||
979 | int (*flush_one)(struct inode *, struct list_head *, int); | ||
980 | struct nfs_page *req; | ||
981 | int wpages = NFS_SERVER(inode)->wpages; | ||
982 | int wsize = NFS_SERVER(inode)->wsize; | 938 | int wsize = NFS_SERVER(inode)->wsize; |
983 | int error; | ||
984 | 939 | ||
985 | flush_one = nfs_flush_one; | ||
986 | if (wsize < PAGE_CACHE_SIZE) | 940 | if (wsize < PAGE_CACHE_SIZE) |
987 | flush_one = nfs_flush_multi; | 941 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); |
988 | /* For single writes, FLUSH_STABLE is more efficient */ | 942 | else |
989 | if (npages <= wpages && npages == NFS_I(inode)->npages | 943 | nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags); |
990 | && nfs_list_entry(head->next)->wb_bytes <= wsize) | ||
991 | how |= FLUSH_STABLE; | ||
992 | |||
993 | do { | ||
994 | nfs_coalesce_requests(head, &one_request, wpages); | ||
995 | req = nfs_list_entry(one_request.next); | ||
996 | error = flush_one(inode, &one_request, how); | ||
997 | if (error < 0) | ||
998 | goto out_err; | ||
999 | } while (!list_empty(head)); | ||
1000 | return 0; | ||
1001 | out_err: | ||
1002 | while (!list_empty(head)) { | ||
1003 | req = nfs_list_entry(head->next); | ||
1004 | nfs_list_remove_request(req); | ||
1005 | nfs_redirty_request(req); | ||
1006 | nfs_end_page_writeback(req->wb_page); | ||
1007 | nfs_clear_page_writeback(req); | ||
1008 | } | ||
1009 | return error; | ||
1010 | } | 944 | } |
1011 | 945 | ||
1012 | /* | 946 | /* |
@@ -1330,31 +1264,7 @@ static const struct rpc_call_ops nfs_commit_ops = { | |||
1330 | .rpc_call_done = nfs_commit_done, | 1264 | .rpc_call_done = nfs_commit_done, |
1331 | .rpc_release = nfs_commit_release, | 1265 | .rpc_release = nfs_commit_release, |
1332 | }; | 1266 | }; |
1333 | #else | ||
1334 | static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how) | ||
1335 | { | ||
1336 | return 0; | ||
1337 | } | ||
1338 | #endif | ||
1339 | |||
1340 | static long nfs_flush_mapping(struct address_space *mapping, struct writeback_control *wbc, int how) | ||
1341 | { | ||
1342 | struct nfs_inode *nfsi = NFS_I(mapping->host); | ||
1343 | LIST_HEAD(head); | ||
1344 | long res; | ||
1345 | |||
1346 | spin_lock(&nfsi->req_lock); | ||
1347 | res = nfs_scan_dirty(mapping, wbc, &head); | ||
1348 | spin_unlock(&nfsi->req_lock); | ||
1349 | if (res) { | ||
1350 | int error = nfs_flush_list(mapping->host, &head, res, how); | ||
1351 | if (error < 0) | ||
1352 | return error; | ||
1353 | } | ||
1354 | return res; | ||
1355 | } | ||
1356 | 1267 | ||
1357 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | ||
1358 | int nfs_commit_inode(struct inode *inode, int how) | 1268 | int nfs_commit_inode(struct inode *inode, int how) |
1359 | { | 1269 | { |
1360 | struct nfs_inode *nfsi = NFS_I(inode); | 1270 | struct nfs_inode *nfsi = NFS_I(inode); |
@@ -1371,13 +1281,18 @@ int nfs_commit_inode(struct inode *inode, int how) | |||
1371 | } | 1281 | } |
1372 | return res; | 1282 | return res; |
1373 | } | 1283 | } |
1284 | #else | ||
1285 | static inline int nfs_commit_list(struct inode *inode, struct list_head *head, int how) | ||
1286 | { | ||
1287 | return 0; | ||
1288 | } | ||
1374 | #endif | 1289 | #endif |
1375 | 1290 | ||
1376 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) | 1291 | long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_control *wbc, int how) |
1377 | { | 1292 | { |
1378 | struct inode *inode = mapping->host; | 1293 | struct inode *inode = mapping->host; |
1379 | struct nfs_inode *nfsi = NFS_I(inode); | 1294 | struct nfs_inode *nfsi = NFS_I(inode); |
1380 | unsigned long idx_start, idx_end; | 1295 | pgoff_t idx_start, idx_end; |
1381 | unsigned int npages = 0; | 1296 | unsigned int npages = 0; |
1382 | LIST_HEAD(head); | 1297 | LIST_HEAD(head); |
1383 | int nocommit = how & FLUSH_NOCOMMIT; | 1298 | int nocommit = how & FLUSH_NOCOMMIT; |
@@ -1390,41 +1305,24 @@ long nfs_sync_mapping_wait(struct address_space *mapping, struct writeback_contr | |||
1390 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; | 1305 | idx_start = wbc->range_start >> PAGE_CACHE_SHIFT; |
1391 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; | 1306 | idx_end = wbc->range_end >> PAGE_CACHE_SHIFT; |
1392 | if (idx_end > idx_start) { | 1307 | if (idx_end > idx_start) { |
1393 | unsigned long l_npages = 1 + idx_end - idx_start; | 1308 | pgoff_t l_npages = 1 + idx_end - idx_start; |
1394 | npages = l_npages; | 1309 | npages = l_npages; |
1395 | if (sizeof(npages) != sizeof(l_npages) && | 1310 | if (sizeof(npages) != sizeof(l_npages) && |
1396 | (unsigned long)npages != l_npages) | 1311 | (pgoff_t)npages != l_npages) |
1397 | npages = 0; | 1312 | npages = 0; |
1398 | } | 1313 | } |
1399 | } | 1314 | } |
1400 | how &= ~FLUSH_NOCOMMIT; | 1315 | how &= ~FLUSH_NOCOMMIT; |
1401 | spin_lock(&nfsi->req_lock); | 1316 | spin_lock(&nfsi->req_lock); |
1402 | do { | 1317 | do { |
1403 | wbc->pages_skipped = 0; | ||
1404 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); | 1318 | ret = nfs_wait_on_requests_locked(inode, idx_start, npages); |
1405 | if (ret != 0) | 1319 | if (ret != 0) |
1406 | continue; | 1320 | continue; |
1407 | pages = nfs_scan_dirty(mapping, wbc, &head); | ||
1408 | if (pages != 0) { | ||
1409 | spin_unlock(&nfsi->req_lock); | ||
1410 | if (how & FLUSH_INVALIDATE) { | ||
1411 | nfs_cancel_dirty_list(&head); | ||
1412 | ret = pages; | ||
1413 | } else | ||
1414 | ret = nfs_flush_list(inode, &head, pages, how); | ||
1415 | spin_lock(&nfsi->req_lock); | ||
1416 | continue; | ||
1417 | } | ||
1418 | if (wbc->pages_skipped != 0) | ||
1419 | continue; | ||
1420 | if (nocommit) | 1321 | if (nocommit) |
1421 | break; | 1322 | break; |
1422 | pages = nfs_scan_commit(inode, &head, idx_start, npages); | 1323 | pages = nfs_scan_commit(inode, &head, idx_start, npages); |
1423 | if (pages == 0) { | 1324 | if (pages == 0) |
1424 | if (wbc->pages_skipped != 0) | ||
1425 | continue; | ||
1426 | break; | 1325 | break; |
1427 | } | ||
1428 | if (how & FLUSH_INVALIDATE) { | 1326 | if (how & FLUSH_INVALIDATE) { |
1429 | spin_unlock(&nfsi->req_lock); | 1327 | spin_unlock(&nfsi->req_lock); |
1430 | nfs_cancel_commit_list(&head); | 1328 | nfs_cancel_commit_list(&head); |
@@ -1456,7 +1354,7 @@ int nfs_wb_all(struct inode *inode) | |||
1456 | }; | 1354 | }; |
1457 | int ret; | 1355 | int ret; |
1458 | 1356 | ||
1459 | ret = generic_writepages(mapping, &wbc); | 1357 | ret = nfs_writepages(mapping, &wbc); |
1460 | if (ret < 0) | 1358 | if (ret < 0) |
1461 | goto out; | 1359 | goto out; |
1462 | ret = nfs_sync_mapping_wait(mapping, &wbc, 0); | 1360 | ret = nfs_sync_mapping_wait(mapping, &wbc, 0); |
@@ -1479,11 +1377,9 @@ int nfs_sync_mapping_range(struct address_space *mapping, loff_t range_start, lo | |||
1479 | }; | 1377 | }; |
1480 | int ret; | 1378 | int ret; |
1481 | 1379 | ||
1482 | if (!(how & FLUSH_NOWRITEPAGE)) { | 1380 | ret = nfs_writepages(mapping, &wbc); |
1483 | ret = generic_writepages(mapping, &wbc); | 1381 | if (ret < 0) |
1484 | if (ret < 0) | 1382 | goto out; |
1485 | goto out; | ||
1486 | } | ||
1487 | ret = nfs_sync_mapping_wait(mapping, &wbc, how); | 1383 | ret = nfs_sync_mapping_wait(mapping, &wbc, how); |
1488 | if (ret >= 0) | 1384 | if (ret >= 0) |
1489 | return 0; | 1385 | return 0; |
@@ -1506,7 +1402,7 @@ int nfs_wb_page_priority(struct inode *inode, struct page *page, int how) | |||
1506 | int ret; | 1402 | int ret; |
1507 | 1403 | ||
1508 | BUG_ON(!PageLocked(page)); | 1404 | BUG_ON(!PageLocked(page)); |
1509 | if (!(how & FLUSH_NOWRITEPAGE) && clear_page_dirty_for_io(page)) { | 1405 | if (clear_page_dirty_for_io(page)) { |
1510 | ret = nfs_writepage_locked(page, &wbc); | 1406 | ret = nfs_writepage_locked(page, &wbc); |
1511 | if (ret < 0) | 1407 | if (ret < 0) |
1512 | goto out; | 1408 | goto out; |
@@ -1531,10 +1427,18 @@ int nfs_wb_page(struct inode *inode, struct page* page) | |||
1531 | 1427 | ||
1532 | int nfs_set_page_dirty(struct page *page) | 1428 | int nfs_set_page_dirty(struct page *page) |
1533 | { | 1429 | { |
1534 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | 1430 | struct address_space *mapping = page->mapping; |
1431 | struct inode *inode; | ||
1432 | spinlock_t *req_lock; | ||
1535 | struct nfs_page *req; | 1433 | struct nfs_page *req; |
1536 | int ret; | 1434 | int ret; |
1537 | 1435 | ||
1436 | if (!mapping) | ||
1437 | goto out_raced; | ||
1438 | inode = mapping->host; | ||
1439 | if (!inode) | ||
1440 | goto out_raced; | ||
1441 | req_lock = &NFS_I(inode)->req_lock; | ||
1538 | spin_lock(req_lock); | 1442 | spin_lock(req_lock); |
1539 | req = nfs_page_find_request_locked(page); | 1443 | req = nfs_page_find_request_locked(page); |
1540 | if (req != NULL) { | 1444 | if (req != NULL) { |
@@ -1547,6 +1451,8 @@ int nfs_set_page_dirty(struct page *page) | |||
1547 | ret = __set_page_dirty_nobuffers(page); | 1451 | ret = __set_page_dirty_nobuffers(page); |
1548 | spin_unlock(req_lock); | 1452 | spin_unlock(req_lock); |
1549 | return ret; | 1453 | return ret; |
1454 | out_raced: | ||
1455 | return !TestSetPageDirty(page); | ||
1550 | } | 1456 | } |
1551 | 1457 | ||
1552 | 1458 | ||