Commit 8db4a1d1 authored by Mike Snitzer's avatar Mike Snitzer Committed by Anna Schumaker
Browse files

NFSv4/flexfiles: fix to allocate mirror->dss before use



Move mirror_array's dss_count initialization and dss allocation to
ff_layout_alloc_mirror(), just before the loop that initializes each
nfs4_ff_layout_ds_stripe's nfs_file_localio.

Also handle NULL return from kcalloc() and remove one level of indent
in ff_layout_alloc_mirror().

This commit fixes dangling nfsd_serv refcount issues seen when using
NFS LOCALIO and then attempting to stop the NFSD service.

Fixes: 20b1d75f ("NFSv4/flexfiles: Add support for striped layouts")
Signed-off-by: default avatarMike Snitzer <snitzer@kernel.org>
Signed-off-by: default avatarAnna Schumaker <anna.schumaker@oracle.com>
parent 3a866087
Loading
Loading
Loading
Loading
+21 −14
Original line number Diff line number Diff line
@@ -270,19 +270,31 @@ ff_layout_remove_mirror(struct nfs4_ff_layout_mirror *mirror)
	mirror->layout = NULL;
}

static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags)
static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(u32 dss_count,
							    gfp_t gfp_flags)
{
	struct nfs4_ff_layout_mirror *mirror;
	u32 dss_id;

	mirror = kzalloc(sizeof(*mirror), gfp_flags);
	if (mirror != NULL) {
	if (mirror == NULL)
		return NULL;

	spin_lock_init(&mirror->lock);
	refcount_set(&mirror->ref, 1);
	INIT_LIST_HEAD(&mirror->mirrors);
		for (dss_id = 0; dss_id < mirror->dss_count; dss_id++)
			nfs_localio_file_init(&mirror->dss[dss_id].nfl);

	mirror->dss_count = dss_count;
	mirror->dss =
		kcalloc(dss_count, sizeof(struct nfs4_ff_layout_ds_stripe),
			gfp_flags);
	if (mirror->dss == NULL) {
		kfree(mirror);
		return NULL;
	}

	for (u32 dss_id = 0; dss_id < mirror->dss_count; dss_id++)
		nfs_localio_file_init(&mirror->dss[dss_id].nfl);

	return mirror;
}

@@ -507,17 +519,12 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
		if (dss_count > 1 && stripe_unit == 0)
			goto out_err_free;

		fls->mirror_array[i] = ff_layout_alloc_mirror(gfp_flags);
		fls->mirror_array[i] = ff_layout_alloc_mirror(dss_count, gfp_flags);
		if (fls->mirror_array[i] == NULL) {
			rc = -ENOMEM;
			goto out_err_free;
		}

		fls->mirror_array[i]->dss_count = dss_count;
		fls->mirror_array[i]->dss =
		    kcalloc(dss_count, sizeof(struct nfs4_ff_layout_ds_stripe),
			    gfp_flags);

		for (dss_id = 0; dss_id < dss_count; dss_id++) {
			dss_info = &fls->mirror_array[i]->dss[dss_id];
			dss_info->mirror = fls->mirror_array[i];