nfs3xdr.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,104 行 · 第 1/2 页
C
1,104 行
/* * linux/fs/nfsd/nfs3xdr.c * * XDR support for nfsd/protocol version 3. * * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> * * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()! */#include <linux/types.h>#include <linux/time.h>#include <linux/nfs3.h>#include <linux/list.h>#include <linux/spinlock.h>#include <linux/dcache.h>#include <linux/namei.h>#include <linux/mm.h>#include <linux/vfs.h>#include <linux/sunrpc/xdr.h>#include <linux/sunrpc/svc.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/xdr3.h>#define NFSDDBG_FACILITY NFSDDBG_XDR#ifdef NFSD_OPTIMIZE_SPACE# define inline#endif/* * Mapping of S_IF* types to NFS file types */static u32 nfs3_ftypes[] = { NF3NON, NF3FIFO, NF3CHR, NF3BAD, NF3DIR, NF3BAD, NF3BLK, NF3BAD, NF3REG, NF3BAD, NF3LNK, NF3BAD, NF3SOCK, NF3BAD, NF3LNK, NF3BAD,};/* * XDR functions for basic NFS types */static inline u32 *encode_time3(u32 *p, struct timespec *time){ *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); return p;}static inline u32 *decode_time3(u32 *p, struct timespec *time){ time->tv_sec = ntohl(*p++); time->tv_nsec = ntohl(*p++); return p;}static inline u32 *decode_fh(u32 *p, struct svc_fh *fhp){ unsigned int size; fh_init(fhp, NFS3_FHSIZE); size = ntohl(*p++); if (size > NFS3_FHSIZE) return NULL; memcpy(&fhp->fh_handle.fh_base, p, size); fhp->fh_handle.fh_size = size; return p + XDR_QUADLEN(size);}static inline u32 *encode_fh(u32 *p, struct svc_fh *fhp){ unsigned int size = fhp->fh_handle.fh_size; *p++ = htonl(size); if (size) p[XDR_QUADLEN(size)-1]=0; memcpy(p, &fhp->fh_handle.fh_base, size); return p + XDR_QUADLEN(size);}/* * Decode a file name and make sure that the path contains * no slashes or null bytes. */static inline u32 *decode_filename(u32 *p, char **namp, int *lenp){ char *name; int i; if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) { for (i = 0, name = *namp; i < *lenp; i++, name++) { if (*name == '\0' || *name == '/') return NULL; } } return p;}static inline u32 *decode_pathname(u32 *p, char **namp, int *lenp){ char *name; int i; if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXPATHLEN)) != NULL) { for (i = 0, name = *namp; i < *lenp; i++, name++) { if (*name == '\0') return NULL; } } return p;}static inline u32 *decode_sattr3(u32 *p, struct iattr *iap){ u32 tmp; iap->ia_valid = 0; if (*p++) { iap->ia_valid |= ATTR_MODE; iap->ia_mode = ntohl(*p++); } if (*p++) { iap->ia_valid |= ATTR_UID; iap->ia_uid = ntohl(*p++); } if (*p++) { iap->ia_valid |= ATTR_GID; iap->ia_gid = ntohl(*p++); } if (*p++) { u64 newsize; iap->ia_valid |= ATTR_SIZE; p = xdr_decode_hyper(p, &newsize); if (newsize <= NFS_OFFSET_MAX) iap->ia_size = newsize; else iap->ia_size = NFS_OFFSET_MAX; } if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ iap->ia_valid |= ATTR_ATIME; } else if (tmp == 2) { /* set to client time */ iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; iap->ia_atime.tv_sec = ntohl(*p++); iap->ia_atime.tv_nsec = ntohl(*p++); } if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ iap->ia_valid |= ATTR_MTIME; } else if (tmp == 2) { /* set to client time */ iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; iap->ia_mtime.tv_sec = ntohl(*p++); iap->ia_mtime.tv_nsec = ntohl(*p++); } return p;}static inline u32 *encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp){ struct vfsmount *mnt = fhp->fh_export->ex_mnt; struct dentry *dentry = fhp->fh_dentry; struct kstat stat; struct timespec time; vfs_getattr(mnt, dentry, &stat); *p++ = htonl(nfs3_ftypes[(stat.mode & S_IFMT) >> 12]); *p++ = htonl((u32) stat.mode); *p++ = htonl((u32) stat.nlink); *p++ = htonl((u32) nfsd_ruid(rqstp, stat.uid)); *p++ = htonl((u32) nfsd_rgid(rqstp, stat.gid)); if (S_ISLNK(stat.mode) && stat.size > NFS3_MAXPATHLEN) { p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { p = xdr_encode_hyper(p, (u64) stat.size); } p = xdr_encode_hyper(p, ((u64)stat.blocks) << 9); *p++ = htonl((u32) MAJOR(stat.rdev)); *p++ = htonl((u32) MINOR(stat.rdev)); if (is_fsid(fhp, rqstp->rq_reffh)) p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); else p = xdr_encode_hyper(p, (u64) huge_encode_dev(stat.dev)); p = xdr_encode_hyper(p, (u64) stat.ino); p = encode_time3(p, &stat.atime); lease_get_mtime(dentry->d_inode, &time); p = encode_time3(p, &time); p = encode_time3(p, &stat.ctime); return p;}static inline u32 *encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp){ struct inode *inode = fhp->fh_dentry->d_inode; /* Attributes to follow */ *p++ = xdr_one; *p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]); *p++ = htonl((u32) fhp->fh_post_mode); *p++ = htonl((u32) fhp->fh_post_nlink); *p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid)); *p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid)); if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) { p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { p = xdr_encode_hyper(p, (u64) fhp->fh_post_size); } p = xdr_encode_hyper(p, ((u64)fhp->fh_post_blocks) << 9); *p++ = fhp->fh_post_rdev[0]; *p++ = fhp->fh_post_rdev[1]; if (is_fsid(fhp, rqstp->rq_reffh)) p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); else p = xdr_encode_hyper(p, (u64)huge_encode_dev(inode->i_sb->s_dev)); p = xdr_encode_hyper(p, (u64) inode->i_ino); p = encode_time3(p, &fhp->fh_post_atime); p = encode_time3(p, &fhp->fh_post_mtime); p = encode_time3(p, &fhp->fh_post_ctime); return p;}/* * Encode post-operation attributes. * The inode may be NULL if the call failed because of a stale file * handle. In this case, no attributes are returned. */static u32 *encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp){ struct dentry *dentry = fhp->fh_dentry; if (dentry && dentry->d_inode != NULL) { *p++ = xdr_one; /* attributes follow */ return encode_fattr3(rqstp, p, fhp); } *p++ = xdr_zero; return p;}/* * Enocde weak cache consistency data */static u32 *encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp){ struct dentry *dentry = fhp->fh_dentry; if (dentry && dentry->d_inode && fhp->fh_post_saved) { if (fhp->fh_pre_saved) { *p++ = xdr_one; p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); p = encode_time3(p, &fhp->fh_pre_mtime); p = encode_time3(p, &fhp->fh_pre_ctime); } else { *p++ = xdr_zero; } return encode_saved_post_attr(rqstp, p, fhp); } /* no pre- or post-attrs */ *p++ = xdr_zero; return encode_post_op_attr(rqstp, p, fhp);}/* * XDR decode functions */intnfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args){ if (!(p = decode_fh(p, &args->fh))) return 0; return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_sattrargs *args){ if (!(p = decode_fh(p, &args->fh)) || !(p = decode_sattr3(p, &args->attrs))) return 0; if ((args->check_guard = ntohl(*p++)) != 0) { struct timespec time; p = decode_time3(p, &time); args->guardtime = time.tv_sec; } return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_diropargs *args){ if (!(p = decode_fh(p, &args->fh)) || !(p = decode_filename(p, &args->name, &args->len))) return 0; return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_accessargs *args){ if (!(p = decode_fh(p, &args->fh))) return 0; args->access = ntohl(*p++); return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readargs *args){ unsigned int len; int v,pn; if (!(p = decode_fh(p, &args->fh)) || !(p = xdr_decode_hyper(p, &args->offset))) return 0; len = args->count = ntohl(*p++); if (len > NFSSVC_MAXBLKSIZE) len = NFSSVC_MAXBLKSIZE; /* set up the kvec */ v=0; while (len > 0) { pn = rqstp->rq_resused; svc_take_page(rqstp); args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]); args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE; len -= args->vec[v].iov_len; v++; } args->vlen = v; return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_writeargs *args){ unsigned int len, v, hdr; if (!(p = decode_fh(p, &args->fh)) || !(p = xdr_decode_hyper(p, &args->offset))) return 0; args->count = ntohl(*p++); args->stable = ntohl(*p++); len = args->len = ntohl(*p++); hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; if (rqstp->rq_arg.len < len + hdr) return 0; args->vec[0].iov_base = (void*)p; args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; if (len > NFSSVC_MAXBLKSIZE) len = NFSSVC_MAXBLKSIZE; v= 0; while (len > args->vec[v].iov_len) { len -= args->vec[v].iov_len; v++; args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]); args->vec[v].iov_len = PAGE_SIZE; } args->vec[v].iov_len = len; args->vlen = v+1; return args->count == args->len && args->vec[0].iov_len > 0;}intnfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_createargs *args){ if (!(p = decode_fh(p, &args->fh)) || !(p = decode_filename(p, &args->name, &args->len))) return 0; switch (args->createmode = ntohl(*p++)) { case NFS3_CREATE_UNCHECKED: case NFS3_CREATE_GUARDED: if (!(p = decode_sattr3(p, &args->attrs))) return 0; break; case NFS3_CREATE_EXCLUSIVE: args->verf = p; p += 2; break; default: return 0; } return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_createargs *args){ if (!(p = decode_fh(p, &args->fh)) || !(p = decode_filename(p, &args->name, &args->len)) || !(p = decode_sattr3(p, &args->attrs))) return 0; return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_symlinkargs *args){ unsigned int len; int avail; char *old, *new; struct kvec *vec; if (!(p = decode_fh(p, &args->ffh)) || !(p = decode_filename(p, &args->fname, &args->flen)) || !(p = decode_sattr3(p, &args->attrs)) ) return 0; /* now decode the pathname, which might be larger than the first page. * As we have to check for nul's anyway, we copy it into a new page * This page appears in the rq_res.pages list, but as pages_len is always * 0, it won't get in the way */ svc_take_page(rqstp); len = ntohl(*p++); if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE) return 0; args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); args->tlen = len; /* first copy and check from the first page */ old = (char*)p; vec = &rqstp->rq_arg.head[0]; avail = vec->iov_len - (old - (char*)vec->iov_base); while (len && avail && *old) { *new++ = *old++; len--; avail--; } /* now copy next page if there is one */ if (len && !avail && rqstp->rq_arg.page_len) { avail = rqstp->rq_arg.page_len; if (avail > PAGE_SIZE) avail = PAGE_SIZE; old = page_address(rqstp->rq_arg.pages[0]); } while (len && avail && *old) { *new++ = *old++; len--; avail--; } *new = '\0'; if (len) return 0; return 1;}intnfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_mknodargs *args){ if (!(p = decode_fh(p, &args->fh)) || !(p = decode_filename(p, &args->name, &args->len))) return 0; args->ftype = ntohl(*p++); if (args->ftype == NF3BLK || args->ftype == NF3CHR || args->ftype == NF3SOCK || args->ftype == NF3FIFO) { if (!(p = decode_sattr3(p, &args->attrs))) return 0; } if (args->ftype == NF3BLK || args->ftype == NF3CHR) { args->major = ntohl(*p++); args->minor = ntohl(*p++); } return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_renameargs *args){ if (!(p = decode_fh(p, &args->ffh)) || !(p = decode_filename(p, &args->fname, &args->flen)) || !(p = decode_fh(p, &args->tfh)) || !(p = decode_filename(p, &args->tname, &args->tlen))) return 0; return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readlinkargs *args){ if (!(p = decode_fh(p, &args->fh))) return 0; svc_take_page(rqstp); args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]); return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_linkargs *args){ if (!(p = decode_fh(p, &args->ffh)) || !(p = decode_fh(p, &args->tfh)) || !(p = decode_filename(p, &args->tname, &args->tlen))) return 0; return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p, struct nfsd3_readdirargs *args){ if (!(p = decode_fh(p, &args->fh))) return 0; p = xdr_decode_hyper(p, &args->cookie); args->verf = p; p += 2; args->dircount = ~0; args->count = ntohl(*p++);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?