NFSv4/pNFS: Don't call _nfs4_pnfs_v3_ds_connect multiple times
[ Upstream commit f46f84931a0aa344678efe412d4b071d84d8a805 ]
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: fc821d5920
("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>
This commit is contained in:
parent
9f02e9dd8c
commit
3b03882123
|
@ -556,19 +556,16 @@ out:
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add);
|
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();
|
might_sleep();
|
||||||
wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING,
|
return wait_on_bit(&ds->ds_state, NFS4DS_CONNECTING, TASK_KILLABLE);
|
||||||
TASK_KILLABLE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
|
static void nfs4_clear_ds_conn_bit(struct nfs4_pnfs_ds *ds)
|
||||||
{
|
{
|
||||||
smp_mb__before_atomic();
|
smp_mb__before_atomic();
|
||||||
clear_bit(NFS4DS_CONNECTING, &ds->ds_state);
|
clear_and_wake_up_bit(NFS4DS_CONNECTING, &ds->ds_state);
|
||||||
smp_mb__after_atomic();
|
|
||||||
wake_up_bit(&ds->ds_state, NFS4DS_CONNECTING);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfs_client *(*get_v3_ds_connect)(
|
static struct nfs_client *(*get_v3_ds_connect)(
|
||||||
|
@ -734,30 +731,33 @@ int nfs4_pnfs_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds,
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
again:
|
do {
|
||||||
err = 0;
|
err = nfs4_wait_ds_connect(ds);
|
||||||
if (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) == 0) {
|
if (err || ds->ds_clp)
|
||||||
if (version == 3) {
|
goto out;
|
||||||
err = _nfs4_pnfs_v3_ds_connect(mds_srv, ds, timeo,
|
if (nfs4_test_deviceid_unavailable(devid))
|
||||||
retrans);
|
return -ENODEV;
|
||||||
} else if (version == 4) {
|
} while (test_and_set_bit(NFS4DS_CONNECTING, &ds->ds_state) != 0);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
nfs4_clear_ds_conn_bit(ds);
|
if (ds->ds_clp)
|
||||||
} else {
|
goto connect_done;
|
||||||
nfs4_wait_ds_connect(ds);
|
|
||||||
|
|
||||||
/* what was waited on didn't connect AND didn't mark unavail */
|
switch (version) {
|
||||||
if (!ds->ds_clp && !nfs4_test_deviceid_unavailable(devid))
|
case 3:
|
||||||
goto again;
|
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
|
* At this point the ds->ds_clp should be ready, but it might have
|
||||||
* hit an error.
|
* hit an error.
|
||||||
|
|
Loading…
Reference in New Issue