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>
This commit is contained in:
parent
264e3e889d
commit
f8512ad0da
|
@ -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);
|
||||
|
|
|
@ -39,6 +39,7 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*,
|
|||
unsigned int, unsigned int);
|
||||
static void nfs_pageio_init_write(struct nfs_pageio_descriptor *desc,
|
||||
struct inode *inode, int ioflags);
|
||||
static void nfs_redirty_request(struct nfs_page *req);
|
||||
static const struct rpc_call_ops nfs_write_partial_ops;
|
||||
static const struct rpc_call_ops nfs_write_full_ops;
|
||||
static const struct rpc_call_ops nfs_commit_ops;
|
||||
|
@ -288,7 +289,12 @@ static int nfs_page_async_flush(struct nfs_pageio_descriptor *pgio,
|
|||
BUG();
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
nfs_pageio_add_request(pgio, req);
|
||||
if (!nfs_pageio_add_request(pgio, req)) {
|
||||
nfs_redirty_request(req);
|
||||
nfs_end_page_writeback(page);
|
||||
nfs_clear_page_tag_locked(req);
|
||||
return pgio->pg_error;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue