int setup_callback_client(struct nfs4_client *clp) { 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 = XPRT_TRANSPORT_TCP, .address = (struct sockaddr *) &cb->cb_addr, .addrsize = cb->cb_addrlen, .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; if (cb->cb_minorversion) { args.bc_xprt = clp->cl_cb_xprt; args.protocol = XPRT_TRANSPORT_BC_TCP; } /* 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 *callback_cred; int set_callback_cred(void) { callback_cred = rpc_lookup_machine_cred(); if (!callback_cred) return -ENOMEM; return 0; }
int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn) { struct rpc_timeout timeparms = { .to_initval = max_cb_time(), .to_retries = 0, }; struct rpc_create_args args = { .net = &init_net, .address = (struct sockaddr *) &conn->cb_addr, .addrsize = conn->cb_addrlen, .timeout = &timeparms, .program = &cb_program, .version = 0, .authflavor = clp->cl_flavor, .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), }; struct rpc_clnt *client; if (clp->cl_minorversion == 0) { if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) return -EINVAL; args.client_name = clp->cl_principal; args.prognumber = conn->cb_prog, args.protocol = XPRT_TRANSPORT_TCP; clp->cl_cb_ident = conn->cb_ident; } else { args.bc_xprt = conn->cb_xprt; args.prognumber = clp->cl_cb_session->se_cb_prog; args.protocol = XPRT_TRANSPORT_BC_TCP; } /* 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); } clp->cl_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 = container_of(calldata, struct nfs4_client, cl_cb_null); if (task->tk_status) warn_no_callback_path(clp, task->tk_status); else atomic_set(&clp->cl_cb_set, 1); } static const struct rpc_call_ops nfsd4_cb_probe_ops = { /* XXX: release method to ensure we set the cb channel down if * necessary on early failure? */ .rpc_call_done = nfsd4_cb_probe_done, }; static struct rpc_cred *callback_cred; int set_callback_cred(void) { if (callback_cred) return 0; callback_cred = rpc_lookup_machine_cred(); if (!callback_cred) return -ENOMEM; return 0; } static struct workqueue_struct *callback_wq; static void do_probe_callback(struct nfs4_client *clp) { struct nfsd4_callback *cb = &clp->cl_cb_null; cb->cb_op = NULL; cb->cb_clp = clp; cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; cb->cb_msg.rpc_argp = NULL; cb->cb_msg.rpc_resp = NULL; cb->cb_msg.rpc_cred = callback_cred; cb->cb_ops = &nfsd4_cb_probe_ops; queue_work(callback_wq, &cb->cb_work); } /* * Poke the callback thread to process any updates to the callback * parameters, and send a null probe. */ void nfsd4_probe_callback(struct nfs4_client *clp) { set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); do_probe_callback(clp); }
int setup_callback_client(struct nfs4_client *clp) { 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 = XPRT_TRANSPORT_TCP, .address = (struct sockaddr *) &cb->cb_addr, .addrsize = cb->cb_addrlen, .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; if (cb->cb_minorversion) { args.bc_xprt = clp->cl_cb_xprt; args.protocol = XPRT_TRANSPORT_BC_TCP; } /* 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 *callback_cred; int set_callback_cred(void) { if (callback_cred) return 0; callback_cred = rpc_lookup_machine_cred(); if (!callback_cred) return -ENOMEM; return 0; } 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, .rpc_cred = callback_cred }; int status; status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, &nfsd4_cb_probe_ops, (void *)clp); 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); }