diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-08-22 13:44:32 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-08-24 15:51:08 -0400 |
commit | 79558f3610efd7928e8882b2eaca3093b283630e (patch) | |
tree | 125f16640cd7f9de2074dae89a9c6c405703029c /fs/nfs/read.c | |
parent | 01df9c5e918ae5559f2d96da0143f8bfbb9e6171 (diff) |
NFS: Fix issue with EIO on NFS read
The problem is that we may be caching writes that would extend the file and
create a hole in the region that we are reading. In this case, we need to
detect the eof from the server, ensure that we zero out the pages that
are part of the hole and mark them as up to date.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
(cherry picked from 856b603b01b99146918c093969b6cb1b1b0f1c01 commit)
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 65c0c5b32351..da9cf11c326f 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
@@ -116,10 +116,17 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) | |||
116 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | 116 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; |
117 | base &= ~PAGE_CACHE_MASK; | 117 | base &= ~PAGE_CACHE_MASK; |
118 | pglen = PAGE_CACHE_SIZE - base; | 118 | pglen = PAGE_CACHE_SIZE - base; |
119 | if (pglen < remainder) | 119 | for (;;) { |
120 | if (remainder <= pglen) { | ||
121 | memclear_highpage_flush(*pages, base, remainder); | ||
122 | break; | ||
123 | } | ||
120 | memclear_highpage_flush(*pages, base, pglen); | 124 | memclear_highpage_flush(*pages, base, pglen); |
121 | else | 125 | pages++; |
122 | memclear_highpage_flush(*pages, base, remainder); | 126 | remainder -= pglen; |
127 | pglen = PAGE_CACHE_SIZE; | ||
128 | base = 0; | ||
129 | } | ||
123 | } | 130 | } |
124 | 131 | ||
125 | /* | 132 | /* |
@@ -476,6 +483,8 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | |||
476 | unsigned int base = data->args.pgbase; | 483 | unsigned int base = data->args.pgbase; |
477 | struct page **pages; | 484 | struct page **pages; |
478 | 485 | ||
486 | if (data->res.eof) | ||
487 | count = data->args.count; | ||
479 | if (unlikely(count == 0)) | 488 | if (unlikely(count == 0)) |
480 | return; | 489 | return; |
481 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; | 490 | pages = &data->args.pages[base >> PAGE_CACHE_SHIFT]; |
@@ -483,11 +492,7 @@ static void nfs_readpage_set_pages_uptodate(struct nfs_read_data *data) | |||
483 | count += base; | 492 | count += base; |
484 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | 493 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) |
485 | SetPageUptodate(*pages); | 494 | SetPageUptodate(*pages); |
486 | /* | 495 | if (count != 0) |
487 | * Was this an eof or a short read? If the latter, don't mark the page | ||
488 | * as uptodate yet. | ||
489 | */ | ||
490 | if (count > 0 && (data->res.eof || data->args.count == data->res.count)) | ||
491 | SetPageUptodate(*pages); | 496 | SetPageUptodate(*pages); |
492 | } | 497 | } |
493 | 498 | ||
@@ -502,6 +507,8 @@ static void nfs_readpage_set_pages_error(struct nfs_read_data *data) | |||
502 | count += base; | 507 | count += base; |
503 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) | 508 | for (;count >= PAGE_CACHE_SIZE; count -= PAGE_CACHE_SIZE, pages++) |
504 | SetPageError(*pages); | 509 | SetPageError(*pages); |
510 | if (count != 0) | ||
511 | SetPageError(*pages); | ||
505 | } | 512 | } |
506 | 513 | ||
507 | /* | 514 | /* |