mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 06:34:12 +08:00
nfsd4: allow 4.0 clients to change callback path
The rfc allows a client to change the callback parameters, but we didn't previously implement it. Teach the callbacks to rerun themselves (by placing themselves on a workqueue) when they recognize that their rpc task has been killed and that the callback connection has changed. Then we can change the callback connection by setting up a new rpc client, modifying the nfs4 client to point at it, waiting for any work in progress to complete, and then shutting down the old client. Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
This commit is contained in:
parent
2bf23875f5
commit
4b21d0defc
@ -457,9 +457,8 @@ static int max_cb_time(void)
|
|||||||
/* Reference counting, callback cleanup, etc., all look racy as heck.
|
/* Reference counting, callback cleanup, etc., all look racy as heck.
|
||||||
* And why is cl_cb_set an atomic? */
|
* And why is cl_cb_set an atomic? */
|
||||||
|
|
||||||
int setup_callback_client(struct nfs4_client *clp)
|
int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
|
||||||
{
|
{
|
||||||
struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
|
|
||||||
struct rpc_timeout timeparms = {
|
struct rpc_timeout timeparms = {
|
||||||
.to_initval = max_cb_time(),
|
.to_initval = max_cb_time(),
|
||||||
.to_retries = 0,
|
.to_retries = 0,
|
||||||
@ -481,7 +480,7 @@ int setup_callback_client(struct nfs4_client *clp)
|
|||||||
if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
|
if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (cb->cb_minorversion) {
|
if (cb->cb_minorversion) {
|
||||||
args.bc_xprt = clp->cl_cb_conn.cb_xprt;
|
args.bc_xprt = cb->cb_xprt;
|
||||||
args.protocol = XPRT_TRANSPORT_BC_TCP;
|
args.protocol = XPRT_TRANSPORT_BC_TCP;
|
||||||
}
|
}
|
||||||
/* Create RPC client */
|
/* Create RPC client */
|
||||||
@ -491,7 +490,7 @@ int setup_callback_client(struct nfs4_client *clp)
|
|||||||
PTR_ERR(client));
|
PTR_ERR(client));
|
||||||
return PTR_ERR(client);
|
return PTR_ERR(client);
|
||||||
}
|
}
|
||||||
clp->cl_cb_client = client;
|
nfsd4_set_callback_client(clp, client);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -548,14 +547,13 @@ void do_probe_callback(struct nfs4_client *clp)
|
|||||||
/*
|
/*
|
||||||
* Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
|
* Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
|
||||||
*/
|
*/
|
||||||
void
|
void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
|
||||||
nfsd4_probe_callback(struct nfs4_client *clp)
|
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
BUG_ON(atomic_read(&clp->cl_cb_set));
|
BUG_ON(atomic_read(&clp->cl_cb_set));
|
||||||
|
|
||||||
status = setup_callback_client(clp);
|
status = setup_callback_client(clp, cb);
|
||||||
if (status) {
|
if (status) {
|
||||||
warn_no_callback_path(clp, status);
|
warn_no_callback_path(clp, status);
|
||||||
return;
|
return;
|
||||||
@ -645,18 +643,32 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
|
static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
|
||||||
{
|
{
|
||||||
struct nfs4_delegation *dp = calldata;
|
struct nfs4_delegation *dp = calldata;
|
||||||
struct nfs4_client *clp = dp->dl_client;
|
struct nfs4_client *clp = dp->dl_client;
|
||||||
|
struct rpc_clnt *current_rpc_client = clp->cl_cb_client;
|
||||||
|
|
||||||
nfsd4_cb_done(task, calldata);
|
nfsd4_cb_done(task, calldata);
|
||||||
|
|
||||||
|
if (current_rpc_client == NULL) {
|
||||||
|
/* We're shutting down; give up. */
|
||||||
|
/* XXX: err, or is it ok just to fall through
|
||||||
|
* and rpc_restart_call? */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (task->tk_status) {
|
switch (task->tk_status) {
|
||||||
case -EIO:
|
case -EIO:
|
||||||
/* Network partition? */
|
/* Network partition? */
|
||||||
atomic_set(&clp->cl_cb_set, 0);
|
atomic_set(&clp->cl_cb_set, 0);
|
||||||
warn_no_callback_path(clp, task->tk_status);
|
warn_no_callback_path(clp, task->tk_status);
|
||||||
|
if (current_rpc_client != task->tk_client) {
|
||||||
|
/* queue a callback on the new connection: */
|
||||||
|
nfsd4_cb_recall(dp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
case -EBADHANDLE:
|
case -EBADHANDLE:
|
||||||
case -NFS4ERR_BAD_STATEID:
|
case -NFS4ERR_BAD_STATEID:
|
||||||
/* Race: client probably got cb_recall
|
/* Race: client probably got cb_recall
|
||||||
@ -705,8 +717,7 @@ void nfsd4_destroy_callback_queue(void)
|
|||||||
destroy_workqueue(callback_wq);
|
destroy_workqueue(callback_wq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfsd4_set_callback_client(struct nfs4_client *clp, struct rpc_clnt
|
void nfsd4_set_callback_client(struct nfs4_client *clp, struct rpc_clnt *new)
|
||||||
*new)
|
|
||||||
{
|
{
|
||||||
struct rpc_clnt *old = clp->cl_cb_client;
|
struct rpc_clnt *old = clp->cl_cb_client;
|
||||||
|
|
||||||
|
@ -1312,7 +1312,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
|||||||
cstate->minorversion;
|
cstate->minorversion;
|
||||||
unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog;
|
unconf->cl_cb_conn.cb_prog = cr_ses->callback_prog;
|
||||||
unconf->cl_cb_seq_nr = 1;
|
unconf->cl_cb_seq_nr = 1;
|
||||||
nfsd4_probe_callback(unconf);
|
nfsd4_probe_callback(unconf, &unconf->cl_cb_conn);
|
||||||
}
|
}
|
||||||
conf = unconf;
|
conf = unconf;
|
||||||
} else {
|
} else {
|
||||||
@ -1605,9 +1605,8 @@ 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 {
|
||||||
/* XXX: We just turn off callbacks until we can handle
|
|
||||||
* change request correctly. */
|
|
||||||
atomic_set(&conf->cl_cb_set, 0);
|
atomic_set(&conf->cl_cb_set, 0);
|
||||||
|
nfsd4_probe_callback(conf, &unconf->cl_cb_conn);
|
||||||
expire_client(unconf);
|
expire_client(unconf);
|
||||||
status = nfs_ok;
|
status = nfs_ok;
|
||||||
|
|
||||||
@ -1641,7 +1640,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
|
|||||||
}
|
}
|
||||||
move_to_confirmed(unconf);
|
move_to_confirmed(unconf);
|
||||||
conf = unconf;
|
conf = unconf;
|
||||||
nfsd4_probe_callback(conf);
|
nfsd4_probe_callback(conf, &conf->cl_cb_conn);
|
||||||
status = nfs_ok;
|
status = nfs_ok;
|
||||||
}
|
}
|
||||||
} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
|
} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
|
||||||
|
@ -390,7 +390,7 @@ extern int nfs4_in_grace(void);
|
|||||||
extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
|
extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
|
||||||
extern void nfs4_free_stateowner(struct kref *kref);
|
extern void nfs4_free_stateowner(struct kref *kref);
|
||||||
extern int set_callback_cred(void);
|
extern int set_callback_cred(void);
|
||||||
extern void nfsd4_probe_callback(struct nfs4_client *clp);
|
extern void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *);
|
||||||
extern void nfsd4_do_callback_rpc(struct work_struct *);
|
extern void nfsd4_do_callback_rpc(struct work_struct *);
|
||||||
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
|
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
|
||||||
extern int nfsd4_create_callback_queue(void);
|
extern int nfsd4_create_callback_queue(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user