162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/nfs/callback_xdr.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 Trond Myklebust 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * NFSv4 callback encode/decode procedures 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/sunrpc/svc.h> 1162306a36Sopenharmony_ci#include <linux/nfs4.h> 1262306a36Sopenharmony_ci#include <linux/nfs_fs.h> 1362306a36Sopenharmony_ci#include <linux/ratelimit.h> 1462306a36Sopenharmony_ci#include <linux/printk.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/sunrpc/bc_xprt.h> 1762306a36Sopenharmony_ci#include "nfs4_fs.h" 1862306a36Sopenharmony_ci#include "callback.h" 1962306a36Sopenharmony_ci#include "internal.h" 2062306a36Sopenharmony_ci#include "nfs4session.h" 2162306a36Sopenharmony_ci#include "nfs4trace.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define CB_OP_TAGLEN_MAXSZ (512) 2462306a36Sopenharmony_ci#define CB_OP_HDR_RES_MAXSZ (2 * 4) // opcode, status 2562306a36Sopenharmony_ci#define CB_OP_GETATTR_BITMAP_MAXSZ (4 * 4) // bitmap length, 3 bitmaps 2662306a36Sopenharmony_ci#define CB_OP_GETATTR_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ 2762306a36Sopenharmony_ci CB_OP_GETATTR_BITMAP_MAXSZ + \ 2862306a36Sopenharmony_ci /* change, size, ctime, mtime */\ 2962306a36Sopenharmony_ci (2 + 2 + 3 + 3) * 4) 3062306a36Sopenharmony_ci#define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#if defined(CONFIG_NFS_V4_1) 3362306a36Sopenharmony_ci#define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 3462306a36Sopenharmony_ci#define CB_OP_DEVICENOTIFY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 3562306a36Sopenharmony_ci#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \ 3662306a36Sopenharmony_ci NFS4_MAX_SESSIONID_LEN + \ 3762306a36Sopenharmony_ci (1 + 3) * 4) // seqid, 3 slotids 3862306a36Sopenharmony_ci#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 3962306a36Sopenharmony_ci#define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 4062306a36Sopenharmony_ci#define CB_OP_NOTIFY_LOCK_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 4162306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_1 */ 4262306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 4362306a36Sopenharmony_ci#define CB_OP_OFFLOAD_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ) 4462306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_2 */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_CALLBACK 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* Internal error code */ 4962306a36Sopenharmony_ci#define NFS4ERR_RESOURCE_HDR 11050 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct callback_op { 5262306a36Sopenharmony_ci __be32 (*process_op)(void *, void *, struct cb_process_state *); 5362306a36Sopenharmony_ci __be32 (*decode_args)(struct svc_rqst *, struct xdr_stream *, void *); 5462306a36Sopenharmony_ci __be32 (*encode_res)(struct svc_rqst *, struct xdr_stream *, 5562306a36Sopenharmony_ci const void *); 5662306a36Sopenharmony_ci long res_maxsize; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic struct callback_op callback_ops[]; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic __be32 nfs4_callback_null(struct svc_rqst *rqstp) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci return htonl(NFS4_OK); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * svc_process_common() looks for an XDR encoder to know when 6862306a36Sopenharmony_ci * not to drop a Reply. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_cistatic bool nfs4_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci return true; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, 7662306a36Sopenharmony_ci const char **str, size_t maxlen) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci ssize_t err; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci err = xdr_stream_decode_opaque_inline(xdr, (void **)str, maxlen); 8162306a36Sopenharmony_ci if (err < 0) 8262306a36Sopenharmony_ci return cpu_to_be32(NFS4ERR_RESOURCE); 8362306a36Sopenharmony_ci *len = err; 8462306a36Sopenharmony_ci return 0; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci __be32 *p; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 9262306a36Sopenharmony_ci if (unlikely(p == NULL)) 9362306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 9462306a36Sopenharmony_ci fh->size = ntohl(*p); 9562306a36Sopenharmony_ci if (fh->size > NFS4_FHSIZE) 9662306a36Sopenharmony_ci return htonl(NFS4ERR_BADHANDLE); 9762306a36Sopenharmony_ci p = xdr_inline_decode(xdr, fh->size); 9862306a36Sopenharmony_ci if (unlikely(p == NULL)) 9962306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 10062306a36Sopenharmony_ci memcpy(&fh->data[0], p, fh->size); 10162306a36Sopenharmony_ci memset(&fh->data[fh->size], 0, sizeof(fh->data) - fh->size); 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci __be32 *p; 10862306a36Sopenharmony_ci unsigned int attrlen; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 11162306a36Sopenharmony_ci if (unlikely(p == NULL)) 11262306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 11362306a36Sopenharmony_ci attrlen = ntohl(*p); 11462306a36Sopenharmony_ci p = xdr_inline_decode(xdr, attrlen << 2); 11562306a36Sopenharmony_ci if (unlikely(p == NULL)) 11662306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 11762306a36Sopenharmony_ci if (likely(attrlen > 0)) 11862306a36Sopenharmony_ci bitmap[0] = ntohl(*p++); 11962306a36Sopenharmony_ci if (attrlen > 1) 12062306a36Sopenharmony_ci bitmap[1] = ntohl(*p); 12162306a36Sopenharmony_ci return 0; 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci __be32 *p; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci p = xdr_inline_decode(xdr, NFS4_STATEID_SIZE); 12962306a36Sopenharmony_ci if (unlikely(p == NULL)) 13062306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 13162306a36Sopenharmony_ci memcpy(stateid->data, p, NFS4_STATEID_SIZE); 13262306a36Sopenharmony_ci return 0; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic __be32 decode_delegation_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci stateid->type = NFS4_DELEGATION_STATEID_TYPE; 13862306a36Sopenharmony_ci return decode_stateid(xdr, stateid); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci __be32 *p; 14462306a36Sopenharmony_ci __be32 status; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci status = decode_string(xdr, &hdr->taglen, &hdr->tag, CB_OP_TAGLEN_MAXSZ); 14762306a36Sopenharmony_ci if (unlikely(status != 0)) 14862306a36Sopenharmony_ci return status; 14962306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 12); 15062306a36Sopenharmony_ci if (unlikely(p == NULL)) 15162306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 15262306a36Sopenharmony_ci hdr->minorversion = ntohl(*p++); 15362306a36Sopenharmony_ci /* Check for minor version support */ 15462306a36Sopenharmony_ci if (hdr->minorversion <= NFS4_MAX_MINOR_VERSION) { 15562306a36Sopenharmony_ci hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 and v4.2 */ 15662306a36Sopenharmony_ci } else { 15762306a36Sopenharmony_ci pr_warn_ratelimited("NFS: %s: NFSv4 server callback with " 15862306a36Sopenharmony_ci "illegal minor version %u!\n", 15962306a36Sopenharmony_ci __func__, hdr->minorversion); 16062306a36Sopenharmony_ci return htonl(NFS4ERR_MINOR_VERS_MISMATCH); 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci hdr->nops = ntohl(*p); 16362306a36Sopenharmony_ci return 0; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci __be32 *p; 16962306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 17062306a36Sopenharmony_ci if (unlikely(p == NULL)) 17162306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE_HDR); 17262306a36Sopenharmony_ci *op = ntohl(*p); 17362306a36Sopenharmony_ci return 0; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic __be32 decode_getattr_args(struct svc_rqst *rqstp, 17762306a36Sopenharmony_ci struct xdr_stream *xdr, void *argp) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct cb_getattrargs *args = argp; 18062306a36Sopenharmony_ci __be32 status; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci status = decode_fh(xdr, &args->fh); 18362306a36Sopenharmony_ci if (unlikely(status != 0)) 18462306a36Sopenharmony_ci return status; 18562306a36Sopenharmony_ci return decode_bitmap(xdr, args->bitmap); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic __be32 decode_recall_args(struct svc_rqst *rqstp, 18962306a36Sopenharmony_ci struct xdr_stream *xdr, void *argp) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct cb_recallargs *args = argp; 19262306a36Sopenharmony_ci __be32 *p; 19362306a36Sopenharmony_ci __be32 status; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci status = decode_delegation_stateid(xdr, &args->stateid); 19662306a36Sopenharmony_ci if (unlikely(status != 0)) 19762306a36Sopenharmony_ci return status; 19862306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 19962306a36Sopenharmony_ci if (unlikely(p == NULL)) 20062306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 20162306a36Sopenharmony_ci args->truncate = ntohl(*p); 20262306a36Sopenharmony_ci return decode_fh(xdr, &args->fh); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci#if defined(CONFIG_NFS_V4_1) 20662306a36Sopenharmony_cistatic __be32 decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci stateid->type = NFS4_LAYOUT_STATEID_TYPE; 20962306a36Sopenharmony_ci return decode_stateid(xdr, stateid); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic __be32 decode_layoutrecall_args(struct svc_rqst *rqstp, 21362306a36Sopenharmony_ci struct xdr_stream *xdr, void *argp) 21462306a36Sopenharmony_ci{ 21562306a36Sopenharmony_ci struct cb_layoutrecallargs *args = argp; 21662306a36Sopenharmony_ci __be32 *p; 21762306a36Sopenharmony_ci __be32 status = 0; 21862306a36Sopenharmony_ci uint32_t iomode; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4 * sizeof(uint32_t)); 22162306a36Sopenharmony_ci if (unlikely(p == NULL)) 22262306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci args->cbl_layout_type = ntohl(*p++); 22562306a36Sopenharmony_ci /* Depite the spec's xdr, iomode really belongs in the FILE switch, 22662306a36Sopenharmony_ci * as it is unusable and ignored with the other types. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci iomode = ntohl(*p++); 22962306a36Sopenharmony_ci args->cbl_layoutchanged = ntohl(*p++); 23062306a36Sopenharmony_ci args->cbl_recall_type = ntohl(*p++); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (args->cbl_recall_type == RETURN_FILE) { 23362306a36Sopenharmony_ci args->cbl_range.iomode = iomode; 23462306a36Sopenharmony_ci status = decode_fh(xdr, &args->cbl_fh); 23562306a36Sopenharmony_ci if (unlikely(status != 0)) 23662306a36Sopenharmony_ci return status; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 2 * sizeof(uint64_t)); 23962306a36Sopenharmony_ci if (unlikely(p == NULL)) 24062306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 24162306a36Sopenharmony_ci p = xdr_decode_hyper(p, &args->cbl_range.offset); 24262306a36Sopenharmony_ci p = xdr_decode_hyper(p, &args->cbl_range.length); 24362306a36Sopenharmony_ci return decode_layout_stateid(xdr, &args->cbl_stateid); 24462306a36Sopenharmony_ci } else if (args->cbl_recall_type == RETURN_FSID) { 24562306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 2 * sizeof(uint64_t)); 24662306a36Sopenharmony_ci if (unlikely(p == NULL)) 24762306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 24862306a36Sopenharmony_ci p = xdr_decode_hyper(p, &args->cbl_fsid.major); 24962306a36Sopenharmony_ci p = xdr_decode_hyper(p, &args->cbl_fsid.minor); 25062306a36Sopenharmony_ci } else if (args->cbl_recall_type != RETURN_ALL) 25162306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci} 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cistatic 25662306a36Sopenharmony_ci__be32 decode_devicenotify_args(struct svc_rqst *rqstp, 25762306a36Sopenharmony_ci struct xdr_stream *xdr, 25862306a36Sopenharmony_ci void *argp) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct cb_devicenotifyargs *args = argp; 26162306a36Sopenharmony_ci uint32_t tmp, n, i; 26262306a36Sopenharmony_ci __be32 *p; 26362306a36Sopenharmony_ci __be32 status = 0; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* Num of device notifications */ 26662306a36Sopenharmony_ci p = xdr_inline_decode(xdr, sizeof(uint32_t)); 26762306a36Sopenharmony_ci if (unlikely(p == NULL)) { 26862306a36Sopenharmony_ci status = htonl(NFS4ERR_BADXDR); 26962306a36Sopenharmony_ci goto out; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci n = ntohl(*p++); 27262306a36Sopenharmony_ci if (n == 0) 27362306a36Sopenharmony_ci goto out; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL); 27662306a36Sopenharmony_ci if (!args->devs) { 27762306a36Sopenharmony_ci status = htonl(NFS4ERR_DELAY); 27862306a36Sopenharmony_ci goto out; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* Decode each dev notification */ 28262306a36Sopenharmony_ci for (i = 0; i < n; i++) { 28362306a36Sopenharmony_ci struct cb_devicenotifyitem *dev = &args->devs[i]; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci p = xdr_inline_decode(xdr, (4 * sizeof(uint32_t)) + 28662306a36Sopenharmony_ci NFS4_DEVICEID4_SIZE); 28762306a36Sopenharmony_ci if (unlikely(p == NULL)) { 28862306a36Sopenharmony_ci status = htonl(NFS4ERR_BADXDR); 28962306a36Sopenharmony_ci goto err; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci tmp = ntohl(*p++); /* bitmap size */ 29362306a36Sopenharmony_ci if (tmp != 1) { 29462306a36Sopenharmony_ci status = htonl(NFS4ERR_INVAL); 29562306a36Sopenharmony_ci goto err; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci dev->cbd_notify_type = ntohl(*p++); 29862306a36Sopenharmony_ci if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE && 29962306a36Sopenharmony_ci dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) { 30062306a36Sopenharmony_ci status = htonl(NFS4ERR_INVAL); 30162306a36Sopenharmony_ci goto err; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci tmp = ntohl(*p++); /* opaque size */ 30562306a36Sopenharmony_ci if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) && 30662306a36Sopenharmony_ci (tmp != NFS4_DEVICEID4_SIZE + 8)) || 30762306a36Sopenharmony_ci ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) && 30862306a36Sopenharmony_ci (tmp != NFS4_DEVICEID4_SIZE + 4))) { 30962306a36Sopenharmony_ci status = htonl(NFS4ERR_INVAL); 31062306a36Sopenharmony_ci goto err; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci dev->cbd_layout_type = ntohl(*p++); 31362306a36Sopenharmony_ci memcpy(dev->cbd_dev_id.data, p, NFS4_DEVICEID4_SIZE); 31462306a36Sopenharmony_ci p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) { 31762306a36Sopenharmony_ci p = xdr_inline_decode(xdr, sizeof(uint32_t)); 31862306a36Sopenharmony_ci if (unlikely(p == NULL)) { 31962306a36Sopenharmony_ci status = htonl(NFS4ERR_BADXDR); 32062306a36Sopenharmony_ci goto err; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci dev->cbd_immediate = ntohl(*p++); 32362306a36Sopenharmony_ci } else { 32462306a36Sopenharmony_ci dev->cbd_immediate = 0; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci dprintk("%s: type %d layout 0x%x immediate %d\n", 32862306a36Sopenharmony_ci __func__, dev->cbd_notify_type, dev->cbd_layout_type, 32962306a36Sopenharmony_ci dev->cbd_immediate); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci args->ndevs = n; 33262306a36Sopenharmony_ci dprintk("%s: ndevs %d\n", __func__, args->ndevs); 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_cierr: 33562306a36Sopenharmony_ci kfree(args->devs); 33662306a36Sopenharmony_ciout: 33762306a36Sopenharmony_ci args->devs = NULL; 33862306a36Sopenharmony_ci args->ndevs = 0; 33962306a36Sopenharmony_ci dprintk("%s: status %d ndevs %d\n", 34062306a36Sopenharmony_ci __func__, ntohl(status), args->ndevs); 34162306a36Sopenharmony_ci return status; 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic __be32 decode_sessionid(struct xdr_stream *xdr, 34562306a36Sopenharmony_ci struct nfs4_sessionid *sid) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci __be32 *p; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN); 35062306a36Sopenharmony_ci if (unlikely(p == NULL)) 35162306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci memcpy(sid->data, p, NFS4_MAX_SESSIONID_LEN); 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic __be32 decode_rc_list(struct xdr_stream *xdr, 35862306a36Sopenharmony_ci struct referring_call_list *rc_list) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci __be32 *p; 36162306a36Sopenharmony_ci int i; 36262306a36Sopenharmony_ci __be32 status; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci status = decode_sessionid(xdr, &rc_list->rcl_sessionid); 36562306a36Sopenharmony_ci if (status) 36662306a36Sopenharmony_ci goto out; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci status = htonl(NFS4ERR_RESOURCE); 36962306a36Sopenharmony_ci p = xdr_inline_decode(xdr, sizeof(uint32_t)); 37062306a36Sopenharmony_ci if (unlikely(p == NULL)) 37162306a36Sopenharmony_ci goto out; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci rc_list->rcl_nrefcalls = ntohl(*p++); 37462306a36Sopenharmony_ci if (rc_list->rcl_nrefcalls) { 37562306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 37662306a36Sopenharmony_ci rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); 37762306a36Sopenharmony_ci if (unlikely(p == NULL)) 37862306a36Sopenharmony_ci goto out; 37962306a36Sopenharmony_ci rc_list->rcl_refcalls = kmalloc_array(rc_list->rcl_nrefcalls, 38062306a36Sopenharmony_ci sizeof(*rc_list->rcl_refcalls), 38162306a36Sopenharmony_ci GFP_KERNEL); 38262306a36Sopenharmony_ci if (unlikely(rc_list->rcl_refcalls == NULL)) 38362306a36Sopenharmony_ci goto out; 38462306a36Sopenharmony_ci for (i = 0; i < rc_list->rcl_nrefcalls; i++) { 38562306a36Sopenharmony_ci rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++); 38662306a36Sopenharmony_ci rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++); 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci status = 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciout: 39262306a36Sopenharmony_ci return status; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic __be32 decode_cb_sequence_args(struct svc_rqst *rqstp, 39662306a36Sopenharmony_ci struct xdr_stream *xdr, 39762306a36Sopenharmony_ci void *argp) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci struct cb_sequenceargs *args = argp; 40062306a36Sopenharmony_ci __be32 *p; 40162306a36Sopenharmony_ci int i; 40262306a36Sopenharmony_ci __be32 status; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci status = decode_sessionid(xdr, &args->csa_sessionid); 40562306a36Sopenharmony_ci if (status) 40662306a36Sopenharmony_ci return status; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 5 * sizeof(uint32_t)); 40962306a36Sopenharmony_ci if (unlikely(p == NULL)) 41062306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci args->csa_addr = svc_addr(rqstp); 41362306a36Sopenharmony_ci args->csa_sequenceid = ntohl(*p++); 41462306a36Sopenharmony_ci args->csa_slotid = ntohl(*p++); 41562306a36Sopenharmony_ci args->csa_highestslotid = ntohl(*p++); 41662306a36Sopenharmony_ci args->csa_cachethis = ntohl(*p++); 41762306a36Sopenharmony_ci args->csa_nrclists = ntohl(*p++); 41862306a36Sopenharmony_ci args->csa_rclists = NULL; 41962306a36Sopenharmony_ci if (args->csa_nrclists) { 42062306a36Sopenharmony_ci args->csa_rclists = kmalloc_array(args->csa_nrclists, 42162306a36Sopenharmony_ci sizeof(*args->csa_rclists), 42262306a36Sopenharmony_ci GFP_KERNEL); 42362306a36Sopenharmony_ci if (unlikely(args->csa_rclists == NULL)) 42462306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci for (i = 0; i < args->csa_nrclists; i++) { 42762306a36Sopenharmony_ci status = decode_rc_list(xdr, &args->csa_rclists[i]); 42862306a36Sopenharmony_ci if (status) { 42962306a36Sopenharmony_ci args->csa_nrclists = i; 43062306a36Sopenharmony_ci goto out_free; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ciout_free: 43762306a36Sopenharmony_ci for (i = 0; i < args->csa_nrclists; i++) 43862306a36Sopenharmony_ci kfree(args->csa_rclists[i].rcl_refcalls); 43962306a36Sopenharmony_ci kfree(args->csa_rclists); 44062306a36Sopenharmony_ci return status; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic __be32 decode_recallany_args(struct svc_rqst *rqstp, 44462306a36Sopenharmony_ci struct xdr_stream *xdr, 44562306a36Sopenharmony_ci void *argp) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct cb_recallanyargs *args = argp; 44862306a36Sopenharmony_ci uint32_t bitmap[2]; 44962306a36Sopenharmony_ci __be32 *p, status; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 45262306a36Sopenharmony_ci if (unlikely(p == NULL)) 45362306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 45462306a36Sopenharmony_ci args->craa_objs_to_keep = ntohl(*p++); 45562306a36Sopenharmony_ci status = decode_bitmap(xdr, bitmap); 45662306a36Sopenharmony_ci if (unlikely(status)) 45762306a36Sopenharmony_ci return status; 45862306a36Sopenharmony_ci args->craa_type_mask = bitmap[0]; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return 0; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_cistatic __be32 decode_recallslot_args(struct svc_rqst *rqstp, 46462306a36Sopenharmony_ci struct xdr_stream *xdr, 46562306a36Sopenharmony_ci void *argp) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct cb_recallslotargs *args = argp; 46862306a36Sopenharmony_ci __be32 *p; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 47162306a36Sopenharmony_ci if (unlikely(p == NULL)) 47262306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 47362306a36Sopenharmony_ci args->crsa_target_highest_slotid = ntohl(*p++); 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic __be32 decode_lockowner(struct xdr_stream *xdr, struct cb_notify_lock_args *args) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci __be32 *p; 48062306a36Sopenharmony_ci unsigned int len; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 12); 48362306a36Sopenharmony_ci if (unlikely(p == NULL)) 48462306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci p = xdr_decode_hyper(p, &args->cbnl_owner.clientid); 48762306a36Sopenharmony_ci len = be32_to_cpu(*p); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci p = xdr_inline_decode(xdr, len); 49062306a36Sopenharmony_ci if (unlikely(p == NULL)) 49162306a36Sopenharmony_ci return htonl(NFS4ERR_BADXDR); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* Only try to decode if the length is right */ 49462306a36Sopenharmony_ci if (len == 20) { 49562306a36Sopenharmony_ci p += 2; /* skip "lock id:" */ 49662306a36Sopenharmony_ci args->cbnl_owner.s_dev = be32_to_cpu(*p++); 49762306a36Sopenharmony_ci xdr_decode_hyper(p, &args->cbnl_owner.id); 49862306a36Sopenharmony_ci args->cbnl_valid = true; 49962306a36Sopenharmony_ci } else { 50062306a36Sopenharmony_ci args->cbnl_owner.s_dev = 0; 50162306a36Sopenharmony_ci args->cbnl_owner.id = 0; 50262306a36Sopenharmony_ci args->cbnl_valid = false; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci return 0; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cistatic __be32 decode_notify_lock_args(struct svc_rqst *rqstp, 50862306a36Sopenharmony_ci struct xdr_stream *xdr, void *argp) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct cb_notify_lock_args *args = argp; 51162306a36Sopenharmony_ci __be32 status; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci status = decode_fh(xdr, &args->cbnl_fh); 51462306a36Sopenharmony_ci if (unlikely(status != 0)) 51562306a36Sopenharmony_ci return status; 51662306a36Sopenharmony_ci return decode_lockowner(xdr, args); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_1 */ 52062306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 52162306a36Sopenharmony_cistatic __be32 decode_write_response(struct xdr_stream *xdr, 52262306a36Sopenharmony_ci struct cb_offloadargs *args) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci __be32 *p; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* skip the always zero field */ 52762306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 52862306a36Sopenharmony_ci if (unlikely(!p)) 52962306a36Sopenharmony_ci goto out; 53062306a36Sopenharmony_ci p++; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci /* decode count, stable_how, verifier */ 53362306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 8 + 4); 53462306a36Sopenharmony_ci if (unlikely(!p)) 53562306a36Sopenharmony_ci goto out; 53662306a36Sopenharmony_ci p = xdr_decode_hyper(p, &args->wr_count); 53762306a36Sopenharmony_ci args->wr_writeverf.committed = be32_to_cpup(p); 53862306a36Sopenharmony_ci p = xdr_inline_decode(xdr, NFS4_VERIFIER_SIZE); 53962306a36Sopenharmony_ci if (likely(p)) { 54062306a36Sopenharmony_ci memcpy(&args->wr_writeverf.verifier.data[0], p, 54162306a36Sopenharmony_ci NFS4_VERIFIER_SIZE); 54262306a36Sopenharmony_ci return 0; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ciout: 54562306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic __be32 decode_offload_args(struct svc_rqst *rqstp, 54962306a36Sopenharmony_ci struct xdr_stream *xdr, 55062306a36Sopenharmony_ci void *data) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct cb_offloadargs *args = data; 55362306a36Sopenharmony_ci __be32 *p; 55462306a36Sopenharmony_ci __be32 status; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* decode fh */ 55762306a36Sopenharmony_ci status = decode_fh(xdr, &args->coa_fh); 55862306a36Sopenharmony_ci if (unlikely(status != 0)) 55962306a36Sopenharmony_ci return status; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci /* decode stateid */ 56262306a36Sopenharmony_ci status = decode_stateid(xdr, &args->coa_stateid); 56362306a36Sopenharmony_ci if (unlikely(status != 0)) 56462306a36Sopenharmony_ci return status; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* decode status */ 56762306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 56862306a36Sopenharmony_ci if (unlikely(!p)) 56962306a36Sopenharmony_ci goto out; 57062306a36Sopenharmony_ci args->error = ntohl(*p++); 57162306a36Sopenharmony_ci if (!args->error) { 57262306a36Sopenharmony_ci status = decode_write_response(xdr, args); 57362306a36Sopenharmony_ci if (unlikely(status != 0)) 57462306a36Sopenharmony_ci return status; 57562306a36Sopenharmony_ci } else { 57662306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 8); 57762306a36Sopenharmony_ci if (unlikely(!p)) 57862306a36Sopenharmony_ci goto out; 57962306a36Sopenharmony_ci p = xdr_decode_hyper(p, &args->wr_count); 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ciout: 58362306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_2 */ 58662306a36Sopenharmony_cistatic __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci if (unlikely(xdr_stream_encode_opaque(xdr, str, len) < 0)) 58962306a36Sopenharmony_ci return cpu_to_be32(NFS4ERR_RESOURCE); 59062306a36Sopenharmony_ci return 0; 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_cistatic __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, size_t sz) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci if (xdr_stream_encode_uint32_array(xdr, bitmap, sz) < 0) 59662306a36Sopenharmony_ci return cpu_to_be32(NFS4ERR_RESOURCE); 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cistatic __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci __be32 *p; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!(bitmap[0] & FATTR4_WORD0_CHANGE)) 60562306a36Sopenharmony_ci return 0; 60662306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 8); 60762306a36Sopenharmony_ci if (unlikely(!p)) 60862306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 60962306a36Sopenharmony_ci p = xdr_encode_hyper(p, change); 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci __be32 *p; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (!(bitmap[0] & FATTR4_WORD0_SIZE)) 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 8); 62062306a36Sopenharmony_ci if (unlikely(!p)) 62162306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 62262306a36Sopenharmony_ci p = xdr_encode_hyper(p, size); 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec64 *time) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci __be32 *p; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 12); 63162306a36Sopenharmony_ci if (unlikely(!p)) 63262306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 63362306a36Sopenharmony_ci p = xdr_encode_hyper(p, time->tv_sec); 63462306a36Sopenharmony_ci *p = htonl(time->tv_nsec); 63562306a36Sopenharmony_ci return 0; 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec64 *time) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) 64162306a36Sopenharmony_ci return 0; 64262306a36Sopenharmony_ci return encode_attr_time(xdr,time); 64362306a36Sopenharmony_ci} 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec64 *time) 64662306a36Sopenharmony_ci{ 64762306a36Sopenharmony_ci if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) 64862306a36Sopenharmony_ci return 0; 64962306a36Sopenharmony_ci return encode_attr_time(xdr,time); 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci __be32 status; 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci hdr->status = xdr_reserve_space(xdr, 4); 65762306a36Sopenharmony_ci if (unlikely(hdr->status == NULL)) 65862306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 65962306a36Sopenharmony_ci status = encode_string(xdr, hdr->taglen, hdr->tag); 66062306a36Sopenharmony_ci if (unlikely(status != 0)) 66162306a36Sopenharmony_ci return status; 66262306a36Sopenharmony_ci hdr->nops = xdr_reserve_space(xdr, 4); 66362306a36Sopenharmony_ci if (unlikely(hdr->nops == NULL)) 66462306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 66562306a36Sopenharmony_ci return 0; 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci __be32 *p; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 8); 67362306a36Sopenharmony_ci if (unlikely(p == NULL)) 67462306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE_HDR); 67562306a36Sopenharmony_ci *p++ = htonl(op); 67662306a36Sopenharmony_ci *p = res; 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, 68162306a36Sopenharmony_ci const void *resp) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci const struct cb_getattrres *res = resp; 68462306a36Sopenharmony_ci __be32 *savep = NULL; 68562306a36Sopenharmony_ci __be32 status = res->status; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (unlikely(status != 0)) 68862306a36Sopenharmony_ci goto out; 68962306a36Sopenharmony_ci status = encode_attr_bitmap(xdr, res->bitmap, ARRAY_SIZE(res->bitmap)); 69062306a36Sopenharmony_ci if (unlikely(status != 0)) 69162306a36Sopenharmony_ci goto out; 69262306a36Sopenharmony_ci status = cpu_to_be32(NFS4ERR_RESOURCE); 69362306a36Sopenharmony_ci savep = xdr_reserve_space(xdr, sizeof(*savep)); 69462306a36Sopenharmony_ci if (unlikely(!savep)) 69562306a36Sopenharmony_ci goto out; 69662306a36Sopenharmony_ci status = encode_attr_change(xdr, res->bitmap, res->change_attr); 69762306a36Sopenharmony_ci if (unlikely(status != 0)) 69862306a36Sopenharmony_ci goto out; 69962306a36Sopenharmony_ci status = encode_attr_size(xdr, res->bitmap, res->size); 70062306a36Sopenharmony_ci if (unlikely(status != 0)) 70162306a36Sopenharmony_ci goto out; 70262306a36Sopenharmony_ci status = encode_attr_ctime(xdr, res->bitmap, &res->ctime); 70362306a36Sopenharmony_ci if (unlikely(status != 0)) 70462306a36Sopenharmony_ci goto out; 70562306a36Sopenharmony_ci status = encode_attr_mtime(xdr, res->bitmap, &res->mtime); 70662306a36Sopenharmony_ci *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1))); 70762306a36Sopenharmony_ciout: 70862306a36Sopenharmony_ci return status; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci#if defined(CONFIG_NFS_V4_1) 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_cistatic __be32 encode_sessionid(struct xdr_stream *xdr, 71462306a36Sopenharmony_ci const struct nfs4_sessionid *sid) 71562306a36Sopenharmony_ci{ 71662306a36Sopenharmony_ci __be32 *p; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN); 71962306a36Sopenharmony_ci if (unlikely(p == NULL)) 72062306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci memcpy(p, sid, NFS4_MAX_SESSIONID_LEN); 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic __be32 encode_cb_sequence_res(struct svc_rqst *rqstp, 72762306a36Sopenharmony_ci struct xdr_stream *xdr, 72862306a36Sopenharmony_ci const void *resp) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci const struct cb_sequenceres *res = resp; 73162306a36Sopenharmony_ci __be32 *p; 73262306a36Sopenharmony_ci __be32 status = res->csr_status; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci if (unlikely(status != 0)) 73562306a36Sopenharmony_ci return status; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci status = encode_sessionid(xdr, &res->csr_sessionid); 73862306a36Sopenharmony_ci if (status) 73962306a36Sopenharmony_ci return status; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); 74262306a36Sopenharmony_ci if (unlikely(p == NULL)) 74362306a36Sopenharmony_ci return htonl(NFS4ERR_RESOURCE); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci *p++ = htonl(res->csr_sequenceid); 74662306a36Sopenharmony_ci *p++ = htonl(res->csr_slotid); 74762306a36Sopenharmony_ci *p++ = htonl(res->csr_highestslotid); 74862306a36Sopenharmony_ci *p++ = htonl(res->csr_target_highestslotid); 74962306a36Sopenharmony_ci return 0; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic __be32 75362306a36Sopenharmony_cipreprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci if (op_nr == OP_CB_SEQUENCE) { 75662306a36Sopenharmony_ci if (nop != 0) 75762306a36Sopenharmony_ci return htonl(NFS4ERR_SEQUENCE_POS); 75862306a36Sopenharmony_ci } else { 75962306a36Sopenharmony_ci if (nop == 0) 76062306a36Sopenharmony_ci return htonl(NFS4ERR_OP_NOT_IN_SESSION); 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci switch (op_nr) { 76462306a36Sopenharmony_ci case OP_CB_GETATTR: 76562306a36Sopenharmony_ci case OP_CB_RECALL: 76662306a36Sopenharmony_ci case OP_CB_SEQUENCE: 76762306a36Sopenharmony_ci case OP_CB_RECALL_ANY: 76862306a36Sopenharmony_ci case OP_CB_RECALL_SLOT: 76962306a36Sopenharmony_ci case OP_CB_LAYOUTRECALL: 77062306a36Sopenharmony_ci case OP_CB_NOTIFY_DEVICEID: 77162306a36Sopenharmony_ci case OP_CB_NOTIFY_LOCK: 77262306a36Sopenharmony_ci *op = &callback_ops[op_nr]; 77362306a36Sopenharmony_ci break; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci case OP_CB_NOTIFY: 77662306a36Sopenharmony_ci case OP_CB_PUSH_DELEG: 77762306a36Sopenharmony_ci case OP_CB_RECALLABLE_OBJ_AVAIL: 77862306a36Sopenharmony_ci case OP_CB_WANTS_CANCELLED: 77962306a36Sopenharmony_ci return htonl(NFS4ERR_NOTSUPP); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci default: 78262306a36Sopenharmony_ci return htonl(NFS4ERR_OP_ILLEGAL); 78362306a36Sopenharmony_ci } 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return htonl(NFS_OK); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic void nfs4_callback_free_slot(struct nfs4_session *session, 78962306a36Sopenharmony_ci struct nfs4_slot *slot) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct nfs4_slot_table *tbl = &session->bc_slot_table; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci spin_lock(&tbl->slot_tbl_lock); 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * Let the state manager know callback processing done. 79662306a36Sopenharmony_ci * A single slot, so highest used slotid is either 0 or -1 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_ci nfs4_free_slot(tbl, slot); 79962306a36Sopenharmony_ci spin_unlock(&tbl->slot_tbl_lock); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic void nfs4_cb_free_slot(struct cb_process_state *cps) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci if (cps->slot) { 80562306a36Sopenharmony_ci nfs4_callback_free_slot(cps->clp->cl_session, cps->slot); 80662306a36Sopenharmony_ci cps->slot = NULL; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci#else /* CONFIG_NFS_V4_1 */ 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic __be32 81362306a36Sopenharmony_cipreprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci return htonl(NFS4ERR_MINOR_VERS_MISMATCH); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic void nfs4_cb_free_slot(struct cb_process_state *cps) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_1 */ 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 82462306a36Sopenharmony_cistatic __be32 82562306a36Sopenharmony_cipreprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op) 82662306a36Sopenharmony_ci{ 82762306a36Sopenharmony_ci __be32 status = preprocess_nfs41_op(nop, op_nr, op); 82862306a36Sopenharmony_ci if (status != htonl(NFS4ERR_OP_ILLEGAL)) 82962306a36Sopenharmony_ci return status; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (op_nr == OP_CB_OFFLOAD) { 83262306a36Sopenharmony_ci *op = &callback_ops[op_nr]; 83362306a36Sopenharmony_ci return htonl(NFS_OK); 83462306a36Sopenharmony_ci } else 83562306a36Sopenharmony_ci return htonl(NFS4ERR_NOTSUPP); 83662306a36Sopenharmony_ci return htonl(NFS4ERR_OP_ILLEGAL); 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ci#else /* CONFIG_NFS_V4_2 */ 83962306a36Sopenharmony_cistatic __be32 84062306a36Sopenharmony_cipreprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci return htonl(NFS4ERR_MINOR_VERS_MISMATCH); 84362306a36Sopenharmony_ci} 84462306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_2 */ 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic __be32 84762306a36Sopenharmony_cipreprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci switch (op_nr) { 85062306a36Sopenharmony_ci case OP_CB_GETATTR: 85162306a36Sopenharmony_ci case OP_CB_RECALL: 85262306a36Sopenharmony_ci *op = &callback_ops[op_nr]; 85362306a36Sopenharmony_ci break; 85462306a36Sopenharmony_ci default: 85562306a36Sopenharmony_ci return htonl(NFS4ERR_OP_ILLEGAL); 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci return htonl(NFS_OK); 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_cistatic __be32 process_op(int nop, struct svc_rqst *rqstp, 86262306a36Sopenharmony_ci struct cb_process_state *cps) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct xdr_stream *xdr_out = &rqstp->rq_res_stream; 86562306a36Sopenharmony_ci struct callback_op *op = &callback_ops[0]; 86662306a36Sopenharmony_ci unsigned int op_nr; 86762306a36Sopenharmony_ci __be32 status; 86862306a36Sopenharmony_ci long maxlen; 86962306a36Sopenharmony_ci __be32 res; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci status = decode_op_hdr(&rqstp->rq_arg_stream, &op_nr); 87262306a36Sopenharmony_ci if (unlikely(status)) 87362306a36Sopenharmony_ci return status; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci switch (cps->minorversion) { 87662306a36Sopenharmony_ci case 0: 87762306a36Sopenharmony_ci status = preprocess_nfs4_op(op_nr, &op); 87862306a36Sopenharmony_ci break; 87962306a36Sopenharmony_ci case 1: 88062306a36Sopenharmony_ci status = preprocess_nfs41_op(nop, op_nr, &op); 88162306a36Sopenharmony_ci break; 88262306a36Sopenharmony_ci case 2: 88362306a36Sopenharmony_ci status = preprocess_nfs42_op(nop, op_nr, &op); 88462306a36Sopenharmony_ci break; 88562306a36Sopenharmony_ci default: 88662306a36Sopenharmony_ci status = htonl(NFS4ERR_MINOR_VERS_MISMATCH); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (status == htonl(NFS4ERR_OP_ILLEGAL)) 89062306a36Sopenharmony_ci op_nr = OP_CB_ILLEGAL; 89162306a36Sopenharmony_ci if (status) 89262306a36Sopenharmony_ci goto encode_hdr; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci if (cps->drc_status) { 89562306a36Sopenharmony_ci status = cps->drc_status; 89662306a36Sopenharmony_ci goto encode_hdr; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci maxlen = xdr_out->end - xdr_out->p; 90062306a36Sopenharmony_ci if (maxlen > 0 && maxlen < PAGE_SIZE) { 90162306a36Sopenharmony_ci status = op->decode_args(rqstp, &rqstp->rq_arg_stream, 90262306a36Sopenharmony_ci rqstp->rq_argp); 90362306a36Sopenharmony_ci if (likely(status == 0)) 90462306a36Sopenharmony_ci status = op->process_op(rqstp->rq_argp, rqstp->rq_resp, 90562306a36Sopenharmony_ci cps); 90662306a36Sopenharmony_ci } else 90762306a36Sopenharmony_ci status = htonl(NFS4ERR_RESOURCE); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ciencode_hdr: 91062306a36Sopenharmony_ci res = encode_op_hdr(xdr_out, op_nr, status); 91162306a36Sopenharmony_ci if (unlikely(res)) 91262306a36Sopenharmony_ci return res; 91362306a36Sopenharmony_ci if (op->encode_res != NULL && status == 0) 91462306a36Sopenharmony_ci status = op->encode_res(rqstp, xdr_out, rqstp->rq_resp); 91562306a36Sopenharmony_ci return status; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci/* 91962306a36Sopenharmony_ci * Decode, process and encode a COMPOUND 92062306a36Sopenharmony_ci */ 92162306a36Sopenharmony_cistatic __be32 nfs4_callback_compound(struct svc_rqst *rqstp) 92262306a36Sopenharmony_ci{ 92362306a36Sopenharmony_ci struct cb_compound_hdr_arg hdr_arg = { 0 }; 92462306a36Sopenharmony_ci struct cb_compound_hdr_res hdr_res = { NULL }; 92562306a36Sopenharmony_ci struct cb_process_state cps = { 92662306a36Sopenharmony_ci .drc_status = 0, 92762306a36Sopenharmony_ci .clp = NULL, 92862306a36Sopenharmony_ci .net = SVC_NET(rqstp), 92962306a36Sopenharmony_ci }; 93062306a36Sopenharmony_ci unsigned int nops = 0; 93162306a36Sopenharmony_ci __be32 status; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci status = decode_compound_hdr_arg(&rqstp->rq_arg_stream, &hdr_arg); 93462306a36Sopenharmony_ci if (status == htonl(NFS4ERR_RESOURCE)) 93562306a36Sopenharmony_ci return rpc_garbage_args; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (hdr_arg.minorversion == 0) { 93862306a36Sopenharmony_ci cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident); 93962306a36Sopenharmony_ci if (!cps.clp) { 94062306a36Sopenharmony_ci trace_nfs_cb_no_clp(rqstp->rq_xid, hdr_arg.cb_ident); 94162306a36Sopenharmony_ci goto out_invalidcred; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci if (!check_gss_callback_principal(cps.clp, rqstp)) { 94462306a36Sopenharmony_ci trace_nfs_cb_badprinc(rqstp->rq_xid, hdr_arg.cb_ident); 94562306a36Sopenharmony_ci nfs_put_client(cps.clp); 94662306a36Sopenharmony_ci goto out_invalidcred; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci cps.minorversion = hdr_arg.minorversion; 95162306a36Sopenharmony_ci hdr_res.taglen = hdr_arg.taglen; 95262306a36Sopenharmony_ci hdr_res.tag = hdr_arg.tag; 95362306a36Sopenharmony_ci if (encode_compound_hdr_res(&rqstp->rq_res_stream, &hdr_res) != 0) { 95462306a36Sopenharmony_ci if (cps.clp) 95562306a36Sopenharmony_ci nfs_put_client(cps.clp); 95662306a36Sopenharmony_ci return rpc_system_err; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci while (status == 0 && nops != hdr_arg.nops) { 95962306a36Sopenharmony_ci status = process_op(nops, rqstp, &cps); 96062306a36Sopenharmony_ci nops++; 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return 96462306a36Sopenharmony_ci * resource error in cb_compound status without returning op */ 96562306a36Sopenharmony_ci if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) { 96662306a36Sopenharmony_ci status = htonl(NFS4ERR_RESOURCE); 96762306a36Sopenharmony_ci nops--; 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci *hdr_res.status = status; 97162306a36Sopenharmony_ci *hdr_res.nops = htonl(nops); 97262306a36Sopenharmony_ci nfs4_cb_free_slot(&cps); 97362306a36Sopenharmony_ci nfs_put_client(cps.clp); 97462306a36Sopenharmony_ci return rpc_success; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ciout_invalidcred: 97762306a36Sopenharmony_ci pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n"); 97862306a36Sopenharmony_ci rqstp->rq_auth_stat = rpc_autherr_badcred; 97962306a36Sopenharmony_ci return rpc_success; 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_cistatic int 98362306a36Sopenharmony_cinfs_callback_dispatch(struct svc_rqst *rqstp) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci const struct svc_procedure *procp = rqstp->rq_procinfo; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci *rqstp->rq_accept_statp = procp->pc_func(rqstp); 98862306a36Sopenharmony_ci return 1; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci/* 99262306a36Sopenharmony_ci * Define NFS4 callback COMPOUND ops. 99362306a36Sopenharmony_ci */ 99462306a36Sopenharmony_cistatic struct callback_op callback_ops[] = { 99562306a36Sopenharmony_ci [0] = { 99662306a36Sopenharmony_ci .res_maxsize = CB_OP_HDR_RES_MAXSZ, 99762306a36Sopenharmony_ci }, 99862306a36Sopenharmony_ci [OP_CB_GETATTR] = { 99962306a36Sopenharmony_ci .process_op = nfs4_callback_getattr, 100062306a36Sopenharmony_ci .decode_args = decode_getattr_args, 100162306a36Sopenharmony_ci .encode_res = encode_getattr_res, 100262306a36Sopenharmony_ci .res_maxsize = CB_OP_GETATTR_RES_MAXSZ, 100362306a36Sopenharmony_ci }, 100462306a36Sopenharmony_ci [OP_CB_RECALL] = { 100562306a36Sopenharmony_ci .process_op = nfs4_callback_recall, 100662306a36Sopenharmony_ci .decode_args = decode_recall_args, 100762306a36Sopenharmony_ci .res_maxsize = CB_OP_RECALL_RES_MAXSZ, 100862306a36Sopenharmony_ci }, 100962306a36Sopenharmony_ci#if defined(CONFIG_NFS_V4_1) 101062306a36Sopenharmony_ci [OP_CB_LAYOUTRECALL] = { 101162306a36Sopenharmony_ci .process_op = nfs4_callback_layoutrecall, 101262306a36Sopenharmony_ci .decode_args = decode_layoutrecall_args, 101362306a36Sopenharmony_ci .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ, 101462306a36Sopenharmony_ci }, 101562306a36Sopenharmony_ci [OP_CB_NOTIFY_DEVICEID] = { 101662306a36Sopenharmony_ci .process_op = nfs4_callback_devicenotify, 101762306a36Sopenharmony_ci .decode_args = decode_devicenotify_args, 101862306a36Sopenharmony_ci .res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ, 101962306a36Sopenharmony_ci }, 102062306a36Sopenharmony_ci [OP_CB_SEQUENCE] = { 102162306a36Sopenharmony_ci .process_op = nfs4_callback_sequence, 102262306a36Sopenharmony_ci .decode_args = decode_cb_sequence_args, 102362306a36Sopenharmony_ci .encode_res = encode_cb_sequence_res, 102462306a36Sopenharmony_ci .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, 102562306a36Sopenharmony_ci }, 102662306a36Sopenharmony_ci [OP_CB_RECALL_ANY] = { 102762306a36Sopenharmony_ci .process_op = nfs4_callback_recallany, 102862306a36Sopenharmony_ci .decode_args = decode_recallany_args, 102962306a36Sopenharmony_ci .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, 103062306a36Sopenharmony_ci }, 103162306a36Sopenharmony_ci [OP_CB_RECALL_SLOT] = { 103262306a36Sopenharmony_ci .process_op = nfs4_callback_recallslot, 103362306a36Sopenharmony_ci .decode_args = decode_recallslot_args, 103462306a36Sopenharmony_ci .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ, 103562306a36Sopenharmony_ci }, 103662306a36Sopenharmony_ci [OP_CB_NOTIFY_LOCK] = { 103762306a36Sopenharmony_ci .process_op = nfs4_callback_notify_lock, 103862306a36Sopenharmony_ci .decode_args = decode_notify_lock_args, 103962306a36Sopenharmony_ci .res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ, 104062306a36Sopenharmony_ci }, 104162306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_1 */ 104262306a36Sopenharmony_ci#ifdef CONFIG_NFS_V4_2 104362306a36Sopenharmony_ci [OP_CB_OFFLOAD] = { 104462306a36Sopenharmony_ci .process_op = nfs4_callback_offload, 104562306a36Sopenharmony_ci .decode_args = decode_offload_args, 104662306a36Sopenharmony_ci .res_maxsize = CB_OP_OFFLOAD_RES_MAXSZ, 104762306a36Sopenharmony_ci }, 104862306a36Sopenharmony_ci#endif /* CONFIG_NFS_V4_2 */ 104962306a36Sopenharmony_ci}; 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci/* 105262306a36Sopenharmony_ci * Define NFS4 callback procedures 105362306a36Sopenharmony_ci */ 105462306a36Sopenharmony_cistatic const struct svc_procedure nfs4_callback_procedures1[] = { 105562306a36Sopenharmony_ci [CB_NULL] = { 105662306a36Sopenharmony_ci .pc_func = nfs4_callback_null, 105762306a36Sopenharmony_ci .pc_encode = nfs4_encode_void, 105862306a36Sopenharmony_ci .pc_xdrressize = 1, 105962306a36Sopenharmony_ci .pc_name = "NULL", 106062306a36Sopenharmony_ci }, 106162306a36Sopenharmony_ci [CB_COMPOUND] = { 106262306a36Sopenharmony_ci .pc_func = nfs4_callback_compound, 106362306a36Sopenharmony_ci .pc_encode = nfs4_encode_void, 106462306a36Sopenharmony_ci .pc_argsize = 256, 106562306a36Sopenharmony_ci .pc_argzero = 256, 106662306a36Sopenharmony_ci .pc_ressize = 256, 106762306a36Sopenharmony_ci .pc_xdrressize = NFS4_CALLBACK_BUFSIZE, 106862306a36Sopenharmony_ci .pc_name = "COMPOUND", 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci}; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic DEFINE_PER_CPU_ALIGNED(unsigned long, 107362306a36Sopenharmony_ci nfs4_callback_count1[ARRAY_SIZE(nfs4_callback_procedures1)]); 107462306a36Sopenharmony_ciconst struct svc_version nfs4_callback_version1 = { 107562306a36Sopenharmony_ci .vs_vers = 1, 107662306a36Sopenharmony_ci .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1), 107762306a36Sopenharmony_ci .vs_proc = nfs4_callback_procedures1, 107862306a36Sopenharmony_ci .vs_count = nfs4_callback_count1, 107962306a36Sopenharmony_ci .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, 108062306a36Sopenharmony_ci .vs_dispatch = nfs_callback_dispatch, 108162306a36Sopenharmony_ci .vs_hidden = true, 108262306a36Sopenharmony_ci .vs_need_cong_ctrl = true, 108362306a36Sopenharmony_ci}; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_cistatic DEFINE_PER_CPU_ALIGNED(unsigned long, 108662306a36Sopenharmony_ci nfs4_callback_count4[ARRAY_SIZE(nfs4_callback_procedures1)]); 108762306a36Sopenharmony_ciconst struct svc_version nfs4_callback_version4 = { 108862306a36Sopenharmony_ci .vs_vers = 4, 108962306a36Sopenharmony_ci .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1), 109062306a36Sopenharmony_ci .vs_proc = nfs4_callback_procedures1, 109162306a36Sopenharmony_ci .vs_count = nfs4_callback_count4, 109262306a36Sopenharmony_ci .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, 109362306a36Sopenharmony_ci .vs_dispatch = nfs_callback_dispatch, 109462306a36Sopenharmony_ci .vs_hidden = true, 109562306a36Sopenharmony_ci .vs_need_cong_ctrl = true, 109662306a36Sopenharmony_ci}; 1097