nfs2xdr.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:19k
- /*
- * linux/fs/nfs/nfs2xdr.c
- *
- * XDR functions to encode/decode NFS RPC arguments and results.
- *
- * Copyright (C) 1992, 1993, 1994 Rick Sladkey
- * Copyright (C) 1996 Olaf Kirch
- * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
- * FIFO's need special handling in NFSv2
- */
- #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/sunrpc/clnt.h>
- #include <linux/nfs.h>
- #include <linux/nfs2.h>
- #include <linux/nfs_fs.h>
- /* Uncomment this to support servers requiring longword lengths */
- #define NFS_PAD_WRITES 1
- #define NFSDBG_FACILITY NFSDBG_XDR
- /* #define NFS_PARANOIA 1 */
- extern int nfs_stat_to_errno(int stat);
- /* Mapping from NFS error code to "errno" error code. */
- #define errno_NFSERR_IO EIO
- /*
- * Declare the space requirements for NFS arguments and replies as
- * number of 32bit-words
- */
- #define NFS_fhandle_sz 8
- #define NFS_sattr_sz 8
- #define NFS_filename_sz 1+(NFS2_MAXNAMLEN>>2)
- #define NFS_path_sz 1+(NFS2_MAXPATHLEN>>2)
- #define NFS_fattr_sz 17
- #define NFS_info_sz 5
- #define NFS_entry_sz NFS_filename_sz+3
- #define NFS_enc_void_sz 0
- #define NFS_diropargs_sz NFS_fhandle_sz+NFS_filename_sz
- #define NFS_sattrargs_sz NFS_fhandle_sz+NFS_sattr_sz
- #define NFS_readlinkargs_sz NFS_fhandle_sz
- #define NFS_readargs_sz NFS_fhandle_sz+3
- #define NFS_writeargs_sz NFS_fhandle_sz+4
- #define NFS_createargs_sz NFS_diropargs_sz+NFS_sattr_sz
- #define NFS_renameargs_sz NFS_diropargs_sz+NFS_diropargs_sz
- #define NFS_linkargs_sz NFS_fhandle_sz+NFS_diropargs_sz
- #define NFS_symlinkargs_sz NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
- #define NFS_readdirargs_sz NFS_fhandle_sz+2
- #define NFS_dec_void_sz 0
- #define NFS_attrstat_sz 1+NFS_fattr_sz
- #define NFS_diropres_sz 1+NFS_fhandle_sz+NFS_fattr_sz
- #define NFS_readlinkres_sz 1
- #define NFS_readres_sz 1+NFS_fattr_sz+1
- #define NFS_writeres_sz NFS_attrstat_sz
- #define NFS_stat_sz 1
- #define NFS_readdirres_sz 1
- #define NFS_statfsres_sz 1+NFS_info_sz
- /*
- * Common NFS XDR functions as inlines
- */
- static inline u32 *
- xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
- {
- memcpy(p, fhandle->data, NFS2_FHSIZE);
- return p + XDR_QUADLEN(NFS2_FHSIZE);
- }
- static inline u32 *
- xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
- {
- /* Zero handle first to allow comparisons */
- memset(fhandle, 0, sizeof(*fhandle));
- /* NFSv2 handles have a fixed length */
- fhandle->size = NFS2_FHSIZE;
- memcpy(fhandle->data, p, NFS2_FHSIZE);
- return p + XDR_QUADLEN(NFS2_FHSIZE);
- }
- 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_time(u32 *p, u64 *timep)
- {
- u64 tmp = (u64)ntohl(*p++) << 32;
- *timep = tmp + (u64)ntohl(*p++);
- return p;
- }
- static inline u32 *
- xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
- {
- fattr->type = (enum nfs_ftype) ntohl(*p++);
- fattr->mode = ntohl(*p++);
- fattr->nlink = ntohl(*p++);
- fattr->uid = ntohl(*p++);
- fattr->gid = ntohl(*p++);
- fattr->size = ntohl(*p++);
- fattr->du.nfs2.blocksize = ntohl(*p++);
- fattr->rdev = ntohl(*p++);
- fattr->du.nfs2.blocks = ntohl(*p++);
- fattr->fsid = ntohl(*p++);
- fattr->fileid = ntohl(*p++);
- p = xdr_decode_time(p, &fattr->atime);
- p = xdr_decode_time(p, &fattr->mtime);
- p = xdr_decode_time(p, &fattr->ctime);
- fattr->valid |= NFS_ATTR_FATTR;
- if (fattr->type == NFCHR && fattr->rdev == NFS2_FIFO_DEV) {
- fattr->type = NFFIFO;
- fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
- fattr->rdev = 0;
- }
- return p;
- }
- #define SATTR(p, attr, flag, field)
- *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
- static inline u32 *
- xdr_encode_sattr(u32 *p, struct iattr *attr)
- {
- SATTR(p, attr, ATTR_MODE, ia_mode);
- SATTR(p, attr, ATTR_UID, ia_uid);
- SATTR(p, attr, ATTR_GID, ia_gid);
- SATTR(p, attr, ATTR_SIZE, ia_size);
- if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
- *p++ = htonl(attr->ia_atime);
- *p++ = 0;
- } else {
- *p++ = ~(u32) 0;
- *p++ = ~(u32) 0;
- }
- if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
- *p++ = htonl(attr->ia_mtime);
- *p++ = 0;
- } else {
- *p++ = ~(u32) 0;
- *p++ = ~(u32) 0;
- }
- return p;
- }
- #undef SATTR
- /*
- * NFS encode functions
- */
- /*
- * Encode void argument
- */
- static int
- nfs_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
- * GETATTR, READLINK, STATFS
- */
- static int
- nfs_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
- nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
- {
- p = xdr_encode_fhandle(p, args->fh);
- p = xdr_encode_sattr(p, args->sattr);
- req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
- return 0;
- }
- /*
- * Encode directory ops argument
- * LOOKUP, REMOVE, RMDIR
- */
- static int
- nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_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;
- }
- /*
- * 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
- nfs_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++ = htonl(args->offset);
- *p++ = htonl(args->count);
- *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 + NFS_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;
- }
- /*
- * Decode READ reply
- */
- static int
- nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
- {
- struct iovec *iov = req->rq_rvec;
- int status, count, recvd, hdrlen;
- if ((status = ntohl(*p++)))
- return -nfs_stat_to_errno(status);
- p = xdr_decode_fattr(p, res->fattr);
- count = ntohl(*p++);
- hdrlen = (u8 *) p - (u8 *) iov->iov_base;
- if (iov->iov_len > hdrlen) {
- dprintk("NFS: READ header is short. iovec will be shifted.n");
- xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
- }
- recvd = req->rq_rlen - hdrlen;
- if (count > recvd) {
- printk(KERN_WARNING "NFS: server cheating in read reply: "
- "count %d > recvd %dn", count, recvd);
- count = recvd;
- }
- dprintk("RPC: readres OK count %dn", count);
- if (count < res->count) {
- xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
- res->count = count;
- res->eof = 1; /* Silly NFSv3ism which can't be helped */
- } else
- res->eof = 0;
- return count;
- }
- /*
- * Write arguments. Splice the buffer to be written into the iovec.
- */
- static int
- nfs_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++ = htonl(args->offset);
- *p++ = htonl(args->offset);
- *p++ = htonl(count);
- *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_writeargs "
- "(nr %d max %d)n", nr, MAX_IOVEC);
- 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 *) "