NFSv4.1: Fix session initialisation races
Session initialisation is not complete until the lease manager has run. We need to ensure that both nfs4_init_session and nfs4_init_ds_session do so, and that they check for any resulting errors in clp->cl_cons_state. Only after this is done, can nfs4_ds_connect check the contents of clp->cl_exchange_flags. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: Andy Adamson <andros@netapp.com>
This commit is contained in:
@@ -591,22 +591,6 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state)
|
|||||||
wake_up_all(&nfs_client_active_wq);
|
wake_up_all(&nfs_client_active_wq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* With sessions, the client is not marked ready until after a
|
|
||||||
* successful EXCHANGE_ID and CREATE_SESSION.
|
|
||||||
*
|
|
||||||
* Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate
|
|
||||||
* other versions of NFS can be tried.
|
|
||||||
*/
|
|
||||||
int nfs4_check_client_ready(struct nfs_client *clp)
|
|
||||||
{
|
|
||||||
if (!nfs4_has_session(clp))
|
|
||||||
return 0;
|
|
||||||
if (clp->cl_cons_state < NFS_CS_READY)
|
|
||||||
return -EPROTONOSUPPORT;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialise the timeout values for a connection
|
* Initialise the timeout values for a connection
|
||||||
*/
|
*/
|
||||||
|
|||||||
+1
-2
@@ -169,7 +169,6 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *,
|
|||||||
struct nfs_fattr *,
|
struct nfs_fattr *,
|
||||||
rpc_authflavor_t);
|
rpc_authflavor_t);
|
||||||
extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
|
extern void nfs_mark_client_ready(struct nfs_client *clp, int state);
|
||||||
extern int nfs4_check_client_ready(struct nfs_client *clp);
|
|
||||||
extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
|
extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
|
||||||
const struct sockaddr *ds_addr,
|
const struct sockaddr *ds_addr,
|
||||||
int ds_addrlen, int ds_proto,
|
int ds_addrlen, int ds_proto,
|
||||||
@@ -234,7 +233,7 @@ extern const u32 nfs41_maxwrite_overhead;
|
|||||||
extern struct rpc_procinfo nfs4_procedures[];
|
extern struct rpc_procinfo nfs4_procedures[];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int nfs4_init_ds_session(struct nfs_client *clp);
|
extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
|
||||||
|
|
||||||
/* proc.c */
|
/* proc.c */
|
||||||
void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
|
void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
|
||||||
|
|||||||
@@ -203,28 +203,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((clp->cl_exchange_flags & EXCHGID4_FLAG_MASK_PNFS) != 0) {
|
status = nfs4_init_ds_session(clp, mds_srv->nfs_client->cl_lease_time);
|
||||||
if (!is_ds_client(clp)) {
|
|
||||||
status = -ENODEV;
|
|
||||||
goto out_put;
|
|
||||||
}
|
|
||||||
ds->ds_clp = clp;
|
|
||||||
dprintk("%s [existing] server=%s\n", __func__,
|
|
||||||
ds->ds_remotestr);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do not set NFS_CS_CHECK_LEASE_TIME instead set the DS lease to
|
|
||||||
* be equal to the MDS lease. Renewal is scheduled in create_session.
|
|
||||||
*/
|
|
||||||
spin_lock(&mds_srv->nfs_client->cl_lock);
|
|
||||||
clp->cl_lease_time = mds_srv->nfs_client->cl_lease_time;
|
|
||||||
spin_unlock(&mds_srv->nfs_client->cl_lock);
|
|
||||||
clp->cl_last_renewal = jiffies;
|
|
||||||
|
|
||||||
/* New nfs_client */
|
|
||||||
status = nfs4_init_ds_session(clp);
|
|
||||||
if (status)
|
if (status)
|
||||||
goto out_put;
|
goto out_put;
|
||||||
|
|
||||||
|
|||||||
+52
-27
@@ -5603,53 +5603,78 @@ int nfs4_proc_destroy_session(struct nfs4_session *session)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With sessions, the client is not marked ready until after a
|
||||||
|
* successful EXCHANGE_ID and CREATE_SESSION.
|
||||||
|
*
|
||||||
|
* Map errors cl_cons_state errors to EPROTONOSUPPORT to indicate
|
||||||
|
* other versions of NFS can be tried.
|
||||||
|
*/
|
||||||
|
static int nfs41_check_session_ready(struct nfs_client *clp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (clp->cl_cons_state == NFS_CS_SESSION_INITING) {
|
||||||
|
ret = nfs4_client_recover_expired_lease(clp);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if (clp->cl_cons_state < NFS_CS_READY)
|
||||||
|
return -EPROTONOSUPPORT;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int nfs4_init_session(struct nfs_server *server)
|
int nfs4_init_session(struct nfs_server *server)
|
||||||
{
|
{
|
||||||
struct nfs_client *clp = server->nfs_client;
|
struct nfs_client *clp = server->nfs_client;
|
||||||
struct nfs4_session *session;
|
struct nfs4_session *session;
|
||||||
unsigned int rsize, wsize;
|
unsigned int rsize, wsize;
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (!nfs4_has_session(clp))
|
if (!nfs4_has_session(clp))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
session = clp->cl_session;
|
session = clp->cl_session;
|
||||||
if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state))
|
spin_lock(&clp->cl_lock);
|
||||||
return 0;
|
if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
|
||||||
|
|
||||||
rsize = server->rsize;
|
rsize = server->rsize;
|
||||||
if (rsize == 0)
|
if (rsize == 0)
|
||||||
rsize = NFS_MAX_FILE_IO_SIZE;
|
rsize = NFS_MAX_FILE_IO_SIZE;
|
||||||
wsize = server->wsize;
|
wsize = server->wsize;
|
||||||
if (wsize == 0)
|
if (wsize == 0)
|
||||||
wsize = NFS_MAX_FILE_IO_SIZE;
|
wsize = NFS_MAX_FILE_IO_SIZE;
|
||||||
|
|
||||||
session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
|
session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
|
||||||
session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
|
session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
|
||||||
|
}
|
||||||
|
spin_unlock(&clp->cl_lock);
|
||||||
|
|
||||||
ret = nfs4_recover_expired_lease(server);
|
return nfs41_check_session_ready(clp);
|
||||||
if (!ret)
|
|
||||||
ret = nfs4_check_client_ready(clp);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int nfs4_init_ds_session(struct nfs_client *clp)
|
int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
|
||||||
{
|
{
|
||||||
struct nfs4_session *session = clp->cl_session;
|
struct nfs4_session *session = clp->cl_session;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state))
|
spin_lock(&clp->cl_lock);
|
||||||
return 0;
|
if (test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state)) {
|
||||||
|
/*
|
||||||
ret = nfs4_client_recover_expired_lease(clp);
|
* Do not set NFS_CS_CHECK_LEASE_TIME instead set the
|
||||||
if (!ret)
|
* DS lease to be equal to the MDS lease.
|
||||||
/* Test for the DS role */
|
*/
|
||||||
if (!is_ds_client(clp))
|
clp->cl_lease_time = lease_time;
|
||||||
ret = -ENODEV;
|
clp->cl_last_renewal = jiffies;
|
||||||
if (!ret)
|
}
|
||||||
ret = nfs4_check_client_ready(clp);
|
spin_unlock(&clp->cl_lock);
|
||||||
return ret;
|
|
||||||
|
|
||||||
|
ret = nfs41_check_session_ready(clp);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
/* Test for the DS role */
|
||||||
|
if (!is_ds_client(clp))
|
||||||
|
return -ENODEV;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
|
EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user