NFSv4: Fix up mirror allocation
There are a number of callers of nfs_pageio_complete() that want to continue using the nfs_pageio_descriptor without needing to call nfs_pageio_init() again. Examples include nfs_pageio_resend() and nfs_pageio_cond_complete(). The problem is that nfs_pageio_complete() also calls nfs_pageio_cleanup_mirroring(), which frees up the array of mirrors. This can lead to writeback errors, in the next call to nfs_pageio_setup_mirroring(). Fix by simply moving the allocation of the mirrors to nfs_pageio_setup_mirroring(). Link: https://bugzilla.kernel.org/show_bug.cgi?id=196709 Reported-by: JianhongYin <yin-jianhong@163.com> Cc: stable@vger.kernel.org # 4.0+ Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
parent
ef954844c7
commit
14abcb0bf5
|
@ -714,9 +714,6 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
|
|||
int io_flags,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct nfs_pgio_mirror *new;
|
||||
int i;
|
||||
|
||||
desc->pg_moreio = 0;
|
||||
desc->pg_inode = inode;
|
||||
desc->pg_ops = pg_ops;
|
||||
|
@ -732,22 +729,10 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
|
|||
desc->pg_mirror_count = 1;
|
||||
desc->pg_mirror_idx = 0;
|
||||
|
||||
if (pg_ops->pg_get_mirror_count) {
|
||||
/* until we have a request, we don't have an lseg and no
|
||||
* idea how many mirrors there will be */
|
||||
new = kcalloc(NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX,
|
||||
sizeof(struct nfs_pgio_mirror), gfp_flags);
|
||||
desc->pg_mirrors_dynamic = new;
|
||||
desc->pg_mirrors = new;
|
||||
|
||||
for (i = 0; i < NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX; i++)
|
||||
nfs_pageio_mirror_init(&desc->pg_mirrors[i], bsize);
|
||||
} else {
|
||||
desc->pg_mirrors_dynamic = NULL;
|
||||
desc->pg_mirrors = desc->pg_mirrors_static;
|
||||
nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_pageio_init);
|
||||
|
||||
/**
|
||||
|
@ -865,32 +850,52 @@ static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static struct nfs_pgio_mirror *
|
||||
nfs_pageio_alloc_mirrors(struct nfs_pageio_descriptor *desc,
|
||||
unsigned int mirror_count)
|
||||
{
|
||||
struct nfs_pgio_mirror *ret;
|
||||
unsigned int i;
|
||||
|
||||
kfree(desc->pg_mirrors_dynamic);
|
||||
desc->pg_mirrors_dynamic = NULL;
|
||||
if (mirror_count == 1)
|
||||
return desc->pg_mirrors_static;
|
||||
ret = kmalloc_array(mirror_count, sizeof(*ret), GFP_NOFS);
|
||||
if (ret != NULL) {
|
||||
for (i = 0; i < mirror_count; i++)
|
||||
nfs_pageio_mirror_init(&ret[i], desc->pg_bsize);
|
||||
desc->pg_mirrors_dynamic = ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs_pageio_setup_mirroring - determine if mirroring is to be used
|
||||
* by calling the pg_get_mirror_count op
|
||||
*/
|
||||
static int nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio,
|
||||
static void nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio,
|
||||
struct nfs_page *req)
|
||||
{
|
||||
int mirror_count = 1;
|
||||
|
||||
if (!pgio->pg_ops->pg_get_mirror_count)
|
||||
return 0;
|
||||
unsigned int mirror_count = 1;
|
||||
|
||||
if (pgio->pg_ops->pg_get_mirror_count)
|
||||
mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req);
|
||||
if (mirror_count == pgio->pg_mirror_count || pgio->pg_error < 0)
|
||||
return;
|
||||
|
||||
if (pgio->pg_error < 0)
|
||||
return pgio->pg_error;
|
||||
|
||||
if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN_ON_ONCE(!pgio->pg_mirrors_dynamic))
|
||||
return -EINVAL;
|
||||
if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX) {
|
||||
pgio->pg_error = -EINVAL;
|
||||
return;
|
||||
}
|
||||
|
||||
pgio->pg_mirrors = nfs_pageio_alloc_mirrors(pgio, mirror_count);
|
||||
if (pgio->pg_mirrors == NULL) {
|
||||
pgio->pg_error = -ENOMEM;
|
||||
pgio->pg_mirrors = pgio->pg_mirrors_static;
|
||||
mirror_count = 1;
|
||||
}
|
||||
pgio->pg_mirror_count = mirror_count;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue