| From 54e4a0dfa25d9365c4e80a639e80d9213eb6edbe Mon Sep 17 00:00:00 2001 |
| From: Trond Myklebust <trond.myklebust@primarydata.com> |
| Date: Sun, 27 Nov 2016 15:12:39 -0500 |
| Subject: pNFS: Fix a deadlock between read resends and layoutreturn |
| |
| From: Trond Myklebust <trond.myklebust@primarydata.com> |
| |
| commit 54e4a0dfa25d9365c4e80a639e80d9213eb6edbe upstream. |
| |
| We must not call nfs_pageio_init_read() on a new nfs_pageio_descriptor |
| while holding a reference to a layout segment, as that can deadlock |
| pnfs_update_layout(). |
| |
| Fixes: d67ae825a59d6 ("pnfs/flexfiles: Add the FlexFile Layout Driver") |
| Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/nfs/flexfilelayout/flexfilelayout.c | 4 ++++ |
| fs/nfs/pnfs.c | 4 ++++ |
| 2 files changed, 8 insertions(+) |
| |
| --- a/fs/nfs/flexfilelayout/flexfilelayout.c |
| +++ b/fs/nfs/flexfilelayout/flexfilelayout.c |
| @@ -28,6 +28,9 @@ |
| |
| static struct group_info *ff_zero_group; |
| |
| +static void ff_layout_read_record_layoutstats_done(struct rpc_task *task, |
| + struct nfs_pgio_header *hdr); |
| + |
| static struct pnfs_layout_hdr * |
| ff_layout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags) |
| { |
| @@ -1293,6 +1296,7 @@ static int ff_layout_read_done_cb(struct |
| hdr->pgio_mirror_idx + 1, |
| &hdr->pgio_mirror_idx)) |
| goto out_eagain; |
| + ff_layout_read_record_layoutstats_done(task, hdr); |
| pnfs_read_resend_pnfs(hdr); |
| return task->tk_status; |
| case -NFS4ERR_RESET_TO_MDS: |
| --- a/fs/nfs/pnfs.c |
| +++ b/fs/nfs/pnfs.c |
| @@ -2248,6 +2248,10 @@ void pnfs_read_resend_pnfs(struct nfs_pg |
| struct nfs_pageio_descriptor pgio; |
| |
| if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
| + /* Prevent deadlocks with layoutreturn! */ |
| + pnfs_put_lseg(hdr->lseg); |
| + hdr->lseg = NULL; |
| + |
| nfs_pageio_init_read(&pgio, hdr->inode, false, |
| hdr->completion_ops); |
| hdr->task.tk_status = nfs_pageio_resend(&pgio, hdr); |