📄 nfs4xdr.c
字号:
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 + -