diff options
Diffstat (limited to 'sys/fs/nfsclient/nfs_clrpcops.c')
-rw-r--r-- | sys/fs/nfsclient/nfs_clrpcops.c | 542 |
1 files changed, 437 insertions, 105 deletions
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 8c5532268287..2f3c59b68518 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -142,6 +142,7 @@ static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, int *, int *); +static bool nfscl_invalidfname(bool, char *, int); static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, struct nfscllockowner *, u_int64_t, u_int64_t, u_int32_t, struct ucred *, NFSPROC_T *, int); @@ -389,13 +390,25 @@ nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) mode |= NFSV4OPEN_ACCESSREAD; if (amode & FWRITE) mode |= NFSV4OPEN_ACCESSWRITE; + if (NFSHASNFSV4N(nmp)) { + if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 && + nfs_numnfscbd > 0 && + (vn_irflag_read(vp) & VIRF_NAMEDATTR) == 0) { + if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) + mode |= NFSV4OPEN_WANTWRITEDELEG; + else + mode |= NFSV4OPEN_WANTANYDELEG; + } else + mode |= NFSV4OPEN_WANTNODELEG; + } nfhp = np->n_fhp; retrycnt = 0; do { dp = NULL; - error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, - cred, p, NULL, &op, &newone, &ret, 1, true); + error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, + (mode & NFSV4OPEN_ACCESSBOTH), 1, cred, p, NULL, + &op, &newone, &ret, 1, true); if (error) { return (error); } @@ -440,7 +453,7 @@ nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) NFSUNLOCKNODE(np); (void) nfscl_deleg(nmp->nm_mountp, op->nfso_own->nfsow_clp, - nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); + nfhp->nfh_fh, nfhp->nfh_len, cred, p, dp); } } else if (NFSHASNFSV4N(nmp)) { /* @@ -473,7 +486,7 @@ nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) NFSUNLOCKNODE(np); (void) nfscl_deleg(nmp->nm_mountp, op->nfso_own->nfsow_clp, - nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); + nfhp->nfh_fh, nfhp->nfh_len, cred, p, dp); } } else { error = EIO; @@ -547,7 +560,8 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, cred); NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); - *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); + *tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH | + NFSV4OPEN_WANTDELEGMASK)); *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; @@ -664,6 +678,13 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, &ret, &acesize, p); if (error) goto nfsmout; + } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && + NFSHASNFSV4N(nmp)) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(uint32_t, *tl); + if (deleg == NFSV4OPEN_CONTENTION || + deleg == NFSV4OPEN_RESOURCE) + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; @@ -675,7 +696,7 @@ nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, ("nfsrpc_openrpc: Getattr repstat")); error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, p, cred); if (error) goto nfsmout; } @@ -1334,7 +1355,7 @@ nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, if ((nd->nd_flag & ND_NFSV4) != 0) error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL, - NULL, NULL); + NULL, NULL, NULL); else error = nfsm_loadattr(nd, nap); } else @@ -1546,7 +1567,7 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, NFSM_BUILD(tl, uint32_t *, 6 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(NFSV4OP_OPEN); *tl++ = 0; /* seqid, ignored. */ - *tl++ = txdr_unsigned(openmode); + *tl++ = txdr_unsigned(openmode | NFSV4OPEN_WANTNODELEG); *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); *tl++ = 0; /* ClientID, ignored. */ *tl = 0; @@ -1668,6 +1689,13 @@ nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, ndp->nfsdl_stateid.other[0] = *tl++; ndp->nfsdl_stateid.other[1] = *tl++; ndp->nfsdl_stateid.other[2] = *tl++; + } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && + NFSHASNFSV4N(nmp)) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(uint32_t, *tl); + if (deleg == NFSV4OPEN_CONTENTION || + deleg == NFSV4OPEN_RESOURCE) + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; @@ -2396,7 +2424,7 @@ nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, *tl = vtonfsv34_type(vtyp); } if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) - nfscl_fillsattr(nd, vap, dvp, 0, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); if ((nd->nd_flag & ND_NFSV3) && (vtyp == VCHR || vtyp == VBLK)) { NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); @@ -2484,7 +2512,7 @@ nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, */ if (dp != NULL) (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, - (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); + (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, dp); nfscl_ownerrelease(nmp, owp, error, newone, unlocked); if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || @@ -2595,8 +2623,17 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, */ NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(owp->nfsow_seqid); - *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | - NFSV4OPEN_ACCESSREAD); + if (NFSHASNFSV4N(nmp)) { + if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 && + nfs_numnfscbd > 0) + *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | + NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG); + else + *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | + NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG); + } else + *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | + NFSV4OPEN_ACCESSREAD); *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; @@ -2609,14 +2646,16 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, if (NFSHASSESSPERSIST(nmp)) { /* Use GUARDED for persistent sessions. */ *tl = txdr_unsigned(NFSCREATE_GUARDED); - nfscl_fillsattr(nd, vap, dvp, 0, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, + 0); } else { /* Otherwise, use EXCLUSIVE4_1. */ *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); *tl++ = cverf.lval[0]; *tl = cverf.lval[1]; - nfscl_fillsattr(nd, vap, dvp, 0, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, + 0); } } else { /* NFSv4.0 */ @@ -2627,7 +2666,7 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, } } else { *tl = txdr_unsigned(NFSCREATE_UNCHECKED); - nfscl_fillsattr(nd, vap, dvp, 0, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); @@ -2714,6 +2753,13 @@ nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, &ret, &acesize, p); if (error) goto nfsmout; + } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && + NFSHASNFSV4N(nmp)) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(uint32_t, *tl); + if (deleg == NFSV4OPEN_CONTENTION || + deleg == NFSV4OPEN_RESOURCE) + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; @@ -2813,22 +2859,28 @@ nfsmout: * Nfs remove rpc */ int -nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, - struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp) +nfsrpc_remove(struct vnode *dvp, char *name, int namelen, struct vnode *vp, + struct nfsvattr *nap, int *attrflagp, nfsremove_status *file_status, + struct nfsvattr *dnap, int *dattrflagp, struct ucred *cred, NFSPROC_T *p) { - u_int32_t *tl; + uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsnode *np; struct nfsmount *nmp; nfsv4stateid_t dstateid; - int error, ret = 0, i; + nfsattrbit_t attrbits; + int error, i, ret; *dattrflagp = 0; + *attrflagp = 0; + *file_status = UNKNOWN; + ret = 0; if (namelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); nmp = VFSTONFS(dvp->v_mount); tryagain: - if (NFSHASNFSV4(nmp) && ret == 0) { + if (NFSHASNFSV4(nmp) && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 || + !NFSHASNFSV4N(nmp)) && ret == 0) { ret = nfscl_removedeleg(vp, p, &dstateid); if (ret == 1) { NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp, cred); @@ -2853,9 +2905,19 @@ tryagain: } if (ret == 0) NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp, cred); - (void) nfsm_strtom(nd, name, namelen); + (void)nfsm_strtom(nd, name, namelen); + if (ret == 0 && (nd->nd_flag & ND_NFSV4) != 0) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_PUTFH); + np = VTONFS(vp); + (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + NFSGETATTR_ATTRBIT(&attrbits); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + (void)nfsrv_putattrbit(nd, &attrbits); + } error = nfscl_request(nd, dvp, p, cred); - if (error) + if (error != 0) return (error); if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { /* For NFSv4, parse out any Delereturn replies. */ @@ -2878,7 +2940,41 @@ tryagain: } error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); } - if (nd->nd_repstat && !error) + if (ret == 0 && (nd->nd_flag & (ND_NFSV4 | + ND_NOMOREDATA)) == ND_NFSV4) { + /* Parse out the Remove reply for NFSPROC_REMOVE. */ + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 2 * NFSX_HYPER); + /* No use for change info for now. */ + /* The Remove succeeded. */ + nd->nd_repstat = 0; + } + if (ret == 0 && (nd->nd_flag & (ND_NFSV4 | + ND_NOMOREDATA)) == ND_NFSV4) { + /* Parse out the PutFH, Getattr for NFSPROC_REMOVE. */ + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*(tl + 1) != 0) { + i = fxdr_unsigned(int, *(tl + 1)); + if (i == NFSERR_STALE) + *file_status = DELETED; + } else { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*(tl + 1) != 0) { + i = fxdr_unsigned(int, *(tl + 1)); + if (i == NFSERR_STALE) + *file_status = DELETED; + } else { + error = nfsm_loadattr(nd, nap); + if (error == 0) { + *attrflagp = 1; + if (nap->na_nlink == 0) + *file_status = NLINK_ZERO; + else + *file_status = VALID; + } + } + } + } + if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); @@ -2889,12 +2985,14 @@ nfsmout: * Do an nfs rename rpc. */ int -nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, - vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, - NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, - int *fattrflagp, int *tattrflagp) +nfsrpc_rename(struct vnode *fdvp, struct vnode *fvp, char *fnameptr, + int fnamelen, struct vnode *tdvp, struct vnode *tvp, char *tnameptr, + int tnamelen, nfsremove_status *tvp_status, struct nfsvattr *fnap, + struct nfsvattr *tnap, int *fattrflagp, int *tattrflagp, + struct nfsvattr *tvpnap, int *tvpattrflagp, struct ucred *cred, + NFSPROC_T *p) { - u_int32_t *tl; + uint32_t *tl; struct nfsrv_descript nfsd, *nd = &nfsd; struct nfsmount *nmp; struct nfsnode *np; @@ -2904,11 +3002,14 @@ nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, *fattrflagp = 0; *tattrflagp = 0; + *tvpattrflagp = 0; + *tvp_status = UNKNOWN; nmp = VFSTONFS(fdvp->v_mount); if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) return (ENAMETOOLONG); tryagain: - if (NFSHASNFSV4(nmp) && ret == 0) { + if (NFSHASNFSV4(nmp) && ((nmp->nm_flag & NFSMNT_NOCTO) == 0 || + !NFSHASNFSV4N(nmp)) && ret == 0) { ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, &tdstateid, &gottd, p); if (gotfd && gottd) { @@ -2961,29 +3062,44 @@ tryagain: } if (ret == 0) NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp, cred); - if (nd->nd_flag & ND_NFSV4) { + if ((nd->nd_flag & ND_NFSV4) != 0) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); NFSWCCATTR_ATTRBIT(&attrbits); - (void) nfsrv_putattrbit(nd, &attrbits); + (void)nfsrv_putattrbit(nd, &attrbits); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_PUTFH); (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, VTONFS(tdvp)->n_fhp->nfh_len, 0); NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_GETATTR); - (void) nfsrv_putattrbit(nd, &attrbits); + (void)nfsrv_putattrbit(nd, &attrbits); nd->nd_flag |= ND_V4WCCATTR; NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_RENAME); } - (void) nfsm_strtom(nd, fnameptr, fnamelen); - if (!(nd->nd_flag & ND_NFSV4)) + (void)nfsm_strtom(nd, fnameptr, fnamelen); + if ((nd->nd_flag & ND_NFSV4) == 0) (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, VTONFS(tdvp)->n_fhp->nfh_len, 0); - (void) nfsm_strtom(nd, tnameptr, tnamelen); + (void)nfsm_strtom(nd, tnameptr, tnamelen); + if (ret == 0 && (nd->nd_flag & ND_NFSV4) != 0) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + /* When tvp == NULL, it doesn't matter which dvp is used. */ + *tl = txdr_unsigned(NFSV4OP_PUTFH); + if (tvp != NULL) + (void)nfsm_fhtom(nmp, nd, VTONFS(tvp)->n_fhp->nfh_fh, + VTONFS(tvp)->n_fhp->nfh_len, 0); + else + (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, + VTONFS(tdvp)->n_fhp->nfh_len, 0); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSGETATTR_ATTRBIT(&attrbits); + (void)nfsrv_putattrbit(nd, &attrbits); + } error = nfscl_request(nd, fdvp, p, cred); - if (error) + if (error != 0) return (error); if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { /* For NFSv4, parse out any Delereturn replies. */ @@ -2999,7 +3115,7 @@ tryagain: for (i = 0; i < (ret * 2); i++) { if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { - NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) { if (i == 1 && ret > 1) { /* @@ -3019,23 +3135,57 @@ tryagain: } /* Now, the first wcc attribute reply. */ if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { - NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) nd->nd_flag |= ND_NOMOREDATA; } error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, NULL); /* and the second wcc attribute reply. */ if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && - !error) { - NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); + error == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); if (*(tl + 1)) nd->nd_flag |= ND_NOMOREDATA; } - if (!error) + if (error == 0) error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, NULL, NULL); } - if (nd->nd_repstat && !error) + if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && + ret == 0 && error == 0) { + /* Parse out the rename successful reply. */ + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + + 4 * NFSX_HYPER); + nd->nd_repstat = 0; /* Rename succeeded. */ + /* Parse PutFH reply for tvp. */ + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*(tl + 1) != 0) { + if (tvp != NULL) { + i = fxdr_unsigned(int, *(tl + 1)); + if (i == NFSERR_STALE) + *tvp_status = DELETED; + } + } else { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*(tl + 1) != 0) { + if (tvp != NULL) { + i = fxdr_unsigned(int, *(tl + 1)); + if (i == NFSERR_STALE) + *tvp_status = DELETED; + } + } else { + error = nfsm_loadattr(nd, tvpnap); + if (error == 0 && tvp != NULL) { + *tvpattrflagp = 1; + if (tvpnap->na_nlink == 0) + *tvp_status = NLINK_ZERO; + else + *tvp_status = VALID; + } + } + } + } + if (nd->nd_repstat != 0 && error == 0) error = nd->nd_repstat; nfsmout: m_freem(nd->nd_mrep); @@ -3068,14 +3218,19 @@ nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, VTONFS(dvp)->n_fhp->nfh_len, 0); if (nd->nd_flag & ND_NFSV4) { NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); - *tl = txdr_unsigned(NFSV4OP_GETATTR); - NFSWCCATTR_ATTRBIT(&attrbits); - (void) nfsrv_putattrbit(nd, &attrbits); - nd->nd_flag |= ND_V4WCCATTR; - NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OP_LINK); } (void) nfsm_strtom(nd, name, namelen); + if (nd->nd_flag & ND_NFSV4) { + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + NFSGETATTR_ATTRBIT(&attrbits); + (void)nfsrv_putattrbit(nd, &attrbits); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + (void)nfsrv_putattrbit(nd, &attrbits); + } error = nfscl_request(nd, vp, p, cred); if (error) return (error); @@ -3084,19 +3239,28 @@ nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, if (!error) error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); - } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { + } else if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0) { /* - * First, parse out the PutFH and Getattr result. + * First and parse out the PutFH and Link results. */ - NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (!(*(tl + 1))) - NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); - if (*(tl + 1)) + NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED + + 2 * NFSX_HYPER); + if (*(tl + 3)) nd->nd_flag |= ND_NOMOREDATA; /* - * Get the pre-op attributes. + * Get the directory post-op attributes. */ - error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); + if ((nd->nd_flag & ND_NOMOREDATA) == 0) + error = nfscl_postop_attr(nd, dnap, dattrflagp); + if (error == 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) { + /* Get rid of the RestoreFH reply. */ + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + if (*(tl + 1)) + nd->nd_flag |= ND_NOMOREDATA; + } + /* Get the file's post-op attributes. */ + if (error == 0 && (nd->nd_flag & ND_NOMOREDATA) == 0) + error = nfscl_postop_attr(nd, nap, attrflagp); } if (nd->nd_repstat && !error) error = nd->nd_repstat; @@ -3195,7 +3359,7 @@ nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, *tl = txdr_unsigned(NFDIR); } (void) nfsm_strtom(nd, name, namelen); - nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1 | NFSSATTR_NEWFILE, 0); if (nd->nd_flag & ND_NFSV4) { NFSGETATTR_ATTRBIT(&attrbits); NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); @@ -3280,6 +3444,31 @@ nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, } /* + * Check to make sure the file name in a Readdir reply is valid. + */ +static bool +nfscl_invalidfname(bool is_v4, char *name, int len) +{ + int i; + char *cp; + + if (is_v4 && ((len == 1 && name[0] == '.') || + (len == 2 && name[0] == '.' && name[1] == '.'))) { + printf("Readdir NFSv4 reply has dot or dotdot in it\n"); + return (true); + } + cp = name; + for (i = 0; i < len; i++, cp++) { + if (*cp == '/' || *cp == '\0') { + printf("Readdir reply file name had imbedded / or nul" + " byte\n"); + return (true); + } + } + return (false); +} + +/* * Readdir rpc. * Always returns with either uio_resid unchanged, if you are at the * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks @@ -3327,10 +3516,13 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsattrbit_t attrbits, dattrbits; u_int32_t rderr, *tl2 = NULL; size_t tresid; + bool validentry; KASSERT(uiop->uio_iovcnt == 1 && (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, ("nfs readdirrpc bad uio")); + KASSERT(uiop->uio_segflg == UIO_SYSSPACE, + ("nfsrpc_readdir: uio userspace")); ncookie.lval[0] = ncookie.lval[1] = 0; /* * There is no point in reading a lot more than uio_resid, however @@ -3405,7 +3597,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, p, cred); if (error) { dotdotfileid = dotfileid; } else if (gotmnton) { @@ -3550,6 +3742,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, /* loop through the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { + validentry = true; if (nd->nd_flag & ND_NFSV4) { NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); ncookie.lval[0] = *tl++; @@ -3588,6 +3781,17 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, uiop->uio_resid) bigenough = 0; if (bigenough) { + struct iovec saviov; + off_t savoff; + ssize_t savresid; + int savblksiz; + + saviov.iov_base = uiop->uio_iov->iov_base; + saviov.iov_len = uiop->uio_iov->iov_len; + savoff = uiop->uio_offset; + savresid = uiop->uio_resid; + savblksiz = blksiz; + dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; @@ -3603,20 +3807,36 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + DIRHDSIZ; uiop->uio_iov->iov_len -= DIRHDSIZ; + cp = uiop->uio_iov->iov_base; error = nfsm_mbufuio(nd, uiop, len); if (error) goto nfsmout; - cp = uiop->uio_iov->iov_base; - tlen -= len; - NFSBZERO(cp, tlen); - cp += tlen; /* points to cookie storage */ - tl2 = (u_int32_t *)cp; - uiop->uio_iov->iov_base = - (char *)uiop->uio_iov->iov_base + tlen + - NFSX_HYPER; - uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; - uiop->uio_resid -= tlen + NFSX_HYPER; - uiop->uio_offset += (tlen + NFSX_HYPER); + /* Check for an invalid file name. */ + if (nfscl_invalidfname( + (nd->nd_flag & ND_NFSV4) != 0, cp, len)) { + /* Skip over this entry. */ + uiop->uio_iov->iov_base = + saviov.iov_base; + uiop->uio_iov->iov_len = + saviov.iov_len; + uiop->uio_offset = savoff; + uiop->uio_resid = savresid; + blksiz = savblksiz; + validentry = false; + } else { + cp = uiop->uio_iov->iov_base; + tlen -= len; + NFSBZERO(cp, tlen); + cp += tlen; /* points to cookie store */ + tl2 = (u_int32_t *)cp; + uiop->uio_iov->iov_base = + (char *)uiop->uio_iov->iov_base + + tlen + NFSX_HYPER; + uiop->uio_iov->iov_len -= tlen + + NFSX_HYPER; + uiop->uio_resid -= tlen + NFSX_HYPER; + uiop->uio_offset += (tlen + NFSX_HYPER); + } } else { error = nfsm_advance(nd, NFSM_RNDUP(len), -1); if (error) @@ -3627,7 +3847,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, &rderr, p, cred); + NULL, NULL, &rderr, NULL, p, cred); if (error) goto nfsmout; NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); @@ -3640,7 +3860,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, ncookie.lval[0] = 0; ncookie.lval[1] = *tl++; } - if (bigenough) { + if (bigenough && validentry) { if (nd->nd_flag & ND_NFSV4) { if (rderr) { dp->d_fileno = 0; @@ -3777,11 +3997,16 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, size_t tresid; u_int32_t *tl2 = NULL, rderr; struct timespec dctime, ts; - bool attr_ok; + bool attr_ok, named_dir, validentry; KASSERT(uiop->uio_iovcnt == 1 && (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, ("nfs readdirplusrpc bad uio")); + KASSERT(uiop->uio_segflg == UIO_SYSSPACE, + ("nfsrpc_readdirplus: uio userspace")); + named_dir = false; + if ((vp->v_irflag & VIRF_NAMEDDIR) != 0) + named_dir = true; ncookie.lval[0] = ncookie.lval[1] = 0; timespecclear(&dctime); *attrflagp = 0; @@ -3847,7 +4072,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = UINT64_MAX; error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, p, cred); if (error) { dotdotfileid = dotfileid; } else if (gotmnton) { @@ -3933,6 +4158,13 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, NFSATTRBIT_TIMECREATE)) NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); + if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, + NFSATTRBIT_HIDDEN) || + !NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, + NFSATTRBIT_SYSTEM)) { + NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN); + NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM); + } } /* @@ -3986,6 +4218,7 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, /* loop through the dir entries, doctoring them to 4bsd form */ while (more_dirs && bigenough) { + validentry = true; NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); if (nd->nd_flag & ND_NFSV4) { ncookie.lval[0] = *tl++; @@ -4017,6 +4250,17 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, uiop->uio_resid) bigenough = 0; if (bigenough) { + struct iovec saviov; + off_t savoff; + ssize_t savresid; + int savblksiz; + + saviov.iov_base = uiop->uio_iov->iov_base; + saviov.iov_len = uiop->uio_iov->iov_len; + savoff = uiop->uio_offset; + savresid = uiop->uio_resid; + savblksiz = blksiz; + dp = (struct dirent *)uiop->uio_iov->iov_base; dp->d_pad0 = dp->d_pad1 = 0; dp->d_off = 0; @@ -4035,25 +4279,42 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, cnp->cn_nameptr = uiop->uio_iov->iov_base; cnp->cn_namelen = len; NFSCNHASHZERO(cnp); + cp = uiop->uio_iov->iov_base; error = nfsm_mbufuio(nd, uiop, len); if (error) goto nfsmout; - cp = uiop->uio_iov->iov_base; - tlen -= len; - NFSBZERO(cp, tlen); - cp += tlen; /* points to cookie storage */ - tl2 = (u_int32_t *)cp; - if (len == 2 && cnp->cn_nameptr[0] == '.' && - cnp->cn_nameptr[1] == '.') - isdotdot = 1; - else - isdotdot = 0; - uiop->uio_iov->iov_base = - (char *)uiop->uio_iov->iov_base + tlen + - NFSX_HYPER; - uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; - uiop->uio_resid -= tlen + NFSX_HYPER; - uiop->uio_offset += (tlen + NFSX_HYPER); + /* Check for an invalid file name. */ + if (nfscl_invalidfname( + (nd->nd_flag & ND_NFSV4) != 0, cp, len)) { + /* Skip over this entry. */ + uiop->uio_iov->iov_base = + saviov.iov_base; + uiop->uio_iov->iov_len = + saviov.iov_len; + uiop->uio_offset = savoff; + uiop->uio_resid = savresid; + blksiz = savblksiz; + validentry = false; + } else { + cp = uiop->uio_iov->iov_base; + tlen -= len; + NFSBZERO(cp, tlen); + cp += tlen; /* points to cookie store */ + tl2 = (u_int32_t *)cp; + if (len == 2 && + cnp->cn_nameptr[0] == '.' && + cnp->cn_nameptr[1] == '.') + isdotdot = 1; + else + isdotdot = 0; + uiop->uio_iov->iov_base = + (char *)uiop->uio_iov->iov_base + + tlen + NFSX_HYPER; + uiop->uio_iov->iov_len -= tlen + + NFSX_HYPER; + uiop->uio_resid -= tlen + NFSX_HYPER; + uiop->uio_offset += (tlen + NFSX_HYPER); + } } else { error = nfsm_advance(nd, NFSM_RNDUP(len), -1); if (error) @@ -4085,12 +4346,12 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, nfsva.na_mntonfileno = 0xffffffff; error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, &rderr, p, cred); + NULL, NULL, &rderr, NULL, p, cred); if (error) goto nfsmout; } - if (bigenough) { + if (bigenough && validentry) { if (nd->nd_flag & ND_NFSV4) { if (rderr) { dp->d_fileno = 0; @@ -4190,7 +4451,8 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, if (cnp->cn_namelen <= NCHNAMLEN && ndp->ni_dvp != ndp->ni_vp && (newvp->v_type != VDIR || - dctime.tv_sec != 0)) { + dctime.tv_sec != 0) && + !named_dir) { cache_enter_time_flags(ndp->ni_dvp, ndp->ni_vp, cnp, &nfsva.na_ctime, @@ -4747,7 +5009,7 @@ nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, if (nd->nd_repstat == 0) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL, - p, cred); + NULL, p, cred); if (!error) { nmp->nm_fsid[0] = nap->na_filesid[0]; nmp->nm_fsid[1] = nap->na_filesid[1]; @@ -4800,7 +5062,7 @@ nfsmout: * nfs pathconf rpc */ int -nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, +nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, bool *has_namedattrp, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) { struct nfsrv_descript nfsd, *nd = &nfsd; @@ -4810,6 +5072,7 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, int error; struct nfsnode *np; + *has_namedattrp = false; *attrflagp = 0; nmp = VFSTONFS(vp->v_mount); if (NFSHASNFSV4(nmp)) { @@ -4836,8 +5099,8 @@ nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, return (error); if (nd->nd_repstat == 0) { error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, - pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, - cred); + pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, + has_namedattrp, p, cred); if (!error) *attrflagp = 1; } else { @@ -5132,7 +5395,7 @@ nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) return (error); if (!nd->nd_repstat) error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, - NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, NULL, p, cred); else error = nd->nd_repstat; m_freem(nd->nd_mrep); @@ -5173,7 +5436,8 @@ nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, NFSZERO_ATTRBIT(&attrbits); NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); (void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0, - &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); + &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, false, false, + false); error = nfscl_request(nd, vp, p, cred); if (error) return (error); @@ -8109,7 +8373,8 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 0, 0, cred); NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); - *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); + *tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH | + NFSV4OPEN_WANTDELEGMASK)); *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; @@ -8210,6 +8475,13 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, &ret, &acesize, p); if (error != 0) goto nfsmout; + } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && + NFSHASNFSV4N(nmp)) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(uint32_t, *tl); + if (deleg == NFSV4OPEN_CONTENTION || + deleg == NFSV4OPEN_RESOURCE) + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; @@ -8224,7 +8496,7 @@ nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, if (*++tl == 0) { error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, - NULL, NULL, NULL, p, cred); + NULL, NULL, NULL, NULL, p, cred); if (error != 0) goto nfsmout; if (ndp != NULL) { @@ -8301,8 +8573,17 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, */ NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); *tl++ = txdr_unsigned(owp->nfsow_seqid); - *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | - NFSV4OPEN_ACCESSREAD); + if (NFSHASNFSV4N(nmp)) { + if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 && + nfs_numnfscbd > 0) + *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | + NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG); + else + *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | + NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG); + } else + *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | + NFSV4OPEN_ACCESSREAD); *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); tsep = nfsmnt_mdssession(nmp); *tl++ = tsep->nfsess_clientid.lval[0]; @@ -8314,18 +8595,18 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, if (NFSHASSESSPERSIST(nmp)) { /* Use GUARDED for persistent sessions. */ *tl = txdr_unsigned(NFSCREATE_GUARDED); - nfscl_fillsattr(nd, vap, dvp, 0, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } else { /* Otherwise, use EXCLUSIVE4_1. */ *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); *tl++ = cverf.lval[0]; *tl = cverf.lval[1]; - nfscl_fillsattr(nd, vap, dvp, 0, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } } else { *tl = txdr_unsigned(NFSCREATE_UNCHECKED); - nfscl_fillsattr(nd, vap, dvp, 0, 0); + nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); } NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); @@ -8421,6 +8702,13 @@ nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, &ret, &acesize, p); if (error != 0) goto nfsmout; + } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && + NFSHASNFSV4N(nmp)) { + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + deleg = fxdr_unsigned(uint32_t, *tl); + if (deleg == NFSV4OPEN_CONTENTION || + deleg == NFSV4OPEN_RESOURCE) + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); } else if (deleg != NFSV4OPEN_DELEGATENONE) { error = NFSERR_BADXDR; goto nfsmout; @@ -9258,7 +9546,7 @@ nfsm_split(struct mbuf *mp, uint64_t xfer) if (pgno == m->m_epg_npgs) panic("nfsm_split: eroneous ext_pgs mbuf"); - m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs); + m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs, 0); m2->m_epg_flags |= EPG_FLAG_ANON; /* @@ -9381,6 +9669,50 @@ nfsmout: } /* + * nfs opeattr rpc + */ +int +nfsrpc_openattr(struct nfsmount *nmp, struct vnode *vp, uint8_t *fhp, int fhlen, + bool createit, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, + struct nfsfh **nfhpp, int *attrflagp) +{ + uint32_t *tl; + struct nfsrv_descript nfsd, *nd = &nfsd; + nfsattrbit_t attrbits; + int error = 0; + + *attrflagp = 0; + nfscl_reqstart(nd, NFSPROC_OPENATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0, + cred); + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + if (createit) + *tl = newnfs_true; + else + *tl = newnfs_false; + NFSGETATTR_ATTRBIT(&attrbits); + NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); + *tl++ = txdr_unsigned(NFSV4OP_GETFH); + *tl = txdr_unsigned(NFSV4OP_GETATTR); + (void)nfsrv_putattrbit(nd, &attrbits); + error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, + NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); + if (error != 0) + return (error); + if (nd->nd_repstat == 0) { + NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); + error = nfsm_getfh(nd, nfhpp); + if (error != 0) + goto nfsmout; + error = nfscl_postop_attr(nd, nap, attrflagp); + } +nfsmout: + m_freem(nd->nd_mrep); + if (error == 0 && nd->nd_repstat != 0) + error = nd->nd_repstat; + return (error); +} + +/* * Do roughly what nfs_statfs() does for NFSv4, but when called with a shared * locked vnode. */ |