diff options
author | Fred Isaman <iisaman@citi.umich.edu> | 2008-03-19 18:24:39 +0300 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-03-20 00:59:02 +0300 |
commit | f8512ad0da16cbe156f3a7627971cdf0b39c4138 (patch) | |
tree | 2658c63faeda07505793ccc747ee4efbffdaa69c /fs/nfs/read.c | |
parent | 264e3e889d86e552b4191d69bb60f4f3b383135a (diff) | |
download | linux-f8512ad0da16cbe156f3a7627971cdf0b39c4138.tar.xz |
nfs: don't ignore return value from nfs_pageio_add_request
Ignoring the return value from nfs_pageio_add_request can cause deadlocks.
In read path:
call nfs_pageio_add_request from readpage_async_filler
assume at this point that there are requests already in desc, that
can't be merged with the current request.
so nfs_pageio_doio is fired up to clear out desc.
assume something goes wrong in setting up the io, so desc->pg_error is set.
This causes nfs_pageio_add_request to return 0, *WITHOUT* adding the original
request.
BUT, since return code is ignored, readpage_async_filler assumes it has
been added, and does nothing further, leaving page locked.
do_generic_mapping_read will eventually call lock_page, resulting in deadlock
In write path:
page is marked dirty by generic_perform_write
nfs_writepages is called
call nfs_pageio_add_request from nfs_page_async_flush
assume at this point that there are requests already in desc, that
can't be merged with the current request.
so nfs_pageio_doio is fired up to clear out desc.
assume something goes wrong in setting up the io, so desc->pg_error is set.
This causes nfs_page_async_flush to return 0, *WITHOUT* adding the original
request, yet marking the request as locked (PG_BUSY) and in writeback,
clearing dirty marks.
The next time a write is done to the page, deadlock will result as
nfs_write_end calls nfs_update_request
Signed-off-by: Fred Isaman <iisaman@citi.umich.edu>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/read.c')
-rw-r--r-- | fs/nfs/read.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 3d7d9631e125..5a70be589bbe 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -533,7 +533,10 @@ readpage_async_filler(void *data, struct page *page) if (len < PAGE_CACHE_SIZE) zero_user_segment(page, len, PAGE_CACHE_SIZE); - nfs_pageio_add_request(desc->pgio, new); + if (!nfs_pageio_add_request(desc->pgio, new)) { + error = desc->pgio->pg_error; + goto out_unlock; + } return 0; out_error: error = PTR_ERR(new); |