aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/nfsclient/nfs_clrpcops.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient/nfs_clrpcops.c')
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c542
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.
*/