diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-05-20 10:18:27 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-05-24 10:44:20 -0400 |
commit | 7fe7f8487ae742239dd8c66596e2311c30d057d1 (patch) | |
tree | c506bd7dcacc9d5b25b3295bd1f327e534532c54 /fs/nfs/pagelist.c | |
parent | 585a2858b970cb6e2e5ca4877eefd18b4dba8ed4 (diff) | |
download | linux-7fe7f8487ae742239dd8c66596e2311c30d057d1.tar.gz linux-7fe7f8487ae742239dd8c66596e2311c30d057d1.tar.bz2 linux-7fe7f8487ae742239dd8c66596e2311c30d057d1.zip |
NFS: Avoid a deadlock situation on write
When processes are allowed to attempt to lock a non-contiguous range of nfs
write requests, it is possible for generic_writepages to 'wrap round' the
address space, and call writepage() on a request that is already locked by
the same process.
We avoid the deadlock by checking if the page index is contiguous with the
list of nfs write requests that is already held in our
nfs_pageio_descriptor prior to attempting to lock a new request.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/pagelist.c')
-rw-r--r-- | fs/nfs/pagelist.c | 20 |
1 files changed, 20 insertions, 0 deletions
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index cbdd1c6aaa94..c5bb51a29e80 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c @@ -355,6 +355,26 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) nfs_pageio_doio(desc); } +/** + * nfs_pageio_cond_complete - Conditional I/O completion + * @desc: pointer to io descriptor + * @index: page index + * + * It is important to ensure that processes don't try to take locks + * on non-contiguous ranges of pages as that might deadlock. This + * function should be called before attempting to wait on a locked + * nfs_page. It will complete the I/O if the page index 'index' + * is not contiguous with the existing list of pages in 'desc'. + */ +void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) +{ + if (!list_empty(&desc->pg_list)) { + struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev); + if (index != prev->wb_index + 1) + nfs_pageio_doio(desc); + } +} + #define NFS_SCAN_MAXENTRIES 16 /** * nfs_scan_list - Scan a list for matching requests |