diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/write.c | 68 |
1 files changed, 24 insertions, 44 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 74e86601d978..de9a16a8f7e4 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -75,7 +75,6 @@ | |||
75 | * Local function declarations | 75 | * Local function declarations |
76 | */ | 76 | */ |
77 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, | 77 | static struct nfs_page * nfs_update_request(struct nfs_open_context*, |
78 | struct inode *, | ||
79 | struct page *, | 78 | struct page *, |
80 | unsigned int, unsigned int); | 79 | unsigned int, unsigned int); |
81 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 80 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
@@ -215,10 +214,10 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int | |||
215 | * Write a page synchronously. | 214 | * Write a page synchronously. |
216 | * Offset is the data offset within the page. | 215 | * Offset is the data offset within the page. |
217 | */ | 216 | */ |
218 | static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode, | 217 | static int nfs_writepage_sync(struct nfs_open_context *ctx, struct page *page, |
219 | struct page *page, unsigned int offset, unsigned int count, | 218 | unsigned int offset, unsigned int count, int how) |
220 | int how) | ||
221 | { | 219 | { |
220 | struct inode *inode = page->mapping->host; | ||
222 | unsigned int wsize = NFS_SERVER(inode)->wsize; | 221 | unsigned int wsize = NFS_SERVER(inode)->wsize; |
223 | int result, written = 0; | 222 | int result, written = 0; |
224 | struct nfs_write_data *wdata; | 223 | struct nfs_write_data *wdata; |
@@ -283,15 +282,23 @@ io_error: | |||
283 | return written ? written : result; | 282 | return written ? written : result; |
284 | } | 283 | } |
285 | 284 | ||
286 | static int nfs_writepage_async(struct nfs_open_context *ctx, | 285 | static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, |
287 | struct inode *inode, struct page *page, | ||
288 | unsigned int offset, unsigned int count) | 286 | unsigned int offset, unsigned int count) |
289 | { | 287 | { |
290 | struct nfs_page *req; | 288 | struct nfs_page *req; |
289 | int ret; | ||
291 | 290 | ||
292 | req = nfs_update_request(ctx, inode, page, offset, count); | 291 | for (;;) { |
293 | if (IS_ERR(req)) | 292 | req = nfs_update_request(ctx, page, offset, count); |
294 | return PTR_ERR(req); | 293 | if (!IS_ERR(req)) |
294 | break; | ||
295 | ret = PTR_ERR(req); | ||
296 | if (ret != -EBUSY) | ||
297 | return ret; | ||
298 | ret = nfs_wb_page(page->mapping->host, page); | ||
299 | if (ret != 0) | ||
300 | return ret; | ||
301 | } | ||
295 | /* Update file length */ | 302 | /* Update file length */ |
296 | nfs_grow_file(page, offset, count); | 303 | nfs_grow_file(page, offset, count); |
297 | /* Set the PG_uptodate flag? */ | 304 | /* Set the PG_uptodate flag? */ |
@@ -317,14 +324,13 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) | |||
317 | struct nfs_open_context *ctx; | 324 | struct nfs_open_context *ctx; |
318 | struct inode *inode = page->mapping->host; | 325 | struct inode *inode = page->mapping->host; |
319 | unsigned offset; | 326 | unsigned offset; |
320 | int priority = wb_priority(wbc); | ||
321 | int err; | 327 | int err; |
322 | 328 | ||
323 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); | 329 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE); |
324 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); | 330 | nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1); |
325 | 331 | ||
326 | /* Ensure we've flushed out any previous writes */ | 332 | /* Ensure we've flushed out any previous writes */ |
327 | nfs_wb_page_priority(inode, page, priority); | 333 | nfs_wb_page_priority(inode, page, wb_priority(wbc)); |
328 | 334 | ||
329 | err = 0; | 335 | err = 0; |
330 | offset = nfs_page_length(page); | 336 | offset = nfs_page_length(page); |
@@ -338,12 +344,11 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc) | |||
338 | } | 344 | } |
339 | lock_kernel(); | 345 | lock_kernel(); |
340 | if (!IS_SYNC(inode)) { | 346 | if (!IS_SYNC(inode)) { |
341 | err = nfs_writepage_async(ctx, inode, page, 0, offset); | 347 | err = nfs_writepage_setup(ctx, page, 0, offset); |
342 | if (!wbc->for_writepages) | 348 | if (!wbc->for_writepages) |
343 | nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); | 349 | nfs_flush_mapping(page->mapping, wbc, wb_priority(wbc)); |
344 | } else { | 350 | } else { |
345 | err = nfs_writepage_sync(ctx, inode, page, 0, | 351 | err = nfs_writepage_sync(ctx, page, 0, offset, wb_priority(wbc)); |
346 | offset, priority); | ||
347 | if (err >= 0) { | 352 | if (err >= 0) { |
348 | if (err != offset) | 353 | if (err != offset) |
349 | redirty_page_for_writepage(wbc, page); | 354 | redirty_page_for_writepage(wbc, page); |
@@ -643,17 +648,16 @@ static int nfs_wait_on_write_congestion(struct address_space *mapping, int intr) | |||
643 | * Note: Should always be called with the Page Lock held! | 648 | * Note: Should always be called with the Page Lock held! |
644 | */ | 649 | */ |
645 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, | 650 | static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx, |
646 | struct inode *inode, struct page *page, | 651 | struct page *page, unsigned int offset, unsigned int bytes) |
647 | unsigned int offset, unsigned int bytes) | ||
648 | { | 652 | { |
649 | struct nfs_server *server = NFS_SERVER(inode); | 653 | struct inode *inode = page->mapping->host; |
650 | struct nfs_inode *nfsi = NFS_I(inode); | 654 | struct nfs_inode *nfsi = NFS_I(inode); |
651 | struct nfs_page *req, *new = NULL; | 655 | struct nfs_page *req, *new = NULL; |
652 | unsigned long rqend, end; | 656 | unsigned long rqend, end; |
653 | 657 | ||
654 | end = offset + bytes; | 658 | end = offset + bytes; |
655 | 659 | ||
656 | if (nfs_wait_on_write_congestion(page->mapping, server->flags & NFS_MOUNT_INTR)) | 660 | if (nfs_wait_on_write_congestion(page->mapping, NFS_SERVER(inode)->flags & NFS_MOUNT_INTR)) |
657 | return ERR_PTR(-ERESTARTSYS); | 661 | return ERR_PTR(-ERESTARTSYS); |
658 | for (;;) { | 662 | for (;;) { |
659 | /* Loop over all inode entries and see if we find | 663 | /* Loop over all inode entries and see if we find |
@@ -764,7 +768,6 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
764 | { | 768 | { |
765 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 769 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
766 | struct inode *inode = page->mapping->host; | 770 | struct inode *inode = page->mapping->host; |
767 | struct nfs_page *req; | ||
768 | int status = 0; | 771 | int status = 0; |
769 | 772 | ||
770 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); | 773 | nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE); |
@@ -775,7 +778,7 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
775 | (long long)(page_offset(page) +offset)); | 778 | (long long)(page_offset(page) +offset)); |
776 | 779 | ||
777 | if (IS_SYNC(inode)) { | 780 | if (IS_SYNC(inode)) { |
778 | status = nfs_writepage_sync(ctx, inode, page, offset, count, 0); | 781 | status = nfs_writepage_sync(ctx, page, offset, count, 0); |
779 | if (status > 0) { | 782 | if (status > 0) { |
780 | if (offset == 0 && status == PAGE_CACHE_SIZE) | 783 | if (offset == 0 && status == PAGE_CACHE_SIZE) |
781 | SetPageUptodate(page); | 784 | SetPageUptodate(page); |
@@ -793,31 +796,8 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
793 | offset = 0; | 796 | offset = 0; |
794 | } | 797 | } |
795 | 798 | ||
796 | /* | 799 | status = nfs_writepage_setup(ctx, page, offset, count); |
797 | * Try to find an NFS request corresponding to this page | ||
798 | * and update it. | ||
799 | * If the existing request cannot be updated, we must flush | ||
800 | * it out now. | ||
801 | */ | ||
802 | do { | ||
803 | req = nfs_update_request(ctx, inode, page, offset, count); | ||
804 | status = (IS_ERR(req)) ? PTR_ERR(req) : 0; | ||
805 | if (status != -EBUSY) | ||
806 | break; | ||
807 | /* Request could not be updated. Flush it out and try again */ | ||
808 | status = nfs_wb_page(inode, page); | ||
809 | } while (status >= 0); | ||
810 | if (status < 0) | ||
811 | goto done; | ||
812 | |||
813 | status = 0; | ||
814 | 800 | ||
815 | /* Update file length */ | ||
816 | nfs_grow_file(page, offset, count); | ||
817 | /* Set the PG_uptodate flag? */ | ||
818 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | ||
819 | nfs_unlock_request(req); | ||
820 | done: | ||
821 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", | 801 | dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n", |
822 | status, (long long)i_size_read(inode)); | 802 | status, (long long)i_size_read(inode)); |
823 | if (status < 0) | 803 | if (status < 0) |