⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfs3xdr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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/* * 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 __be32 *encode_time3(__be32 *p, struct timespec *time){	*p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);	return p;}static __be32 *decode_time3(__be32 *p, struct timespec *time){	time->tv_sec = ntohl(*p++);	time->tv_nsec = ntohl(*p++);	return p;}static __be32 *decode_fh(__be32 *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);}/* Helper function for NFSv3 ACL code */__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp){	return decode_fh(p, fhp);}static __be32 *encode_fh(__be32 *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 __be32 *decode_filename(__be32 *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 __be32 *decode_sattr3(__be32 *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 __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp){	u64 f;	switch(fsid_source(fhp)) {	default:	case FSIDSOURCE_DEV:		p = xdr_encode_hyper(p, (u64)huge_encode_dev				     (fhp->fh_dentry->d_inode->i_sb->s_dev));		break;	case FSIDSOURCE_FSID:		p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);		break;	case FSIDSOURCE_UUID:		f = ((u64*)fhp->fh_export->ex_uuid)[0];		f ^= ((u64*)fhp->fh_export->ex_uuid)[1];		p = xdr_encode_hyper(p, f);		break;	}	return p;}static __be32 *encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,	      struct kstat *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));	p = encode_fsid(p, fhp);	p = xdr_encode_hyper(p, stat->ino);	p = encode_time3(p, &stat->atime);	p = encode_time3(p, &stat->mtime);	p = encode_time3(p, &stat->ctime);	return p;}static __be32 *encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp){	/* Attributes to follow */	*p++ = xdr_one;	return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);}/* * 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 __be32 *encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp){	struct dentry *dentry = fhp->fh_dentry;	if (dentry && dentry->d_inode) {	        int err;		struct kstat stat;		err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat);		if (!err) {			*p++ = xdr_one;		/* attributes follow */			lease_get_mtime(dentry->d_inode, &stat.mtime);			return encode_fattr3(rqstp, p, fhp, &stat);		}	}	*p++ = xdr_zero;	return p;}/* Helper for NFSv3 ACLs */__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp){	return encode_post_op_attr(rqstp, p, fhp);}/* * Enocde weak cache consistency data */static __be32 *encode_wcc_data(struct svc_rqst *rqstp, __be32 *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);}/* * Fill in the post_op attr for the wcc data */void fill_post_wcc(struct svc_fh *fhp){	int err;	if (fhp->fh_post_saved)		printk("nfsd: inode locked twice during operation.\n");	err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry,			&fhp->fh_post_attr);	if (err)		fhp->fh_post_saved = 0;	else		fhp->fh_post_saved = 1;}/* * XDR decode functions */intnfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *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, __be32 *p,					struct nfsd3_sattrargs *args){	if (!(p = decode_fh(p, &args->fh)))		return 0;	p = decode_sattr3(p, &args->attrs);	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, __be32 *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, __be32 *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, __be32 *p,					struct nfsd3_readargs *args){	unsigned int len;	int v,pn;	u32 max_blocksize = svc_max_payload(rqstp);	if (!(p = decode_fh(p, &args->fh)))		return 0;	p = xdr_decode_hyper(p, &args->offset);	len = args->count = ntohl(*p++);	if (len > max_blocksize)		len = max_blocksize;	/* set up the kvec */	v=0;	while (len > 0) {		pn = rqstp->rq_resused++;		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);		rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;		len -= rqstp->rq_vec[v].iov_len;		v++;	}	args->vlen = v;	return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,					struct nfsd3_writeargs *args){	unsigned int len, v, hdr, dlen;	u32 max_blocksize = svc_max_payload(rqstp);	if (!(p = decode_fh(p, &args->fh)))		return 0;	p = xdr_decode_hyper(p, &args->offset);	args->count = ntohl(*p++);	args->stable = ntohl(*p++);	len = args->len = ntohl(*p++);	/*	 * The count must equal the amount of data passed.	 */	if (args->count != args->len)		return 0;	/*	 * Check to make sure that we got the right number of	 * bytes.	 */	hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;	dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len		- hdr;	/*	 * Round the length of the data which was specified up to	 * the next multiple of XDR units and then compare that	 * against the length which was actually received.	 * Note that when RPCSEC/GSS (for example) is used, the	 * data buffer can be padded so dlen might be larger	 * than required.  It must never be smaller.	 */	if (dlen < XDR_QUADLEN(len)*4)		return 0;	if (args->count > max_blocksize) {		args->count = max_blocksize;		len = args->len = max_blocksize;	}	rqstp->rq_vec[0].iov_base = (void*)p;	rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;	v = 0;	while (len > rqstp->rq_vec[v].iov_len) {		len -= rqstp->rq_vec[v].iov_len;		v++;		rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);		rqstp->rq_vec[v].iov_len = PAGE_SIZE;	}	rqstp->rq_vec[v].iov_len = len;	args->vlen = v + 1;	return 1;}intnfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *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:		p = decode_sattr3(p, &args->attrs);		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, __be32 *p,					struct nfsd3_createargs *args){	if (!(p = decode_fh(p, &args->fh)) ||	    !(p = decode_filename(p, &args->name, &args->len)))		return 0;	p = decode_sattr3(p, &args->attrs);	return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *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))		)		return 0;	p = decode_sattr3(p, &args->attrs);	/* 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	 */	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++]);	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, __be32 *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)		p = decode_sattr3(p, &args->attrs);	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, __be32 *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, __be32 *p,					struct nfsd3_readlinkargs *args){	if (!(p = decode_fh(p, &args->fh)))		return 0;	args->buffer =		page_address(rqstp->rq_respages[rqstp->rq_resused++]);	return xdr_argsize_check(rqstp, p);}intnfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *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, __be32 *p,					struct nfsd3_readdirargs *args){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -