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

📄 nfs4xdr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  fs/nfs/nfs4xdr.c * *  Server-side XDR for NFSv4 * *  Copyright (c) 2002 The Regents of the University of Michigan. *  All rights reserved. * *  Kendrick Smith <kmsmith@umich.edu> *  Andy Adamson   <andros@umich.edu> * *  Redistribution and use in source and binary forms, with or without *  modification, are permitted provided that the following conditions *  are met: * *  1. Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. *  2. Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution. *  3. Neither the name of the University nor the names of its *     contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * TODO: Neil Brown made the following observation:  We currently * initially reserve NFSD_BUFSIZE space on the transmit queue and * never release any of that until the request is complete. * It would be good to calculate a new maximum response size while * decoding the COMPOUND, and call svc_reserve with this number * at the end of nfs4svc_decode_compoundargs. */#include <linux/param.h>#include <linux/smp.h>#include <linux/fs.h>#include <linux/namei.h>#include <linux/vfs.h>#include <linux/sunrpc/xdr.h>#include <linux/sunrpc/svc.h>#include <linux/sunrpc/clnt.h>#include <linux/nfsd/nfsd.h>#include <linux/nfsd/state.h>#include <linux/nfsd/xdr4.h>#include <linux/nfsd_idmap.h>#include <linux/nfs4.h>#include <linux/nfs4_acl.h>#include <linux/sunrpc/gss_api.h>#include <linux/sunrpc/svcauth_gss.h>#define NFSDDBG_FACILITY		NFSDDBG_XDR/* * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing * directory in order to indicate to the client that a filesystem boundary is present * We use a fixed fsid for a referral */#define NFS4_REFERRAL_FSID_MAJOR	0x8000000ULL#define NFS4_REFERRAL_FSID_MINOR	0x8000000ULLstatic __be32check_filename(char *str, int len, __be32 err){	int i;	if (len == 0)		return nfserr_inval;	if (isdotent(str, len))		return err;	for (i = 0; i < len; i++)		if (str[i] == '/')			return err;	return 0;}/* * START OF "GENERIC" DECODE ROUTINES. *   These may look a little ugly since they are imported from a "generic" * set of XDR encode/decode routines which are intended to be shared by * all of our NFSv4 implementations (OpenBSD, MacOS X...). * * If the pain of reading these is too great, it should be a straightforward * task to translate them into Linux-specific versions which are more * consistent with the style used in NFSv2/v3... */#define DECODE_HEAD				\	__be32 *p;				\	__be32 status#define DECODE_TAIL				\	status = 0;				\out:						\	return status;				\xdr_error:					\	dprintk("NFSD: xdr error (%s:%d)\n",	\			__FILE__, __LINE__);	\	status = nfserr_bad_xdr;		\	goto out#define READ32(x)         (x) = ntohl(*p++)#define READ64(x)         do {			\	(x) = (u64)ntohl(*p++) << 32;		\	(x) |= ntohl(*p++);			\} while (0)#define READTIME(x)       do {			\	p++;					\	(x) = ntohl(*p++);			\	p++;					\} while (0)#define READMEM(x,nbytes) do {			\	x = (char *)p;				\	p += XDR_QUADLEN(nbytes);		\} while (0)#define SAVEMEM(x,nbytes) do {			\	if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ 		savemem(argp, p, nbytes) :	\ 		(char *)p)) {			\		dprintk("NFSD: xdr error (%s:%d)\n", \				__FILE__, __LINE__); \		goto xdr_error;			\		}				\	p += XDR_QUADLEN(nbytes);		\} while (0)#define COPYMEM(x,nbytes) do {			\	memcpy((x), p, nbytes);			\	p += XDR_QUADLEN(nbytes);		\} while (0)/* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */#define READ_BUF(nbytes)  do {			\	if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) {	\		p = argp->p;			\		argp->p += XDR_QUADLEN(nbytes);	\	} else if (!(p = read_buf(argp, nbytes))) { \		dprintk("NFSD: xdr error (%s:%d)\n", \				__FILE__, __LINE__); \		goto xdr_error;			\	}					\} while (0)static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes){	/* We want more bytes than seem to be available.	 * Maybe we need a new page, maybe we have just run out	 */	int avail = (char*)argp->end - (char*)argp->p;	__be32 *p;	if (avail + argp->pagelen < nbytes)		return NULL;	if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */		return NULL;	/* ok, we can do it with the current plus the next page */	if (nbytes <= sizeof(argp->tmp))		p = argp->tmp;	else {		kfree(argp->tmpp);		p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL);		if (!p)			return NULL;			}	memcpy(p, argp->p, avail);	/* step to next page */	argp->p = page_address(argp->pagelist[0]);	argp->pagelist++;	if (argp->pagelen < PAGE_SIZE) {		argp->end = p + (argp->pagelen>>2);		argp->pagelen = 0;	} else {		argp->end = p + (PAGE_SIZE>>2);		argp->pagelen -= PAGE_SIZE;	}	memcpy(((char*)p)+avail, argp->p, (nbytes - avail));	argp->p += XDR_QUADLEN(nbytes - avail);	return p;}static intdefer_free(struct nfsd4_compoundargs *argp,		void (*release)(const void *), void *p){	struct tmpbuf *tb;	tb = kmalloc(sizeof(*tb), GFP_KERNEL);	if (!tb)		return -ENOMEM;	tb->buf = p;	tb->release = release;	tb->next = argp->to_free;	argp->to_free = tb;	return 0;}static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes){	if (p == argp->tmp) {		p = kmalloc(nbytes, GFP_KERNEL);		if (!p)			return NULL;		memcpy(p, argp->tmp, nbytes);	} else {		BUG_ON(p != argp->tmpp);		argp->tmpp = NULL;	}	if (defer_free(argp, kfree, p)) {		kfree(p);		return NULL;	} else		return (char *)p;}static __be32nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval){	u32 bmlen;	DECODE_HEAD;	bmval[0] = 0;	bmval[1] = 0;	READ_BUF(4);	READ32(bmlen);	if (bmlen > 1000)		goto xdr_error;	READ_BUF(bmlen << 2);	if (bmlen > 0)		READ32(bmval[0]);	if (bmlen > 1)		READ32(bmval[1]);	DECODE_TAIL;}static __be32nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,    struct nfs4_acl **acl){	int expected_len, len = 0;	u32 dummy32;	char *buf;	int host_err;	DECODE_HEAD;	iattr->ia_valid = 0;	if ((status = nfsd4_decode_bitmap(argp, bmval)))		return status;	/*	 * According to spec, unsupported attributes return ERR_ATTRNOTSUPP;	 * read-only attributes return ERR_INVAL.	 */	if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))		return nfserr_attrnotsupp;	if ((bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0) || (bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1))		return nfserr_inval;	READ_BUF(4);	READ32(expected_len);	if (bmval[0] & FATTR4_WORD0_SIZE) {		READ_BUF(8);		len += 8;		READ64(iattr->ia_size);		iattr->ia_valid |= ATTR_SIZE;	}	if (bmval[0] & FATTR4_WORD0_ACL) {		int nace;		struct nfs4_ace *ace;		READ_BUF(4); len += 4;		READ32(nace);		if (nace > NFS4_ACL_MAX)			return nfserr_resource;		*acl = nfs4_acl_new(nace);		if (*acl == NULL) {			host_err = -ENOMEM;			goto out_nfserr;		}		defer_free(argp, kfree, *acl);		(*acl)->naces = nace;		for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) {			READ_BUF(16); len += 16;			READ32(ace->type);			READ32(ace->flag);			READ32(ace->access_mask);			READ32(dummy32);			READ_BUF(dummy32);			len += XDR_QUADLEN(dummy32) << 2;			READMEM(buf, dummy32);			ace->whotype = nfs4_acl_get_whotype(buf, dummy32);			host_err = 0;			if (ace->whotype != NFS4_ACL_WHO_NAMED)				ace->who = 0;			else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)				host_err = nfsd_map_name_to_gid(argp->rqstp,						buf, dummy32, &ace->who);			else				host_err = nfsd_map_name_to_uid(argp->rqstp,						buf, dummy32, &ace->who);			if (host_err)				goto out_nfserr;		}	} else		*acl = NULL;	if (bmval[1] & FATTR4_WORD1_MODE) {		READ_BUF(4);		len += 4;		READ32(iattr->ia_mode);		iattr->ia_mode &= (S_IFMT | S_IALLUGO);		iattr->ia_valid |= ATTR_MODE;	}	if (bmval[1] & FATTR4_WORD1_OWNER) {		READ_BUF(4);		len += 4;		READ32(dummy32);		READ_BUF(dummy32);		len += (XDR_QUADLEN(dummy32) << 2);		READMEM(buf, dummy32);		if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))			goto out_nfserr;		iattr->ia_valid |= ATTR_UID;	}	if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) {		READ_BUF(4);		len += 4;		READ32(dummy32);		READ_BUF(dummy32);		len += (XDR_QUADLEN(dummy32) << 2);		READMEM(buf, dummy32);		if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))			goto out_nfserr;		iattr->ia_valid |= ATTR_GID;	}	if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {		READ_BUF(4);		len += 4;		READ32(dummy32);		switch (dummy32) {		case NFS4_SET_TO_CLIENT_TIME:			/* We require the high 32 bits of 'seconds' to be 0, and we ignore			   all 32 bits of 'nseconds'. */			READ_BUF(12);			len += 12;			READ32(dummy32);			if (dummy32)				return nfserr_inval;			READ32(iattr->ia_atime.tv_sec);			READ32(iattr->ia_atime.tv_nsec);			if (iattr->ia_atime.tv_nsec >= (u32)1000000000)				return nfserr_inval;			iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET);			break;		case NFS4_SET_TO_SERVER_TIME:			iattr->ia_valid |= ATTR_ATIME;			break;		default:			goto xdr_error;		}	}	if (bmval[1] & FATTR4_WORD1_TIME_METADATA) {		/* We require the high 32 bits of 'seconds' to be 0, and we ignore		   all 32 bits of 'nseconds'. */		READ_BUF(12);		len += 12;		READ32(dummy32);		if (dummy32)			return nfserr_inval;		READ32(iattr->ia_ctime.tv_sec);		READ32(iattr->ia_ctime.tv_nsec);		if (iattr->ia_ctime.tv_nsec >= (u32)1000000000)			return nfserr_inval;		iattr->ia_valid |= ATTR_CTIME;	}	if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {		READ_BUF(4);		len += 4;		READ32(dummy32);		switch (dummy32) {		case NFS4_SET_TO_CLIENT_TIME:			/* We require the high 32 bits of 'seconds' to be 0, and we ignore			   all 32 bits of 'nseconds'. */			READ_BUF(12);			len += 12;			READ32(dummy32);			if (dummy32)				return nfserr_inval;			READ32(iattr->ia_mtime.tv_sec);			READ32(iattr->ia_mtime.tv_nsec);			if (iattr->ia_mtime.tv_nsec >= (u32)1000000000)				return nfserr_inval;			iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET);			break;		case NFS4_SET_TO_SERVER_TIME:			iattr->ia_valid |= ATTR_MTIME;			break;		default:			goto xdr_error;		}	}	if (len != expected_len)		goto xdr_error;	DECODE_TAIL;out_nfserr:	status = nfserrno(host_err);	goto out;}static __be32nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access){	DECODE_HEAD;	READ_BUF(4);	READ32(access->ac_req_access);	DECODE_TAIL;}static __be32nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close){	DECODE_HEAD;	close->cl_stateowner = NULL;	READ_BUF(4 + sizeof(stateid_t));	READ32(close->cl_seqid);	READ32(close->cl_stateid.si_generation);	COPYMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));	DECODE_TAIL;}static __be32nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit){	DECODE_HEAD;	READ_BUF(12);	READ64(commit->co_offset);	READ32(commit->co_count);	DECODE_TAIL;}static __be32nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create){	DECODE_HEAD;	READ_BUF(4);	READ32(create->cr_type);	switch (create->cr_type) {	case NF4LNK:		READ_BUF(4);		READ32(create->cr_linklen);		READ_BUF(create->cr_linklen);		SAVEMEM(create->cr_linkname, create->cr_linklen);		break;	case NF4BLK:	case NF4CHR:		READ_BUF(8);		READ32(create->cr_specdata1);		READ32(create->cr_specdata2);		break;	case NF4SOCK:	case NF4FIFO:	case NF4DIR:	default:		break;	}	READ_BUF(4);	READ32(create->cr_namelen);	READ_BUF(create->cr_namelen);	SAVEMEM(create->cr_name, create->cr_namelen);	if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))		return status;	if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl)))		goto out;	DECODE_TAIL;}static inline __be32nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr){	DECODE_HEAD;	READ_BUF(sizeof(stateid_t));	READ32(dr->dr_stateid.si_generation);	COPYMEM(&dr->dr_stateid.si_opaque, sizeof(stateid_opaque_t));	DECODE_TAIL;}static inline __be32nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr){	return nfsd4_decode_bitmap(argp, getattr->ga_bmval);}static __be32nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)

⌨️ 快捷键说明

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