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

📄 nfs4xdr.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			if (argp->pagelen < 4) {				/* There isn't an opcode still on the wire */				op->opnum = OP_WRITE + 1;				op->status = nfserr_bad_xdr;				argp->opcnt = i+1;				break;			}			/*			 * False alarm. We just hit a page boundary, but there			 * is still data available.  Move pointer across page			 * boundary.  *snip from READ_BUF*			 */			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;			}		}		op->opnum = ntohl(*argp->p++);		switch (op->opnum) {		case 2: /* Reserved operation */			op->opnum = OP_ILLEGAL;			if (argp->minorversion == 0)				op->status = nfserr_op_illegal;			else				op->status = nfserr_minor_vers_mismatch;			break;		case OP_ACCESS:			op->status = nfsd4_decode_access(argp, &op->u.access);			break;		case OP_CLOSE:			op->status = nfsd4_decode_close(argp, &op->u.close);			break;		case OP_COMMIT:			op->status = nfsd4_decode_commit(argp, &op->u.commit);			break;		case OP_CREATE:			op->status = nfsd4_decode_create(argp, &op->u.create);			break;		case OP_DELEGRETURN:			op->status = nfsd4_decode_delegreturn(argp, &op->u.delegreturn);			break;		case OP_GETATTR:			op->status = nfsd4_decode_getattr(argp, &op->u.getattr);			break;		case OP_GETFH:			op->status = nfs_ok;			break;		case OP_LINK:			op->status = nfsd4_decode_link(argp, &op->u.link);			break;		case OP_LOCK:			op->status = nfsd4_decode_lock(argp, &op->u.lock);			break;		case OP_LOCKT:			op->status = nfsd4_decode_lockt(argp, &op->u.lockt);			break;		case OP_LOCKU:			op->status = nfsd4_decode_locku(argp, &op->u.locku);			break;		case OP_LOOKUP:			op->status = nfsd4_decode_lookup(argp, &op->u.lookup);			break;		case OP_LOOKUPP:			op->status = nfs_ok;			break;		case OP_NVERIFY:			op->status = nfsd4_decode_verify(argp, &op->u.nverify);			break;		case OP_OPEN:			op->status = nfsd4_decode_open(argp, &op->u.open);			break;		case OP_OPEN_CONFIRM:			op->status = nfsd4_decode_open_confirm(argp, &op->u.open_confirm);			break;		case OP_OPEN_DOWNGRADE:			op->status = nfsd4_decode_open_downgrade(argp, &op->u.open_downgrade);			break;		case OP_PUTFH:			op->status = nfsd4_decode_putfh(argp, &op->u.putfh);			break;		case OP_PUTROOTFH:			op->status = nfs_ok;			break;		case OP_READ:			op->status = nfsd4_decode_read(argp, &op->u.read);			break;		case OP_READDIR:			op->status = nfsd4_decode_readdir(argp, &op->u.readdir);			break;		case OP_READLINK:			op->status = nfs_ok;			break;		case OP_REMOVE:			op->status = nfsd4_decode_remove(argp, &op->u.remove);			break;		case OP_RENAME:			op->status = nfsd4_decode_rename(argp, &op->u.rename);			break;		case OP_RESTOREFH:			op->status = nfs_ok;			break;		case OP_RENEW:			op->status = nfsd4_decode_renew(argp, &op->u.renew);			break;		case OP_SAVEFH:			op->status = nfs_ok;			break;		case OP_SECINFO:			op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);			break;		case OP_SETATTR:			op->status = nfsd4_decode_setattr(argp, &op->u.setattr);			break;		case OP_SETCLIENTID:			op->status = nfsd4_decode_setclientid(argp, &op->u.setclientid);			break;		case OP_SETCLIENTID_CONFIRM:			op->status = nfsd4_decode_setclientid_confirm(argp, &op->u.setclientid_confirm);			break;		case OP_VERIFY:			op->status = nfsd4_decode_verify(argp, &op->u.verify);			break;		case OP_WRITE:			op->status = nfsd4_decode_write(argp, &op->u.write);			break;		case OP_RELEASE_LOCKOWNER:			op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner);			break;		default:			op->opnum = OP_ILLEGAL;			op->status = nfserr_op_illegal;			break;		}		if (op->status) {			argp->opcnt = i+1;			break;		}	}	DECODE_TAIL;}/* * END OF "GENERIC" DECODE ROUTINES. *//* * START OF "GENERIC" ENCODE 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 ENCODE_HEAD              __be32 *p#define WRITE32(n)               *p++ = htonl(n)#define WRITE64(n)               do {				\	*p++ = htonl((u32)((n) >> 32));				\	*p++ = htonl((u32)(n));					\} while (0)#define WRITEMEM(ptr,nbytes)     do {				\	*(p + XDR_QUADLEN(nbytes) -1) = 0;                      \	memcpy(p, ptr, nbytes);					\	p += XDR_QUADLEN(nbytes);				\} while (0)#define WRITECINFO(c)		do {				\	*p++ = htonl(c.atomic);					\	*p++ = htonl(c.before_ctime_sec);				\	*p++ = htonl(c.before_ctime_nsec);				\	*p++ = htonl(c.after_ctime_sec);				\	*p++ = htonl(c.after_ctime_nsec);				\} while (0)#define RESERVE_SPACE(nbytes)	do {				\	p = resp->p;						\	BUG_ON(p + XDR_QUADLEN(nbytes) > resp->end);		\} while (0)#define ADJUST_ARGS()		resp->p = p/* * Header routine to setup seqid operation replay cache */#define ENCODE_SEQID_OP_HEAD					\	__be32 *p;						\	__be32 *save;						\								\	save = resp->p;/* * Routine for encoding the result of a "seqid-mutating" NFSv4 operation.  This * is where sequence id's are incremented, and the replay cache is filled. * Note that we increment sequence id's here, at the last moment, so we're sure * we know whether the error to be returned is a sequence id mutating error. */#define ENCODE_SEQID_OP_TAIL(stateowner) do {			\	if (seqid_mutating_err(nfserr) && stateowner) { 	\		stateowner->so_seqid++;				\		stateowner->so_replay.rp_status = nfserr;   	\		stateowner->so_replay.rp_buflen = 		\			  (((char *)(resp)->p - (char *)save)); \		memcpy(stateowner->so_replay.rp_buf, save,      \ 			stateowner->so_replay.rp_buflen); 	\	} } while (0);/* Encode as an array of strings the string given with components * seperated @sep. */static __be32 nfsd4_encode_components(char sep, char *components,				   __be32 **pp, int *buflen){	__be32 *p = *pp;	__be32 *countp = p;	int strlen, count=0;	char *str, *end;	dprintk("nfsd4_encode_components(%s)\n", components);	if ((*buflen -= 4) < 0)		return nfserr_resource;	WRITE32(0); /* We will fill this in with @count later */	end = str = components;	while (*end) {		for (; *end && (*end != sep); end++)			; /* Point to end of component */		strlen = end - str;		if (strlen) {			if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)				return nfserr_resource;			WRITE32(strlen);			WRITEMEM(str, strlen);			count++;		}		else			end++;		str = end;	}	*pp = p;	p = countp;	WRITE32(count);	return 0;}/* * encode a location element of a fs_locations structure */static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,				    __be32 **pp, int *buflen){	__be32 status;	__be32 *p = *pp;	status = nfsd4_encode_components(':', location->hosts, &p, buflen);	if (status)		return status;	status = nfsd4_encode_components('/', location->path, &p, buflen);	if (status)		return status;	*pp = p;	return 0;}/* * Return the path to an export point in the pseudo filesystem namespace * Returned string is safe to use as long as the caller holds a reference * to @exp. */static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat){	struct svc_fh tmp_fh;	char *path, *rootpath;	fh_init(&tmp_fh, NFS4_FHSIZE);	*stat = exp_pseudoroot(rqstp, &tmp_fh);	if (*stat)		return NULL;	rootpath = tmp_fh.fh_export->ex_path;	path = exp->ex_path;	if (strncmp(path, rootpath, strlen(rootpath))) {		dprintk("nfsd: fs_locations failed;"			"%s is not contained in %s\n", path, rootpath);		*stat = nfserr_notsupp;		return NULL;	}	return path + strlen(rootpath);}/* *  encode a fs_locations structure */static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,				     struct svc_export *exp,				     __be32 **pp, int *buflen){	__be32 status;	int i;	__be32 *p = *pp;	struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;	char *root = nfsd4_path(rqstp, exp, &status);	if (status)		return status;	status = nfsd4_encode_components('/', root, &p, buflen);	if (status)		return status;	if ((*buflen -= 4) < 0)		return nfserr_resource;	WRITE32(fslocs->locations_count);	for (i=0; i<fslocs->locations_count; i++) {		status = nfsd4_encode_fs_location4(&fslocs->locations[i],						   &p, buflen);		if (status)			return status;	}	*pp = p;	return 0;}static u32 nfs4_ftypes[16] = {        NF4BAD,  NF4FIFO, NF4CHR, NF4BAD,        NF4DIR,  NF4BAD,  NF4BLK, NF4BAD,        NF4REG,  NF4BAD,  NF4LNK, NF4BAD,        NF4SOCK, NF4BAD,  NF4LNK, NF4BAD,};static __be32nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,			__be32 **p, int *buflen){	int status;	if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)		return nfserr_resource;	if (whotype != NFS4_ACL_WHO_NAMED)		status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1));	else if (group)		status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1));	else		status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1));	if (status < 0)		return nfserrno(status);	*p = xdr_encode_opaque(*p, NULL, status);	*buflen -= (XDR_QUADLEN(status) << 2) + 4;	BUG_ON(*buflen < 0);	return 0;}static inline __be32nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen){	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);}static inline __be32nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen){	return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);}static inline __be32nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,		__be32 **p, int *buflen){	return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);}#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \			      FATTR4_WORD0_RDATTR_ERROR)#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEIDstatic __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err){	/* As per referral draft:  */	if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||	    *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {		if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||	            *bmval0 & FATTR4_WORD0_FS_LOCATIONS)			*rdattr_err = NFSERR_MOVED;		else			return nfserr_moved;	}	*bmval0 &= WORD0_ABSENT_FS_ATTRS;	*bmval1 &= WORD1_ABSENT_FS_ATTRS;	return 0;}/* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. * * @countp is the buffer size in _words_; upon successful return this becomes * replaced with the number of words written. */__be32nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,		struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,		struct svc_rqst *rqstp){	u32 bmval0 = bmval[0];	u32 bmval1 = bmval[1];	struct kstat stat;	struct svc_fh tempfh;	struct kstatfs statfs;	int buflen = *countp << 2;	__be32 *attrlenp;	u32 dummy;	u64 dummy64;	u32 rdattr_err = 0;	__be32 *p = buffer;	__be32 status;	int err;	int aclsupport = 0;	struct nfs4_acl *acl = NULL;	BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);	BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);	BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);	if (exp->ex_fslocs.migrated) {		status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);		if (status)			goto out;	}	err = vfs_getattr(exp->ex_mnt, dentry, &stat);	if (err)		goto out_nfserr;	if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL |			FATTR4_WORD0_MAXNAME)) ||	    (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |		       FATTR4_WORD1_SPACE_TOTAL))) {		err = vfs_statfs(dentry, &statfs);		if (err)			goto out_nfserr;	}	if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {		fh_init(&tempfh, NFS4_FHSIZE);		status = fh_compose(&tempfh, exp, dentry, NULL);		if (status)			goto out;		fhp = &tempfh;	}	if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT			| FATTR4_WORD0_SUPPORTED_ATTRS)) {		err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);		aclsupport = (err == 0);		if (bmval0 & FATTR4_WORD0_ACL) {			if (err == -EOPNOTSUPP)				bmval0 &= ~FATTR4_WORD0_ACL;			else if (err == -EINVAL) {				status = nfserr_attrnotsupp;				goto out;			} else if (err != 0)				goto out_nfserr;		}	}	if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {		if (exp->ex_fslocs.locations == NULL) {			bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;		}	}	if ((buflen -= 16) < 0)		goto out_resource;	WRITE32(2);	WRITE32(bmval0);	WRITE32(bmval1);	attrlenp = p++;                /* to be backfilled later */	if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {		u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;		if ((buflen -= 12) < 0)			goto out_resource;		if (!aclsupport)			word0 &= ~FATTR4_WORD0_ACL;		if (!exp->ex_fslocs.locations)			word0 &= ~FATTR4_WORD0_FS_LOCATIONS;		WRITE32(2);		WRITE32(word0);		WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);	}	if (bmval0 & FATTR4_WORD0_TYPE) {		if ((buflen -= 4) < 0)			goto out_resource;		dummy = nfs4_ftypes[(stat.mode & S_IFMT) >> 12];		if (dummy == NF4BAD)			goto out_serverfault;		WRITE32(dummy);	}	if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {		if ((buflen -= 4) < 0)			goto out_resource;		if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)			WRITE32(NFS4_FH_PERSISTENT);		else			WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);	}	if (bmval0 & FATTR4_WORD0_CHANGE) {		/*		 * Note: This _must_ be consistent with the scheme for writing		 * change_info, so any changes made here must be reflected there		 * as well.  (See xdr4.h:set_change_info() and the WRITECINFO()		 * macro above.)		 */		if ((buflen -= 8) < 0)			goto out_resource;		WRITE32(stat.ctime.tv_sec);		WRITE32(stat.ctime.tv_nsec);	}

⌨️ 快捷键说明

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