cregit-Linux how code gets into the kernel

Release 4.10 fs/nfs/callback_xdr.c

Directory: fs/nfs
/*
 * linux/fs/nfs/callback_xdr.c
 *
 * Copyright (C) 2004 Trond Myklebust
 *
 * NFSv4 callback encode/decode procedures
 */
#include <linux/kernel.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include <linux/ratelimit.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/sunrpc/bc_xprt.h>
#include "nfs4_fs.h"
#include "callback.h"
#include "internal.h"
#include "nfs4session.h"


#define CB_OP_TAGLEN_MAXSZ		(512)

#define CB_OP_HDR_RES_MAXSZ		(2 * 4) 
// opcode, status

#define CB_OP_GETATTR_BITMAP_MAXSZ	(4 * 4) 
// bitmap length, 3 bitmaps

#define CB_OP_GETATTR_RES_MAXSZ		(CB_OP_HDR_RES_MAXSZ + \
                                         CB_OP_GETATTR_BITMAP_MAXSZ + \
					 /* change, size, ctime, mtime */\
                                         (2 + 2 + 3 + 3) * 4)

#define CB_OP_RECALL_RES_MAXSZ		(CB_OP_HDR_RES_MAXSZ)

#if defined(CONFIG_NFS_V4_1)

#define CB_OP_LAYOUTRECALL_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)

#define CB_OP_DEVICENOTIFY_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)

#define CB_OP_SEQUENCE_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ + \
                                         NFS4_MAX_SESSIONID_LEN + \
                                         (1 + 3) * 4) // seqid, 3 slotids

#define CB_OP_RECALLANY_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)

#define CB_OP_RECALLSLOT_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)

#define CB_OP_NOTIFY_LOCK_RES_MAXSZ	(CB_OP_HDR_RES_MAXSZ)
#endif /* CONFIG_NFS_V4_1 */


#define NFSDBG_FACILITY NFSDBG_CALLBACK

/* Internal error code */

#define NFS4ERR_RESOURCE_HDR	11050


typedef __be32 (*callback_process_op_t)(void *, void *,
					struct cb_process_state *);

typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);

typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);



struct callback_op {
	
callback_process_op_t process_op;
	
callback_decode_arg_t decode_args;
	
callback_encode_res_t encode_res;
	
long res_maxsize;
};


static struct callback_op callback_ops[];


static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp) { return htonl(NFS4_OK); }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust2496.00%150.00%
al viroal viro14.00%150.00%
Total25100.00%2100.00%


static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_argsize_check(rqstp, p); }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust2696.30%150.00%
al viroal viro13.70%150.00%
Total27100.00%2100.00%


static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy) { return xdr_ressize_check(rqstp, p); }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust2696.30%150.00%
al viroal viro13.70%150.00%
Total27100.00%2100.00%


static __be32 *read_buf(struct xdr_stream *xdr, size_t nbytes) { __be32 *p; p = xdr_inline_decode(xdr, nbytes); if (unlikely(p == NULL)) printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n"); return p; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust4393.48%250.00%
al viroal viro24.35%125.00%
jeff laytonjeff layton12.17%125.00%
Total46100.00%4100.00%


static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str) { __be32 *p; p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); *len = ntohl(*p); if (*len != 0) { p = read_buf(xdr, *len); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); *str = (const char *)p; } else *str = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust11098.21%133.33%
al viroal viro21.79%266.67%
Total112100.00%3100.00%


static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh) { __be32 *p; p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); fh->size = ntohl(*p); if (fh->size > NFS4_FHSIZE) return htonl(NFS4ERR_BADHANDLE); p = read_buf(xdr, fh->size); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); memcpy(&fh->data[0], p, fh->size); memset(&fh->data[fh->size], 0, sizeof(fh->data) - fh->size); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust13898.57%133.33%
al viroal viro21.43%266.67%
Total140100.00%3100.00%


static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap) { __be32 *p; unsigned int attrlen; p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); attrlen = ntohl(*p); p = read_buf(xdr, attrlen << 2); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); if (likely(attrlen > 0)) bitmap[0] = ntohl(*p++); if (attrlen > 1) bitmap[1] = ntohl(*p); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust12098.36%133.33%
al viroal viro21.64%266.67%
Total122100.00%3100.00%


static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) { __be32 *p; p = read_buf(xdr, NFS4_STATEID_SIZE); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); memcpy(stateid->data, p, NFS4_STATEID_SIZE); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust5596.49%360.00%
al viroal viro23.51%240.00%
Total57100.00%5100.00%


static __be32 decode_delegation_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) { stateid->type = NFS4_DELEGATION_STATEID_TYPE; return decode_stateid(xdr, stateid); }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust29100.00%1100.00%
Total29100.00%1100.00%


static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr) { __be32 *p; __be32 status; status = decode_string(xdr, &hdr->taglen, &hdr->tag); if (unlikely(status != 0)) return status; /* We do not like overly long tags! */ if (hdr->taglen > CB_OP_TAGLEN_MAXSZ) { printk("NFS: NFSv4 CALLBACK %s: client sent tag of length %u\n", __func__, hdr->taglen); return htonl(NFS4ERR_RESOURCE); } p = read_buf(xdr, 12); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); hdr->minorversion = ntohl(*p++); /* Check for minor version support */ if (hdr->minorversion <= NFS4_MAX_MINOR_VERSION) { hdr->cb_ident = ntohl(*p++); /* ignored by v4.1 and v4.2 */ } else { pr_warn_ratelimited("NFS: %s: NFSv4 server callback with " "illegal minor version %u!\n", __func__, hdr->minorversion); return htonl(NFS4ERR_MINOR_VERS_MISMATCH); } hdr->nops = ntohl(*p); dprintk("%s: minorversion %d nops %d\n", __func__, hdr->minorversion, hdr->nops); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust13773.26%218.18%
benny halevybenny halevy3217.11%218.18%
andy adamsonandy adamson84.28%19.09%
al viroal viro31.60%218.18%
weston andros adamsonweston andros adamson21.07%19.09%
harvey harrisonharvey harrison21.07%19.09%
bryan schumakerbryan schumaker21.07%19.09%
steve dicksonsteve dickson10.53%19.09%
Total187100.00%11100.00%


static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op) { __be32 *p; p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE_HDR); *op = ntohl(*p); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust5394.64%125.00%
al viroal viro23.57%250.00%
andy adamsonandy adamson11.79%125.00%
Total56100.00%4100.00%


static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args) { __be32 status; status = decode_fh(xdr, &args->fh); if (unlikely(status != 0)) goto out; status = decode_bitmap(xdr, args->bitmap); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust7092.11%125.00%
benny halevybenny halevy33.95%125.00%
al viroal viro22.63%125.00%
harvey harrisonharvey harrison11.32%125.00%
Total76100.00%4100.00%


static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args) { __be32 *p; __be32 status; status = decode_delegation_stateid(xdr, &args->stateid); if (unlikely(status != 0)) goto out; p = read_buf(xdr, 4); if (unlikely(p == NULL)) { status = htonl(NFS4ERR_RESOURCE); goto out; } args->truncate = ntohl(*p); status = decode_fh(xdr, &args->fh); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust11393.39%228.57%
benny halevybenny halevy32.48%114.29%
al viroal viro32.48%228.57%
alexey dobriyanalexey dobriyan10.83%114.29%
harvey harrisonharvey harrison10.83%114.29%
Total121100.00%7100.00%

#if defined(CONFIG_NFS_V4_1)
static __be32 decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) { stateid->type = NFS4_LAYOUT_STATEID_TYPE; return decode_stateid(xdr, stateid); }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust29100.00%1100.00%
Total29100.00%1100.00%


static __be32 decode_layoutrecall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_layoutrecallargs *args) { __be32 *p; __be32 status = 0; uint32_t iomode; p = read_buf(xdr, 4 * sizeof(uint32_t)); if (unlikely(p == NULL)) { status = htonl(NFS4ERR_BADXDR); goto out; } args->cbl_layout_type = ntohl(*p++); /* Depite the spec's xdr, iomode really belongs in the FILE switch, * as it is unusable and ignored with the other types. */ iomode = ntohl(*p++); args->cbl_layoutchanged = ntohl(*p++); args->cbl_recall_type = ntohl(*p++); if (args->cbl_recall_type == RETURN_FILE) { args->cbl_range.iomode = iomode; status = decode_fh(xdr, &args->cbl_fh); if (unlikely(status != 0)) goto out; p = read_buf(xdr, 2 * sizeof(uint64_t)); if (unlikely(p == NULL)) { status = htonl(NFS4ERR_BADXDR); goto out; } p = xdr_decode_hyper(p, &args->cbl_range.offset); p = xdr_decode_hyper(p, &args->cbl_range.length); status = decode_layout_stateid(xdr, &args->cbl_stateid); if (unlikely(status != 0)) goto out; } else if (args->cbl_recall_type == RETURN_FSID) { p = read_buf(xdr, 2 * sizeof(uint64_t)); if (unlikely(p == NULL)) { status = htonl(NFS4ERR_BADXDR); goto out; } p = xdr_decode_hyper(p, &args->cbl_fsid.major); p = xdr_decode_hyper(p, &args->cbl_fsid.minor); } else if (args->cbl_recall_type != RETURN_ALL) { status = htonl(NFS4ERR_BADXDR); goto out; } dprintk("%s: ltype 0x%x iomode %d changed %d recall_type %d\n", __func__, args->cbl_layout_type, iomode, args->cbl_layoutchanged, args->cbl_recall_type); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; }

Contributors

PersonTokensPropCommitsCommitProp
fred isamanfred isaman37199.46%133.33%
trond myklebusttrond myklebust10.27%133.33%
lucas de marchilucas de marchi10.27%133.33%
Total373100.00%3100.00%


static __be32 decode_devicenotify_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_devicenotifyargs *args) { __be32 *p; __be32 status = 0; u32 tmp; int n, i; args->ndevs = 0; /* Num of device notifications */ p = read_buf(xdr, sizeof(uint32_t)); if (unlikely(p == NULL)) { status = htonl(NFS4ERR_BADXDR); goto out; } n = ntohl(*p++); if (n <= 0) goto out; if (n > ULONG_MAX / sizeof(*args->devs)) { status = htonl(NFS4ERR_BADXDR); goto out; } args->devs = kmalloc_array(n, sizeof(*args->devs), GFP_KERNEL); if (!args->devs) { status = htonl(NFS4ERR_DELAY); goto out; } /* Decode each dev notification */ for (i = 0; i < n; i++) { struct cb_devicenotifyitem *dev = &args->devs[i]; p = read_buf(xdr, (4 * sizeof(uint32_t)) + NFS4_DEVICEID4_SIZE); if (unlikely(p == NULL)) { status = htonl(NFS4ERR_BADXDR); goto err; } tmp = ntohl(*p++); /* bitmap size */ if (tmp != 1) { status = htonl(NFS4ERR_INVAL); goto err; } dev->cbd_notify_type = ntohl(*p++); if (dev->cbd_notify_type != NOTIFY_DEVICEID4_CHANGE && dev->cbd_notify_type != NOTIFY_DEVICEID4_DELETE) { status = htonl(NFS4ERR_INVAL); goto err; } tmp = ntohl(*p++); /* opaque size */ if (((dev->cbd_notify_type == NOTIFY_DEVICEID4_CHANGE) && (tmp != NFS4_DEVICEID4_SIZE + 8)) || ((dev->cbd_notify_type == NOTIFY_DEVICEID4_DELETE) && (tmp != NFS4_DEVICEID4_SIZE + 4))) { status = htonl(NFS4ERR_INVAL); goto err; } dev->cbd_layout_type = ntohl(*p++); memcpy(dev->cbd_dev_id.data, p, NFS4_DEVICEID4_SIZE); p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE); if (dev->cbd_layout_type == NOTIFY_DEVICEID4_CHANGE) { p = read_buf(xdr, sizeof(uint32_t)); if (unlikely(p == NULL)) { status = htonl(NFS4ERR_BADXDR); goto err; } dev->cbd_immediate = ntohl(*p++); } else { dev->cbd_immediate = 0; } args->ndevs++; dprintk("%s: type %d layout 0x%x immediate %d\n", __func__, dev->cbd_notify_type, dev->cbd_layout_type, dev->cbd_immediate); } out: dprintk("%s: status %d ndevs %d\n", __func__, ntohl(status), args->ndevs); return status; err: kfree(args->devs); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
marc eshelmarc eshel47694.44%133.33%
dan carpenterdan carpenter265.16%133.33%
trond myklebusttrond myklebust20.40%133.33%
Total504100.00%3100.00%


static __be32 decode_sessionid(struct xdr_stream *xdr, struct nfs4_sessionid *sid) { __be32 *p; p = read_buf(xdr, NFS4_MAX_SESSIONID_LEN); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); memcpy(sid->data, p, NFS4_MAX_SESSIONID_LEN); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy5493.10%133.33%
kinglong meekinglong mee23.45%133.33%
andy adamsonandy adamson23.45%133.33%
Total58100.00%3100.00%


static __be32 decode_rc_list(struct xdr_stream *xdr, struct referring_call_list *rc_list) { __be32 *p; int i; __be32 status; status = decode_sessionid(xdr, &rc_list->rcl_sessionid); if (status) goto out; status = htonl(NFS4ERR_RESOURCE); p = read_buf(xdr, sizeof(uint32_t)); if (unlikely(p == NULL)) goto out; rc_list->rcl_nrefcalls = ntohl(*p++); if (rc_list->rcl_nrefcalls) { p = read_buf(xdr, rc_list->rcl_nrefcalls * 2 * sizeof(uint32_t)); if (unlikely(p == NULL)) goto out; rc_list->rcl_refcalls = kmalloc_array(rc_list->rcl_nrefcalls, sizeof(*rc_list->rcl_refcalls), GFP_KERNEL); if (unlikely(rc_list->rcl_refcalls == NULL)) goto out; for (i = 0; i < rc_list->rcl_nrefcalls; i++) { rc_list->rcl_refcalls[i].rc_sequenceid = ntohl(*p++); rc_list->rcl_refcalls[i].rc_slotid = ntohl(*p++); } } status = 0; out: return status; }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy21397.71%133.33%
andy adamsonandy adamson31.38%133.33%
trond myklebusttrond myklebust20.92%133.33%
Total218100.00%3100.00%


static __be32 decode_cb_sequence_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_sequenceargs *args) { __be32 *p; int i; __be32 status; status = decode_sessionid(xdr, &args->csa_sessionid); if (status) goto out; status = htonl(NFS4ERR_RESOURCE); p = read_buf(xdr, 5 * sizeof(uint32_t)); if (unlikely(p == NULL)) goto out; args->csa_addr = svc_addr(rqstp); args->csa_sequenceid = ntohl(*p++); args->csa_slotid = ntohl(*p++); args->csa_highestslotid = ntohl(*p++); args->csa_cachethis = ntohl(*p++); args->csa_nrclists = ntohl(*p++); args->csa_rclists = NULL; if (args->csa_nrclists) { args->csa_rclists = kmalloc_array(args->csa_nrclists, sizeof(*args->csa_rclists), GFP_KERNEL); if (unlikely(args->csa_rclists == NULL)) goto out; for (i = 0; i < args->csa_nrclists; i++) { status = decode_rc_list(xdr, &args->csa_rclists[i]); if (status) { args->csa_nrclists = i; goto out_free; } } } status = 0; dprintk("%s: sessionid %x:%x:%x:%x sequenceid %u slotid %u " "highestslotid %u cachethis %d nrclists %u\n", __func__, ((u32 *)&args->csa_sessionid)[0], ((u32 *)&args->csa_sessionid)[1], ((u32 *)&args->csa_sessionid)[2], ((u32 *)&args->csa_sessionid)[3], args->csa_sequenceid, args->csa_slotid, args->csa_highestslotid, args->csa_cachethis, args->csa_nrclists); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; out_free: for (i = 0; i < args->csa_nrclists; i++) kfree(args->csa_rclists[i].rcl_refcalls); kfree(args->csa_rclists); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy37396.38%120.00%
trond myklebusttrond myklebust82.07%120.00%
andy adamsonandy adamson30.78%120.00%
dan carpenterdan carpenter20.52%120.00%
ricardo labiagaricardo labiaga10.26%120.00%
Total387100.00%5100.00%


static __be32 decode_recallany_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallanyargs *args) { uint32_t bitmap[2]; __be32 *p, status; p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_BADXDR); args->craa_objs_to_keep = ntohl(*p++); status = decode_bitmap(xdr, bitmap); if (unlikely(status)) return status; args->craa_type_mask = bitmap[0]; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexandros batsakisalexandros batsakis8080.81%133.33%
peng taopeng tao1717.17%133.33%
andy adamsonandy adamson22.02%133.33%
Total99100.00%3100.00%


static __be32 decode_recallslot_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallslotargs *args) { __be32 *p; p = read_buf(xdr, 4); if (unlikely(p == NULL)) return htonl(NFS4ERR_BADXDR); args->crsa_target_highest_slotid = ntohl(*p++); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andy adamsonandy adamson6298.41%266.67%
trond myklebusttrond myklebust11.59%133.33%
Total63100.00%3100.00%


static __be32 decode_lockowner(struct xdr_stream *xdr, struct cb_notify_lock_args *args) { __be32 *p; unsigned int len; p = read_buf(xdr, 12); if (unlikely(p == NULL)) return htonl(NFS4ERR_BADXDR); p = xdr_decode_hyper(p, &args->cbnl_owner.clientid); len = be32_to_cpu(*p); p = read_buf(xdr, len); if (unlikely(p == NULL)) return htonl(NFS4ERR_BADXDR); /* Only try to decode if the length is right */ if (len == 20) { p += 2; /* skip "lock id:" */ args->cbnl_owner.s_dev = be32_to_cpu(*p++); xdr_decode_hyper(p, &args->cbnl_owner.id); args->cbnl_valid = true; } else { args->cbnl_owner.s_dev = 0; args->cbnl_owner.id = 0; args->cbnl_valid = false; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
jeff laytonjeff layton167100.00%1100.00%
Total167100.00%1100.00%


static __be32 decode_notify_lock_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_notify_lock_args *args) { __be32 status; status = decode_fh(xdr, &args->cbnl_fh); if (unlikely(status != 0)) goto out; status = decode_lockowner(xdr, args); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; }

Contributors

PersonTokensPropCommitsCommitProp
jeff laytonjeff layton74100.00%1100.00%
Total74100.00%1100.00%

#endif /* CONFIG_NFS_V4_1 */
static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str) { __be32 *p; p = xdr_reserve_space(xdr, 4 + len); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); xdr_encode_opaque(p, str, len); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust6096.77%133.33%
al viroal viro23.23%266.67%
Total62100.00%3100.00%

#define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) #define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep) { __be32 bm[2]; __be32 *p; bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0); bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1); if (bm[1] != 0) { p = xdr_reserve_space(xdr, 16); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); *p++ = htonl(2); *p++ = bm[0]; *p++ = bm[1]; } else if (bm[0] != 0) { p = xdr_reserve_space(xdr, 12); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); *p++ = htonl(1); *p++ = bm[0]; } else { p = xdr_reserve_space(xdr, 8); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); *p++ = htonl(0); } *savep = p; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust21798.19%133.33%
al viroal viro41.81%266.67%
Total221100.00%3100.00%


static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change) { __be32 *p; if (!(bitmap[0] & FATTR4_WORD0_CHANGE)) return 0; p = xdr_reserve_space(xdr, 8); if (unlikely(!p)) return htonl(NFS4ERR_RESOURCE); p = xdr_encode_hyper(p, change); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust7095.89%125.00%
al viroal viro22.74%250.00%
harvey harrisonharvey harrison11.37%125.00%
Total73100.00%4100.00%


static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size) { __be32 *p; if (!(bitmap[0] & FATTR4_WORD0_SIZE)) return 0; p = xdr_reserve_space(xdr, 8); if (unlikely(!p)) return htonl(NFS4ERR_RESOURCE); p = xdr_encode_hyper(p, size); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust7095.89%125.00%
al viroal viro22.74%250.00%
harvey harrisonharvey harrison11.37%125.00%
Total73100.00%4100.00%


static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time) { __be32 *p; p = xdr_reserve_space(xdr, 12); if (unlikely(!p)) return htonl(NFS4ERR_RESOURCE); p = xdr_encode_hyper(p, time->tv_sec); *p = htonl(time->tv_nsec); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust6595.59%125.00%
al viroal viro22.94%250.00%
harvey harrisonharvey harrison11.47%125.00%
Total68100.00%4100.00%


static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time) { if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA)) return 0; return encode_attr_time(xdr,time); }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust4497.78%150.00%
al viroal viro12.22%150.00%
Total45100.00%2100.00%


static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time) { if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY)) return 0; return encode_attr_time(xdr,time); }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust4497.78%150.00%
al viroal viro12.22%150.00%
Total45100.00%2100.00%


static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr) { __be32 status; hdr->status = xdr_reserve_space(xdr, 4); if (unlikely(hdr->status == NULL)) return htonl(NFS4ERR_RESOURCE); status = encode_string(xdr, hdr->taglen, hdr->tag); if (unlikely(status != 0)) return status; hdr->nops = xdr_reserve_space(xdr, 4); if (unlikely(hdr->nops == NULL)) return htonl(NFS4ERR_RESOURCE); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust10398.10%150.00%
al viroal viro21.90%150.00%
Total105100.00%2100.00%


static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res) { __be32 *p; p = xdr_reserve_space(xdr, 8); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE_HDR); *p++ = htonl(op); *p = res; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust5893.55%125.00%
al viroal viro34.84%250.00%
andy adamsonandy adamson11.61%125.00%
Total62100.00%4100.00%


static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res) { __be32 *savep = NULL; __be32 status = res->status; if (unlikely(status != 0)) goto out; status = encode_attr_bitmap(xdr, res->bitmap, &savep); if (unlikely(status != 0)) goto out; status = encode_attr_change(xdr, res->bitmap, res->change_attr); if (unlikely(status != 0)) goto out; status = encode_attr_size(xdr, res->bitmap, res->size); if (unlikely(status != 0)) goto out; status = encode_attr_ctime(xdr, res->bitmap, &res->ctime); if (unlikely(status != 0)) goto out; status = encode_attr_mtime(xdr, res->bitmap, &res->mtime); *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1))); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust21196.79%233.33%
al viroal viro31.38%233.33%
benny halevybenny halevy31.38%116.67%
harvey harrisonharvey harrison10.46%116.67%
Total218100.00%6100.00%

#if defined(CONFIG_NFS_V4_1)
static __be32 encode_sessionid(struct xdr_stream *xdr, const struct nfs4_sessionid *sid) { __be32 *p; p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); memcpy(p, sid, NFS4_MAX_SESSIONID_LEN); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy5392.98%133.33%
kinglong meekinglong mee23.51%133.33%
andy adamsonandy adamson23.51%133.33%
Total57100.00%3100.00%


static __be32 encode_cb_sequence_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_sequenceres *res) { __be32 *p; __be32 status = res->csr_status; if (unlikely(status != 0)) goto out; status = encode_sessionid(xdr, &res->csr_sessionid); if (status) goto out; p = xdr_reserve_space(xdr, 4 * sizeof(uint32_t)); if (unlikely(p == NULL)) return htonl(NFS4ERR_RESOURCE); *p++ = htonl(res->csr_sequenceid); *p++ = htonl(res->csr_slotid); *p++ = htonl(res->csr_highestslotid); *p++ = htonl(res->csr_target_highestslotid); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(status)); return status; }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy14292.21%125.00%
kinglong meekinglong mee95.84%125.00%
andy adamsonandy adamson21.30%125.00%
dan carpenterdan carpenter10.65%125.00%
Total154100.00%4100.00%


static __be32 preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) { if (op_nr == OP_CB_SEQUENCE) { if (nop != 0) return htonl(NFS4ERR_SEQUENCE_POS); } else { if (nop == 0) return htonl(NFS4ERR_OP_NOT_IN_SESSION); } switch (op_nr) { case OP_CB_GETATTR: case OP_CB_RECALL: case OP_CB_SEQUENCE: case OP_CB_RECALL_ANY: case OP_CB_RECALL_SLOT: case OP_CB_LAYOUTRECALL: case OP_CB_NOTIFY_DEVICEID: case OP_CB_NOTIFY_LOCK: *op = &callback_ops[op_nr]; break; case OP_CB_NOTIFY: case OP_CB_PUSH_DELEG: case OP_CB_RECALLABLE_OBJ_AVAIL: case OP_CB_WANTS_CANCELLED: return htonl(NFS4ERR_NOTSUPP); default: return htonl(NFS4ERR_OP_ILLEGAL); } return htonl(NFS_OK); }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy11088.00%337.50%
alexandros batsakisalexandros batsakis32.40%112.50%
andy adamsonandy adamson32.40%112.50%
marc eshelmarc eshel32.40%112.50%
jeff laytonjeff layton32.40%112.50%
fred isamanfred isaman32.40%112.50%
Total125100.00%8100.00%


static void nfs4_callback_free_slot(struct nfs4_session *session, struct nfs4_slot *slot) { struct nfs4_slot_table *tbl = &session->bc_slot_table; spin_lock(&tbl->slot_tbl_lock); /* * Let the state manager know callback processing done. * A single slot, so highest used slotid is either 0 or -1 */ nfs4_free_slot(tbl, slot); nfs4_slot_tbl_drain_complete(tbl); spin_unlock(&tbl->slot_tbl_lock); }

Contributors

PersonTokensPropCommitsCommitProp
andy adamsonandy adamson4480.00%250.00%
trond myklebusttrond myklebust1120.00%250.00%
Total55100.00%4100.00%


static void nfs4_cb_free_slot(struct cb_process_state *cps) { if (cps->slot) { nfs4_callback_free_slot(cps->clp->cl_session, cps->slot); cps->slot = NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
andy adamsonandy adamson2155.26%133.33%
trond myklebusttrond myklebust1744.74%266.67%
Total38100.00%3100.00%

#else /* CONFIG_NFS_V4_1 */
static __be32 preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op) { return htonl(NFS4ERR_MINOR_VERS_MISMATCH); }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy25100.00%1100.00%
Total25100.00%1100.00%


static void nfs4_cb_free_slot(struct cb_process_state *cps) { }

Contributors

PersonTokensPropCommitsCommitProp
andy adamsonandy adamson880.00%150.00%
trond myklebusttrond myklebust220.00%150.00%
Total10100.00%2100.00%

#endif /* CONFIG_NFS_V4_1 */ #ifdef CONFIG_NFS_V4_2
static __be32 preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op) { __be32 status = preprocess_nfs41_op(nop, op_nr, op); if (status != htonl(NFS4ERR_OP_ILLEGAL)) return status; if (op_nr == OP_CB_OFFLOAD) return htonl(NFS4ERR_NOTSUPP); return htonl(NFS4ERR_OP_ILLEGAL); }

Contributors

PersonTokensPropCommitsCommitProp
bryan schumakerbryan schumaker61100.00%1100.00%
Total61100.00%1100.00%

#else /* CONFIG_NFS_V4_2 */
static __be32 preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op) { return htonl(NFS4ERR_MINOR_VERS_MISMATCH); }

Contributors

PersonTokensPropCommitsCommitProp
bryan schumakerbryan schumaker25100.00%1100.00%
Total25100.00%1100.00%

#endif /* CONFIG_NFS_V4_2 */
static __be32 preprocess_nfs4_op(unsigned int op_nr, struct callback_op **op) { switch (op_nr) { case OP_CB_GETATTR: case OP_CB_RECALL: *op = &callback_ops[op_nr]; break; default: return htonl(NFS4ERR_OP_ILLEGAL); } return htonl(NFS_OK); }

Contributors

PersonTokensPropCommitsCommitProp
benny halevybenny halevy51100.00%1100.00%
Total51100.00%1100.00%


static __be32 process_op(int nop, struct svc_rqst *rqstp, struct xdr_stream *xdr_in, void *argp, struct xdr_stream *xdr_out, void *resp, struct cb_process_state *cps) { struct callback_op *op = &callback_ops[0]; unsigned int op_nr; __be32 status; long maxlen; __be32 res; dprintk("%s: start\n", __func__); status = decode_op_hdr(xdr_in, &op_nr); if (unlikely(status)) return status; dprintk("%s: minorversion=%d nop=%d op_nr=%u\n", __func__, cps->minorversion, nop, op_nr); switch (cps->minorversion) { case 0: status = preprocess_nfs4_op(op_nr, &op); break; case 1: status = preprocess_nfs41_op(nop, op_nr, &op); break; case 2: status = preprocess_nfs42_op(nop, op_nr, &op); break; default: status = htonl(NFS4ERR_MINOR_VERS_MISMATCH); } if (status == htonl(NFS4ERR_OP_ILLEGAL)) op_nr = OP_CB_ILLEGAL; if (status) goto encode_hdr; if (cps->drc_status) { status = cps->drc_status; goto encode_hdr; } maxlen = xdr_out->end - xdr_out->p; if (maxlen > 0 && maxlen < PAGE_SIZE) { status = op->decode_args(rqstp, xdr_in, argp); if (likely(status == 0)) status = op->process_op(argp, resp, cps); } else status = htonl(NFS4ERR_RESOURCE); encode_hdr: res = encode_op_hdr(xdr_out, op_nr, status); if (unlikely(res)) return res; if (op->encode_res != NULL && status == 0) status = op->encode_res(rqstp, xdr_out, resp); dprintk("%s: done, status = %d\n", __func__, ntohl(status)); return status; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust19759.70%216.67%
bryan schumakerbryan schumaker4513.64%216.67%
benny halevybenny halevy4212.73%216.67%
andy adamsonandy adamson4112.42%433.33%
al viroal viro30.91%18.33%
harvey harrisonharvey harrison20.61%18.33%
Total330100.00%12100.00%

/* * Decode, process and encode a COMPOUND */
static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp) { struct cb_compound_hdr_arg hdr_arg = { 0 }; struct cb_compound_hdr_res hdr_res = { NULL }; struct xdr_stream xdr_in, xdr_out; __be32 *p, status; struct cb_process_state cps = { .drc_status = 0, .clp = NULL, .net = SVC_NET(rqstp), }; unsigned int nops = 0; dprintk("%s: start\n", __func__); xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base); p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len); xdr_init_encode(&xdr_out, &rqstp->rq_res, p); status = decode_compound_hdr_arg(&xdr_in, &hdr_arg); if (status == htonl(NFS4ERR_RESOURCE)) return rpc_garbage_args; if (hdr_arg.minorversion == 0) { cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident); if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) goto out_invalidcred; } cps.minorversion = hdr_arg.minorversion; hdr_res.taglen = hdr_arg.taglen; hdr_res.tag = hdr_arg.tag; if (encode_compound_hdr_res(&xdr_out, &hdr_res) != 0) return rpc_system_err; while (status == 0 && nops != hdr_arg.nops) { status = process_op(nops, rqstp, &xdr_in, argp, &xdr_out, resp, &cps); nops++; } /* Buffer overflow in decode_ops_hdr or encode_ops_hdr. Return * resource error in cb_compound status without returning op */ if (unlikely(status == htonl(NFS4ERR_RESOURCE_HDR))) { status = htonl(NFS4ERR_RESOURCE); nops--; } *hdr_res.status = status; *hdr_res.nops = htonl(nops); nfs4_cb_free_slot(&cps); nfs_put_client(cps.clp); dprintk("%s: done, status = %u\n", __func__, ntohl(status)); return rpc_success; out_invalidcred: pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n"); return rpc_autherr_badcred; }

Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust24163.25%419.05%
andy adamsonandy adamson9625.20%523.81%
chuck leverchuck lever133.41%14.76%
stanislav kinsburskystanislav kinsbursky112.89%314.29%
bryan schumakerbryan schumaker82.10%14.76%
benny halevybenny halevy51.31%29.52%
al viroal viro30.79%29.52%
harvey harrisonharvey harrison20.52%14.76%
benjamin coddingtonbenjamin coddington10.26%14.76%
vaishali thakkarvaishali thakkar10.26%14.76%
Total381100.00%21100.00%

/* * Define NFS4 callback COMPOUND ops. */ static struct callback_op callback_ops[] = { [0] = { .res_maxsize = CB_OP_HDR_RES_MAXSZ, }, [OP_CB_GETATTR] = { .process_op = (callback_process_op_t)nfs4_callback_getattr, .decode_args = (callback_decode_arg_t)decode_getattr_args, .encode_res = (callback_encode_res_t)encode_getattr_res, .res_maxsize = CB_OP_GETATTR_RES_MAXSZ, }, [OP_CB_RECALL] = { .process_op = (callback_process_op_t)nfs4_callback_recall, .decode_args = (callback_decode_arg_t)decode_recall_args, .res_maxsize = CB_OP_RECALL_RES_MAXSZ, }, #if defined(CONFIG_NFS_V4_1) [OP_CB_LAYOUTRECALL] = { .process_op = (callback_process_op_t)nfs4_callback_layoutrecall, .decode_args = (callback_decode_arg_t)decode_layoutrecall_args, .res_maxsize = CB_OP_LAYOUTRECALL_RES_MAXSZ, }, [OP_CB_NOTIFY_DEVICEID] = { .process_op = (callback_process_op_t)nfs4_callback_devicenotify, .decode_args = (callback_decode_arg_t)decode_devicenotify_args, .res_maxsize = CB_OP_DEVICENOTIFY_RES_MAXSZ, }, [OP_CB_SEQUENCE] = { .process_op = (callback_process_op_t)nfs4_callback_sequence, .decode_args = (callback_decode_arg_t)decode_cb_sequence_args, .encode_res = (callback_encode_res_t)encode_cb_sequence_res, .res_maxsize = CB_OP_SEQUENCE_RES_MAXSZ, }, [OP_CB_RECALL_ANY] = { .process_op = (callback_process_op_t)nfs4_callback_recallany, .decode_args = (callback_decode_arg_t)decode_recallany_args, .res_maxsize = CB_OP_RECALLANY_RES_MAXSZ, }, [OP_CB_RECALL_SLOT] = { .process_op = (callback_process_op_t)nfs4_callback_recallslot, .decode_args = (callback_decode_arg_t)decode_recallslot_args, .res_maxsize = CB_OP_RECALLSLOT_RES_MAXSZ, }, [OP_CB_NOTIFY_LOCK] = { .process_op = (callback_process_op_t)nfs4_callback_notify_lock, .decode_args = (callback_decode_arg_t)decode_notify_lock_args, .res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ, }, #endif /* CONFIG_NFS_V4_1 */ }; /* * Define NFS4 callback procedures */ static struct svc_procedure nfs4_callback_procedures1[] = { [CB_NULL] = { .pc_func = nfs4_callback_null, .pc_decode = (kxdrproc_t)nfs4_decode_void, .pc_encode = (kxdrproc_t)nfs4_encode_void, .pc_xdrressize = 1, }, [CB_COMPOUND] = { .pc_func = nfs4_callback_compound, .pc_encode = (kxdrproc_t)nfs4_encode_void, .pc_argsize = 256, .pc_ressize = 256, .pc_xdrressize = NFS4_CALLBACK_BUFSIZE, } }; struct svc_version nfs4_callback_version1 = { .vs_vers = 1, .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1), .vs_proc = nfs4_callback_procedures1, .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, .vs_dispatch = NULL, .vs_hidden = 1, }; struct svc_version nfs4_callback_version4 = { .vs_vers = 4, .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1), .vs_proc = nfs4_callback_procedures1, .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, .vs_dispatch = NULL, .vs_hidden = 1, };

Overall Contributors

PersonTokensPropCommitsCommitProp
trond myklebusttrond myklebust271845.93%1523.44%
benny halevybenny halevy118720.06%69.38%
marc eshelmarc eshel5108.62%11.56%
fred isamanfred isaman4056.84%11.56%
andy adamsonandy adamson3455.83%914.06%
jeff laytonjeff layton2814.75%34.69%
bryan schumakerbryan schumaker1502.53%23.12%
alexandros batsakisalexandros batsakis1482.50%23.12%
al viroal viro540.91%34.69%
dan carpenterdan carpenter290.49%34.69%
kinglong meekinglong mee220.37%34.69%
peng taopeng tao170.29%11.56%
chuck leverchuck lever130.22%11.56%
harvey harrisonharvey harrison120.20%23.12%
stanislav kinsburskystanislav kinsbursky110.19%34.69%
steve dicksonsteve dickson60.10%23.12%
tejun heotejun heo30.05%11.56%
weston andros adamsonweston andros adamson20.03%11.56%
ricardo labiagaricardo labiaga10.02%11.56%
benjamin coddingtonbenjamin coddington10.02%11.56%
alexey dobriyanalexey dobriyan10.02%11.56%
vaishali thakkarvaishali thakkar10.02%11.56%
lucas de marchilucas de marchi10.02%11.56%
Total5918100.00%64100.00%
Directory: fs/nfs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.