static int decode_cb_sequence4res(struct xdr_stream *xdr, struct nfsd4_callback *cb) { enum nfsstat4 nfserr; int status; if (cb->cb_minorversion == 0) return 0; status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr); if (unlikely(status)) goto out; if (unlikely(nfserr != NFS4_OK)) goto out_default; status = decode_cb_sequence4resok(xdr, cb); out: return status; out_default: return nfs_cb_stat_to_errno(nfserr); }
static int decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) { __be32 *p; u32 op; int32_t nfserr; READ_BUF(8); READ32(op); if (op != expected) { dprintk("NFSD: decode_cb_op_hdr: Callback server returned " " operation %d but we issued a request for %d\n", op, expected); return -EIO; } READ32(nfserr); if (nfserr != NFS_OK) return -nfs_cb_stat_to_errno(nfserr); return 0; }
/* * 20.2. Operation 4: CB_RECALL - Recall a Delegation */ static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr, const struct nfsd4_callback *cb) { const struct nfs4_delegation *args = cb->cb_op; struct nfs4_cb_compound_hdr hdr = { .ident = cb->cb_clp->cl_cb_ident, .minorversion = cb->cb_minorversion, }; encode_cb_compound4args(xdr, &hdr); encode_cb_sequence4args(xdr, cb, &hdr); encode_cb_recall4args(xdr, args, &hdr); encode_cb_nops(&hdr); } /* * NFSv4.0 and NFSv4.1 XDR decode functions * * NFSv4.0 callback result types are defined in section 15 of RFC * 3530: "Network File System (NFS) version 4 Protocol" and section 20 * of RFC 5661: "Network File System (NFS) Version 4 Minor Version 1 * Protocol". */ static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, struct xdr_stream *xdr, void *__unused) { return 0; } /* * 20.2. Operation 4: CB_RECALL - Recall a Delegation */ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, struct xdr_stream *xdr, struct nfsd4_callback *cb) { struct nfs4_cb_compound_hdr hdr; enum nfsstat4 nfserr; int status; status = decode_cb_compound4res(xdr, &hdr); if (unlikely(status)) goto out; if (cb != NULL) { status = decode_cb_sequence4res(xdr, cb); if (unlikely(status)) goto out; } status = decode_cb_op_status(xdr, OP_CB_RECALL, &nfserr); if (unlikely(status)) goto out; if (unlikely(nfserr != NFS4_OK)) status = nfs_cb_stat_to_errno(nfserr); out: return status; } /* * RPC procedure tables */ #define PROC(proc, call, argtype, restype) \ [NFSPROC4_CLNT_##proc] = { \ .p_proc = NFSPROC4_CB_##call, \ .p_encode = (kxdreproc_t)nfs4_xdr_enc_##argtype, \ .p_decode = (kxdrdproc_t)nfs4_xdr_dec_##restype, \ .p_arglen = NFS4_enc_##argtype##_sz, \ .p_replen = NFS4_dec_##restype##_sz, \ .p_statidx = NFSPROC4_CB_##call, \ .p_name = #proc, \ } static struct rpc_procinfo nfs4_cb_procedures[] = { PROC(CB_NULL, NULL, cb_null, cb_null), PROC(CB_RECALL, COMPOUND, cb_recall, cb_recall), }; static struct rpc_version nfs_cb_version4 = { /* * Note on the callback rpc program version number: despite language in rfc * 5661 section 18.36.3 requiring servers to use 4 in this field, the * official xdr descriptions for both 4.0 and 4.1 specify version 1, and * in practice that appears to be what implementations use. The section * 18.36.3 language is expected to be fixed in an erratum. */ .number = 1, .nrprocs = ARRAY_SIZE(nfs4_cb_procedures), .procs = nfs4_cb_procedures }; static struct rpc_version *nfs_cb_version[] = { &nfs_cb_version4, }; static struct rpc_program cb_program; static struct rpc_stat cb_stats = { .program = &cb_program }; #define NFS4_CALLBACK 0x40000000 static struct rpc_program cb_program = { .name = "nfs4_cb", .number = NFS4_CALLBACK, .nrvers = ARRAY_SIZE(nfs_cb_version), .version = nfs_cb_version, .stats = &cb_stats, .pipe_dir_name = "/nfsd4_cb", }; static int max_cb_time(void) { return max(nfsd4_lease/10, (time_t)1) * HZ; } static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) { 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, .saddress = (struct sockaddr *) &conn->cb_saddr, .timeout = &timeparms, .program = &cb_program, .version = 0, .authflavor = clp->cl_flavor, .flags = (RPC_CLNT_CREATE_NOPING | RPC