static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) { struct nfs4_delegation *dp = calldata; struct nfs4_client *clp = dp->dl_client; nfsd4_cb_done(task, calldata); switch (task->tk_status) { case -EIO: /* Network partition? */ atomic_set(&clp->cl_cb_conn.cb_set, 0); warn_no_callback_path(clp, task->tk_status); case -EBADHANDLE: case -NFS4ERR_BAD_STATEID: /* Race: client probably got cb_recall * before open reply granting delegation */ break; default: /* success, or error we can't handle */ goto done; } if (dp->dl_retries--) { rpc_delay(task, 2*HZ); task->tk_status = 0; rpc_restart_call(task); return; } else { atomic_set(&clp->cl_cb_conn.cb_set, 0); warn_no_callback_path(clp, task->tk_status); } done: kfree(task->tk_msg.rpc_argp); }
static void nlmclnt_unlock_callback(struct rpc_task *task) { struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata; int status = req->a_res.status; if (RPC_ASSASSINATED(task)) goto die; if (task->tk_status < 0) { dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status); goto retry_rebind; } if (status == NLM_LCK_DENIED_GRACE_PERIOD) { rpc_delay(task, NLMCLNT_GRACE_WAIT); goto retry_unlock; } if (status != NLM_LCK_GRANTED) printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status); die: nlm_release_host(req->a_host); kfree(req); return; retry_rebind: nlm_rebind_host(req->a_host); retry_unlock: rpc_restart_call(task); }
/** * nfs_async_unlink_done - Sillydelete post-processing * @task: rpc_task of the sillydelete * * Do the directory attribute update. */ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata) { struct nfs_unlinkdata *data = calldata; struct inode *dir = data->dir; if (!NFS_PROTO(dir)->unlink_done(task, dir)) rpc_restart_call(task); }
static int nfs_async_handle_expired_key(struct rpc_task *task) { if (task->tk_status != -EKEYEXPIRED) return 0; task->tk_status = 0; rpc_restart_call(task); rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); return 1; }
static int nfs3_async_handle_jukebox(struct rpc_task *task) { if (task->tk_status != -EJUKEBOX) return 0; task->tk_status = 0; rpc_restart_call(task); rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); return 1; }
static int nfs3_async_handle_jukebox(struct rpc_task *task, struct inode *inode) { if (task->tk_status != -EJUKEBOX) return 0; nfs_inc_stats(inode, NFSIOS_DELAY); task->tk_status = 0; rpc_restart_call(task); rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); return 1; }
static void nlmclnt_cancel_callback(struct rpc_task *task) { struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata; if (RPC_ASSASSINATED(task)) goto die; if (task->tk_status < 0) { dprintk("lockd: CANCEL call error %d, retrying.\n", task->tk_status); goto retry_cancel; } dprintk("lockd: cancel status %d (task %d)\n", req->a_res.status, task->tk_pid); switch (req->a_res.status) { case NLM_LCK_GRANTED: case NLM_LCK_DENIED_GRACE_PERIOD: /* Everything's good */ break; case NLM_LCK_DENIED_NOLOCKS: dprintk("lockd: CANCEL failed (server has no locks)\n"); goto retry_cancel; default: printk(KERN_NOTICE "lockd: weird return %d for CANCEL call\n", req->a_res.status); } die: rpc_release_task(task); nlm_release_host(req->a_host); kfree(req); return; retry_cancel: nlm_rebind_host(req->a_host); rpc_restart_call(task); rpc_delay(task, 30 * HZ); return; }
static void nlmclnt_unlock_callback(struct rpc_task *task) { struct nlm_rqst *req = (struct nlm_rqst *) task->tk_calldata; int status = req->a_res.status; if (RPC_ASSASSINATED(task)) goto die; if (task->tk_status < 0) { dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status); nlm_rebind_host(req->a_host); rpc_restart_call(task); return; } if (status != NLM_LCK_GRANTED && status != NLM_LCK_DENIED_GRACE_PERIOD) { printk("lockd: unexpected unlock status: %d\n", status); } die: rpc_release_task(task); }
int setup_callback_client(struct nfs4_client *clp) { struct sockaddr_in addr; struct nfs4_cb_conn *cb = &clp->cl_cb_conn; struct rpc_timeout timeparms = { .to_initval = max_cb_time(), .to_retries = 0, }; struct rpc_create_args args = { .protocol = IPPROTO_TCP, .address = (struct sockaddr *)&addr, .addrsize = sizeof(addr), .timeout = &timeparms, .program = &cb_program, .prognumber = cb->cb_prog, .version = nfs_cb_version[1]->number, .authflavor = clp->cl_flavor, .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), .client_name = clp->cl_principal, }; struct rpc_clnt *client; if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) return -EINVAL; /* Initialize address */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(cb->cb_port); addr.sin_addr.s_addr = htonl(cb->cb_addr); /* Create RPC client */ client = rpc_create(&args); if (IS_ERR(client)) { dprintk("NFSD: couldn't create callback client: %ld\n", PTR_ERR(client)); return PTR_ERR(client); } cb->cb_client = client; return 0; } static void warn_no_callback_path(struct nfs4_client *clp, int reason) { dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", (int)clp->cl_name.len, clp->cl_name.data, reason); } static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) { struct nfs4_client *clp = calldata; if (task->tk_status) warn_no_callback_path(clp, task->tk_status); else atomic_set(&clp->cl_cb_conn.cb_set, 1); put_nfs4_client(clp); } static const struct rpc_call_ops nfsd4_cb_probe_ops = { .rpc_call_done = nfsd4_cb_probe_done, }; static struct rpc_cred *lookup_cb_cred(struct nfs4_cb_conn *cb) { struct auth_cred acred = { .machine_cred = 1 }; /* * Note in the gss case this doesn't actually have to wait for a * gss upcall (or any calls to the client); this just creates a * non-uptodate cred which the rpc state machine will fill in with * a refresh_upcall later. */ return rpcauth_lookup_credcache(cb->cb_client->cl_auth, &acred, RPCAUTH_LOOKUP_NEW); } void do_probe_callback(struct nfs4_client *clp) { struct nfs4_cb_conn *cb = &clp->cl_cb_conn; struct rpc_message msg = { .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], .rpc_argp = clp, }; struct rpc_cred *cred; int status; cred = lookup_cb_cred(cb); if (IS_ERR(cred)) { status = PTR_ERR(cred); goto out; } cb->cb_cred = cred; msg.rpc_cred = cb->cb_cred; status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT, &nfsd4_cb_probe_ops, (void *)clp); out: if (status) { warn_no_callback_path(clp, status); put_nfs4_client(clp); } } /* * Set up the callback client and put a NFSPROC4_CB_NULL on the wire... */ void nfsd4_probe_callback(struct nfs4_client *clp) { int status; BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set)); status = setup_callback_client(clp); if (status) { warn_no_callback_path(clp, status); return; } /* the task holds a reference to the nfs4_client struct */ atomic_inc(&clp->cl_count); do_probe_callback(clp); } static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) { struct nfs4_delegation *dp = calldata; struct nfs4_client *clp = dp->dl_client; switch (task->tk_status) { case -EIO: /* Network partition? */ atomic_set(&clp->cl_cb_conn.cb_set, 0); warn_no_callback_path(clp, task->tk_status); case -EBADHANDLE: case -NFS4ERR_BAD_STATEID: /* Race: client probably got cb_recall * before open reply granting delegation */ break; default: /* success, or error we can't handle */ return; } if (dp->dl_retries--) { rpc_delay(task, 2*HZ); task->tk_status = 0; rpc_restart_call(task); } else { atomic_set(&clp->cl_cb_conn.cb_set, 0); warn_no_callback_path(clp, task->tk_status); } } static void nfsd4_cb_recall_release(void *calldata) { struct nfs4_delegation *dp = calldata; struct nfs4_client *clp = dp->dl_client; nfs4_put_delegation(dp); put_nfs4_client(clp); } static const struct rpc_call_ops nfsd4_cb_recall_ops = { .rpc_call_done = nfsd4_cb_recall_done, .rpc_release = nfsd4_cb_recall_release, }; /* * called with dp->dl_count inc'ed. */ void nfsd4_cb_recall(struct nfs4_delegation *dp) { struct nfs4_client *clp = dp->dl_client; struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; struct rpc_message msg = { .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], .rpc_argp = dp, .rpc_cred = clp->cl_cb_conn.cb_cred }; int status; dp->dl_retries = 1; status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp); if (status) { put_nfs4_client(clp); nfs4_put_delegation(dp); } }