Commit 77a3569d authored by J. Bruce Fields's avatar J. Bruce Fields Committed by J. Bruce Fields

nfsd4: keep finer-grained callback status

Distinguish between when the callback channel is known to be down, and
when it is not yet confirmed.  This will be useful in the 4.1 case.

Also, we don't seem to be using the fact that this field is atomic.
Signed-off-by: default avatarJ. Bruce Fields <bfields@citi.umich.edu>
parent f0418aa4
...@@ -470,8 +470,6 @@ static int max_cb_time(void) ...@@ -470,8 +470,6 @@ static int max_cb_time(void)
return max(nfsd4_lease/10, (time_t)1) * HZ; return max(nfsd4_lease/10, (time_t)1) * HZ;
} }
/* Reference counting, callback cleanup, etc., all look racy as heck.
* And why is cl_cb_set an atomic? */
static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
{ {
...@@ -526,14 +524,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason) ...@@ -526,14 +524,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
(int)clp->cl_name.len, clp->cl_name.data, reason); (int)clp->cl_name.len, clp->cl_name.data, reason);
} }
static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
{
clp->cl_cb_state = NFSD4_CB_DOWN;
warn_no_callback_path(clp, reason);
}
static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
{ {
struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
if (task->tk_status) if (task->tk_status)
warn_no_callback_path(clp, task->tk_status); nfsd4_mark_cb_down(clp, task->tk_status);
else else
atomic_set(&clp->cl_cb_set, 1); clp->cl_cb_state = NFSD4_CB_UP;
} }
static const struct rpc_call_ops nfsd4_cb_probe_ops = { static const struct rpc_call_ops nfsd4_cb_probe_ops = {
...@@ -579,14 +583,15 @@ static void do_probe_callback(struct nfs4_client *clp) ...@@ -579,14 +583,15 @@ static void do_probe_callback(struct nfs4_client *clp)
*/ */
void nfsd4_probe_callback(struct nfs4_client *clp) void nfsd4_probe_callback(struct nfs4_client *clp)
{ {
/* XXX: atomicity? Also, should we be using cl_cb_flags? */
clp->cl_cb_state = NFSD4_CB_UNKNOWN;
set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
do_probe_callback(clp); do_probe_callback(clp);
} }
void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
{ {
BUG_ON(atomic_read(&clp->cl_cb_set)); clp->cl_cb_state = NFSD4_CB_UNKNOWN;
spin_lock(&clp->cl_lock); spin_lock(&clp->cl_lock);
memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
spin_unlock(&clp->cl_lock); spin_unlock(&clp->cl_lock);
...@@ -693,8 +698,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) ...@@ -693,8 +698,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
break; break;
default: default:
/* Network partition? */ /* Network partition? */
atomic_set(&clp->cl_cb_set, 0); nfsd4_mark_cb_down(clp, task->tk_status);
warn_no_callback_path(clp, task->tk_status);
if (current_rpc_client != task->tk_client) { if (current_rpc_client != task->tk_client) {
/* queue a callback on the new connection: */ /* queue a callback on the new connection: */
atomic_inc(&dp->dl_count); atomic_inc(&dp->dl_count);
...@@ -707,10 +711,8 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) ...@@ -707,10 +711,8 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
task->tk_status = 0; task->tk_status = 0;
rpc_restart_call_prepare(task); rpc_restart_call_prepare(task);
return; return;
} else { } else
atomic_set(&clp->cl_cb_set, 0); nfsd4_mark_cb_down(clp, task->tk_status);
warn_no_callback_path(clp, task->tk_status);
}
} }
static void nfsd4_cb_recall_release(void *calldata) static void nfsd4_cb_recall_release(void *calldata)
......
...@@ -1071,7 +1071,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, ...@@ -1071,7 +1071,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_refcount, 0); atomic_set(&clp->cl_refcount, 0);
atomic_set(&clp->cl_cb_set, 0); clp->cl_cb_state = NFSD4_CB_UNKNOWN;
INIT_LIST_HEAD(&clp->cl_idhash); INIT_LIST_HEAD(&clp->cl_idhash);
INIT_LIST_HEAD(&clp->cl_strhash); INIT_LIST_HEAD(&clp->cl_strhash);
INIT_LIST_HEAD(&clp->cl_openowners); INIT_LIST_HEAD(&clp->cl_openowners);
...@@ -2003,7 +2003,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, ...@@ -2003,7 +2003,6 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse; status = nfserr_clid_inuse;
else { else {
atomic_set(&conf->cl_cb_set, 0);
nfsd4_change_callback(conf, &unconf->cl_cb_conn); nfsd4_change_callback(conf, &unconf->cl_cb_conn);
nfsd4_probe_callback(conf); nfsd4_probe_callback(conf);
expire_client(unconf); expire_client(unconf);
...@@ -2633,7 +2632,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta ...@@ -2633,7 +2632,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
{ {
struct nfs4_delegation *dp; struct nfs4_delegation *dp;
struct nfs4_stateowner *sop = stp->st_stateowner; struct nfs4_stateowner *sop = stp->st_stateowner;
int cb_up = atomic_read(&sop->so_client->cl_cb_set); /* XXX: or unknown and nfsv4.1: */
int cb_up = (sop->so_client->cl_cb_state == NFSD4_CB_UP);
struct file_lock *fl; struct file_lock *fl;
int status, flag = 0; int status, flag = 0;
...@@ -2823,7 +2823,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -2823,7 +2823,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
renew_client(clp); renew_client(clp);
status = nfserr_cb_path_down; status = nfserr_cb_path_down;
if (!list_empty(&clp->cl_delegations) if (!list_empty(&clp->cl_delegations)
&& !atomic_read(&clp->cl_cb_set)) && clp->cl_cb_state != NFSD4_CB_UP)
goto out; goto out;
status = nfs_ok; status = nfs_ok;
out: out:
......
...@@ -242,7 +242,10 @@ struct nfs4_client { ...@@ -242,7 +242,10 @@ struct nfs4_client {
unsigned long cl_cb_flags; unsigned long cl_cb_flags;
struct rpc_clnt *cl_cb_client; struct rpc_clnt *cl_cb_client;
u32 cl_cb_ident; u32 cl_cb_ident;
atomic_t cl_cb_set; #define NFSD4_CB_UP 0
#define NFSD4_CB_UNKNOWN 1
#define NFSD4_CB_DOWN 2
int cl_cb_state;
struct nfsd4_callback cl_cb_null; struct nfsd4_callback cl_cb_null;
struct nfsd4_session *cl_cb_session; struct nfsd4_session *cl_cb_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