Skip to content

Commit

Permalink
NFSv4/pNFS: Don't call _nfs4_pnfs_v3_ds_connect multiple times
Browse files Browse the repository at this point in the history
[ Upstream commit f46f849 ]

After we grab the lock in nfs4_pnfs_ds_connect(), there is no check for
whether or not ds->ds_clp has already been initialised, so we can end up
adding the same transports multiple times.

Fixes: fc821d5 ("pnfs/NFSv4.1: Add multipath capabilities to pNFS flexfiles servers over NFSv3")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
Trond Myklebust authored and gregkh committed Jul 20, 2021
1 parent 13fc99a commit ea37d4c
Showing 1 changed file with 26 additions and 26 deletions.
52 changes: 26 additions & 26 deletions fs/nfs/pnfs_nfs.c
Expand Up @@ -805,19 +805,16 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
}
EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add);

static void nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds)
static int nfs4_wait_ds_connect(struct nfs4_pnfs_ds *ds)
{
might_sleep();
wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING,
TASK_KILLABLE);
return wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING, TASK_KILLABLE);
}

static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
{
smp_mb__before_atomic();
clear_bit(NFS4DS_CONNECTING, &ds->ds_state);
smp_mb__after_atomic();
wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING);
clear_and_wake_up_bit(NFS4DS_CONNECTING, &ds->ds_state);
}

static struct nfs_client *(*get_v3_ds_connect)(
Expand Down Expand Up @@ -993,30 +990,33 @@ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
{
int err;

again:
err = 0;
if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
if (version == 3) {
err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo,
retrans);
} else if (version == 4) {
err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo,
retrans, minor_version);
} else {
dprintk("%s: unsupported DS version %d\n", __func__,
version);
err = -EPROTONOSUPPORT;
}
do {
err = nfs4_wait_ds_connect(ds);
if (err || ds->ds_clp)
goto out;
if (nfs4_test_deviceid_unavailable(devid))
return -ENODEV;
} while (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) != 0);

nfs4_clear_ds_conn_bit(ds);
} else {
nfs4_wait_ds_connect(ds);
if (ds->ds_clp)
goto connect_done;

/* what was waited on didn't connect AND didn't mark unavail */
if (!ds->ds_clp && !nfs4_test_deviceid_unavailable(devid))
goto again;
switch (version) {
case 3:
err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo, retrans);
break;
case 4:
err = _nfs4_pnfs_v4_ds_connect(mds_srv, ds, timeo, retrans,
minor_version);
break;
default:
dprintk("%s: unsupported DS version %d\n", __func__, version);
err = -EPROTONOSUPPORT;
}

connect_done:
nfs4_clear_ds_conn_bit(ds);
out:
/*
* At this point the ds->ds_clp should be ready, but it might have
* hit an error.
Expand Down

0 comments on commit ea37d4c

Please sign in to comment.