Commit 7b38c368 authored by Trond Myklebust's avatar Trond Myklebust

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Cc: Andy Adamson <andros@netapp.com>
parent acdeb69d
...@@ -591,22 +591,6 @@ void nfs_mark_client_ready(struct nfs_client *clp, int state) ...@@ -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
*/ */
......
...@@ -169,7 +169,6 @@ extern struct nfs_server *nfs_clone_server(struct nfs_server *, ...@@ -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; ...@@ -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) ...@@ -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;
......
...@@ -5603,19 +5603,39 @@ int nfs4_proc_destroy_session(struct nfs4_session *session) ...@@ -5603,19 +5603,39 @@ 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)
...@@ -5626,30 +5646,35 @@ int nfs4_init_session(struct nfs_server *server) ...@@ -5626,30 +5646,35 @@ int nfs4_init_session(struct nfs_server *server)
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)) {
/*
* Do not set NFS_CS_CHECK_LEASE_TIME instead set the
* DS lease to be equal to the MDS lease.
*/
clp->cl_lease_time = lease_time;
clp->cl_last_renewal = jiffies;
}
spin_unlock(&clp->cl_lock);
ret = nfs4_client_recover_expired_lease(clp); ret = nfs41_check_session_ready(clp);
if (!ret) if (ret)
return ret;
/* Test for the DS role */ /* Test for the DS role */
if (!is_ds_client(clp)) if (!is_ds_client(clp))
ret = -ENODEV; return -ENODEV;
if (!ret) return 0;
ret = nfs4_check_client_ready(clp);
return ret;
} }
EXPORT_SYMBOL_GPL(nfs4_init_ds_session); EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment