nfs3xdr.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:25k
- /*
- * linux/fs/nfs/nfs3xdr.c
- *
- * XDR functions to encode/decode NFSv3 RPC arguments and results.
- *
- * Copyright (C) 1996, 1997 Olaf Kirch
- */
- #include <linux/param.h>
- #include <linux/sched.h>
- #include <linux/mm.h>
- #include <linux/slab.h>
- #include <linux/utsname.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/in.h>
- #include <linux/pagemap.h>
- #include <linux/proc_fs.h>
- #include <linux/kdev_t.h>
- #include <linux/sunrpc/clnt.h>
- #include <linux/nfs.h>
- #include <linux/nfs3.h>
- #include <linux/nfs_fs.h>
- /* Uncomment this to support servers requiring longword lengths */
- #define NFS_PAD_WRITES 1
- #define NFSDBG_FACILITY NFSDBG_XDR
- /* Mapping from NFS error code to "errno" error code. */
- #define errno_NFSERR_IO EIO
- extern int nfs_stat_to_errno(int);
- /*
- * Declare the space requirements for NFS arguments and replies as
- * number of 32bit-words
- */
- #define NFS3_fhandle_sz 1+16
- #define NFS3_fh_sz NFS3_fhandle_sz /* shorthand */
- #define NFS3_sattr_sz 15
- #define NFS3_filename_sz 1+(NFS3_MAXNAMLEN>>2)
- #define NFS3_path_sz 1+(NFS3_MAXPATHLEN>>2)
- #define NFS3_fattr_sz 21
- #define NFS3_wcc_attr_sz 6
- #define NFS3_pre_op_attr_sz 1+NFS3_wcc_attr_sz
- #define NFS3_post_op_attr_sz 1+NFS3_fattr_sz
- #define NFS3_wcc_data_sz NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
- #define NFS3_fsstat_sz
- #define NFS3_fsinfo_sz
- #define NFS3_pathconf_sz
- #define NFS3_entry_sz NFS3_filename_sz+3
- #define NFS3_enc_void_sz 0
- #define NFS3_sattrargs_sz NFS3_fh_sz+NFS3_sattr_sz+3
- #define NFS3_diropargs_sz NFS3_fh_sz+NFS3_filename_sz
- #define NFS3_accessargs_sz NFS3_fh_sz+1
- #define NFS3_readlinkargs_sz NFS3_fh_sz
- #define NFS3_readargs_sz NFS3_fh_sz+3
- #define NFS3_writeargs_sz NFS3_fh_sz+5
- #define NFS3_createargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
- #define NFS3_mkdirargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
- #define NFS3_symlinkargs_sz NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
- #define NFS3_mknodargs_sz NFS3_diropargs_sz+2+NFS3_sattr_sz
- #define NFS3_renameargs_sz NFS3_diropargs_sz+NFS3_diropargs_sz
- #define NFS3_linkargs_sz NFS3_fh_sz+NFS3_diropargs_sz
- #define NFS3_readdirargs_sz NFS3_fh_sz+2
- #define NFS3_commitargs_sz NFS3_fh_sz+3
- #define NFS3_dec_void_sz 0
- #define NFS3_attrstat_sz 1+NFS3_fattr_sz
- #define NFS3_wccstat_sz 1+NFS3_wcc_data_sz
- #define NFS3_lookupres_sz 1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
- #define NFS3_accessres_sz 1+NFS3_post_op_attr_sz+1
- #define NFS3_readlinkres_sz 1+NFS3_post_op_attr_sz
- #define NFS3_readres_sz 1+NFS3_post_op_attr_sz+3
- #define NFS3_writeres_sz 1+NFS3_wcc_data_sz+4
- #define NFS3_createres_sz 1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
- #define NFS3_renameres_sz 1+(2 * NFS3_wcc_data_sz)
- #define NFS3_linkres_sz 1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
- #define NFS3_readdirres_sz 1+NFS3_post_op_attr_sz+2
- #define NFS3_fsstatres_sz 1+NFS3_post_op_attr_sz+13
- #define NFS3_fsinfores_sz 1+NFS3_post_op_attr_sz+12
- #define NFS3_pathconfres_sz 1+NFS3_post_op_attr_sz+6
- #define NFS3_commitres_sz 1+NFS3_wcc_data_sz+2
- /*
- * Map file type to S_IFMT bits
- */
- static struct {
- unsigned int mode;
- unsigned int nfs2type;
- } nfs_type2fmt[] = {
- { 0, NFNON },
- { S_IFREG, NFREG },
- { S_IFDIR, NFDIR },
- { S_IFBLK, NFBLK },
- { S_IFCHR, NFCHR },
- { S_IFLNK, NFLNK },
- { S_IFSOCK, NFSOCK },
- { S_IFIFO, NFFIFO },
- { 0, NFBAD }
- };
- /*
- * Common NFS XDR functions as inlines
- */
- static inline u32 *
- xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
- {
- *p++ = htonl(fh->size);
- memcpy(p, fh->data, fh->size);
- return p + XDR_QUADLEN(fh->size);
- }
- static inline u32 *
- xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
- {
- /*
- * Zero all nonused bytes
- */
- memset((u8 *)fh, 0, sizeof(*fh));
- if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
- memcpy(fh->data, p, fh->size);
- return p + XDR_QUADLEN(fh->size);
- }
- return NULL;
- }
- /*
- * Encode/decode time.
- * Since the VFS doesn't care for fractional times, we ignore the
- * nanosecond field.
- */
- static inline u32 *
- xdr_encode_time(u32 *p, time_t time)
- {
- *p++ = htonl(time);
- *p++ = 0;
- return p;
- }
- static inline u32 *
- xdr_decode_time3(u32 *p, u64 *timep)
- {
- u64 tmp = (u64)ntohl(*p++) << 32;
- *timep = tmp + (u64)ntohl(*p++);
- return p;
- }
- static inline u32 *
- xdr_encode_time3(u32 *p, u64 time)
- {
- *p++ = htonl(time >> 32);
- *p++ = htonl(time & 0xFFFFFFFF);
- return p;
- }
- static inline u32 *
- xdr_decode_string2(u32 *p, char **string, unsigned int *len,
- unsigned int maxlen)
- {
- *len = ntohl(*p++);
- if (*len > maxlen)
- return NULL;
- *string = (char *) p;
- return p + XDR_QUADLEN(*len);
- }
- static inline u32 *
- xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
- {
- unsigned int type;
- int fmode;
- type = ntohl(*p++);
- if (type >= NF3BAD)
- type = NF3BAD;
- fmode = nfs_type2fmt[type].mode;
- fattr->type = nfs_type2fmt[type].nfs2type;
- fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
- fattr->nlink = ntohl(*p++);
- fattr->uid = ntohl(*p++);
- fattr->gid = ntohl(*p++);
- p = xdr_decode_hyper(p, &fattr->size);
- p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
- /* Turn remote device info into Linux-specific dev_t */
- fattr->rdev = ntohl(*p++) << MINORBITS;
- fattr->rdev |= ntohl(*p++) & MINORMASK;
- p = xdr_decode_hyper(p, &fattr->fsid);
- p = xdr_decode_hyper(p, &fattr->fileid);
- p = xdr_decode_time3(p, &fattr->atime);
- p = xdr_decode_time3(p, &fattr->mtime);
- p = xdr_decode_time3(p, &fattr->ctime);
- /* Update the mode bits */
- fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
- return p;
- }
- static inline u32 *
- xdr_encode_sattr(u32 *p, struct iattr *attr)
- {
- if (attr->ia_valid & ATTR_MODE) {
- *p++ = xdr_one;
- *p++ = htonl(attr->ia_mode);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_UID) {
- *p++ = xdr_one;
- *p++ = htonl(attr->ia_uid);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_GID) {
- *p++ = xdr_one;
- *p++ = htonl(attr->ia_gid);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_SIZE) {
- *p++ = xdr_one;
- p = xdr_encode_hyper(p, (__u64) attr->ia_size);
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_ATIME_SET) {
- *p++ = xdr_two;
- p = xdr_encode_time(p, attr->ia_atime);
- } else if (attr->ia_valid & ATTR_ATIME) {
- *p++ = xdr_one;
- } else {
- *p++ = xdr_zero;
- }
- if (attr->ia_valid & ATTR_MTIME_SET) {
- *p++ = xdr_two;
- p = xdr_encode_time(p, attr->ia_mtime);
- } else if (attr->ia_valid & ATTR_MTIME) {
- *p++ = xdr_one;
- } else {
- *p++ = xdr_zero;
- }
- return p;
- }
- static inline u32 *
- xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
- {
- p = xdr_decode_hyper(p, &fattr->pre_size);
- p = xdr_decode_time3(p, &fattr->pre_mtime);
- p = xdr_decode_time3(p, &fattr->pre_ctime);
- fattr->valid |= NFS_ATTR_WCC;
- return p;
- }
- static inline u32 *
- xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
- {
- if (*p++)
- p = xdr_decode_fattr(p, fattr);
- return p;
- }
- static inline u32 *
- xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
- {
- if (*p++)
- return xdr_decode_wcc_attr(p, fattr);
- return p;
- }
- static inline u32 *
- xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
- {
- p = xdr_decode_pre_op_attr(p, fattr);
- return xdr_decode_post_op_attr(p, fattr);
- }
- /*
- * NFS encode functions
- */
- /*
- * Encode void argument
- */
- static int
- nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
- {
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * Encode file handle argument
- */
- static int
- nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
- {
- p = xdr_encode_fhandle(p, fh);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * Encode SETATTR arguments
- */
- static int
- nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_sattr(p, args->sattr);
- *p++ = htonl(args->guard);
- if (args->guard)
- p = xdr_encode_time3(p, args->guardtime);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * Encode directory ops argument
- */
- static int
- nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_array(p, args->name, args->len);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * Encode access() argument
- */
- static int
- nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- *p++ = htonl(args->access);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * Arguments to a READ call. Since we read data directly into the page
- * cache, we also set up the reply iovec here so that iov[1] points
- * exactly to the page we want to fetch.
- */
- static int
- nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
- {
- struct rpc_auth *auth = req->rq_task->tk_auth;
- int buflen, replen;
- unsigned int nr;
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_hyper(p, args->offset);
- *p++ = htonl(args->count);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* Get the number of buffers in the receive iovec */
- nr = args->nriov;
- if (nr+2 > MAX_IOVEC) {
- printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargsn");
- return -EINVAL;
- }
- /* set up reply iovec */
- replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
- buflen = req->rq_rvec[0].iov_len;
- req->rq_rvec[0].iov_len = replen;
- /* Copy the iovec */
- memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
- req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
- req->rq_rvec[nr+1].iov_len = buflen - replen;
- req->rq_rlen = args->count + buflen;
- req->rq_rnr += nr+1;
- return 0;
- }
- /*
- * Write arguments. Splice the buffer to be written into the iovec.
- */
- static int
- nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
- {
- unsigned int nr;
- u32 count = args->count;
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_hyper(p, args->offset);
- *p++ = htonl(count);
- *p++ = htonl(args->stable);
- *p++ = htonl(count);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- /* Get the number of buffers in the send iovec */
- nr = args->nriov;
- if (nr+2 > MAX_IOVEC) {
- printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargsn");
- return -EINVAL;
- }
- /* Copy the iovec */
- memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
- #ifdef NFS_PAD_WRITES
- /*
- * Some old servers require that the message length
- * be a multiple of 4, so we pad it here if needed.
- */
- if (count & 3) {
- struct iovec *iov = req->rq_svec + nr + 1;
- int pad = 4 - (count & 3);
- iov->iov_base = (void *) "