1191783Srmacklem/*- 2191783Srmacklem * Copyright (c) 1989, 1993 3191783Srmacklem * The Regents of the University of California. All rights reserved. 4191783Srmacklem * 5191783Srmacklem * This code is derived from software contributed to Berkeley by 6191783Srmacklem * Rick Macklem at The University of Guelph. 7191783Srmacklem * 8191783Srmacklem * Redistribution and use in source and binary forms, with or without 9191783Srmacklem * modification, are permitted provided that the following conditions 10191783Srmacklem * are met: 11191783Srmacklem * 1. Redistributions of source code must retain the above copyright 12191783Srmacklem * notice, this list of conditions and the following disclaimer. 13191783Srmacklem * 2. Redistributions in binary form must reproduce the above copyright 14191783Srmacklem * notice, this list of conditions and the following disclaimer in the 15191783Srmacklem * documentation and/or other materials provided with the distribution. 16191783Srmacklem * 4. Neither the name of the University nor the names of its contributors 17191783Srmacklem * may be used to endorse or promote products derived from this software 18191783Srmacklem * without specific prior written permission. 19191783Srmacklem * 20191783Srmacklem * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21191783Srmacklem * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22191783Srmacklem * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23191783Srmacklem * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24191783Srmacklem * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25191783Srmacklem * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26191783Srmacklem * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27191783Srmacklem * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28191783Srmacklem * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29191783Srmacklem * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30191783Srmacklem * SUCH DAMAGE. 31191783Srmacklem * 32191783Srmacklem */ 33191783Srmacklem 34191783Srmacklem#include <sys/cdefs.h> 35191783Srmacklem__FBSDID("$FreeBSD$"); 36191783Srmacklem 37191783Srmacklem/* 38191783Srmacklem * Rpc op calls, generally called from the vnode op calls or through the 39191783Srmacklem * buffer cache, for NFS v2, 3 and 4. 40191783Srmacklem * These do not normally make any changes to vnode arguments or use 41191783Srmacklem * structures that might change between the VFS variants. The returned 42191783Srmacklem * arguments are all at the end, after the NFSPROC_T *p one. 43191783Srmacklem */ 44191783Srmacklem 45191783Srmacklem#ifndef APPLEKEXT 46230446Srmacklem#include "opt_inet6.h" 47230446Srmacklem 48191783Srmacklem#include <fs/nfs/nfsport.h> 49191783Srmacklem 50191783Srmacklem/* 51191783Srmacklem * Global variables 52191783Srmacklem */ 53191783Srmacklemextern int nfs_numnfscbd; 54191783Srmacklemextern struct timeval nfsboottime; 55191783Srmacklemextern u_int32_t newnfs_false, newnfs_true; 56191783Srmacklemextern nfstype nfsv34_type[9]; 57191783Srmacklemextern int nfsrv_useacl; 58191783Srmacklemextern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 59240977Srmacklemextern int nfscl_debuglevel; 60191783SrmacklemNFSCLSTATEMUTEX; 61191783Srmacklemint nfstest_outofseq = 0; 62191783Srmacklemint nfscl_assumeposixlocks = 1; 63191783Srmacklemint nfscl_enablecallb = 0; 64191783Srmacklemshort nfsv4_cbport = NFSV4_CBPORT; 65191783Srmacklemint nfstest_openallsetattr = 0; 66191783Srmacklem#endif /* !APPLEKEXT */ 67191783Srmacklem 68191783Srmacklem#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 69191783Srmacklem 70191783Srmacklemstatic int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, 71191783Srmacklem struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); 72191783Srmacklemstatic int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, 73191783Srmacklem nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *); 74222289Srmacklemstatic int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, 75191783Srmacklem struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, 76191783Srmacklem void *); 77191783Srmacklemstatic int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, 78191783Srmacklem nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, 79191783Srmacklem struct nfsvattr *, struct nfsfh **, int *, int *, void *); 80191783Srmacklemstatic int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, 81191783Srmacklem nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, 82191783Srmacklem NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, 83191783Srmacklem int *, void *, int *); 84191783Srmacklemstatic int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, 85191783Srmacklem struct nfscllockowner *, u_int64_t, u_int64_t, 86191783Srmacklem u_int32_t, struct ucred *, NFSPROC_T *, int); 87191783Srmacklemstatic int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, 88191783Srmacklem struct acl *, nfsv4stateid_t *, void *); 89191783Srmacklem 90191783Srmacklem/* 91191783Srmacklem * nfs null call from vfs. 92191783Srmacklem */ 93191783SrmacklemAPPLESTATIC int 94191783Srmacklemnfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) 95191783Srmacklem{ 96191783Srmacklem int error; 97191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 98191783Srmacklem 99191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_NULL, vp); 100191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 101191783Srmacklem if (nd->nd_repstat && !error) 102191783Srmacklem error = nd->nd_repstat; 103191783Srmacklem mbuf_freem(nd->nd_mrep); 104191783Srmacklem return (error); 105191783Srmacklem} 106191783Srmacklem 107191783Srmacklem/* 108191783Srmacklem * nfs access rpc op. 109191783Srmacklem * For nfs version 3 and 4, use the access rpc to check accessibility. If file 110191783Srmacklem * modes are changed on the server, accesses might still fail later. 111191783Srmacklem */ 112191783SrmacklemAPPLESTATIC int 113191783Srmacklemnfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, 114191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 115191783Srmacklem{ 116191783Srmacklem int error; 117191783Srmacklem u_int32_t mode, rmode; 118191783Srmacklem 119191783Srmacklem if (acmode & VREAD) 120191783Srmacklem mode = NFSACCESS_READ; 121191783Srmacklem else 122191783Srmacklem mode = 0; 123191783Srmacklem if (vnode_vtype(vp) == VDIR) { 124191783Srmacklem if (acmode & VWRITE) 125191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | 126191783Srmacklem NFSACCESS_DELETE); 127191783Srmacklem if (acmode & VEXEC) 128191783Srmacklem mode |= NFSACCESS_LOOKUP; 129191783Srmacklem } else { 130191783Srmacklem if (acmode & VWRITE) 131191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 132191783Srmacklem if (acmode & VEXEC) 133191783Srmacklem mode |= NFSACCESS_EXECUTE; 134191783Srmacklem } 135191783Srmacklem 136191783Srmacklem /* 137191783Srmacklem * Now, just call nfsrpc_accessrpc() to do the actual RPC. 138191783Srmacklem */ 139191783Srmacklem error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode, 140191783Srmacklem NULL); 141191783Srmacklem 142191783Srmacklem /* 143191783Srmacklem * The NFS V3 spec does not clarify whether or not 144191783Srmacklem * the returned access bits can be a superset of 145191783Srmacklem * the ones requested, so... 146191783Srmacklem */ 147191783Srmacklem if (!error && (rmode & mode) != mode) 148191783Srmacklem error = EACCES; 149191783Srmacklem return (error); 150191783Srmacklem} 151191783Srmacklem 152191783Srmacklem/* 153191783Srmacklem * The actual rpc, separated out for Darwin. 154191783Srmacklem */ 155191783SrmacklemAPPLESTATIC int 156191783Srmacklemnfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, 157191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep, 158191783Srmacklem void *stuff) 159191783Srmacklem{ 160191783Srmacklem u_int32_t *tl; 161191783Srmacklem u_int32_t supported, rmode; 162191783Srmacklem int error; 163191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 164191783Srmacklem nfsattrbit_t attrbits; 165191783Srmacklem 166191783Srmacklem *attrflagp = 0; 167191783Srmacklem supported = mode; 168191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp); 169191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 170191783Srmacklem *tl = txdr_unsigned(mode); 171191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 172191783Srmacklem /* 173191783Srmacklem * And do a Getattr op. 174191783Srmacklem */ 175191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 176191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 177191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 178191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 179191783Srmacklem } 180191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 181191783Srmacklem if (error) 182191783Srmacklem return (error); 183191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 184191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 185191783Srmacklem if (error) 186191783Srmacklem goto nfsmout; 187191783Srmacklem } 188191783Srmacklem if (!nd->nd_repstat) { 189191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 190191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 191191783Srmacklem supported = fxdr_unsigned(u_int32_t, *tl++); 192191783Srmacklem } else { 193191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 194191783Srmacklem } 195191783Srmacklem rmode = fxdr_unsigned(u_int32_t, *tl); 196191783Srmacklem if (nd->nd_flag & ND_NFSV4) 197191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 198191783Srmacklem 199191783Srmacklem /* 200191783Srmacklem * It's not obvious what should be done about 201191783Srmacklem * unsupported access modes. For now, be paranoid 202191783Srmacklem * and clear the unsupported ones. 203191783Srmacklem */ 204191783Srmacklem rmode &= supported; 205191783Srmacklem *rmodep = rmode; 206191783Srmacklem } else 207191783Srmacklem error = nd->nd_repstat; 208191783Srmacklemnfsmout: 209191783Srmacklem mbuf_freem(nd->nd_mrep); 210191783Srmacklem return (error); 211191783Srmacklem} 212191783Srmacklem 213191783Srmacklem/* 214191783Srmacklem * nfs open rpc 215191783Srmacklem */ 216191783SrmacklemAPPLESTATIC int 217191783Srmacklemnfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) 218191783Srmacklem{ 219191783Srmacklem struct nfsclopen *op; 220191783Srmacklem struct nfscldeleg *dp; 221191783Srmacklem struct nfsfh *nfhp; 222191783Srmacklem struct nfsnode *np = VTONFS(vp); 223191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 224191783Srmacklem u_int32_t mode, clidrev; 225191783Srmacklem int ret, newone, error, expireret = 0, retrycnt; 226191783Srmacklem 227191783Srmacklem /* 228191783Srmacklem * For NFSv4, Open Ops are only done on Regular Files. 229191783Srmacklem */ 230191783Srmacklem if (vnode_vtype(vp) != VREG) 231191783Srmacklem return (0); 232191783Srmacklem mode = 0; 233191783Srmacklem if (amode & FREAD) 234191783Srmacklem mode |= NFSV4OPEN_ACCESSREAD; 235191783Srmacklem if (amode & FWRITE) 236191783Srmacklem mode |= NFSV4OPEN_ACCESSWRITE; 237191783Srmacklem nfhp = np->n_fhp; 238191783Srmacklem 239191783Srmacklem retrycnt = 0; 240191783Srmacklem#ifdef notdef 241191783Srmacklem{ char name[100]; int namel; 242191783Srmacklemnamel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99; 243191783Srmacklembcopy(NFS4NODENAME(np->n_v4), name, namel); 244191783Srmacklemname[namel] = '\0'; 245191783Srmacklemprintf("rpcopen p=0x%x name=%s",p->p_pid,name); 246191783Srmacklemif (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]); 247191783Srmacklemelse printf(" fhl=0\n"); 248191783Srmacklem} 249191783Srmacklem#endif 250191783Srmacklem do { 251191783Srmacklem dp = NULL; 252191783Srmacklem error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, 253191783Srmacklem cred, p, NULL, &op, &newone, &ret, 1); 254191783Srmacklem if (error) { 255191783Srmacklem return (error); 256191783Srmacklem } 257191783Srmacklem if (nmp->nm_clp != NULL) 258191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 259191783Srmacklem else 260191783Srmacklem clidrev = 0; 261191783Srmacklem if (ret == NFSCLOPEN_DOOPEN) { 262191783Srmacklem if (np->n_v4 != NULL) { 263191783Srmacklem error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data, 264191783Srmacklem np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 265191783Srmacklem np->n_fhp->nfh_len, mode, op, 266191783Srmacklem NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, 267191783Srmacklem 0, 0x0, cred, p, 0, 0); 268191783Srmacklem if (dp != NULL) { 269191783Srmacklem#ifdef APPLE 270191783Srmacklem OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); 271191783Srmacklem#else 272191783Srmacklem NFSLOCKNODE(np); 273191783Srmacklem np->n_flag &= ~NDELEGMOD; 274210034Srmacklem /* 275210034Srmacklem * Invalidate the attribute cache, so that 276210034Srmacklem * attributes that pre-date the issue of a 277210034Srmacklem * delegation are not cached, since the 278210034Srmacklem * cached attributes will remain valid while 279210034Srmacklem * the delegation is held. 280210034Srmacklem */ 281210034Srmacklem NFSINVALATTRCACHE(np); 282191783Srmacklem NFSUNLOCKNODE(np); 283191783Srmacklem#endif 284191783Srmacklem (void) nfscl_deleg(nmp->nm_mountp, 285191783Srmacklem op->nfso_own->nfsow_clp, 286191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); 287191783Srmacklem } 288191783Srmacklem } else { 289191783Srmacklem error = EIO; 290191783Srmacklem } 291191783Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 292206688Srmacklem } else if (ret == NFSCLOPEN_SETCRED) 293206688Srmacklem /* 294206688Srmacklem * This is a new local open on a delegation. It needs 295206688Srmacklem * to have credentials so that an open can be done 296206688Srmacklem * against the server during recovery. 297206688Srmacklem */ 298206688Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 299191783Srmacklem 300191783Srmacklem /* 301191783Srmacklem * nfso_opencnt is the count of how many VOP_OPEN()s have 302191783Srmacklem * been done on this Open successfully and a VOP_CLOSE() 303191783Srmacklem * is expected for each of these. 304191783Srmacklem * If error is non-zero, don't increment it, since the Open 305191783Srmacklem * hasn't succeeded yet. 306191783Srmacklem */ 307191783Srmacklem if (!error) 308191783Srmacklem op->nfso_opencnt++; 309191783Srmacklem nfscl_openrelease(op, error, newone); 310191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 311191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) { 312207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_open"); 313191783Srmacklem } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 314191783Srmacklem && clidrev != 0) { 315191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 316191783Srmacklem retrycnt++; 317191783Srmacklem } 318191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 319191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 320191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 321191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 322191783Srmacklem if (error && retrycnt >= 4) 323191783Srmacklem error = EIO; 324191783Srmacklem return (error); 325191783Srmacklem} 326191783Srmacklem 327191783Srmacklem/* 328191783Srmacklem * the actual open rpc 329191783Srmacklem */ 330191783SrmacklemAPPLESTATIC int 331191783Srmacklemnfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, 332191783Srmacklem u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 333191783Srmacklem u_int8_t *name, int namelen, struct nfscldeleg **dpp, 334191783Srmacklem int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, 335191783Srmacklem int syscred, int recursed) 336191783Srmacklem{ 337191783Srmacklem u_int32_t *tl; 338191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 339191783Srmacklem struct nfscldeleg *dp, *ndp = NULL; 340191783Srmacklem struct nfsvattr nfsva; 341191783Srmacklem u_int32_t rflags, deleg; 342191783Srmacklem nfsattrbit_t attrbits; 343191783Srmacklem int error, ret, acesize, limitby; 344191783Srmacklem 345191783Srmacklem dp = *dpp; 346191783Srmacklem *dpp = NULL; 347191783Srmacklem nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL); 348191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 349191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 350191783Srmacklem *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 351191783Srmacklem *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 352191783Srmacklem *tl++ = op->nfso_own->nfsow_clp->nfsc_clientid.lval[0]; 353191783Srmacklem *tl = op->nfso_own->nfsow_clp->nfsc_clientid.lval[1]; 354191783Srmacklem (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 355191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 356191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 357191783Srmacklem if (reclaim) { 358191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); 359191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 360191783Srmacklem *tl = txdr_unsigned(delegtype); 361191783Srmacklem } else { 362191783Srmacklem if (dp != NULL) { 363191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); 364191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 365191783Srmacklem *tl++ = dp->nfsdl_stateid.seqid; 366191783Srmacklem *tl++ = dp->nfsdl_stateid.other[0]; 367191783Srmacklem *tl++ = dp->nfsdl_stateid.other[1]; 368191783Srmacklem *tl = dp->nfsdl_stateid.other[2]; 369191783Srmacklem } else { 370191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 371191783Srmacklem } 372191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 373191783Srmacklem } 374191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 375191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 376191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 377191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 378191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 379191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 380191783Srmacklem if (syscred) 381191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 382191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 383191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 384191783Srmacklem if (error) 385191783Srmacklem return (error); 386191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 387191783Srmacklem if (!nd->nd_repstat) { 388191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 389191783Srmacklem 6 * NFSX_UNSIGNED); 390191783Srmacklem op->nfso_stateid.seqid = *tl++; 391191783Srmacklem op->nfso_stateid.other[0] = *tl++; 392191783Srmacklem op->nfso_stateid.other[1] = *tl++; 393191783Srmacklem op->nfso_stateid.other[2] = *tl; 394191783Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 395191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 396191783Srmacklem if (error) 397191783Srmacklem goto nfsmout; 398191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 399191783Srmacklem deleg = fxdr_unsigned(u_int32_t, *tl); 400191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 401191783Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 402191783Srmacklem if (!(op->nfso_own->nfsow_clp->nfsc_flags & 403191783Srmacklem NFSCLFLAGS_FIRSTDELEG)) 404191783Srmacklem op->nfso_own->nfsow_clp->nfsc_flags |= 405191783Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 406191783Srmacklem MALLOC(ndp, struct nfscldeleg *, 407191783Srmacklem sizeof (struct nfscldeleg) + newfhlen, 408191783Srmacklem M_NFSCLDELEG, M_WAITOK); 409191783Srmacklem LIST_INIT(&ndp->nfsdl_owner); 410191783Srmacklem LIST_INIT(&ndp->nfsdl_lock); 411191783Srmacklem ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 412191783Srmacklem ndp->nfsdl_fhlen = newfhlen; 413191783Srmacklem NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 414191783Srmacklem newnfs_copyincred(cred, &ndp->nfsdl_cred); 415191783Srmacklem nfscl_lockinit(&ndp->nfsdl_rwlock); 416191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 417191783Srmacklem NFSX_UNSIGNED); 418191783Srmacklem ndp->nfsdl_stateid.seqid = *tl++; 419191783Srmacklem ndp->nfsdl_stateid.other[0] = *tl++; 420191783Srmacklem ndp->nfsdl_stateid.other[1] = *tl++; 421191783Srmacklem ndp->nfsdl_stateid.other[2] = *tl++; 422191783Srmacklem ret = fxdr_unsigned(int, *tl); 423191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 424191783Srmacklem ndp->nfsdl_flags = NFSCLDL_WRITE; 425191783Srmacklem /* 426191783Srmacklem * Indicates how much the file can grow. 427191783Srmacklem */ 428191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 429191783Srmacklem 3 * NFSX_UNSIGNED); 430191783Srmacklem limitby = fxdr_unsigned(int, *tl++); 431191783Srmacklem switch (limitby) { 432191783Srmacklem case NFSV4OPEN_LIMITSIZE: 433191783Srmacklem ndp->nfsdl_sizelimit = fxdr_hyper(tl); 434191783Srmacklem break; 435191783Srmacklem case NFSV4OPEN_LIMITBLOCKS: 436191783Srmacklem ndp->nfsdl_sizelimit = 437191783Srmacklem fxdr_unsigned(u_int64_t, *tl++); 438191783Srmacklem ndp->nfsdl_sizelimit *= 439191783Srmacklem fxdr_unsigned(u_int64_t, *tl); 440191783Srmacklem break; 441191783Srmacklem default: 442191783Srmacklem error = NFSERR_BADXDR; 443191783Srmacklem goto nfsmout; 444191783Srmacklem }; 445191783Srmacklem } else { 446191783Srmacklem ndp->nfsdl_flags = NFSCLDL_READ; 447191783Srmacklem } 448191783Srmacklem if (ret) 449191783Srmacklem ndp->nfsdl_flags |= NFSCLDL_RECALL; 450191783Srmacklem error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 451191783Srmacklem &acesize, p); 452191783Srmacklem if (error) 453191783Srmacklem goto nfsmout; 454191783Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 455191783Srmacklem error = NFSERR_BADXDR; 456191783Srmacklem goto nfsmout; 457191783Srmacklem } 458191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 459191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 460191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 461191783Srmacklem NULL, NULL, NULL, p, cred); 462191783Srmacklem if (error) 463191783Srmacklem goto nfsmout; 464191783Srmacklem if (ndp != NULL) { 465191783Srmacklem ndp->nfsdl_change = nfsva.na_filerev; 466191783Srmacklem ndp->nfsdl_modtime = nfsva.na_mtime; 467191783Srmacklem ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 468191783Srmacklem } 469191783Srmacklem if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { 470191783Srmacklem do { 471191783Srmacklem ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, 472191783Srmacklem cred, p); 473191783Srmacklem if (ret == NFSERR_DELAY) 474207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_open"); 475191783Srmacklem } while (ret == NFSERR_DELAY); 476191783Srmacklem error = ret; 477191783Srmacklem } 478191783Srmacklem if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || 479191783Srmacklem nfscl_assumeposixlocks) 480191783Srmacklem op->nfso_posixlock = 1; 481191783Srmacklem else 482191783Srmacklem op->nfso_posixlock = 0; 483191783Srmacklem 484191783Srmacklem /* 485191783Srmacklem * If the server is handing out delegations, but we didn't 486191783Srmacklem * get one because an OpenConfirm was required, try the 487191783Srmacklem * Open again, to get a delegation. This is a harmless no-op, 488191783Srmacklem * from a server's point of view. 489191783Srmacklem */ 490191783Srmacklem if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && 491191783Srmacklem (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) 492191783Srmacklem && !error && dp == NULL && ndp == NULL && !recursed) { 493191783Srmacklem do { 494191783Srmacklem ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, 495191783Srmacklem newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, 496191783Srmacklem cred, p, syscred, 1); 497191783Srmacklem if (ret == NFSERR_DELAY) 498207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_open2"); 499191783Srmacklem } while (ret == NFSERR_DELAY); 500191783Srmacklem if (ret) { 501191783Srmacklem if (ndp != NULL) 502191783Srmacklem FREE((caddr_t)ndp, M_NFSCLDELEG); 503191783Srmacklem if (ret == NFSERR_STALECLIENTID || 504191783Srmacklem ret == NFSERR_STALEDONTRECOVER) 505191783Srmacklem error = ret; 506191783Srmacklem } 507191783Srmacklem } 508191783Srmacklem } 509191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 510191783Srmacklem error = nd->nd_repstat; 511191783Srmacklem if (error == NFSERR_STALECLIENTID) 512191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 513191783Srmacklemnfsmout: 514191783Srmacklem if (!error) 515191783Srmacklem *dpp = ndp; 516191783Srmacklem else if (ndp != NULL) 517191783Srmacklem FREE((caddr_t)ndp, M_NFSCLDELEG); 518191783Srmacklem mbuf_freem(nd->nd_mrep); 519191783Srmacklem return (error); 520191783Srmacklem} 521191783Srmacklem 522191783Srmacklem/* 523191783Srmacklem * open downgrade rpc 524191783Srmacklem */ 525191783SrmacklemAPPLESTATIC int 526191783Srmacklemnfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, 527191783Srmacklem struct ucred *cred, NFSPROC_T *p) 528191783Srmacklem{ 529191783Srmacklem u_int32_t *tl; 530191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 531191783Srmacklem int error; 532191783Srmacklem 533191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp); 534191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 535191783Srmacklem *tl++ = op->nfso_stateid.seqid; 536191783Srmacklem *tl++ = op->nfso_stateid.other[0]; 537191783Srmacklem *tl++ = op->nfso_stateid.other[1]; 538191783Srmacklem *tl++ = op->nfso_stateid.other[2]; 539191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 540191783Srmacklem *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 541191783Srmacklem *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 542191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 543191783Srmacklem if (error) 544191783Srmacklem return (error); 545191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 546191783Srmacklem if (!nd->nd_repstat) { 547191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 548191783Srmacklem op->nfso_stateid.seqid = *tl++; 549191783Srmacklem op->nfso_stateid.other[0] = *tl++; 550191783Srmacklem op->nfso_stateid.other[1] = *tl++; 551191783Srmacklem op->nfso_stateid.other[2] = *tl; 552191783Srmacklem } 553191783Srmacklem if (nd->nd_repstat && error == 0) 554191783Srmacklem error = nd->nd_repstat; 555191783Srmacklem if (error == NFSERR_STALESTATEID) 556191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 557191783Srmacklemnfsmout: 558191783Srmacklem mbuf_freem(nd->nd_mrep); 559191783Srmacklem return (error); 560191783Srmacklem} 561191783Srmacklem 562191783Srmacklem/* 563191783Srmacklem * V4 Close operation. 564191783Srmacklem */ 565191783SrmacklemAPPLESTATIC int 566192337Srmacklemnfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) 567191783Srmacklem{ 568191783Srmacklem struct nfsclclient *clp; 569191783Srmacklem int error; 570191783Srmacklem 571191783Srmacklem if (vnode_vtype(vp) != VREG) 572191783Srmacklem return (0); 573192337Srmacklem if (doclose) 574195510Srmacklem error = nfscl_doclose(vp, &clp, p); 575192337Srmacklem else 576195510Srmacklem error = nfscl_getclose(vp, &clp); 577191783Srmacklem if (error) 578191783Srmacklem return (error); 579191783Srmacklem 580191783Srmacklem nfscl_clientrelease(clp); 581191783Srmacklem return (0); 582191783Srmacklem} 583191783Srmacklem 584191783Srmacklem/* 585195510Srmacklem * Close the open. 586191783Srmacklem */ 587195510SrmacklemAPPLESTATIC void 588195510Srmacklemnfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p) 589191783Srmacklem{ 590191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 591223747Srmacklem struct nfscllockowner *lp, *nlp; 592191783Srmacklem struct nfscllock *lop, *nlop; 593191783Srmacklem struct ucred *tcred; 594191783Srmacklem u_int64_t off = 0, len = 0; 595191783Srmacklem u_int32_t type = NFSV4LOCKT_READ; 596195510Srmacklem int error, do_unlock, trycnt; 597191783Srmacklem 598191783Srmacklem tcred = newnfs_getcred(); 599195510Srmacklem newnfs_copycred(&op->nfso_cred, tcred); 600195510Srmacklem /* 601195510Srmacklem * (Theoretically this could be done in the same 602195510Srmacklem * compound as the close, but having multiple 603195510Srmacklem * sequenced Ops in the same compound might be 604195510Srmacklem * too scary for some servers.) 605195510Srmacklem */ 606195510Srmacklem if (op->nfso_posixlock) { 607195510Srmacklem off = 0; 608195510Srmacklem len = NFS64BITSSET; 609195510Srmacklem type = NFSV4LOCKT_READ; 610195510Srmacklem } 611195510Srmacklem 612195510Srmacklem /* 613195510Srmacklem * Since this function is only called from VOP_INACTIVE(), no 614195510Srmacklem * other thread will be manipulating this Open. As such, the 615195510Srmacklem * lock lists are not being changed by other threads, so it should 616195510Srmacklem * be safe to do this without locking. 617195510Srmacklem */ 618195510Srmacklem LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 619195510Srmacklem do_unlock = 1; 620195510Srmacklem LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 621191783Srmacklem if (op->nfso_posixlock == 0) { 622195510Srmacklem off = lop->nfslo_first; 623195510Srmacklem len = lop->nfslo_end - lop->nfslo_first; 624195510Srmacklem if (lop->nfslo_type == F_WRLCK) 625195510Srmacklem type = NFSV4LOCKT_WRITE; 626195510Srmacklem else 627195510Srmacklem type = NFSV4LOCKT_READ; 628191783Srmacklem } 629195510Srmacklem if (do_unlock) { 630195510Srmacklem trycnt = 0; 631195510Srmacklem do { 632195510Srmacklem error = nfsrpc_locku(nd, nmp, lp, off, 633195510Srmacklem len, type, tcred, p, 0); 634195510Srmacklem if ((nd->nd_repstat == NFSERR_GRACE || 635195510Srmacklem nd->nd_repstat == NFSERR_DELAY) && 636195510Srmacklem error == 0) 637195510Srmacklem (void) nfs_catnap(PZERO, 638207170Srmacklem (int)nd->nd_repstat, 639195510Srmacklem "nfs_close"); 640195510Srmacklem } while ((nd->nd_repstat == NFSERR_GRACE || 641195510Srmacklem nd->nd_repstat == NFSERR_DELAY) && 642195510Srmacklem error == 0 && trycnt++ < 5); 643195510Srmacklem if (op->nfso_posixlock) 644195510Srmacklem do_unlock = 0; 645191783Srmacklem } 646191783Srmacklem nfscl_freelock(lop, 0); 647191783Srmacklem } 648223747Srmacklem /* 649223747Srmacklem * Do a ReleaseLockOwner. 650223747Srmacklem * The lock owner name nfsl_owner may be used by other opens for 651223747Srmacklem * other files but the lock_owner4 name that nfsrpc_rellockown() 652223747Srmacklem * puts on the wire has the file handle for this file appended 653223747Srmacklem * to it, so it can be done now. 654223747Srmacklem */ 655229674Srmacklem (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh, 656229674Srmacklem lp->nfsl_open->nfso_fhlen, tcred, p); 657195510Srmacklem } 658191783Srmacklem 659195510Srmacklem /* 660195510Srmacklem * There could be other Opens for different files on the same 661195510Srmacklem * OpenOwner, so locking is required. 662195510Srmacklem */ 663195510Srmacklem NFSLOCKCLSTATE(); 664195510Srmacklem nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 665195510Srmacklem NFSUNLOCKCLSTATE(); 666195510Srmacklem do { 667195510Srmacklem error = nfscl_tryclose(op, tcred, nmp, p); 668195510Srmacklem if (error == NFSERR_GRACE) 669207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_close"); 670195510Srmacklem } while (error == NFSERR_GRACE); 671195510Srmacklem NFSLOCKCLSTATE(); 672195510Srmacklem nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); 673195510Srmacklem 674223747Srmacklem LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) 675223747Srmacklem nfscl_freelockowner(lp, 0); 676195510Srmacklem nfscl_freeopen(op, 0); 677195510Srmacklem NFSUNLOCKCLSTATE(); 678191783Srmacklem NFSFREECRED(tcred); 679191783Srmacklem} 680191783Srmacklem 681191783Srmacklem/* 682191783Srmacklem * The actual Close RPC. 683191783Srmacklem */ 684191783SrmacklemAPPLESTATIC int 685191783Srmacklemnfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp, 686191783Srmacklem struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p, 687191783Srmacklem int syscred) 688191783Srmacklem{ 689191783Srmacklem u_int32_t *tl; 690191783Srmacklem int error; 691191783Srmacklem 692191783Srmacklem nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh, 693191783Srmacklem op->nfso_fhlen, NULL); 694191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 695191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 696191783Srmacklem *tl++ = op->nfso_stateid.seqid; 697191783Srmacklem *tl++ = op->nfso_stateid.other[0]; 698191783Srmacklem *tl++ = op->nfso_stateid.other[1]; 699191783Srmacklem *tl = op->nfso_stateid.other[2]; 700191783Srmacklem if (syscred) 701191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 702191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 703191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 704191783Srmacklem if (error) 705191783Srmacklem return (error); 706191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 707191783Srmacklem if (nd->nd_repstat == 0) 708191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 709191783Srmacklem error = nd->nd_repstat; 710191783Srmacklem if (error == NFSERR_STALESTATEID) 711191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 712191783Srmacklemnfsmout: 713191783Srmacklem mbuf_freem(nd->nd_mrep); 714191783Srmacklem return (error); 715191783Srmacklem} 716191783Srmacklem 717191783Srmacklem/* 718191783Srmacklem * V4 Open Confirm RPC. 719191783Srmacklem */ 720191783SrmacklemAPPLESTATIC int 721191783Srmacklemnfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen, 722191783Srmacklem struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) 723191783Srmacklem{ 724191783Srmacklem u_int32_t *tl; 725191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 726191783Srmacklem int error; 727191783Srmacklem 728191783Srmacklem nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, VFSTONFS(vnode_mount(vp)), 729191783Srmacklem nfhp, fhlen, NULL); 730191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 731191783Srmacklem *tl++ = op->nfso_stateid.seqid; 732191783Srmacklem *tl++ = op->nfso_stateid.other[0]; 733191783Srmacklem *tl++ = op->nfso_stateid.other[1]; 734191783Srmacklem *tl++ = op->nfso_stateid.other[2]; 735191783Srmacklem *tl = txdr_unsigned(op->nfso_own->nfsow_seqid); 736191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 737191783Srmacklem if (error) 738191783Srmacklem return (error); 739191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 740191783Srmacklem if (!nd->nd_repstat) { 741191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 742191783Srmacklem op->nfso_stateid.seqid = *tl++; 743191783Srmacklem op->nfso_stateid.other[0] = *tl++; 744191783Srmacklem op->nfso_stateid.other[1] = *tl++; 745191783Srmacklem op->nfso_stateid.other[2] = *tl; 746191783Srmacklem } 747191783Srmacklem error = nd->nd_repstat; 748191783Srmacklem if (error == NFSERR_STALESTATEID) 749191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 750191783Srmacklemnfsmout: 751191783Srmacklem mbuf_freem(nd->nd_mrep); 752191783Srmacklem return (error); 753191783Srmacklem} 754191783Srmacklem 755191783Srmacklem/* 756191783Srmacklem * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs() 757191783Srmacklem * when a mount has just occurred and when the server replies NFSERR_EXPIRED. 758191783Srmacklem */ 759191783SrmacklemAPPLESTATIC int 760191783Srmacklemnfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, 761191783Srmacklem struct ucred *cred, NFSPROC_T *p) 762191783Srmacklem{ 763191783Srmacklem u_int32_t *tl; 764191783Srmacklem struct nfsrv_descript nfsd; 765191783Srmacklem struct nfsrv_descript *nd = &nfsd; 766191783Srmacklem nfsattrbit_t attrbits; 767191783Srmacklem u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9]; 768191783Srmacklem u_short port; 769195825Srmacklem int error, isinet6 = 0, callblen; 770191783Srmacklem nfsquad_t confirm; 771191783Srmacklem u_int32_t lease; 772191783Srmacklem static u_int32_t rev = 0; 773191783Srmacklem 774191783Srmacklem if (nfsboottime.tv_sec == 0) 775191783Srmacklem NFSSETBOOTTIME(nfsboottime); 776191783Srmacklem nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL); 777191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 778191783Srmacklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 779191783Srmacklem *tl = txdr_unsigned(rev++); 780191783Srmacklem (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 781191783Srmacklem 782191783Srmacklem /* 783191783Srmacklem * set up the callback address 784191783Srmacklem */ 785191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 786191783Srmacklem *tl = txdr_unsigned(NFS_CALLBCKPROG); 787191783Srmacklem callblen = strlen(nfsv4_callbackaddr); 788191783Srmacklem if (callblen == 0) 789191783Srmacklem cp = nfscl_getmyip(nmp, &isinet6); 790191783Srmacklem if (nfscl_enablecallb && nfs_numnfscbd > 0 && 791191783Srmacklem (callblen > 0 || cp != NULL)) { 792191783Srmacklem port = htons(nfsv4_cbport); 793191783Srmacklem cp2 = (u_int8_t *)&port; 794191783Srmacklem#ifdef INET6 795191783Srmacklem if ((callblen > 0 && 796191783Srmacklem strchr(nfsv4_callbackaddr, ':')) || isinet6) { 797191783Srmacklem char ip6buf[INET6_ADDRSTRLEN], *ip6add; 798191783Srmacklem 799191783Srmacklem (void) nfsm_strtom(nd, "tcp6", 4); 800191783Srmacklem if (callblen == 0) { 801191783Srmacklem ip6_sprintf(ip6buf, (struct in6_addr *)cp); 802191783Srmacklem ip6add = ip6buf; 803191783Srmacklem } else { 804191783Srmacklem ip6add = nfsv4_callbackaddr; 805191783Srmacklem } 806191783Srmacklem snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", 807191783Srmacklem ip6add, cp2[0], cp2[1]); 808191783Srmacklem } else 809191783Srmacklem#endif 810191783Srmacklem { 811191783Srmacklem (void) nfsm_strtom(nd, "tcp", 3); 812191783Srmacklem if (callblen == 0) 813191783Srmacklem snprintf(addr, INET6_ADDRSTRLEN + 9, 814191783Srmacklem "%d.%d.%d.%d.%d.%d", cp[0], cp[1], 815191783Srmacklem cp[2], cp[3], cp2[0], cp2[1]); 816191783Srmacklem else 817191783Srmacklem snprintf(addr, INET6_ADDRSTRLEN + 9, 818191783Srmacklem "%s.%d.%d", nfsv4_callbackaddr, 819191783Srmacklem cp2[0], cp2[1]); 820191783Srmacklem } 821191783Srmacklem (void) nfsm_strtom(nd, addr, strlen(addr)); 822191783Srmacklem } else { 823191783Srmacklem (void) nfsm_strtom(nd, "tcp", 3); 824191783Srmacklem (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11); 825191783Srmacklem } 826191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 827191783Srmacklem *tl = txdr_unsigned(clp->nfsc_cbident); 828191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 829191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 830191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 831191783Srmacklem if (error) 832191783Srmacklem return (error); 833191783Srmacklem if (nd->nd_repstat == 0) { 834191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 835191783Srmacklem clp->nfsc_clientid.lval[0] = *tl++; 836191783Srmacklem clp->nfsc_clientid.lval[1] = *tl++; 837191783Srmacklem confirm.lval[0] = *tl++; 838191783Srmacklem confirm.lval[1] = *tl; 839191783Srmacklem mbuf_freem(nd->nd_mrep); 840191783Srmacklem nd->nd_mrep = NULL; 841191783Srmacklem 842191783Srmacklem /* 843191783Srmacklem * and confirm it. 844191783Srmacklem */ 845191783Srmacklem nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL); 846191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 847191783Srmacklem *tl++ = clp->nfsc_clientid.lval[0]; 848191783Srmacklem *tl++ = clp->nfsc_clientid.lval[1]; 849191783Srmacklem *tl++ = confirm.lval[0]; 850191783Srmacklem *tl = confirm.lval[1]; 851191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 852191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 853191783Srmacklem cred, NFS_PROG, NFS_VER4, NULL, 1, NULL); 854191783Srmacklem if (error) 855191783Srmacklem return (error); 856191783Srmacklem mbuf_freem(nd->nd_mrep); 857191783Srmacklem nd->nd_mrep = NULL; 858191783Srmacklem if (nd->nd_repstat == 0) { 859191783Srmacklem nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh, 860191783Srmacklem nmp->nm_fhsize, NULL); 861191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 862191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 863191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 864191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 865191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 866191783Srmacklem cred, NFS_PROG, NFS_VER4, NULL, 1, NULL); 867191783Srmacklem if (error) 868191783Srmacklem return (error); 869191783Srmacklem if (nd->nd_repstat == 0) { 870191783Srmacklem error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL, 871191783Srmacklem NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred); 872191783Srmacklem if (error) 873191783Srmacklem goto nfsmout; 874191783Srmacklem clp->nfsc_renew = NFSCL_RENEW(lease); 875191783Srmacklem clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 876191783Srmacklem clp->nfsc_clientidrev++; 877191783Srmacklem if (clp->nfsc_clientidrev == 0) 878191783Srmacklem clp->nfsc_clientidrev++; 879191783Srmacklem } 880191783Srmacklem } 881191783Srmacklem } 882191783Srmacklem error = nd->nd_repstat; 883191783Srmacklemnfsmout: 884191783Srmacklem mbuf_freem(nd->nd_mrep); 885191783Srmacklem return (error); 886191783Srmacklem} 887191783Srmacklem 888191783Srmacklem/* 889191783Srmacklem * nfs getattr call. 890191783Srmacklem */ 891191783SrmacklemAPPLESTATIC int 892191783Srmacklemnfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 893191783Srmacklem struct nfsvattr *nap, void *stuff) 894191783Srmacklem{ 895191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 896191783Srmacklem int error; 897191783Srmacklem nfsattrbit_t attrbits; 898191783Srmacklem 899191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 900191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 901191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 902191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 903191783Srmacklem } 904191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 905191783Srmacklem if (error) 906191783Srmacklem return (error); 907191783Srmacklem if (!nd->nd_repstat) 908191783Srmacklem error = nfsm_loadattr(nd, nap); 909191783Srmacklem else 910191783Srmacklem error = nd->nd_repstat; 911191783Srmacklem mbuf_freem(nd->nd_mrep); 912191783Srmacklem return (error); 913191783Srmacklem} 914191783Srmacklem 915191783Srmacklem/* 916191783Srmacklem * nfs getattr call with non-vnode arguemnts. 917191783Srmacklem */ 918191783SrmacklemAPPLESTATIC int 919191783Srmacklemnfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, 920191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp) 921191783Srmacklem{ 922191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 923191783Srmacklem int error, vers = NFS_VER2; 924191783Srmacklem nfsattrbit_t attrbits; 925191783Srmacklem 926191783Srmacklem nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL); 927191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 928191783Srmacklem vers = NFS_VER4; 929191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 930191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 931191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 932191783Srmacklem vers = NFS_VER3; 933191783Srmacklem } 934191783Srmacklem if (syscred) 935191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 936191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 937191783Srmacklem NFS_PROG, vers, NULL, 1, xidp); 938191783Srmacklem if (error) 939191783Srmacklem return (error); 940191783Srmacklem if (!nd->nd_repstat) 941191783Srmacklem error = nfsm_loadattr(nd, nap); 942191783Srmacklem else 943191783Srmacklem error = nd->nd_repstat; 944191783Srmacklem mbuf_freem(nd->nd_mrep); 945191783Srmacklem return (error); 946191783Srmacklem} 947191783Srmacklem 948191783Srmacklem/* 949191783Srmacklem * Do an nfs setattr operation. 950191783Srmacklem */ 951191783SrmacklemAPPLESTATIC int 952191783Srmacklemnfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, 953191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp, 954191783Srmacklem void *stuff) 955191783Srmacklem{ 956191783Srmacklem int error, expireret = 0, openerr, retrycnt; 957191783Srmacklem u_int32_t clidrev = 0, mode; 958191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 959191783Srmacklem struct nfsfh *nfhp; 960191783Srmacklem nfsv4stateid_t stateid; 961191783Srmacklem void *lckp; 962191783Srmacklem 963191783Srmacklem if (nmp->nm_clp != NULL) 964191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 965191783Srmacklem if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size)) 966191783Srmacklem mode = NFSV4OPEN_ACCESSWRITE; 967191783Srmacklem else 968191783Srmacklem mode = NFSV4OPEN_ACCESSREAD; 969191783Srmacklem retrycnt = 0; 970191783Srmacklem do { 971191783Srmacklem lckp = NULL; 972191783Srmacklem openerr = 1; 973191783Srmacklem if (NFSHASNFSV4(nmp)) { 974191783Srmacklem nfhp = VTONFS(vp)->n_fhp; 975191783Srmacklem error = nfscl_getstateid(vp, nfhp->nfh_fh, 976191783Srmacklem nfhp->nfh_len, mode, cred, p, &stateid, &lckp); 977191783Srmacklem if (error && vnode_vtype(vp) == VREG && 978191783Srmacklem (mode == NFSV4OPEN_ACCESSWRITE || 979191783Srmacklem nfstest_openallsetattr)) { 980191783Srmacklem /* 981191783Srmacklem * No Open stateid, so try and open the file 982191783Srmacklem * now. 983191783Srmacklem */ 984191783Srmacklem if (mode == NFSV4OPEN_ACCESSWRITE) 985191783Srmacklem openerr = nfsrpc_open(vp, FWRITE, cred, 986191783Srmacklem p); 987191783Srmacklem else 988191783Srmacklem openerr = nfsrpc_open(vp, FREAD, cred, 989191783Srmacklem p); 990191783Srmacklem if (!openerr) 991191783Srmacklem (void) nfscl_getstateid(vp, 992191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, 993191783Srmacklem mode, cred, p, &stateid, &lckp); 994191783Srmacklem } 995191783Srmacklem } 996191783Srmacklem if (vap != NULL) 997191783Srmacklem error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p, 998191783Srmacklem rnap, attrflagp, stuff); 999191783Srmacklem else 1000191783Srmacklem error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid, 1001191783Srmacklem stuff); 1002191783Srmacklem if (error == NFSERR_STALESTATEID) 1003191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1004191783Srmacklem if (lckp != NULL) 1005191783Srmacklem nfscl_lockderef(lckp); 1006191783Srmacklem if (!openerr) 1007192337Srmacklem (void) nfsrpc_close(vp, 0, p); 1008191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1009191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1010191783Srmacklem error == NFSERR_OLDSTATEID) { 1011207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_setattr"); 1012191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1013191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1014191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1015191783Srmacklem } 1016191783Srmacklem retrycnt++; 1017191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1018191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1019191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1020191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1021191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1022191783Srmacklem if (error && retrycnt >= 4) 1023191783Srmacklem error = EIO; 1024191783Srmacklem return (error); 1025191783Srmacklem} 1026191783Srmacklem 1027191783Srmacklemstatic int 1028191783Srmacklemnfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, 1029191783Srmacklem nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 1030191783Srmacklem struct nfsvattr *rnap, int *attrflagp, void *stuff) 1031191783Srmacklem{ 1032191783Srmacklem u_int32_t *tl; 1033191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1034191783Srmacklem int error; 1035191783Srmacklem nfsattrbit_t attrbits; 1036191783Srmacklem 1037191783Srmacklem *attrflagp = 0; 1038191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp); 1039191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1040191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1041191783Srmacklem vap->va_type = vnode_vtype(vp); 1042191783Srmacklem nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0); 1043191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1044191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1045191783Srmacklem *tl = newnfs_false; 1046191783Srmacklem } else if (nd->nd_flag & ND_NFSV4) { 1047191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1048191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1049191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1050191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1051191783Srmacklem } 1052191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1053191783Srmacklem if (error) 1054191783Srmacklem return (error); 1055191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1056191783Srmacklem error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff); 1057191783Srmacklem if ((nd->nd_flag & ND_NFSV4) && !error) 1058191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1059191783Srmacklem if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error) 1060191783Srmacklem error = nfscl_postop_attr(nd, rnap, attrflagp, stuff); 1061191783Srmacklem mbuf_freem(nd->nd_mrep); 1062191783Srmacklem if (nd->nd_repstat && !error) 1063191783Srmacklem error = nd->nd_repstat; 1064191783Srmacklem return (error); 1065191783Srmacklem} 1066191783Srmacklem 1067191783Srmacklem/* 1068191783Srmacklem * nfs lookup rpc 1069191783Srmacklem */ 1070191783SrmacklemAPPLESTATIC int 1071191783Srmacklemnfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, 1072191783Srmacklem NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, 1073191783Srmacklem struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff) 1074191783Srmacklem{ 1075191783Srmacklem u_int32_t *tl; 1076191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1077191783Srmacklem struct nfsmount *nmp; 1078191783Srmacklem struct nfsnode *np; 1079191783Srmacklem struct nfsfh *nfhp; 1080191783Srmacklem nfsattrbit_t attrbits; 1081191783Srmacklem int error = 0, lookupp = 0; 1082191783Srmacklem 1083191783Srmacklem *attrflagp = 0; 1084191783Srmacklem *dattrflagp = 0; 1085191783Srmacklem if (vnode_vtype(dvp) != VDIR) 1086191783Srmacklem return (ENOTDIR); 1087191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 1088191783Srmacklem if (len > NFS_MAXNAMLEN) 1089191783Srmacklem return (ENAMETOOLONG); 1090191783Srmacklem if (NFSHASNFSV4(nmp) && len == 1 && 1091191783Srmacklem name[0] == '.') { 1092191783Srmacklem /* 1093191783Srmacklem * Just return the current dir's fh. 1094191783Srmacklem */ 1095191783Srmacklem np = VTONFS(dvp); 1096191783Srmacklem MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1097191783Srmacklem np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1098191783Srmacklem nfhp->nfh_len = np->n_fhp->nfh_len; 1099191783Srmacklem NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1100191783Srmacklem *nfhpp = nfhp; 1101191783Srmacklem return (0); 1102191783Srmacklem } 1103191783Srmacklem if (NFSHASNFSV4(nmp) && len == 2 && 1104191783Srmacklem name[0] == '.' && name[1] == '.') { 1105191783Srmacklem lookupp = 1; 1106191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp); 1107191783Srmacklem } else { 1108191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp); 1109191783Srmacklem (void) nfsm_strtom(nd, name, len); 1110191783Srmacklem } 1111191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1112191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1113191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1114191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1115191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1116191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1117191783Srmacklem } 1118191783Srmacklem error = nfscl_request(nd, dvp, p, cred, stuff); 1119191783Srmacklem if (error) 1120191783Srmacklem return (error); 1121191783Srmacklem if (nd->nd_repstat) { 1122191783Srmacklem /* 1123191783Srmacklem * When an NFSv4 Lookupp returns ENOENT, it means that 1124191783Srmacklem * the lookup is at the root of an fs, so return this dir. 1125191783Srmacklem */ 1126191783Srmacklem if (nd->nd_repstat == NFSERR_NOENT && lookupp) { 1127191783Srmacklem np = VTONFS(dvp); 1128191783Srmacklem MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1129191783Srmacklem np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1130191783Srmacklem nfhp->nfh_len = np->n_fhp->nfh_len; 1131191783Srmacklem NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1132191783Srmacklem *nfhpp = nfhp; 1133191783Srmacklem mbuf_freem(nd->nd_mrep); 1134191783Srmacklem return (0); 1135191783Srmacklem } 1136191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1137191783Srmacklem error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1138265339Srmacklem else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 1139265339Srmacklem ND_NFSV4) { 1140265339Srmacklem /* Load the directory attributes. */ 1141265339Srmacklem error = nfsm_loadattr(nd, dnap); 1142265339Srmacklem if (error == 0) 1143265339Srmacklem *dattrflagp = 1; 1144265339Srmacklem } 1145191783Srmacklem goto nfsmout; 1146191783Srmacklem } 1147191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 1148265339Srmacklem /* Load the directory attributes. */ 1149265339Srmacklem error = nfsm_loadattr(nd, dnap); 1150265339Srmacklem if (error != 0) 1151191783Srmacklem goto nfsmout; 1152265339Srmacklem *dattrflagp = 1; 1153265339Srmacklem /* Skip over the Lookup and GetFH operation status values. */ 1154265339Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1155191783Srmacklem } 1156191783Srmacklem error = nfsm_getfh(nd, nfhpp); 1157191783Srmacklem if (error) 1158191783Srmacklem goto nfsmout; 1159191783Srmacklem 1160191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1161191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) 1162191783Srmacklem error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1163191783Srmacklemnfsmout: 1164191783Srmacklem mbuf_freem(nd->nd_mrep); 1165191783Srmacklem if (!error && nd->nd_repstat) 1166191783Srmacklem error = nd->nd_repstat; 1167191783Srmacklem return (error); 1168191783Srmacklem} 1169191783Srmacklem 1170191783Srmacklem/* 1171191783Srmacklem * Do a readlink rpc. 1172191783Srmacklem */ 1173191783SrmacklemAPPLESTATIC int 1174191783Srmacklemnfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, 1175191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1176191783Srmacklem{ 1177191783Srmacklem u_int32_t *tl; 1178191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1179191783Srmacklem struct nfsnode *np = VTONFS(vp); 1180191783Srmacklem nfsattrbit_t attrbits; 1181191783Srmacklem int error, len, cangetattr = 1; 1182191783Srmacklem 1183191783Srmacklem *attrflagp = 0; 1184191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READLINK, vp); 1185191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1186191783Srmacklem /* 1187191783Srmacklem * And do a Getattr op. 1188191783Srmacklem */ 1189191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1190191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1191191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1192191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1193191783Srmacklem } 1194191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1195191783Srmacklem if (error) 1196191783Srmacklem return (error); 1197191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1198191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1199191783Srmacklem if (!nd->nd_repstat && !error) { 1200191783Srmacklem NFSM_STRSIZ(len, NFS_MAXPATHLEN); 1201191783Srmacklem /* 1202191783Srmacklem * This seems weird to me, but must have been added to 1203191783Srmacklem * FreeBSD for some reason. The only thing I can think of 1204191783Srmacklem * is that there was/is some server that replies with 1205191783Srmacklem * more link data than it should? 1206191783Srmacklem */ 1207191783Srmacklem if (len == NFS_MAXPATHLEN) { 1208191783Srmacklem NFSLOCKNODE(np); 1209191783Srmacklem if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { 1210191783Srmacklem len = np->n_size; 1211191783Srmacklem cangetattr = 0; 1212191783Srmacklem } 1213191783Srmacklem NFSUNLOCKNODE(np); 1214191783Srmacklem } 1215191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 1216191783Srmacklem if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) 1217191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1218191783Srmacklem } 1219191783Srmacklem if (nd->nd_repstat && !error) 1220191783Srmacklem error = nd->nd_repstat; 1221191783Srmacklemnfsmout: 1222191783Srmacklem mbuf_freem(nd->nd_mrep); 1223191783Srmacklem return (error); 1224191783Srmacklem} 1225191783Srmacklem 1226191783Srmacklem/* 1227191783Srmacklem * Read operation. 1228191783Srmacklem */ 1229191783SrmacklemAPPLESTATIC int 1230191783Srmacklemnfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, 1231191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1232191783Srmacklem{ 1233191783Srmacklem int error, expireret = 0, retrycnt; 1234191783Srmacklem u_int32_t clidrev = 0; 1235191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1236191783Srmacklem struct nfsnode *np = VTONFS(vp); 1237191783Srmacklem struct ucred *newcred; 1238191783Srmacklem struct nfsfh *nfhp = NULL; 1239191783Srmacklem nfsv4stateid_t stateid; 1240191783Srmacklem void *lckp; 1241191783Srmacklem 1242191783Srmacklem if (nmp->nm_clp != NULL) 1243191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1244191783Srmacklem newcred = cred; 1245191783Srmacklem if (NFSHASNFSV4(nmp)) { 1246191783Srmacklem nfhp = np->n_fhp; 1247229953Srmacklem newcred = NFSNEWCRED(cred); 1248191783Srmacklem } 1249191783Srmacklem retrycnt = 0; 1250191783Srmacklem do { 1251191783Srmacklem lckp = NULL; 1252191783Srmacklem if (NFSHASNFSV4(nmp)) 1253191783Srmacklem (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1254191783Srmacklem NFSV4OPEN_ACCESSREAD, newcred, p, &stateid, &lckp); 1255191783Srmacklem error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, 1256191783Srmacklem attrflagp, stuff); 1257191783Srmacklem if (error == NFSERR_STALESTATEID) 1258191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1259191783Srmacklem if (lckp != NULL) 1260191783Srmacklem nfscl_lockderef(lckp); 1261191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1262191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1263191783Srmacklem error == NFSERR_OLDSTATEID) { 1264207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_read"); 1265191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1266191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1267191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1268191783Srmacklem } 1269191783Srmacklem retrycnt++; 1270191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1271191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1272191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1273191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1274191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1275191783Srmacklem if (error && retrycnt >= 4) 1276191783Srmacklem error = EIO; 1277229953Srmacklem if (NFSHASNFSV4(nmp)) 1278191783Srmacklem NFSFREECRED(newcred); 1279191783Srmacklem return (error); 1280191783Srmacklem} 1281191783Srmacklem 1282191783Srmacklem/* 1283191783Srmacklem * The actual read RPC. 1284191783Srmacklem */ 1285191783Srmacklemstatic int 1286191783Srmacklemnfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, 1287191783Srmacklem nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, 1288191783Srmacklem int *attrflagp, void *stuff) 1289191783Srmacklem{ 1290191783Srmacklem u_int32_t *tl; 1291191783Srmacklem int error = 0, len, retlen, tsiz, eof = 0; 1292191783Srmacklem struct nfsrv_descript nfsd; 1293191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1294191783Srmacklem struct nfsrv_descript *nd = &nfsd; 1295220810Srmacklem int rsize; 1296220876Srmacklem off_t tmp_off; 1297191783Srmacklem 1298191783Srmacklem *attrflagp = 0; 1299191783Srmacklem tsiz = uio_uio_resid(uiop); 1300220876Srmacklem tmp_off = uiop->uio_offset + tsiz; 1301220810Srmacklem NFSLOCKMNT(nmp); 1302220876Srmacklem if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1303220810Srmacklem NFSUNLOCKMNT(nmp); 1304191783Srmacklem return (EFBIG); 1305220810Srmacklem } 1306220810Srmacklem rsize = nmp->nm_rsize; 1307220810Srmacklem NFSUNLOCKMNT(nmp); 1308191783Srmacklem nd->nd_mrep = NULL; 1309191783Srmacklem while (tsiz > 0) { 1310191783Srmacklem *attrflagp = 0; 1311220810Srmacklem len = (tsiz > rsize) ? rsize : tsiz; 1312191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READ, vp); 1313191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1314191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1315191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1316191783Srmacklem if (nd->nd_flag & ND_NFSV2) { 1317191783Srmacklem *tl++ = txdr_unsigned(uiop->uio_offset); 1318191783Srmacklem *tl++ = txdr_unsigned(len); 1319191783Srmacklem *tl = 0; 1320191783Srmacklem } else { 1321191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1322191783Srmacklem *(tl + 2) = txdr_unsigned(len); 1323191783Srmacklem } 1324191783Srmacklem /* 1325191783Srmacklem * Since I can't do a Getattr for NFSv4 for Write, there 1326191783Srmacklem * doesn't seem any point in doing one here, either. 1327191783Srmacklem * (See the comment in nfsrpc_writerpc() for more info.) 1328191783Srmacklem */ 1329191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1330191783Srmacklem if (error) 1331191783Srmacklem return (error); 1332191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1333191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1334191783Srmacklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { 1335191783Srmacklem error = nfsm_loadattr(nd, nap); 1336191783Srmacklem if (!error) 1337191783Srmacklem *attrflagp = 1; 1338191783Srmacklem } 1339191783Srmacklem if (nd->nd_repstat || error) { 1340191783Srmacklem if (!error) 1341191783Srmacklem error = nd->nd_repstat; 1342191783Srmacklem goto nfsmout; 1343191783Srmacklem } 1344191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1345191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1346191783Srmacklem eof = fxdr_unsigned(int, *(tl + 1)); 1347191783Srmacklem } else if (nd->nd_flag & ND_NFSV4) { 1348191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1349191783Srmacklem eof = fxdr_unsigned(int, *tl); 1350191783Srmacklem } 1351246285Skib NFSM_STRSIZ(retlen, len); 1352191783Srmacklem error = nfsm_mbufuio(nd, uiop, retlen); 1353191783Srmacklem if (error) 1354191783Srmacklem goto nfsmout; 1355191783Srmacklem mbuf_freem(nd->nd_mrep); 1356191783Srmacklem nd->nd_mrep = NULL; 1357191783Srmacklem tsiz -= retlen; 1358191783Srmacklem if (!(nd->nd_flag & ND_NFSV2)) { 1359191783Srmacklem if (eof || retlen == 0) 1360191783Srmacklem tsiz = 0; 1361191783Srmacklem } else if (retlen < len) 1362191783Srmacklem tsiz = 0; 1363191783Srmacklem } 1364191783Srmacklem return (0); 1365191783Srmacklemnfsmout: 1366191783Srmacklem if (nd->nd_mrep != NULL) 1367191783Srmacklem mbuf_freem(nd->nd_mrep); 1368191783Srmacklem return (error); 1369191783Srmacklem} 1370191783Srmacklem 1371191783Srmacklem/* 1372191783Srmacklem * nfs write operation 1373207082Srmacklem * When called_from_strategy != 0, it should return EIO for an error that 1374207082Srmacklem * indicates recovery is in progress, so that the buffer will be left 1375207082Srmacklem * dirty and be written back to the server later. If it loops around, 1376207082Srmacklem * the recovery thread could get stuck waiting for the buffer and recovery 1377207082Srmacklem * will then deadlock. 1378191783Srmacklem */ 1379191783SrmacklemAPPLESTATIC int 1380222289Srmacklemnfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 1381191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 1382207082Srmacklem void *stuff, int called_from_strategy) 1383191783Srmacklem{ 1384191783Srmacklem int error, expireret = 0, retrycnt, nostateid; 1385191783Srmacklem u_int32_t clidrev = 0; 1386191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1387191783Srmacklem struct nfsnode *np = VTONFS(vp); 1388191783Srmacklem struct ucred *newcred; 1389191783Srmacklem struct nfsfh *nfhp = NULL; 1390191783Srmacklem nfsv4stateid_t stateid; 1391191783Srmacklem void *lckp; 1392191783Srmacklem 1393222289Srmacklem *must_commit = 0; 1394191783Srmacklem if (nmp->nm_clp != NULL) 1395191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1396191783Srmacklem newcred = cred; 1397191783Srmacklem if (NFSHASNFSV4(nmp)) { 1398229953Srmacklem newcred = NFSNEWCRED(cred); 1399191783Srmacklem nfhp = np->n_fhp; 1400191783Srmacklem } 1401191783Srmacklem retrycnt = 0; 1402191783Srmacklem do { 1403191783Srmacklem lckp = NULL; 1404191783Srmacklem nostateid = 0; 1405191783Srmacklem if (NFSHASNFSV4(nmp)) { 1406191783Srmacklem (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1407191783Srmacklem NFSV4OPEN_ACCESSWRITE, newcred, p, &stateid, &lckp); 1408191783Srmacklem if (stateid.other[0] == 0 && stateid.other[1] == 0 && 1409191783Srmacklem stateid.other[2] == 0) { 1410191783Srmacklem nostateid = 1; 1411240977Srmacklem NFSCL_DEBUG(1, "stateid0 in write\n"); 1412191783Srmacklem } 1413191783Srmacklem } 1414191783Srmacklem 1415191783Srmacklem /* 1416191783Srmacklem * If there is no stateid for NFSv4, it means this is an 1417191783Srmacklem * extraneous write after close. Basically a poorly 1418191783Srmacklem * implemented buffer cache. Just don't do the write. 1419191783Srmacklem */ 1420191783Srmacklem if (nostateid) 1421191783Srmacklem error = 0; 1422191783Srmacklem else 1423222289Srmacklem error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, 1424191783Srmacklem newcred, &stateid, p, nap, attrflagp, stuff); 1425191783Srmacklem if (error == NFSERR_STALESTATEID) 1426191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1427191783Srmacklem if (lckp != NULL) 1428191783Srmacklem nfscl_lockderef(lckp); 1429191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1430191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1431191783Srmacklem error == NFSERR_OLDSTATEID) { 1432207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_write"); 1433191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1434191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1435191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1436191783Srmacklem } 1437191783Srmacklem retrycnt++; 1438207082Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 1439207082Srmacklem ((error == NFSERR_STALESTATEID || 1440207082Srmacklem error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || 1441191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1442191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1443191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1444207082Srmacklem if (error != 0 && (retrycnt >= 4 || 1445207082Srmacklem ((error == NFSERR_STALESTATEID || 1446207082Srmacklem error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0))) 1447191783Srmacklem error = EIO; 1448229953Srmacklem if (NFSHASNFSV4(nmp)) 1449191783Srmacklem NFSFREECRED(newcred); 1450191783Srmacklem return (error); 1451191783Srmacklem} 1452191783Srmacklem 1453191783Srmacklem/* 1454191783Srmacklem * The actual write RPC. 1455191783Srmacklem */ 1456191783Srmacklemstatic int 1457191783Srmacklemnfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, 1458222289Srmacklem int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, 1459191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1460191783Srmacklem{ 1461191783Srmacklem u_int32_t *tl; 1462191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1463191783Srmacklem struct nfsnode *np = VTONFS(vp); 1464191783Srmacklem int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; 1465191783Srmacklem int wccflag = 0, wsize; 1466191783Srmacklem int32_t backup; 1467191783Srmacklem struct nfsrv_descript nfsd; 1468191783Srmacklem struct nfsrv_descript *nd = &nfsd; 1469191783Srmacklem nfsattrbit_t attrbits; 1470220876Srmacklem off_t tmp_off; 1471191783Srmacklem 1472209120Skib KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 1473191783Srmacklem *attrflagp = 0; 1474191783Srmacklem tsiz = uio_uio_resid(uiop); 1475220876Srmacklem tmp_off = uiop->uio_offset + tsiz; 1476191783Srmacklem NFSLOCKMNT(nmp); 1477220876Srmacklem if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1478191783Srmacklem NFSUNLOCKMNT(nmp); 1479191783Srmacklem return (EFBIG); 1480191783Srmacklem } 1481191783Srmacklem wsize = nmp->nm_wsize; 1482191783Srmacklem NFSUNLOCKMNT(nmp); 1483191783Srmacklem nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ 1484191783Srmacklem nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ 1485191783Srmacklem while (tsiz > 0) { 1486191783Srmacklem *attrflagp = 0; 1487191783Srmacklem len = (tsiz > wsize) ? wsize : tsiz; 1488191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); 1489191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1490191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1491191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); 1492191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1493191783Srmacklem tl += 2; 1494191783Srmacklem *tl++ = txdr_unsigned(*iomode); 1495191783Srmacklem *tl = txdr_unsigned(len); 1496191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 1497191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); 1498191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1499191783Srmacklem tl += 2; 1500191783Srmacklem *tl++ = txdr_unsigned(len); 1501191783Srmacklem *tl++ = txdr_unsigned(*iomode); 1502191783Srmacklem *tl = txdr_unsigned(len); 1503191783Srmacklem } else { 1504191783Srmacklem u_int32_t x; 1505191783Srmacklem 1506191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1507191783Srmacklem /* 1508191783Srmacklem * Not sure why someone changed this, since the 1509191783Srmacklem * RFC clearly states that "beginoffset" and 1510191783Srmacklem * "totalcount" are ignored, but it wouldn't 1511191783Srmacklem * surprise me if there's a busted server out there. 1512191783Srmacklem */ 1513191783Srmacklem /* Set both "begin" and "current" to non-garbage. */ 1514191783Srmacklem x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1515191783Srmacklem *tl++ = x; /* "begin offset" */ 1516191783Srmacklem *tl++ = x; /* "current offset" */ 1517191783Srmacklem x = txdr_unsigned(len); 1518191783Srmacklem *tl++ = x; /* total to this offset */ 1519191783Srmacklem *tl = x; /* size of this write */ 1520191783Srmacklem 1521191783Srmacklem } 1522191783Srmacklem nfsm_uiombuf(nd, uiop, len); 1523191783Srmacklem /* 1524191783Srmacklem * Although it is tempting to do a normal Getattr Op in the 1525191783Srmacklem * NFSv4 compound, the result can be a nearly hung client 1526191783Srmacklem * system if the Getattr asks for Owner and/or OwnerGroup. 1527191783Srmacklem * It occurs when the client can't map either the Owner or 1528191783Srmacklem * Owner_group name in the Getattr reply to a uid/gid. When 1529191783Srmacklem * there is a cache miss, the kernel does an upcall to the 1530191783Srmacklem * nfsuserd. Then, it can try and read the local /etc/passwd 1531191783Srmacklem * or /etc/group file. It can then block in getnewbuf(), 1532191783Srmacklem * waiting for dirty writes to be pushed to the NFS server. 1533191783Srmacklem * The only reason this doesn't result in a complete 1534191783Srmacklem * deadlock, is that the upcall times out and allows 1535191783Srmacklem * the write to complete. However, progress is so slow 1536191783Srmacklem * that it might just as well be deadlocked. 1537223657Srmacklem * As such, we get the rest of the attributes, but not 1538223657Srmacklem * Owner or Owner_group. 1539191783Srmacklem * nb: nfscl_loadattrcache() needs to be told that these 1540191783Srmacklem * partial attributes from a write rpc are being 1541191783Srmacklem * passed in, via a argument flag. 1542191783Srmacklem */ 1543191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1544191783Srmacklem NFSWRITEGETATTR_ATTRBIT(&attrbits); 1545191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1546191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1547191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1548191783Srmacklem } 1549191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1550191783Srmacklem if (error) 1551191783Srmacklem return (error); 1552191783Srmacklem if (nd->nd_repstat) { 1553191783Srmacklem /* 1554191783Srmacklem * In case the rpc gets retried, roll 1555191783Srmacklem * the uio fileds changed by nfsm_uiombuf() 1556191783Srmacklem * back. 1557191783Srmacklem */ 1558191783Srmacklem uiop->uio_offset -= len; 1559191783Srmacklem uio_uio_resid_add(uiop, len); 1560191783Srmacklem uio_iov_base_add(uiop, -len); 1561191783Srmacklem uio_iov_len_add(uiop, len); 1562191783Srmacklem } 1563191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1564191783Srmacklem error = nfscl_wcc_data(nd, vp, nap, attrflagp, 1565191783Srmacklem &wccflag, stuff); 1566191783Srmacklem if (error) 1567191783Srmacklem goto nfsmout; 1568191783Srmacklem } 1569191783Srmacklem if (!nd->nd_repstat) { 1570191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1571191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1572191783Srmacklem + NFSX_VERF); 1573191783Srmacklem rlen = fxdr_unsigned(int, *tl++); 1574191783Srmacklem if (rlen == 0) { 1575191783Srmacklem error = NFSERR_IO; 1576191783Srmacklem goto nfsmout; 1577191783Srmacklem } else if (rlen < len) { 1578191783Srmacklem backup = len - rlen; 1579191783Srmacklem uio_iov_base_add(uiop, -(backup)); 1580191783Srmacklem uio_iov_len_add(uiop, backup); 1581191783Srmacklem uiop->uio_offset -= backup; 1582191783Srmacklem uio_uio_resid_add(uiop, backup); 1583191783Srmacklem len = rlen; 1584191783Srmacklem } 1585191783Srmacklem commit = fxdr_unsigned(int, *tl++); 1586191783Srmacklem 1587191783Srmacklem /* 1588191783Srmacklem * Return the lowest committment level 1589191783Srmacklem * obtained by any of the RPCs. 1590191783Srmacklem */ 1591191783Srmacklem if (committed == NFSWRITE_FILESYNC) 1592191783Srmacklem committed = commit; 1593191783Srmacklem else if (committed == NFSWRITE_DATASYNC && 1594191783Srmacklem commit == NFSWRITE_UNSTABLE) 1595191783Srmacklem committed = commit; 1596191783Srmacklem NFSLOCKMNT(nmp); 1597191783Srmacklem if (!NFSHASWRITEVERF(nmp)) { 1598191783Srmacklem NFSBCOPY((caddr_t)tl, 1599191783Srmacklem (caddr_t)&nmp->nm_verf[0], 1600191783Srmacklem NFSX_VERF); 1601191783Srmacklem NFSSETWRITEVERF(nmp); 1602222289Srmacklem } else if (NFSBCMP(tl, nmp->nm_verf, 1603222289Srmacklem NFSX_VERF)) { 1604222289Srmacklem *must_commit = 1; 1605222289Srmacklem NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 1606191783Srmacklem } 1607191783Srmacklem NFSUNLOCKMNT(nmp); 1608191783Srmacklem } 1609191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1610191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1611191783Srmacklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 1612191783Srmacklem error = nfsm_loadattr(nd, nap); 1613191783Srmacklem if (!error) 1614191783Srmacklem *attrflagp = NFS_LATTR_NOSHRINK; 1615191783Srmacklem } 1616191783Srmacklem } else { 1617191783Srmacklem error = nd->nd_repstat; 1618191783Srmacklem } 1619191783Srmacklem if (error) 1620191783Srmacklem goto nfsmout; 1621191783Srmacklem NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4)); 1622191783Srmacklem mbuf_freem(nd->nd_mrep); 1623191783Srmacklem nd->nd_mrep = NULL; 1624191783Srmacklem tsiz -= len; 1625191783Srmacklem } 1626191783Srmacklemnfsmout: 1627191783Srmacklem if (nd->nd_mrep != NULL) 1628191783Srmacklem mbuf_freem(nd->nd_mrep); 1629191783Srmacklem *iomode = committed; 1630191783Srmacklem if (nd->nd_repstat && !error) 1631191783Srmacklem error = nd->nd_repstat; 1632191783Srmacklem return (error); 1633191783Srmacklem} 1634191783Srmacklem 1635191783Srmacklem/* 1636191783Srmacklem * nfs mknod rpc 1637191783Srmacklem * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1638191783Srmacklem * mode set to specify the file type and the size field for rdev. 1639191783Srmacklem */ 1640191783SrmacklemAPPLESTATIC int 1641191783Srmacklemnfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1642191783Srmacklem u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p, 1643191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1644191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1645191783Srmacklem{ 1646191783Srmacklem u_int32_t *tl; 1647191783Srmacklem int error = 0; 1648191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1649191783Srmacklem nfsattrbit_t attrbits; 1650191783Srmacklem 1651191783Srmacklem *nfhpp = NULL; 1652191783Srmacklem *attrflagp = 0; 1653191783Srmacklem *dattrflagp = 0; 1654191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1655191783Srmacklem return (ENAMETOOLONG); 1656191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp); 1657191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1658201345Srmacklem if (vtyp == VBLK || vtyp == VCHR) { 1659201345Srmacklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1660201345Srmacklem *tl++ = vtonfsv34_type(vtyp); 1661201345Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1662201345Srmacklem *tl = txdr_unsigned(NFSMINOR(rdev)); 1663201345Srmacklem } else { 1664201345Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1665201345Srmacklem *tl = vtonfsv34_type(vtyp); 1666201345Srmacklem } 1667191783Srmacklem } 1668191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1669191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1670191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1671191783Srmacklem *tl = vtonfsv34_type(vtyp); 1672191783Srmacklem } 1673191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1674191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 1675191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && 1676191783Srmacklem (vtyp == VCHR || vtyp == VBLK)) { 1677191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1678191783Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1679191783Srmacklem *tl = txdr_unsigned(NFSMINOR(rdev)); 1680191783Srmacklem } 1681191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1682191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1683191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1684191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1685191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1686191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1687191783Srmacklem } 1688191783Srmacklem if (nd->nd_flag & ND_NFSV2) 1689191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 1690191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 1691191783Srmacklem if (error) 1692191783Srmacklem return (error); 1693191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1694191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1695191783Srmacklem if (!nd->nd_repstat) { 1696191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1697191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1698191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1699191783Srmacklem if (error) 1700191783Srmacklem goto nfsmout; 1701191783Srmacklem } 1702191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1703191783Srmacklem if (error) 1704191783Srmacklem goto nfsmout; 1705191783Srmacklem } 1706191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1707191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1708191783Srmacklem if (!error && nd->nd_repstat) 1709191783Srmacklem error = nd->nd_repstat; 1710191783Srmacklemnfsmout: 1711191783Srmacklem mbuf_freem(nd->nd_mrep); 1712191783Srmacklem return (error); 1713191783Srmacklem} 1714191783Srmacklem 1715191783Srmacklem/* 1716191783Srmacklem * nfs file create call 1717191783Srmacklem * Mostly just call the approriate routine. (I separated out v4, so that 1718191783Srmacklem * error recovery wouldn't be as difficult.) 1719191783Srmacklem */ 1720191783SrmacklemAPPLESTATIC int 1721191783Srmacklemnfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1722191783Srmacklem nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1723191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1724191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1725191783Srmacklem{ 1726191783Srmacklem int error = 0, newone, expireret = 0, retrycnt, unlocked; 1727191783Srmacklem struct nfsclowner *owp; 1728191783Srmacklem struct nfscldeleg *dp; 1729191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp)); 1730191783Srmacklem u_int32_t clidrev; 1731191783Srmacklem 1732191783Srmacklem if (NFSHASNFSV4(nmp)) { 1733191783Srmacklem retrycnt = 0; 1734191783Srmacklem do { 1735191783Srmacklem dp = NULL; 1736191783Srmacklem error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 1737191783Srmacklem NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 1738191783Srmacklem NULL, 1); 1739191783Srmacklem if (error) 1740191783Srmacklem return (error); 1741191783Srmacklem if (nmp->nm_clp != NULL) 1742191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1743191783Srmacklem else 1744191783Srmacklem clidrev = 0; 1745191783Srmacklem error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode, 1746191783Srmacklem owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1747191783Srmacklem dstuff, &unlocked); 1748210034Srmacklem /* 1749210034Srmacklem * There is no need to invalidate cached attributes here, 1750210034Srmacklem * since new post-delegation issue attributes are always 1751210034Srmacklem * returned by nfsrpc_createv4() and these will update the 1752210034Srmacklem * attribute cache. 1753210034Srmacklem */ 1754191783Srmacklem if (dp != NULL) 1755191783Srmacklem (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 1756191783Srmacklem (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 1757191783Srmacklem nfscl_ownerrelease(owp, error, newone, unlocked); 1758191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1759191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) { 1760207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_open"); 1761191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1762191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1763191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1764191783Srmacklem retrycnt++; 1765191783Srmacklem } 1766191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1767191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1768191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1769191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1770191783Srmacklem if (error && retrycnt >= 4) 1771191783Srmacklem error = EIO; 1772191783Srmacklem } else { 1773191783Srmacklem error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 1774191783Srmacklem fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1775191783Srmacklem dstuff); 1776191783Srmacklem } 1777191783Srmacklem return (error); 1778191783Srmacklem} 1779191783Srmacklem 1780191783Srmacklem/* 1781191783Srmacklem * The create rpc for v2 and 3. 1782191783Srmacklem */ 1783191783Srmacklemstatic int 1784191783Srmacklemnfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1785191783Srmacklem nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1786191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1787191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1788191783Srmacklem{ 1789191783Srmacklem u_int32_t *tl; 1790191783Srmacklem int error = 0; 1791191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1792191783Srmacklem 1793191783Srmacklem *nfhpp = NULL; 1794191783Srmacklem *attrflagp = 0; 1795191783Srmacklem *dattrflagp = 0; 1796191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1797191783Srmacklem return (ENAMETOOLONG); 1798191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1799191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1800191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1801191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1802191783Srmacklem if (fmode & O_EXCL) { 1803191783Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 1804191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1805191783Srmacklem *tl++ = cverf.lval[0]; 1806191783Srmacklem *tl = cverf.lval[1]; 1807191783Srmacklem } else { 1808191783Srmacklem *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 1809191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 1810191783Srmacklem } 1811191783Srmacklem } else { 1812191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 1813191783Srmacklem } 1814191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 1815191783Srmacklem if (error) 1816191783Srmacklem return (error); 1817191783Srmacklem if (nd->nd_repstat == 0) { 1818191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1819191783Srmacklem if (error) 1820191783Srmacklem goto nfsmout; 1821191783Srmacklem } 1822191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1823191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1824191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 1825191783Srmacklem error = nd->nd_repstat; 1826191783Srmacklemnfsmout: 1827191783Srmacklem mbuf_freem(nd->nd_mrep); 1828191783Srmacklem return (error); 1829191783Srmacklem} 1830191783Srmacklem 1831191783Srmacklemstatic int 1832191783Srmacklemnfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1833191783Srmacklem nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 1834191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 1835191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 1836191783Srmacklem int *dattrflagp, void *dstuff, int *unlockedp) 1837191783Srmacklem{ 1838191783Srmacklem u_int32_t *tl; 1839191783Srmacklem int error = 0, deleg, newone, ret, acesize, limitby; 1840191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1841191783Srmacklem struct nfsclopen *op; 1842191783Srmacklem struct nfscldeleg *dp = NULL; 1843191783Srmacklem struct nfsnode *np; 1844191783Srmacklem struct nfsfh *nfhp; 1845191783Srmacklem nfsattrbit_t attrbits; 1846191783Srmacklem nfsv4stateid_t stateid; 1847191783Srmacklem u_int32_t rflags; 1848191783Srmacklem 1849265340Srmacklem np = VTONFS(dvp); 1850191783Srmacklem *unlockedp = 0; 1851191783Srmacklem *nfhpp = NULL; 1852191783Srmacklem *dpp = NULL; 1853191783Srmacklem *attrflagp = 0; 1854191783Srmacklem *dattrflagp = 0; 1855191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1856191783Srmacklem return (ENAMETOOLONG); 1857191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1858191783Srmacklem /* 1859191783Srmacklem * For V4, this is actually an Open op. 1860191783Srmacklem */ 1861191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1862191783Srmacklem *tl++ = txdr_unsigned(owp->nfsow_seqid); 1863191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 1864191783Srmacklem NFSV4OPEN_ACCESSREAD); 1865191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 1866191783Srmacklem *tl++ = owp->nfsow_clp->nfsc_clientid.lval[0]; 1867191783Srmacklem *tl = owp->nfsow_clp->nfsc_clientid.lval[1]; 1868191783Srmacklem (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 1869191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1870191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 1871191783Srmacklem if (fmode & O_EXCL) { 1872191783Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 1873191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1874191783Srmacklem *tl++ = cverf.lval[0]; 1875191783Srmacklem *tl = cverf.lval[1]; 1876191783Srmacklem } else { 1877191783Srmacklem *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 1878191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 1879191783Srmacklem } 1880191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1881191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 1882191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1883265340Srmacklem /* Get the new file's handle and attributes. */ 1884191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1885191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1886191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1887191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1888191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1889265340Srmacklem /* Get the directory's post-op attributes. */ 1890265340Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1891265340Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 1892265340Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 1893265340Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1894265340Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1895265340Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1896191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 1897191783Srmacklem if (error) 1898191783Srmacklem return (error); 1899191783Srmacklem NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 1900191783Srmacklem if (nd->nd_repstat == 0) { 1901191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 1902191783Srmacklem 6 * NFSX_UNSIGNED); 1903191783Srmacklem stateid.seqid = *tl++; 1904191783Srmacklem stateid.other[0] = *tl++; 1905191783Srmacklem stateid.other[1] = *tl++; 1906191783Srmacklem stateid.other[2] = *tl; 1907191783Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 1908191783Srmacklem (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1909191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1910191783Srmacklem deleg = fxdr_unsigned(int, *tl); 1911191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 1912191783Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 1913191783Srmacklem if (!(owp->nfsow_clp->nfsc_flags & 1914191783Srmacklem NFSCLFLAGS_FIRSTDELEG)) 1915191783Srmacklem owp->nfsow_clp->nfsc_flags |= 1916191783Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 1917191783Srmacklem MALLOC(dp, struct nfscldeleg *, 1918191783Srmacklem sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 1919191783Srmacklem M_NFSCLDELEG, M_WAITOK); 1920191783Srmacklem LIST_INIT(&dp->nfsdl_owner); 1921191783Srmacklem LIST_INIT(&dp->nfsdl_lock); 1922191783Srmacklem dp->nfsdl_clp = owp->nfsow_clp; 1923191783Srmacklem newnfs_copyincred(cred, &dp->nfsdl_cred); 1924191783Srmacklem nfscl_lockinit(&dp->nfsdl_rwlock); 1925191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 1926191783Srmacklem NFSX_UNSIGNED); 1927191783Srmacklem dp->nfsdl_stateid.seqid = *tl++; 1928191783Srmacklem dp->nfsdl_stateid.other[0] = *tl++; 1929191783Srmacklem dp->nfsdl_stateid.other[1] = *tl++; 1930191783Srmacklem dp->nfsdl_stateid.other[2] = *tl++; 1931191783Srmacklem ret = fxdr_unsigned(int, *tl); 1932191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 1933191783Srmacklem dp->nfsdl_flags = NFSCLDL_WRITE; 1934191783Srmacklem /* 1935191783Srmacklem * Indicates how much the file can grow. 1936191783Srmacklem */ 1937191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 1938191783Srmacklem 3 * NFSX_UNSIGNED); 1939191783Srmacklem limitby = fxdr_unsigned(int, *tl++); 1940191783Srmacklem switch (limitby) { 1941191783Srmacklem case NFSV4OPEN_LIMITSIZE: 1942191783Srmacklem dp->nfsdl_sizelimit = fxdr_hyper(tl); 1943191783Srmacklem break; 1944191783Srmacklem case NFSV4OPEN_LIMITBLOCKS: 1945191783Srmacklem dp->nfsdl_sizelimit = 1946191783Srmacklem fxdr_unsigned(u_int64_t, *tl++); 1947191783Srmacklem dp->nfsdl_sizelimit *= 1948191783Srmacklem fxdr_unsigned(u_int64_t, *tl); 1949191783Srmacklem break; 1950191783Srmacklem default: 1951191783Srmacklem error = NFSERR_BADXDR; 1952191783Srmacklem goto nfsmout; 1953191783Srmacklem }; 1954191783Srmacklem } else { 1955191783Srmacklem dp->nfsdl_flags = NFSCLDL_READ; 1956191783Srmacklem } 1957191783Srmacklem if (ret) 1958191783Srmacklem dp->nfsdl_flags |= NFSCLDL_RECALL; 1959191783Srmacklem error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 1960191783Srmacklem &acesize, p); 1961191783Srmacklem if (error) 1962191783Srmacklem goto nfsmout; 1963191783Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 1964191783Srmacklem error = NFSERR_BADXDR; 1965191783Srmacklem goto nfsmout; 1966191783Srmacklem } 1967191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1968191783Srmacklem if (error) 1969191783Srmacklem goto nfsmout; 1970265340Srmacklem /* Get rid of the PutFH and Getattr status values. */ 1971265340Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1972265340Srmacklem /* Load the directory attributes. */ 1973265340Srmacklem error = nfsm_loadattr(nd, dnap); 1974265340Srmacklem if (error) 1975265340Srmacklem goto nfsmout; 1976265340Srmacklem *dattrflagp = 1; 1977191783Srmacklem if (dp != NULL && *attrflagp) { 1978191783Srmacklem dp->nfsdl_change = nnap->na_filerev; 1979191783Srmacklem dp->nfsdl_modtime = nnap->na_mtime; 1980191783Srmacklem dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 1981191783Srmacklem } 1982191783Srmacklem /* 1983191783Srmacklem * We can now complete the Open state. 1984191783Srmacklem */ 1985191783Srmacklem nfhp = *nfhpp; 1986191783Srmacklem if (dp != NULL) { 1987191783Srmacklem dp->nfsdl_fhlen = nfhp->nfh_len; 1988191783Srmacklem NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 1989191783Srmacklem } 1990191783Srmacklem /* 1991191783Srmacklem * Get an Open structure that will be 1992191783Srmacklem * attached to the OpenOwner, acquired already. 1993191783Srmacklem */ 1994191783Srmacklem error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 1995191783Srmacklem (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 1996191783Srmacklem cred, p, NULL, &op, &newone, NULL, 0); 1997191783Srmacklem if (error) 1998191783Srmacklem goto nfsmout; 1999191783Srmacklem op->nfso_stateid = stateid; 2000191783Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 2001191783Srmacklem if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 2002191783Srmacklem do { 2003191783Srmacklem ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 2004191783Srmacklem nfhp->nfh_len, op, cred, p); 2005191783Srmacklem if (ret == NFSERR_DELAY) 2006207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_create"); 2007191783Srmacklem } while (ret == NFSERR_DELAY); 2008191783Srmacklem error = ret; 2009191783Srmacklem } 2010191783Srmacklem 2011191783Srmacklem /* 2012191783Srmacklem * If the server is handing out delegations, but we didn't 2013191783Srmacklem * get one because an OpenConfirm was required, try the 2014191783Srmacklem * Open again, to get a delegation. This is a harmless no-op, 2015191783Srmacklem * from a server's point of view. 2016191783Srmacklem */ 2017191783Srmacklem if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 2018191783Srmacklem (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 2019191783Srmacklem !error && dp == NULL) { 2020191783Srmacklem do { 2021191783Srmacklem ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp, 2022191783Srmacklem np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 2023191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, 2024191783Srmacklem (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2025191783Srmacklem name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2026191783Srmacklem if (ret == NFSERR_DELAY) 2027207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2028191783Srmacklem } while (ret == NFSERR_DELAY); 2029191783Srmacklem if (ret) { 2030191783Srmacklem if (dp != NULL) 2031191783Srmacklem FREE((caddr_t)dp, M_NFSCLDELEG); 2032191783Srmacklem if (ret == NFSERR_STALECLIENTID || 2033191783Srmacklem ret == NFSERR_STALEDONTRECOVER) 2034191783Srmacklem error = ret; 2035191783Srmacklem } 2036191783Srmacklem } 2037191783Srmacklem nfscl_openrelease(op, error, newone); 2038191783Srmacklem *unlockedp = 1; 2039191783Srmacklem } 2040191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 2041191783Srmacklem error = nd->nd_repstat; 2042191783Srmacklem if (error == NFSERR_STALECLIENTID) 2043191783Srmacklem nfscl_initiate_recovery(owp->nfsow_clp); 2044191783Srmacklemnfsmout: 2045191783Srmacklem if (!error) 2046191783Srmacklem *dpp = dp; 2047191783Srmacklem else if (dp != NULL) 2048191783Srmacklem FREE((caddr_t)dp, M_NFSCLDELEG); 2049191783Srmacklem mbuf_freem(nd->nd_mrep); 2050191783Srmacklem return (error); 2051191783Srmacklem} 2052191783Srmacklem 2053191783Srmacklem/* 2054191783Srmacklem * Nfs remove rpc 2055191783Srmacklem */ 2056191783SrmacklemAPPLESTATIC int 2057191783Srmacklemnfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2058191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, 2059191783Srmacklem void *dstuff) 2060191783Srmacklem{ 2061191783Srmacklem u_int32_t *tl; 2062191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2063191783Srmacklem struct nfsnode *np; 2064191783Srmacklem struct nfsmount *nmp; 2065191783Srmacklem nfsv4stateid_t dstateid; 2066191783Srmacklem int error, ret = 0, i; 2067191783Srmacklem 2068191783Srmacklem *dattrflagp = 0; 2069191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2070191783Srmacklem return (ENAMETOOLONG); 2071191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 2072191783Srmacklemtryagain: 2073191783Srmacklem if (NFSHASNFSV4(nmp) && ret == 0) { 2074191783Srmacklem ret = nfscl_removedeleg(vp, p, &dstateid); 2075191783Srmacklem if (ret == 1) { 2076191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp); 2077191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2078191783Srmacklem NFSX_UNSIGNED); 2079191783Srmacklem *tl++ = dstateid.seqid; 2080191783Srmacklem *tl++ = dstateid.other[0]; 2081191783Srmacklem *tl++ = dstateid.other[1]; 2082191783Srmacklem *tl++ = dstateid.other[2]; 2083191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2084191783Srmacklem np = VTONFS(dvp); 2085191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2086191783Srmacklem np->n_fhp->nfh_len, 0); 2087191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2088191783Srmacklem *tl = txdr_unsigned(NFSV4OP_REMOVE); 2089191783Srmacklem } 2090191783Srmacklem } else { 2091191783Srmacklem ret = 0; 2092191783Srmacklem } 2093191783Srmacklem if (ret == 0) 2094191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp); 2095191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2096191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2097191783Srmacklem if (error) 2098191783Srmacklem return (error); 2099191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2100191783Srmacklem /* For NFSv4, parse out any Delereturn replies. */ 2101191783Srmacklem if (ret > 0 && nd->nd_repstat != 0 && 2102191783Srmacklem (nd->nd_flag & ND_NOMOREDATA)) { 2103191783Srmacklem /* 2104191783Srmacklem * If the Delegreturn failed, try again without 2105191783Srmacklem * it. The server will Recall, as required. 2106191783Srmacklem */ 2107191783Srmacklem mbuf_freem(nd->nd_mrep); 2108191783Srmacklem goto tryagain; 2109191783Srmacklem } 2110191783Srmacklem for (i = 0; i < (ret * 2); i++) { 2111191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2112191783Srmacklem ND_NFSV4) { 2113191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2114191783Srmacklem if (*(tl + 1)) 2115191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2116191783Srmacklem } 2117191783Srmacklem } 2118191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2119191783Srmacklem } 2120191783Srmacklem if (nd->nd_repstat && !error) 2121191783Srmacklem error = nd->nd_repstat; 2122191783Srmacklemnfsmout: 2123191783Srmacklem mbuf_freem(nd->nd_mrep); 2124191783Srmacklem return (error); 2125191783Srmacklem} 2126191783Srmacklem 2127191783Srmacklem/* 2128191783Srmacklem * Do an nfs rename rpc. 2129191783Srmacklem */ 2130191783SrmacklemAPPLESTATIC int 2131191783Srmacklemnfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2132191783Srmacklem vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2133191783Srmacklem NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2134191783Srmacklem int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff) 2135191783Srmacklem{ 2136191783Srmacklem u_int32_t *tl; 2137191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2138191783Srmacklem struct nfsmount *nmp; 2139191783Srmacklem struct nfsnode *np; 2140191783Srmacklem nfsattrbit_t attrbits; 2141191783Srmacklem nfsv4stateid_t fdstateid, tdstateid; 2142191783Srmacklem int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2143191783Srmacklem 2144191783Srmacklem *fattrflagp = 0; 2145191783Srmacklem *tattrflagp = 0; 2146191783Srmacklem nmp = VFSTONFS(vnode_mount(fdvp)); 2147191783Srmacklem if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2148191783Srmacklem return (ENAMETOOLONG); 2149191783Srmacklemtryagain: 2150191783Srmacklem if (NFSHASNFSV4(nmp) && ret == 0) { 2151191783Srmacklem ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2152191783Srmacklem &tdstateid, &gottd, p); 2153191783Srmacklem if (gotfd && gottd) { 2154191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp); 2155191783Srmacklem } else if (gotfd) { 2156191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp); 2157191783Srmacklem } else if (gottd) { 2158191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp); 2159191783Srmacklem } 2160191783Srmacklem if (gotfd) { 2161191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2162191783Srmacklem *tl++ = fdstateid.seqid; 2163191783Srmacklem *tl++ = fdstateid.other[0]; 2164191783Srmacklem *tl++ = fdstateid.other[1]; 2165191783Srmacklem *tl = fdstateid.other[2]; 2166191783Srmacklem if (gottd) { 2167191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2168191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2169191783Srmacklem np = VTONFS(tvp); 2170191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2171191783Srmacklem np->n_fhp->nfh_len, 0); 2172191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2173191783Srmacklem *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2174191783Srmacklem } 2175191783Srmacklem } 2176191783Srmacklem if (gottd) { 2177191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2178191783Srmacklem *tl++ = tdstateid.seqid; 2179191783Srmacklem *tl++ = tdstateid.other[0]; 2180191783Srmacklem *tl++ = tdstateid.other[1]; 2181191783Srmacklem *tl = tdstateid.other[2]; 2182191783Srmacklem } 2183191783Srmacklem if (ret > 0) { 2184191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2185191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2186191783Srmacklem np = VTONFS(fdvp); 2187191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2188191783Srmacklem np->n_fhp->nfh_len, 0); 2189191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2190191783Srmacklem *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2191191783Srmacklem } 2192191783Srmacklem } else { 2193191783Srmacklem ret = 0; 2194191783Srmacklem } 2195191783Srmacklem if (ret == 0) 2196191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp); 2197191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2198191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2199191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2200191783Srmacklem NFSWCCATTR_ATTRBIT(&attrbits); 2201191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2202191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2203191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2204191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2205191783Srmacklem VTONFS(tdvp)->n_fhp->nfh_len, 0); 2206191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2207191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2208191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2209191783Srmacklem nd->nd_flag |= ND_V4WCCATTR; 2210191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2211191783Srmacklem *tl = txdr_unsigned(NFSV4OP_RENAME); 2212191783Srmacklem } 2213191783Srmacklem (void) nfsm_strtom(nd, fnameptr, fnamelen); 2214191783Srmacklem if (!(nd->nd_flag & ND_NFSV4)) 2215191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2216191783Srmacklem VTONFS(tdvp)->n_fhp->nfh_len, 0); 2217191783Srmacklem (void) nfsm_strtom(nd, tnameptr, tnamelen); 2218191783Srmacklem error = nfscl_request(nd, fdvp, p, cred, fstuff); 2219191783Srmacklem if (error) 2220191783Srmacklem return (error); 2221191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2222191783Srmacklem /* For NFSv4, parse out any Delereturn replies. */ 2223191783Srmacklem if (ret > 0 && nd->nd_repstat != 0 && 2224191783Srmacklem (nd->nd_flag & ND_NOMOREDATA)) { 2225191783Srmacklem /* 2226191783Srmacklem * If the Delegreturn failed, try again without 2227191783Srmacklem * it. The server will Recall, as required. 2228191783Srmacklem */ 2229191783Srmacklem mbuf_freem(nd->nd_mrep); 2230191783Srmacklem goto tryagain; 2231191783Srmacklem } 2232191783Srmacklem for (i = 0; i < (ret * 2); i++) { 2233191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2234191783Srmacklem ND_NFSV4) { 2235191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2236191783Srmacklem if (*(tl + 1)) { 2237191783Srmacklem if (i == 0 && ret > 1) { 2238191783Srmacklem /* 2239191783Srmacklem * If the Delegreturn failed, try again 2240191783Srmacklem * without it. The server will Recall, as 2241191783Srmacklem * required. 2242191783Srmacklem * If ret > 1, the first iteration of this 2243191783Srmacklem * loop is the second DelegReturn result. 2244191783Srmacklem */ 2245191783Srmacklem mbuf_freem(nd->nd_mrep); 2246191783Srmacklem goto tryagain; 2247191783Srmacklem } else { 2248191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2249191783Srmacklem } 2250191783Srmacklem } 2251191783Srmacklem } 2252191783Srmacklem } 2253191783Srmacklem /* Now, the first wcc attribute reply. */ 2254191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2255191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2256191783Srmacklem if (*(tl + 1)) 2257191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2258191783Srmacklem } 2259191783Srmacklem error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, 2260191783Srmacklem fstuff); 2261191783Srmacklem /* and the second wcc attribute reply. */ 2262191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2263191783Srmacklem !error) { 2264191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2265191783Srmacklem if (*(tl + 1)) 2266191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2267191783Srmacklem } 2268191783Srmacklem if (!error) 2269191783Srmacklem error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2270191783Srmacklem NULL, tstuff); 2271191783Srmacklem } 2272191783Srmacklem if (nd->nd_repstat && !error) 2273191783Srmacklem error = nd->nd_repstat; 2274191783Srmacklemnfsmout: 2275191783Srmacklem mbuf_freem(nd->nd_mrep); 2276191783Srmacklem return (error); 2277191783Srmacklem} 2278191783Srmacklem 2279191783Srmacklem/* 2280191783Srmacklem * nfs hard link create rpc 2281191783Srmacklem */ 2282191783SrmacklemAPPLESTATIC int 2283191783Srmacklemnfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2284191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2285191783Srmacklem struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2286191783Srmacklem{ 2287191783Srmacklem u_int32_t *tl; 2288191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2289191783Srmacklem nfsattrbit_t attrbits; 2290191783Srmacklem int error = 0; 2291191783Srmacklem 2292191783Srmacklem *attrflagp = 0; 2293191783Srmacklem *dattrflagp = 0; 2294191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2295191783Srmacklem return (ENAMETOOLONG); 2296191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2297191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2298191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2299191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2300191783Srmacklem } 2301191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2302191783Srmacklem VTONFS(dvp)->n_fhp->nfh_len, 0); 2303191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2304191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2305191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2306191783Srmacklem NFSWCCATTR_ATTRBIT(&attrbits); 2307191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2308191783Srmacklem nd->nd_flag |= ND_V4WCCATTR; 2309191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2310191783Srmacklem *tl = txdr_unsigned(NFSV4OP_LINK); 2311191783Srmacklem } 2312191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2313191783Srmacklem error = nfscl_request(nd, vp, p, cred, dstuff); 2314191783Srmacklem if (error) 2315191783Srmacklem return (error); 2316191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 2317191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2318191783Srmacklem if (!error) 2319191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2320191783Srmacklem NULL, dstuff); 2321191783Srmacklem } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2322191783Srmacklem /* 2323191783Srmacklem * First, parse out the PutFH and Getattr result. 2324191783Srmacklem */ 2325191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2326191783Srmacklem if (!(*(tl + 1))) 2327191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2328191783Srmacklem if (*(tl + 1)) 2329191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2330191783Srmacklem /* 2331191783Srmacklem * Get the pre-op attributes. 2332191783Srmacklem */ 2333191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2334191783Srmacklem } 2335191783Srmacklem if (nd->nd_repstat && !error) 2336191783Srmacklem error = nd->nd_repstat; 2337191783Srmacklemnfsmout: 2338191783Srmacklem mbuf_freem(nd->nd_mrep); 2339191783Srmacklem return (error); 2340191783Srmacklem} 2341191783Srmacklem 2342191783Srmacklem/* 2343191783Srmacklem * nfs symbolic link create rpc 2344191783Srmacklem */ 2345191783SrmacklemAPPLESTATIC int 2346191783Srmacklemnfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target, 2347191783Srmacklem struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2348191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2349191783Srmacklem int *dattrflagp, void *dstuff) 2350191783Srmacklem{ 2351191783Srmacklem u_int32_t *tl; 2352191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2353191783Srmacklem struct nfsmount *nmp; 2354191783Srmacklem int slen, error = 0; 2355191783Srmacklem 2356191783Srmacklem *nfhpp = NULL; 2357191783Srmacklem *attrflagp = 0; 2358191783Srmacklem *dattrflagp = 0; 2359191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 2360191783Srmacklem slen = strlen(target); 2361191783Srmacklem if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2362191783Srmacklem return (ENAMETOOLONG); 2363191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2364191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2365191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2366191783Srmacklem *tl = txdr_unsigned(NFLNK); 2367191783Srmacklem (void) nfsm_strtom(nd, target, slen); 2368191783Srmacklem } 2369191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2370191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2371191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 2372191783Srmacklem if (!(nd->nd_flag & ND_NFSV4)) 2373191783Srmacklem (void) nfsm_strtom(nd, target, slen); 2374191783Srmacklem if (nd->nd_flag & ND_NFSV2) 2375191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2376191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2377191783Srmacklem if (error) 2378191783Srmacklem return (error); 2379191783Srmacklem if (nd->nd_flag & ND_NFSV4) 2380191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2381191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) { 2382191783Srmacklem if (!nd->nd_repstat) 2383191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2384191783Srmacklem if (!error) 2385191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2386191783Srmacklem NULL, dstuff); 2387191783Srmacklem } 2388191783Srmacklem if (nd->nd_repstat && !error) 2389191783Srmacklem error = nd->nd_repstat; 2390191783Srmacklem mbuf_freem(nd->nd_mrep); 2391191783Srmacklem /* 2392191783Srmacklem * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2393191783Srmacklem */ 2394191783Srmacklem if (error == EEXIST) 2395191783Srmacklem error = 0; 2396191783Srmacklem return (error); 2397191783Srmacklem} 2398191783Srmacklem 2399191783Srmacklem/* 2400191783Srmacklem * nfs make dir rpc 2401191783Srmacklem */ 2402191783SrmacklemAPPLESTATIC int 2403191783Srmacklemnfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2404191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2405191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2406191783Srmacklem int *dattrflagp, void *dstuff) 2407191783Srmacklem{ 2408191783Srmacklem u_int32_t *tl; 2409191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2410191783Srmacklem nfsattrbit_t attrbits; 2411191783Srmacklem int error = 0; 2412265389Srmacklem struct nfsfh *fhp; 2413191783Srmacklem 2414191783Srmacklem *nfhpp = NULL; 2415191783Srmacklem *attrflagp = 0; 2416191783Srmacklem *dattrflagp = 0; 2417265389Srmacklem fhp = VTONFS(dvp)->n_fhp; 2418191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2419191783Srmacklem return (ENAMETOOLONG); 2420191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 2421191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2422191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2423191783Srmacklem *tl = txdr_unsigned(NFDIR); 2424191783Srmacklem } 2425191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2426191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2427191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2428191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 2429191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2430191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2431191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2432191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2433265389Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2434265389Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2435265389Srmacklem (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0); 2436265389Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2437265389Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2438265389Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2439191783Srmacklem } 2440191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2441191783Srmacklem if (error) 2442191783Srmacklem return (error); 2443191783Srmacklem if (nd->nd_flag & ND_NFSV4) 2444191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2445191783Srmacklem if (!nd->nd_repstat && !error) { 2446191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2447191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2448191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2449191783Srmacklem } 2450191783Srmacklem if (!error) 2451191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2452265389Srmacklem if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 2453265389Srmacklem /* Get rid of the PutFH and Getattr status values. */ 2454265389Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2455265389Srmacklem /* Load the directory attributes. */ 2456265389Srmacklem error = nfsm_loadattr(nd, dnap); 2457265389Srmacklem if (error == 0) 2458265389Srmacklem *dattrflagp = 1; 2459265389Srmacklem } 2460191783Srmacklem } 2461191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) 2462191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2463191783Srmacklem if (nd->nd_repstat && !error) 2464191783Srmacklem error = nd->nd_repstat; 2465191783Srmacklemnfsmout: 2466191783Srmacklem mbuf_freem(nd->nd_mrep); 2467191783Srmacklem /* 2468191783Srmacklem * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry. 2469191783Srmacklem */ 2470191783Srmacklem if (error == EEXIST) 2471191783Srmacklem error = 0; 2472191783Srmacklem return (error); 2473191783Srmacklem} 2474191783Srmacklem 2475191783Srmacklem/* 2476191783Srmacklem * nfs remove directory call 2477191783Srmacklem */ 2478191783SrmacklemAPPLESTATIC int 2479191783Srmacklemnfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 2480191783Srmacklem NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 2481191783Srmacklem{ 2482191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2483191783Srmacklem int error = 0; 2484191783Srmacklem 2485191783Srmacklem *dattrflagp = 0; 2486191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2487191783Srmacklem return (ENAMETOOLONG); 2488191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 2489191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2490191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2491191783Srmacklem if (error) 2492191783Srmacklem return (error); 2493191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2494191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2495191783Srmacklem if (nd->nd_repstat && !error) 2496191783Srmacklem error = nd->nd_repstat; 2497191783Srmacklem mbuf_freem(nd->nd_mrep); 2498191783Srmacklem /* 2499191783Srmacklem * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2500191783Srmacklem */ 2501191783Srmacklem if (error == ENOENT) 2502191783Srmacklem error = 0; 2503191783Srmacklem return (error); 2504191783Srmacklem} 2505191783Srmacklem 2506191783Srmacklem/* 2507191783Srmacklem * Readdir rpc. 2508191783Srmacklem * Always returns with either uio_resid unchanged, if you are at the 2509191783Srmacklem * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 2510191783Srmacklem * filled in. 2511191783Srmacklem * I felt this would allow caching of directory blocks more easily 2512191783Srmacklem * than returning a pertially filled block. 2513191783Srmacklem * Directory offset cookies: 2514191783Srmacklem * Oh my, what to do with them... 2515191783Srmacklem * I can think of three ways to deal with them: 2516191783Srmacklem * 1 - have the layer above these RPCs maintain a map between logical 2517191783Srmacklem * directory byte offsets and the NFS directory offset cookies 2518191783Srmacklem * 2 - pass the opaque directory offset cookies up into userland 2519191783Srmacklem * and let the libc functions deal with them, via the system call 2520191783Srmacklem * 3 - return them to userland in the "struct dirent", so future versions 2521191783Srmacklem * of libc can use them and do whatever is necessary to amke things work 2522191783Srmacklem * above these rpc calls, in the meantime 2523191783Srmacklem * For now, I do #3 by "hiding" the directory offset cookies after the 2524191783Srmacklem * d_name field in struct dirent. This is space inside d_reclen that 2525191783Srmacklem * will be ignored by anything that doesn't know about them. 2526191783Srmacklem * The directory offset cookies are filled in as the last 8 bytes of 2527191783Srmacklem * each directory entry, after d_name. Someday, the userland libc 2528191783Srmacklem * functions may be able to use these. In the meantime, it satisfies 2529191783Srmacklem * OpenBSD's requirements for cookies being returned. 2530191783Srmacklem * If expects the directory offset cookie for the read to be in uio_offset 2531191783Srmacklem * and returns the one for the next entry after this directory block in 2532191783Srmacklem * there, as well. 2533191783Srmacklem */ 2534191783SrmacklemAPPLESTATIC int 2535191783Srmacklemnfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2536191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2537191783Srmacklem int *eofp, void *stuff) 2538191783Srmacklem{ 2539191783Srmacklem int len, left; 2540191783Srmacklem struct dirent *dp = NULL; 2541191783Srmacklem u_int32_t *tl; 2542191783Srmacklem nfsquad_t cookie, ncookie; 2543191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2544191783Srmacklem struct nfsnode *dnp = VTONFS(vp); 2545191783Srmacklem struct nfsvattr nfsva; 2546191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2547191783Srmacklem int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2548191783Srmacklem int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 2549191783Srmacklem long dotfileid, dotdotfileid = 0; 2550191783Srmacklem u_int32_t fakefileno = 0xffffffff, rderr; 2551191783Srmacklem char *cp; 2552191783Srmacklem nfsattrbit_t attrbits, dattrbits; 2553191783Srmacklem u_int32_t *tl2 = NULL; 2554191783Srmacklem size_t tresid; 2555191783Srmacklem 2556209120Skib KASSERT(uiop->uio_iovcnt == 1 && 2557209120Skib (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2558209120Skib ("nfs readdirrpc bad uio")); 2559191783Srmacklem 2560191783Srmacklem /* 2561191783Srmacklem * There is no point in reading a lot more than uio_resid, however 2562191783Srmacklem * adding one additional DIRBLKSIZ makes sense. Since uio_resid 2563191783Srmacklem * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 2564191783Srmacklem * will never make readsize > nm_readdirsize. 2565191783Srmacklem */ 2566191783Srmacklem readsize = nmp->nm_readdirsize; 2567191783Srmacklem if (readsize > uio_uio_resid(uiop)) 2568191783Srmacklem readsize = uio_uio_resid(uiop) + DIRBLKSIZ; 2569191783Srmacklem 2570191783Srmacklem *attrflagp = 0; 2571191783Srmacklem if (eofp) 2572191783Srmacklem *eofp = 0; 2573191783Srmacklem tresid = uio_uio_resid(uiop); 2574191783Srmacklem cookie.lval[0] = cookiep->nfsuquad[0]; 2575191783Srmacklem cookie.lval[1] = cookiep->nfsuquad[1]; 2576191783Srmacklem nd->nd_mrep = NULL; 2577191783Srmacklem 2578191783Srmacklem /* 2579191783Srmacklem * For NFSv4, first create the "." and ".." entries. 2580191783Srmacklem */ 2581191783Srmacklem if (NFSHASNFSV4(nmp)) { 2582191783Srmacklem reqsize = 6 * NFSX_UNSIGNED; 2583191783Srmacklem NFSGETATTR_ATTRBIT(&dattrbits); 2584191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 2585191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2586191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 2587191783Srmacklem if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2588191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID)) { 2589191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 2590191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 2591191783Srmacklem gotmnton = 1; 2592191783Srmacklem } else { 2593191783Srmacklem /* 2594191783Srmacklem * Must fake it. Use the fileno, except when the 2595191783Srmacklem * fsid is != to that of the directory. For that 2596191783Srmacklem * case, generate a fake fileno that is not the same. 2597191783Srmacklem */ 2598191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2599191783Srmacklem gotmnton = 0; 2600191783Srmacklem } 2601191783Srmacklem 2602191783Srmacklem /* 2603191783Srmacklem * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2604191783Srmacklem */ 2605191783Srmacklem if (uiop->uio_offset == 0) { 2606191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2607191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2608191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2609191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2610191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2611191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 2612191783Srmacklem if (error) 2613191783Srmacklem return (error); 2614265339Srmacklem dotfileid = 0; /* Fake out the compiler. */ 2615265339Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 2616265339Srmacklem error = nfsm_loadattr(nd, &nfsva); 2617265339Srmacklem if (error != 0) 2618265339Srmacklem goto nfsmout; 2619265339Srmacklem dotfileid = nfsva.na_fileid; 2620265339Srmacklem } 2621191783Srmacklem if (nd->nd_repstat == 0) { 2622265339Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2623265339Srmacklem len = fxdr_unsigned(int, *(tl + 4)); 2624191783Srmacklem if (len > 0 && len <= NFSX_V4FHMAX) 2625191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2626191783Srmacklem else 2627191783Srmacklem error = EPERM; 2628191783Srmacklem if (!error) { 2629191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2630191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 2631191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2632191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2633191783Srmacklem NULL, NULL, NULL, p, cred); 2634191783Srmacklem if (error) { 2635191783Srmacklem dotdotfileid = dotfileid; 2636191783Srmacklem } else if (gotmnton) { 2637191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 2638191783Srmacklem dotdotfileid = nfsva.na_mntonfileno; 2639191783Srmacklem else 2640191783Srmacklem dotdotfileid = nfsva.na_fileid; 2641191783Srmacklem } else if (nfsva.na_filesid[0] == 2642191783Srmacklem dnp->n_vattr.na_filesid[0] && 2643191783Srmacklem nfsva.na_filesid[1] == 2644191783Srmacklem dnp->n_vattr.na_filesid[1]) { 2645191783Srmacklem dotdotfileid = nfsva.na_fileid; 2646191783Srmacklem } else { 2647191783Srmacklem do { 2648191783Srmacklem fakefileno--; 2649191783Srmacklem } while (fakefileno == 2650191783Srmacklem nfsva.na_fileid); 2651191783Srmacklem dotdotfileid = fakefileno; 2652191783Srmacklem } 2653191783Srmacklem } 2654191783Srmacklem } else if (nd->nd_repstat == NFSERR_NOENT) { 2655191783Srmacklem /* 2656191783Srmacklem * Lookupp returns NFSERR_NOENT when we are 2657191783Srmacklem * at the root, so just use the current dir. 2658191783Srmacklem */ 2659191783Srmacklem nd->nd_repstat = 0; 2660191783Srmacklem dotdotfileid = dotfileid; 2661191783Srmacklem } else { 2662191783Srmacklem error = nd->nd_repstat; 2663191783Srmacklem } 2664191783Srmacklem mbuf_freem(nd->nd_mrep); 2665191783Srmacklem if (error) 2666191783Srmacklem return (error); 2667191783Srmacklem nd->nd_mrep = NULL; 2668191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2669191783Srmacklem dp->d_type = DT_DIR; 2670191783Srmacklem dp->d_fileno = dotfileid; 2671191783Srmacklem dp->d_namlen = 1; 2672191783Srmacklem dp->d_name[0] = '.'; 2673191783Srmacklem dp->d_name[1] = '\0'; 2674191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2675191783Srmacklem /* 2676191783Srmacklem * Just make these offset cookie 0. 2677191783Srmacklem */ 2678191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2679191783Srmacklem *tl++ = 0; 2680191783Srmacklem *tl = 0; 2681191783Srmacklem blksiz += dp->d_reclen; 2682191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 2683191783Srmacklem uiop->uio_offset += dp->d_reclen; 2684191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 2685191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 2686191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2687191783Srmacklem dp->d_type = DT_DIR; 2688191783Srmacklem dp->d_fileno = dotdotfileid; 2689191783Srmacklem dp->d_namlen = 2; 2690191783Srmacklem dp->d_name[0] = '.'; 2691191783Srmacklem dp->d_name[1] = '.'; 2692191783Srmacklem dp->d_name[2] = '\0'; 2693191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2694191783Srmacklem /* 2695191783Srmacklem * Just make these offset cookie 0. 2696191783Srmacklem */ 2697191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2698191783Srmacklem *tl++ = 0; 2699191783Srmacklem *tl = 0; 2700191783Srmacklem blksiz += dp->d_reclen; 2701191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 2702191783Srmacklem uiop->uio_offset += dp->d_reclen; 2703191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 2704191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 2705191783Srmacklem } 2706191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 2707191783Srmacklem } else { 2708191783Srmacklem reqsize = 5 * NFSX_UNSIGNED; 2709191783Srmacklem } 2710191783Srmacklem 2711191783Srmacklem 2712191783Srmacklem /* 2713191783Srmacklem * Loop around doing readdir rpc's of size readsize. 2714191783Srmacklem * The stopping criteria is EOF or buffer full. 2715191783Srmacklem */ 2716191783Srmacklem while (more_dirs && bigenough) { 2717191783Srmacklem *attrflagp = 0; 2718191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 2719191783Srmacklem if (nd->nd_flag & ND_NFSV2) { 2720191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2721191783Srmacklem *tl++ = cookie.lval[1]; 2722191783Srmacklem *tl = txdr_unsigned(readsize); 2723191783Srmacklem } else { 2724191783Srmacklem NFSM_BUILD(tl, u_int32_t *, reqsize); 2725191783Srmacklem *tl++ = cookie.lval[0]; 2726191783Srmacklem *tl++ = cookie.lval[1]; 2727191783Srmacklem if (cookie.qval == 0) { 2728191783Srmacklem *tl++ = 0; 2729191783Srmacklem *tl++ = 0; 2730191783Srmacklem } else { 2731191783Srmacklem NFSLOCKNODE(dnp); 2732191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[0]; 2733191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[1]; 2734191783Srmacklem NFSUNLOCKNODE(dnp); 2735191783Srmacklem } 2736191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2737191783Srmacklem *tl++ = txdr_unsigned(readsize); 2738191783Srmacklem *tl = txdr_unsigned(readsize); 2739191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2740191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2741191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2742191783Srmacklem (void) nfsrv_putattrbit(nd, &dattrbits); 2743191783Srmacklem } else { 2744191783Srmacklem *tl = txdr_unsigned(readsize); 2745191783Srmacklem } 2746191783Srmacklem } 2747191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 2748191783Srmacklem if (error) 2749191783Srmacklem return (error); 2750191783Srmacklem if (!(nd->nd_flag & ND_NFSV2)) { 2751191783Srmacklem if (nd->nd_flag & ND_NFSV3) 2752191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 2753191783Srmacklem stuff); 2754191783Srmacklem if (!nd->nd_repstat && !error) { 2755191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 2756191783Srmacklem NFSLOCKNODE(dnp); 2757191783Srmacklem dnp->n_cookieverf.nfsuquad[0] = *tl++; 2758191783Srmacklem dnp->n_cookieverf.nfsuquad[1] = *tl; 2759191783Srmacklem NFSUNLOCKNODE(dnp); 2760191783Srmacklem } 2761191783Srmacklem } 2762191783Srmacklem if (nd->nd_repstat || error) { 2763191783Srmacklem if (!error) 2764191783Srmacklem error = nd->nd_repstat; 2765191783Srmacklem goto nfsmout; 2766191783Srmacklem } 2767191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2768191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 2769191783Srmacklem if (!more_dirs) 2770191783Srmacklem tryformoredirs = 0; 2771191783Srmacklem 2772191783Srmacklem /* loop thru the dir entries, doctoring them to 4bsd form */ 2773191783Srmacklem while (more_dirs && bigenough) { 2774191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2775191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2776191783Srmacklem ncookie.lval[0] = *tl++; 2777191783Srmacklem ncookie.lval[1] = *tl++; 2778191783Srmacklem len = fxdr_unsigned(int, *tl); 2779191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 2780191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2781220152Szack nfsva.na_fileid = fxdr_hyper(tl); 2782220152Szack tl += 2; 2783220152Szack len = fxdr_unsigned(int, *tl); 2784191783Srmacklem } else { 2785191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2786191783Srmacklem nfsva.na_fileid = 2787191783Srmacklem fxdr_unsigned(long, *tl++); 2788191783Srmacklem len = fxdr_unsigned(int, *tl); 2789191783Srmacklem } 2790191783Srmacklem if (len <= 0 || len > NFS_MAXNAMLEN) { 2791191783Srmacklem error = EBADRPC; 2792191783Srmacklem goto nfsmout; 2793191783Srmacklem } 2794191783Srmacklem tlen = NFSM_RNDUP(len); 2795191783Srmacklem if (tlen == len) 2796191783Srmacklem tlen += 4; /* To ensure null termination */ 2797191783Srmacklem left = DIRBLKSIZ - blksiz; 2798191783Srmacklem if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) { 2799191783Srmacklem dp->d_reclen += left; 2800191783Srmacklem uio_iov_base_add(uiop, left); 2801191783Srmacklem uio_iov_len_add(uiop, -(left)); 2802191783Srmacklem uio_uio_resid_add(uiop, -(left)); 2803191783Srmacklem uiop->uio_offset += left; 2804191783Srmacklem blksiz = 0; 2805191783Srmacklem } 2806191783Srmacklem if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 2807191783Srmacklem bigenough = 0; 2808191783Srmacklem if (bigenough) { 2809191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2810191783Srmacklem dp->d_namlen = len; 2811191783Srmacklem dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 2812191783Srmacklem dp->d_type = DT_UNKNOWN; 2813191783Srmacklem blksiz += dp->d_reclen; 2814191783Srmacklem if (blksiz == DIRBLKSIZ) 2815191783Srmacklem blksiz = 0; 2816191783Srmacklem uio_uio_resid_add(uiop, -(DIRHDSIZ)); 2817191783Srmacklem uiop->uio_offset += DIRHDSIZ; 2818191783Srmacklem uio_iov_base_add(uiop, DIRHDSIZ); 2819191783Srmacklem uio_iov_len_add(uiop, -(DIRHDSIZ)); 2820191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 2821191783Srmacklem if (error) 2822191783Srmacklem goto nfsmout; 2823191783Srmacklem cp = CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2824191783Srmacklem tlen -= len; 2825191783Srmacklem *cp = '\0'; /* null terminate */ 2826191783Srmacklem cp += tlen; /* points to cookie storage */ 2827191783Srmacklem tl2 = (u_int32_t *)cp; 2828191783Srmacklem uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 2829191783Srmacklem uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 2830191783Srmacklem uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 2831191783Srmacklem uiop->uio_offset += (tlen + NFSX_HYPER); 2832191783Srmacklem } else { 2833191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2834191783Srmacklem if (error) 2835191783Srmacklem goto nfsmout; 2836191783Srmacklem } 2837191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2838191783Srmacklem rderr = 0; 2839191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 2840191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2841191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2842191783Srmacklem NULL, NULL, &rderr, p, cred); 2843191783Srmacklem if (error) 2844191783Srmacklem goto nfsmout; 2845191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2846191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 2847191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2848191783Srmacklem ncookie.lval[0] = *tl++; 2849191783Srmacklem ncookie.lval[1] = *tl++; 2850191783Srmacklem } else { 2851191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2852191783Srmacklem ncookie.lval[0] = 0; 2853191783Srmacklem ncookie.lval[1] = *tl++; 2854191783Srmacklem } 2855191783Srmacklem if (bigenough) { 2856191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2857191783Srmacklem if (rderr) { 2858191783Srmacklem dp->d_fileno = 0; 2859191783Srmacklem } else { 2860191783Srmacklem if (gotmnton) { 2861191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 2862191783Srmacklem dp->d_fileno = nfsva.na_mntonfileno; 2863191783Srmacklem else 2864191783Srmacklem dp->d_fileno = nfsva.na_fileid; 2865191783Srmacklem } else if (nfsva.na_filesid[0] == 2866191783Srmacklem dnp->n_vattr.na_filesid[0] && 2867191783Srmacklem nfsva.na_filesid[1] == 2868191783Srmacklem dnp->n_vattr.na_filesid[1]) { 2869191783Srmacklem dp->d_fileno = nfsva.na_fileid; 2870191783Srmacklem } else { 2871191783Srmacklem do { 2872191783Srmacklem fakefileno--; 2873191783Srmacklem } while (fakefileno == 2874191783Srmacklem nfsva.na_fileid); 2875191783Srmacklem dp->d_fileno = fakefileno; 2876191783Srmacklem } 2877191783Srmacklem dp->d_type = vtonfs_dtype(nfsva.na_type); 2878191783Srmacklem } 2879191783Srmacklem } else { 2880191783Srmacklem dp->d_fileno = nfsva.na_fileid; 2881191783Srmacklem } 2882191783Srmacklem *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 2883191783Srmacklem ncookie.lval[0]; 2884191783Srmacklem *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 2885191783Srmacklem ncookie.lval[1]; 2886191783Srmacklem } 2887191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 2888191783Srmacklem } 2889191783Srmacklem /* 2890191783Srmacklem * If at end of rpc data, get the eof boolean 2891191783Srmacklem */ 2892191783Srmacklem if (!more_dirs) { 2893191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2894191783Srmacklem eof = fxdr_unsigned(int, *tl); 2895191783Srmacklem if (tryformoredirs) 2896191783Srmacklem more_dirs = !eof; 2897191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2898191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 2899191783Srmacklem stuff); 2900191783Srmacklem if (error) 2901191783Srmacklem goto nfsmout; 2902191783Srmacklem } 2903191783Srmacklem } 2904191783Srmacklem mbuf_freem(nd->nd_mrep); 2905191783Srmacklem nd->nd_mrep = NULL; 2906191783Srmacklem } 2907191783Srmacklem /* 2908191783Srmacklem * Fill last record, iff any, out to a multiple of DIRBLKSIZ 2909191783Srmacklem * by increasing d_reclen for the last record. 2910191783Srmacklem */ 2911191783Srmacklem if (blksiz > 0) { 2912191783Srmacklem left = DIRBLKSIZ - blksiz; 2913191783Srmacklem dp->d_reclen += left; 2914191783Srmacklem uio_iov_base_add(uiop, left); 2915191783Srmacklem uio_iov_len_add(uiop, -(left)); 2916191783Srmacklem uio_uio_resid_add(uiop, -(left)); 2917191783Srmacklem uiop->uio_offset += left; 2918191783Srmacklem } 2919191783Srmacklem 2920191783Srmacklem /* 2921191783Srmacklem * If returning no data, assume end of file. 2922191783Srmacklem * If not bigenough, return not end of file, since you aren't 2923191783Srmacklem * returning all the data 2924191783Srmacklem * Otherwise, return the eof flag from the server. 2925191783Srmacklem */ 2926191783Srmacklem if (eofp) { 2927191783Srmacklem if (tresid == ((size_t)(uio_uio_resid(uiop)))) 2928191783Srmacklem *eofp = 1; 2929191783Srmacklem else if (!bigenough) 2930191783Srmacklem *eofp = 0; 2931191783Srmacklem else 2932191783Srmacklem *eofp = eof; 2933191783Srmacklem } 2934191783Srmacklem 2935191783Srmacklem /* 2936191783Srmacklem * Add extra empty records to any remaining DIRBLKSIZ chunks. 2937191783Srmacklem */ 2938191783Srmacklem while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) { 2939191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2940191783Srmacklem dp->d_type = DT_UNKNOWN; 2941191783Srmacklem dp->d_fileno = 0; 2942191783Srmacklem dp->d_namlen = 0; 2943191783Srmacklem dp->d_name[0] = '\0'; 2944191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2945191783Srmacklem *tl++ = cookie.lval[0]; 2946191783Srmacklem *tl = cookie.lval[1]; 2947191783Srmacklem dp->d_reclen = DIRBLKSIZ; 2948191783Srmacklem uio_iov_base_add(uiop, DIRBLKSIZ); 2949191783Srmacklem uio_iov_len_add(uiop, -(DIRBLKSIZ)); 2950191783Srmacklem uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 2951191783Srmacklem uiop->uio_offset += DIRBLKSIZ; 2952191783Srmacklem } 2953191783Srmacklem 2954191783Srmacklemnfsmout: 2955191783Srmacklem if (nd->nd_mrep != NULL) 2956191783Srmacklem mbuf_freem(nd->nd_mrep); 2957191783Srmacklem return (error); 2958191783Srmacklem} 2959191783Srmacklem 2960191783Srmacklem#ifndef APPLE 2961191783Srmacklem/* 2962191783Srmacklem * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 2963191783Srmacklem * (Also used for NFS V4 when mount flag set.) 2964191783Srmacklem * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 2965191783Srmacklem */ 2966191783SrmacklemAPPLESTATIC int 2967191783Srmacklemnfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2968191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2969191783Srmacklem int *eofp, void *stuff) 2970191783Srmacklem{ 2971191783Srmacklem int len, left; 2972191783Srmacklem struct dirent *dp = NULL; 2973191783Srmacklem u_int32_t *tl; 2974191783Srmacklem vnode_t newvp = NULLVP; 2975191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2976191783Srmacklem struct nameidata nami, *ndp = &nami; 2977191783Srmacklem struct componentname *cnp = &ndp->ni_cnd; 2978191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2979191783Srmacklem struct nfsnode *dnp = VTONFS(vp), *np; 2980191783Srmacklem struct nfsvattr nfsva; 2981191783Srmacklem struct nfsfh *nfhp; 2982191783Srmacklem nfsquad_t cookie, ncookie; 2983191783Srmacklem int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2984191783Srmacklem int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 2985220735Srmacklem int isdotdot = 0, unlocknewvp = 0; 2986191783Srmacklem long dotfileid, dotdotfileid = 0, fileno = 0; 2987191783Srmacklem char *cp; 2988191783Srmacklem nfsattrbit_t attrbits, dattrbits; 2989191783Srmacklem size_t tresid; 2990191783Srmacklem u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr; 2991233285Sjhb struct timespec dctime; 2992191783Srmacklem 2993209120Skib KASSERT(uiop->uio_iovcnt == 1 && 2994209120Skib (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2995209120Skib ("nfs readdirplusrpc bad uio")); 2996233285Sjhb timespecclear(&dctime); 2997191783Srmacklem *attrflagp = 0; 2998191783Srmacklem if (eofp != NULL) 2999191783Srmacklem *eofp = 0; 3000191783Srmacklem ndp->ni_dvp = vp; 3001191783Srmacklem nd->nd_mrep = NULL; 3002191783Srmacklem cookie.lval[0] = cookiep->nfsuquad[0]; 3003191783Srmacklem cookie.lval[1] = cookiep->nfsuquad[1]; 3004191783Srmacklem tresid = uio_uio_resid(uiop); 3005191783Srmacklem 3006191783Srmacklem /* 3007191783Srmacklem * For NFSv4, first create the "." and ".." entries. 3008191783Srmacklem */ 3009191783Srmacklem if (NFSHASNFSV4(nmp)) { 3010191783Srmacklem NFSGETATTR_ATTRBIT(&dattrbits); 3011191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 3012191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3013191783Srmacklem if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3014191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID)) { 3015191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 3016191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 3017191783Srmacklem gotmnton = 1; 3018191783Srmacklem } else { 3019191783Srmacklem /* 3020191783Srmacklem * Must fake it. Use the fileno, except when the 3021191783Srmacklem * fsid is != to that of the directory. For that 3022191783Srmacklem * case, generate a fake fileno that is not the same. 3023191783Srmacklem */ 3024191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3025191783Srmacklem gotmnton = 0; 3026191783Srmacklem } 3027191783Srmacklem 3028191783Srmacklem /* 3029191783Srmacklem * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3030191783Srmacklem */ 3031191783Srmacklem if (uiop->uio_offset == 0) { 3032191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3033191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3034191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3035191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3036191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3037191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3038191783Srmacklem if (error) 3039191783Srmacklem return (error); 3040265339Srmacklem dotfileid = 0; /* Fake out the compiler. */ 3041265339Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3042265339Srmacklem error = nfsm_loadattr(nd, &nfsva); 3043265339Srmacklem if (error != 0) 3044265339Srmacklem goto nfsmout; 3045265339Srmacklem dctime = nfsva.na_ctime; 3046265339Srmacklem dotfileid = nfsva.na_fileid; 3047265339Srmacklem } 3048191783Srmacklem if (nd->nd_repstat == 0) { 3049265339Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3050265339Srmacklem len = fxdr_unsigned(int, *(tl + 4)); 3051191783Srmacklem if (len > 0 && len <= NFSX_V4FHMAX) 3052191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3053191783Srmacklem else 3054191783Srmacklem error = EPERM; 3055191783Srmacklem if (!error) { 3056191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3057191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 3058191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3059191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3060191783Srmacklem NULL, NULL, NULL, p, cred); 3061191783Srmacklem if (error) { 3062191783Srmacklem dotdotfileid = dotfileid; 3063191783Srmacklem } else if (gotmnton) { 3064191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 3065191783Srmacklem dotdotfileid = nfsva.na_mntonfileno; 3066191783Srmacklem else 3067191783Srmacklem dotdotfileid = nfsva.na_fileid; 3068191783Srmacklem } else if (nfsva.na_filesid[0] == 3069191783Srmacklem dnp->n_vattr.na_filesid[0] && 3070191783Srmacklem nfsva.na_filesid[1] == 3071191783Srmacklem dnp->n_vattr.na_filesid[1]) { 3072191783Srmacklem dotdotfileid = nfsva.na_fileid; 3073191783Srmacklem } else { 3074191783Srmacklem do { 3075191783Srmacklem fakefileno--; 3076191783Srmacklem } while (fakefileno == 3077191783Srmacklem nfsva.na_fileid); 3078191783Srmacklem dotdotfileid = fakefileno; 3079191783Srmacklem } 3080191783Srmacklem } 3081191783Srmacklem } else if (nd->nd_repstat == NFSERR_NOENT) { 3082191783Srmacklem /* 3083191783Srmacklem * Lookupp returns NFSERR_NOENT when we are 3084191783Srmacklem * at the root, so just use the current dir. 3085191783Srmacklem */ 3086191783Srmacklem nd->nd_repstat = 0; 3087191783Srmacklem dotdotfileid = dotfileid; 3088191783Srmacklem } else { 3089191783Srmacklem error = nd->nd_repstat; 3090191783Srmacklem } 3091191783Srmacklem mbuf_freem(nd->nd_mrep); 3092191783Srmacklem if (error) 3093191783Srmacklem return (error); 3094191783Srmacklem nd->nd_mrep = NULL; 3095191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3096191783Srmacklem dp->d_type = DT_DIR; 3097191783Srmacklem dp->d_fileno = dotfileid; 3098191783Srmacklem dp->d_namlen = 1; 3099191783Srmacklem dp->d_name[0] = '.'; 3100191783Srmacklem dp->d_name[1] = '\0'; 3101191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3102191783Srmacklem /* 3103191783Srmacklem * Just make these offset cookie 0. 3104191783Srmacklem */ 3105191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3106191783Srmacklem *tl++ = 0; 3107191783Srmacklem *tl = 0; 3108191783Srmacklem blksiz += dp->d_reclen; 3109191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 3110191783Srmacklem uiop->uio_offset += dp->d_reclen; 3111191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 3112191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 3113191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3114191783Srmacklem dp->d_type = DT_DIR; 3115191783Srmacklem dp->d_fileno = dotdotfileid; 3116191783Srmacklem dp->d_namlen = 2; 3117191783Srmacklem dp->d_name[0] = '.'; 3118191783Srmacklem dp->d_name[1] = '.'; 3119191783Srmacklem dp->d_name[2] = '\0'; 3120191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3121191783Srmacklem /* 3122191783Srmacklem * Just make these offset cookie 0. 3123191783Srmacklem */ 3124191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3125191783Srmacklem *tl++ = 0; 3126191783Srmacklem *tl = 0; 3127191783Srmacklem blksiz += dp->d_reclen; 3128191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 3129191783Srmacklem uiop->uio_offset += dp->d_reclen; 3130191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 3131191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 3132191783Srmacklem } 3133191783Srmacklem NFSREADDIRPLUS_ATTRBIT(&attrbits); 3134191783Srmacklem if (gotmnton) 3135191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 3136191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 3137191783Srmacklem } 3138191783Srmacklem 3139191783Srmacklem /* 3140191783Srmacklem * Loop around doing readdir rpc's of size nm_readdirsize. 3141191783Srmacklem * The stopping criteria is EOF or buffer full. 3142191783Srmacklem */ 3143191783Srmacklem while (more_dirs && bigenough) { 3144191783Srmacklem *attrflagp = 0; 3145191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3146191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3147191783Srmacklem *tl++ = cookie.lval[0]; 3148191783Srmacklem *tl++ = cookie.lval[1]; 3149191783Srmacklem if (cookie.qval == 0) { 3150191783Srmacklem *tl++ = 0; 3151191783Srmacklem *tl++ = 0; 3152191783Srmacklem } else { 3153191783Srmacklem NFSLOCKNODE(dnp); 3154191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3155191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3156191783Srmacklem NFSUNLOCKNODE(dnp); 3157191783Srmacklem } 3158191783Srmacklem *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3159191783Srmacklem *tl = txdr_unsigned(nmp->nm_readdirsize); 3160191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3161191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3162191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3163191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3164191783Srmacklem (void) nfsrv_putattrbit(nd, &dattrbits); 3165191783Srmacklem } 3166191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3167191783Srmacklem if (error) 3168191783Srmacklem return (error); 3169191783Srmacklem if (nd->nd_flag & ND_NFSV3) 3170191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3171191783Srmacklem if (nd->nd_repstat || error) { 3172191783Srmacklem if (!error) 3173191783Srmacklem error = nd->nd_repstat; 3174191783Srmacklem goto nfsmout; 3175191783Srmacklem } 3176233285Sjhb if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 3177233285Sjhb dctime = nap->na_ctime; 3178191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3179191783Srmacklem NFSLOCKNODE(dnp); 3180191783Srmacklem dnp->n_cookieverf.nfsuquad[0] = *tl++; 3181191783Srmacklem dnp->n_cookieverf.nfsuquad[1] = *tl++; 3182191783Srmacklem NFSUNLOCKNODE(dnp); 3183191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3184191783Srmacklem if (!more_dirs) 3185191783Srmacklem tryformoredirs = 0; 3186191783Srmacklem 3187191783Srmacklem /* loop thru the dir entries, doctoring them to 4bsd form */ 3188191783Srmacklem while (more_dirs && bigenough) { 3189191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3190191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3191191783Srmacklem ncookie.lval[0] = *tl++; 3192191783Srmacklem ncookie.lval[1] = *tl++; 3193191783Srmacklem } else { 3194191783Srmacklem fileno = fxdr_unsigned(long, *++tl); 3195191783Srmacklem tl++; 3196191783Srmacklem } 3197191783Srmacklem len = fxdr_unsigned(int, *tl); 3198191783Srmacklem if (len <= 0 || len > NFS_MAXNAMLEN) { 3199191783Srmacklem error = EBADRPC; 3200191783Srmacklem goto nfsmout; 3201191783Srmacklem } 3202191783Srmacklem tlen = NFSM_RNDUP(len); 3203191783Srmacklem if (tlen == len) 3204191783Srmacklem tlen += 4; /* To ensure null termination */ 3205191783Srmacklem left = DIRBLKSIZ - blksiz; 3206191783Srmacklem if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) { 3207191783Srmacklem dp->d_reclen += left; 3208191783Srmacklem uio_iov_base_add(uiop, left); 3209191783Srmacklem uio_iov_len_add(uiop, -(left)); 3210191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3211191783Srmacklem uiop->uio_offset += left; 3212191783Srmacklem blksiz = 0; 3213191783Srmacklem } 3214191783Srmacklem if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 3215191783Srmacklem bigenough = 0; 3216191783Srmacklem if (bigenough) { 3217191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3218191783Srmacklem dp->d_namlen = len; 3219191783Srmacklem dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 3220191783Srmacklem dp->d_type = DT_UNKNOWN; 3221191783Srmacklem blksiz += dp->d_reclen; 3222191783Srmacklem if (blksiz == DIRBLKSIZ) 3223191783Srmacklem blksiz = 0; 3224191783Srmacklem uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3225191783Srmacklem uiop->uio_offset += DIRHDSIZ; 3226191783Srmacklem uio_iov_base_add(uiop, DIRHDSIZ); 3227191783Srmacklem uio_iov_len_add(uiop, -(DIRHDSIZ)); 3228191783Srmacklem cnp->cn_nameptr = uio_iov_base(uiop); 3229191783Srmacklem cnp->cn_namelen = len; 3230191783Srmacklem NFSCNHASHZERO(cnp); 3231191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 3232191783Srmacklem if (error) 3233191783Srmacklem goto nfsmout; 3234191783Srmacklem cp = uio_iov_base(uiop); 3235191783Srmacklem tlen -= len; 3236191783Srmacklem *cp = '\0'; 3237191783Srmacklem cp += tlen; /* points to cookie storage */ 3238191783Srmacklem tl2 = (u_int32_t *)cp; 3239220735Srmacklem if (len == 2 && cnp->cn_nameptr[0] == '.' && 3240220735Srmacklem cnp->cn_nameptr[1] == '.') 3241220735Srmacklem isdotdot = 1; 3242220735Srmacklem else 3243220735Srmacklem isdotdot = 0; 3244191783Srmacklem uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3245191783Srmacklem uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3246191783Srmacklem uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3247191783Srmacklem uiop->uio_offset += (tlen + NFSX_HYPER); 3248191783Srmacklem } else { 3249191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3250191783Srmacklem if (error) 3251191783Srmacklem goto nfsmout; 3252191783Srmacklem } 3253191783Srmacklem nfhp = NULL; 3254191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 3255191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3256191783Srmacklem ncookie.lval[0] = *tl++; 3257191783Srmacklem ncookie.lval[1] = *tl++; 3258191783Srmacklem attrflag = fxdr_unsigned(int, *tl); 3259191783Srmacklem if (attrflag) { 3260191783Srmacklem error = nfsm_loadattr(nd, &nfsva); 3261191783Srmacklem if (error) 3262191783Srmacklem goto nfsmout; 3263191783Srmacklem } 3264191783Srmacklem NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3265191783Srmacklem if (*tl) { 3266191783Srmacklem error = nfsm_getfh(nd, &nfhp); 3267191783Srmacklem if (error) 3268191783Srmacklem goto nfsmout; 3269191783Srmacklem } 3270191783Srmacklem if (!attrflag && nfhp != NULL) { 3271191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3272191783Srmacklem nfhp = NULL; 3273191783Srmacklem } 3274191783Srmacklem } else { 3275191783Srmacklem rderr = 0; 3276191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 3277191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3278191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3279191783Srmacklem NULL, NULL, &rderr, p, cred); 3280191783Srmacklem if (error) 3281191783Srmacklem goto nfsmout; 3282191783Srmacklem } 3283191783Srmacklem 3284191783Srmacklem if (bigenough) { 3285191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3286191783Srmacklem if (rderr) { 3287191783Srmacklem dp->d_fileno = 0; 3288191783Srmacklem } else if (gotmnton) { 3289191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 3290191783Srmacklem dp->d_fileno = nfsva.na_mntonfileno; 3291191783Srmacklem else 3292191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3293191783Srmacklem } else if (nfsva.na_filesid[0] == 3294191783Srmacklem dnp->n_vattr.na_filesid[0] && 3295191783Srmacklem nfsva.na_filesid[1] == 3296191783Srmacklem dnp->n_vattr.na_filesid[1]) { 3297191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3298191783Srmacklem } else { 3299191783Srmacklem do { 3300191783Srmacklem fakefileno--; 3301191783Srmacklem } while (fakefileno == 3302191783Srmacklem nfsva.na_fileid); 3303191783Srmacklem dp->d_fileno = fakefileno; 3304191783Srmacklem } 3305191783Srmacklem } else { 3306191783Srmacklem dp->d_fileno = fileno; 3307191783Srmacklem } 3308191783Srmacklem *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3309191783Srmacklem ncookie.lval[0]; 3310191783Srmacklem *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3311191783Srmacklem ncookie.lval[1]; 3312191783Srmacklem 3313191783Srmacklem if (nfhp != NULL) { 3314191783Srmacklem if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3315191783Srmacklem dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3316191783Srmacklem VREF(vp); 3317191783Srmacklem newvp = vp; 3318191783Srmacklem unlocknewvp = 0; 3319191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3320191783Srmacklem np = dnp; 3321220735Srmacklem } else if (isdotdot != 0) { 3322220735Srmacklem /* 3323220735Srmacklem * Skip doing a nfscl_nget() call for "..". 3324220735Srmacklem * There's a race between acquiring the nfs 3325220735Srmacklem * node here and lookups that look for the 3326220735Srmacklem * directory being read (in the parent). 3327220735Srmacklem * It would try to get a lock on ".." here, 3328220735Srmacklem * owning the lock on the directory being 3329220735Srmacklem * read. Lookup will hold the lock on ".." 3330220735Srmacklem * and try to acquire the lock on the 3331220735Srmacklem * directory being read. 3332220735Srmacklem * If the directory is unlocked/relocked, 3333220735Srmacklem * then there is a LOR with the buflock 3334220735Srmacklem * vp is relocked. 3335220735Srmacklem */ 3336220735Srmacklem free(nfhp, M_NFSFH); 3337191783Srmacklem } else { 3338191783Srmacklem error = nfscl_nget(vnode_mount(vp), vp, 3339220732Srmacklem nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 3340191783Srmacklem if (!error) { 3341191783Srmacklem newvp = NFSTOV(np); 3342191783Srmacklem unlocknewvp = 1; 3343191783Srmacklem } 3344191783Srmacklem } 3345191783Srmacklem nfhp = NULL; 3346191783Srmacklem if (newvp != NULLVP) { 3347191783Srmacklem error = nfscl_loadattrcache(&newvp, 3348191783Srmacklem &nfsva, NULL, NULL, 0, 0); 3349191783Srmacklem if (error) { 3350191783Srmacklem if (unlocknewvp) 3351191783Srmacklem vput(newvp); 3352191783Srmacklem else 3353191783Srmacklem vrele(newvp); 3354191783Srmacklem goto nfsmout; 3355191783Srmacklem } 3356191783Srmacklem dp->d_type = 3357191783Srmacklem vtonfs_dtype(np->n_vattr.na_type); 3358191783Srmacklem ndp->ni_vp = newvp; 3359191783Srmacklem NFSCNHASH(cnp, HASHINIT); 3360233285Sjhb if (cnp->cn_namelen <= NCHNAMLEN && 3361233285Sjhb (newvp->v_type != VDIR || 3362233285Sjhb dctime.tv_sec != 0)) { 3363233285Sjhb cache_enter_time(ndp->ni_dvp, 3364233285Sjhb ndp->ni_vp, cnp, 3365233285Sjhb &nfsva.na_ctime, 3366233285Sjhb newvp->v_type != VDIR ? NULL : 3367233285Sjhb &dctime); 3368191783Srmacklem } 3369191783Srmacklem if (unlocknewvp) 3370191783Srmacklem vput(newvp); 3371191783Srmacklem else 3372191783Srmacklem vrele(newvp); 3373191783Srmacklem newvp = NULLVP; 3374191783Srmacklem } 3375191783Srmacklem } 3376191783Srmacklem } else if (nfhp != NULL) { 3377191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3378191783Srmacklem } 3379191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3380191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3381191783Srmacklem } 3382191783Srmacklem /* 3383191783Srmacklem * If at end of rpc data, get the eof boolean 3384191783Srmacklem */ 3385191783Srmacklem if (!more_dirs) { 3386191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3387191783Srmacklem eof = fxdr_unsigned(int, *tl); 3388191783Srmacklem if (tryformoredirs) 3389191783Srmacklem more_dirs = !eof; 3390191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3391191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 3392191783Srmacklem stuff); 3393191783Srmacklem if (error) 3394191783Srmacklem goto nfsmout; 3395191783Srmacklem } 3396191783Srmacklem } 3397191783Srmacklem mbuf_freem(nd->nd_mrep); 3398191783Srmacklem nd->nd_mrep = NULL; 3399191783Srmacklem } 3400191783Srmacklem /* 3401191783Srmacklem * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3402191783Srmacklem * by increasing d_reclen for the last record. 3403191783Srmacklem */ 3404191783Srmacklem if (blksiz > 0) { 3405191783Srmacklem left = DIRBLKSIZ - blksiz; 3406191783Srmacklem dp->d_reclen += left; 3407191783Srmacklem uio_iov_base_add(uiop, left); 3408191783Srmacklem uio_iov_len_add(uiop, -(left)); 3409191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3410191783Srmacklem uiop->uio_offset += left; 3411191783Srmacklem } 3412191783Srmacklem 3413191783Srmacklem /* 3414191783Srmacklem * If returning no data, assume end of file. 3415191783Srmacklem * If not bigenough, return not end of file, since you aren't 3416191783Srmacklem * returning all the data 3417191783Srmacklem * Otherwise, return the eof flag from the server. 3418191783Srmacklem */ 3419191783Srmacklem if (eofp != NULL) { 3420191783Srmacklem if (tresid == uio_uio_resid(uiop)) 3421191783Srmacklem *eofp = 1; 3422191783Srmacklem else if (!bigenough) 3423191783Srmacklem *eofp = 0; 3424191783Srmacklem else 3425191783Srmacklem *eofp = eof; 3426191783Srmacklem } 3427191783Srmacklem 3428191783Srmacklem /* 3429191783Srmacklem * Add extra empty records to any remaining DIRBLKSIZ chunks. 3430191783Srmacklem */ 3431191783Srmacklem while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3432191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3433191783Srmacklem dp->d_type = DT_UNKNOWN; 3434191783Srmacklem dp->d_fileno = 0; 3435191783Srmacklem dp->d_namlen = 0; 3436191783Srmacklem dp->d_name[0] = '\0'; 3437191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3438191783Srmacklem *tl++ = cookie.lval[0]; 3439191783Srmacklem *tl = cookie.lval[1]; 3440191783Srmacklem dp->d_reclen = DIRBLKSIZ; 3441191783Srmacklem uio_iov_base_add(uiop, DIRBLKSIZ); 3442191783Srmacklem uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3443191783Srmacklem uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3444191783Srmacklem uiop->uio_offset += DIRBLKSIZ; 3445191783Srmacklem } 3446191783Srmacklem 3447191783Srmacklemnfsmout: 3448191783Srmacklem if (nd->nd_mrep != NULL) 3449191783Srmacklem mbuf_freem(nd->nd_mrep); 3450191783Srmacklem return (error); 3451191783Srmacklem} 3452191783Srmacklem#endif /* !APPLE */ 3453191783Srmacklem 3454191783Srmacklem/* 3455191783Srmacklem * Nfs commit rpc 3456191783Srmacklem */ 3457191783SrmacklemAPPLESTATIC int 3458191783Srmacklemnfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 3459191783Srmacklem NFSPROC_T *p, u_char *verfp, struct nfsvattr *nap, int *attrflagp, 3460191783Srmacklem void *stuff) 3461191783Srmacklem{ 3462191783Srmacklem u_int32_t *tl; 3463191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3464191783Srmacklem nfsattrbit_t attrbits; 3465191783Srmacklem int error; 3466191783Srmacklem 3467191783Srmacklem *attrflagp = 0; 3468191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 3469191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3470191783Srmacklem txdr_hyper(offset, tl); 3471191783Srmacklem tl += 2; 3472191783Srmacklem *tl = txdr_unsigned(cnt); 3473191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3474191783Srmacklem /* 3475191783Srmacklem * And do a Getattr op. 3476191783Srmacklem */ 3477191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3478191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3479191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 3480191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3481191783Srmacklem } 3482191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3483191783Srmacklem if (error) 3484191783Srmacklem return (error); 3485191783Srmacklem error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 3486191783Srmacklem if (!error && !nd->nd_repstat) { 3487191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3488191783Srmacklem NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF); 3489191783Srmacklem if (nd->nd_flag & ND_NFSV4) 3490191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3491191783Srmacklem } 3492191783Srmacklemnfsmout: 3493191783Srmacklem if (!error && nd->nd_repstat) 3494191783Srmacklem error = nd->nd_repstat; 3495191783Srmacklem mbuf_freem(nd->nd_mrep); 3496191783Srmacklem return (error); 3497191783Srmacklem} 3498191783Srmacklem 3499191783Srmacklem/* 3500191783Srmacklem * NFS byte range lock rpc. 3501191783Srmacklem * (Mostly just calls one of the three lower level RPC routines.) 3502191783Srmacklem */ 3503191783SrmacklemAPPLESTATIC int 3504191783Srmacklemnfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 3505222719Srmacklem int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3506191783Srmacklem{ 3507191783Srmacklem struct nfscllockowner *lp; 3508191783Srmacklem struct nfsclclient *clp; 3509191783Srmacklem struct nfsfh *nfhp; 3510191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3511191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3512191783Srmacklem u_int64_t off, len; 3513191783Srmacklem off_t start, end; 3514191783Srmacklem u_int32_t clidrev = 0; 3515191783Srmacklem int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 3516191783Srmacklem int callcnt, dorpc; 3517191783Srmacklem 3518191783Srmacklem /* 3519191783Srmacklem * Convert the flock structure into a start and end and do POSIX 3520191783Srmacklem * bounds checking. 3521191783Srmacklem */ 3522191783Srmacklem switch (fl->l_whence) { 3523191783Srmacklem case SEEK_SET: 3524191783Srmacklem case SEEK_CUR: 3525191783Srmacklem /* 3526191783Srmacklem * Caller is responsible for adding any necessary offset 3527191783Srmacklem * when SEEK_CUR is used. 3528191783Srmacklem */ 3529191783Srmacklem start = fl->l_start; 3530191783Srmacklem off = fl->l_start; 3531191783Srmacklem break; 3532191783Srmacklem case SEEK_END: 3533191783Srmacklem start = size + fl->l_start; 3534191783Srmacklem off = size + fl->l_start; 3535191783Srmacklem break; 3536191783Srmacklem default: 3537191783Srmacklem return (EINVAL); 3538191783Srmacklem }; 3539191783Srmacklem if (start < 0) 3540191783Srmacklem return (EINVAL); 3541191783Srmacklem if (fl->l_len != 0) { 3542191783Srmacklem end = start + fl->l_len - 1; 3543191783Srmacklem if (end < start) 3544191783Srmacklem return (EINVAL); 3545191783Srmacklem } 3546191783Srmacklem 3547191783Srmacklem len = fl->l_len; 3548191783Srmacklem if (len == 0) 3549191783Srmacklem len = NFS64BITSSET; 3550191783Srmacklem retrycnt = 0; 3551191783Srmacklem do { 3552191783Srmacklem nd->nd_repstat = 0; 3553191783Srmacklem if (op == F_GETLK) { 3554191783Srmacklem error = nfscl_getcl(vp, cred, p, &clp); 3555191783Srmacklem if (error) 3556191783Srmacklem return (error); 3557222719Srmacklem error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 3558191783Srmacklem if (!error) { 3559191783Srmacklem clidrev = clp->nfsc_clientidrev; 3560191783Srmacklem error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 3561222719Srmacklem p, id, flags); 3562191783Srmacklem } else if (error == -1) { 3563191783Srmacklem error = 0; 3564191783Srmacklem } 3565191783Srmacklem nfscl_clientrelease(clp); 3566191783Srmacklem } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 3567191783Srmacklem /* 3568191783Srmacklem * We must loop around for all lockowner cases. 3569191783Srmacklem */ 3570191783Srmacklem callcnt = 0; 3571191783Srmacklem error = nfscl_getcl(vp, cred, p, &clp); 3572191783Srmacklem if (error) 3573191783Srmacklem return (error); 3574191783Srmacklem do { 3575191783Srmacklem error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 3576222719Srmacklem clp, id, flags, &lp, &dorpc); 3577191783Srmacklem /* 3578191783Srmacklem * If it returns a NULL lp, we're done. 3579191783Srmacklem */ 3580191783Srmacklem if (lp == NULL) { 3581191783Srmacklem if (callcnt == 0) 3582191783Srmacklem nfscl_clientrelease(clp); 3583191783Srmacklem else 3584222719Srmacklem nfscl_releasealllocks(clp, vp, p, id, flags); 3585191783Srmacklem return (error); 3586191783Srmacklem } 3587191783Srmacklem if (nmp->nm_clp != NULL) 3588191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 3589191783Srmacklem else 3590191783Srmacklem clidrev = 0; 3591191783Srmacklem /* 3592191783Srmacklem * If the server doesn't support Posix lock semantics, 3593191783Srmacklem * only allow locks on the entire file, since it won't 3594191783Srmacklem * handle overlapping byte ranges. 3595191783Srmacklem * There might still be a problem when a lock 3596191783Srmacklem * upgrade/downgrade (read<->write) occurs, since the 3597191783Srmacklem * server "might" expect an unlock first? 3598191783Srmacklem */ 3599191783Srmacklem if (dorpc && (lp->nfsl_open->nfso_posixlock || 3600191783Srmacklem (off == 0 && len == NFS64BITSSET))) { 3601191783Srmacklem /* 3602191783Srmacklem * Since the lock records will go away, we must 3603191783Srmacklem * wait for grace and delay here. 3604191783Srmacklem */ 3605191783Srmacklem do { 3606191783Srmacklem error = nfsrpc_locku(nd, nmp, lp, off, len, 3607191783Srmacklem NFSV4LOCKT_READ, cred, p, 0); 3608191783Srmacklem if ((nd->nd_repstat == NFSERR_GRACE || 3609191783Srmacklem nd->nd_repstat == NFSERR_DELAY) && 3610191783Srmacklem error == 0) 3611207170Srmacklem (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3612207170Srmacklem "nfs_advlock"); 3613191783Srmacklem } while ((nd->nd_repstat == NFSERR_GRACE || 3614191783Srmacklem nd->nd_repstat == NFSERR_DELAY) && error == 0); 3615191783Srmacklem } 3616191783Srmacklem callcnt++; 3617191783Srmacklem } while (error == 0 && nd->nd_repstat == 0); 3618222719Srmacklem nfscl_releasealllocks(clp, vp, p, id, flags); 3619191783Srmacklem } else if (op == F_SETLK) { 3620191783Srmacklem error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 3621222719Srmacklem NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 3622191783Srmacklem if (error || donelocally) { 3623191783Srmacklem return (error); 3624191783Srmacklem } 3625191783Srmacklem if (nmp->nm_clp != NULL) 3626191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 3627191783Srmacklem else 3628191783Srmacklem clidrev = 0; 3629191783Srmacklem nfhp = VTONFS(vp)->n_fhp; 3630191783Srmacklem if (!lp->nfsl_open->nfso_posixlock && 3631191783Srmacklem (off != 0 || len != NFS64BITSSET)) { 3632191783Srmacklem error = EINVAL; 3633191783Srmacklem } else { 3634191783Srmacklem error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 3635191783Srmacklem nfhp->nfh_len, lp, newone, reclaim, off, 3636191783Srmacklem len, fl->l_type, cred, p, 0); 3637191783Srmacklem } 3638191783Srmacklem if (!error) 3639191783Srmacklem error = nd->nd_repstat; 3640191783Srmacklem nfscl_lockrelease(lp, error, newone); 3641191783Srmacklem } else { 3642191783Srmacklem error = EINVAL; 3643191783Srmacklem } 3644191783Srmacklem if (!error) 3645191783Srmacklem error = nd->nd_repstat; 3646191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 3647191783Srmacklem error == NFSERR_STALEDONTRECOVER || 3648191783Srmacklem error == NFSERR_STALECLIENTID || error == NFSERR_DELAY) { 3649207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_advlock"); 3650191783Srmacklem } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 3651191783Srmacklem && clidrev != 0) { 3652191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 3653191783Srmacklem retrycnt++; 3654191783Srmacklem } 3655191783Srmacklem } while (error == NFSERR_GRACE || 3656191783Srmacklem error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3657191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 3658191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 3659191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 3660191783Srmacklem if (error && retrycnt >= 4) 3661191783Srmacklem error = EIO; 3662191783Srmacklem return (error); 3663191783Srmacklem} 3664191783Srmacklem 3665191783Srmacklem/* 3666191783Srmacklem * The lower level routine for the LockT case. 3667191783Srmacklem */ 3668191783SrmacklemAPPLESTATIC int 3669191783Srmacklemnfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 3670191783Srmacklem struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 3671222719Srmacklem struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3672191783Srmacklem{ 3673191783Srmacklem u_int32_t *tl; 3674191783Srmacklem int error, type, size; 3675223747Srmacklem uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3676223747Srmacklem struct nfsnode *np; 3677191783Srmacklem 3678191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 3679191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3680191783Srmacklem if (fl->l_type == F_RDLCK) 3681191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3682191783Srmacklem else 3683191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3684191783Srmacklem txdr_hyper(off, tl); 3685191783Srmacklem tl += 2; 3686191783Srmacklem txdr_hyper(len, tl); 3687191783Srmacklem tl += 2; 3688191783Srmacklem *tl++ = clp->nfsc_clientid.lval[0]; 3689191783Srmacklem *tl = clp->nfsc_clientid.lval[1]; 3690222719Srmacklem nfscl_filllockowner(id, own, flags); 3691223747Srmacklem np = VTONFS(vp); 3692223747Srmacklem NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 3693223747Srmacklem np->n_fhp->nfh_len); 3694223747Srmacklem (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 3695191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 3696191783Srmacklem if (error) 3697191783Srmacklem return (error); 3698191783Srmacklem if (nd->nd_repstat == 0) { 3699191783Srmacklem fl->l_type = F_UNLCK; 3700191783Srmacklem } else if (nd->nd_repstat == NFSERR_DENIED) { 3701191783Srmacklem nd->nd_repstat = 0; 3702191783Srmacklem fl->l_whence = SEEK_SET; 3703191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3704191783Srmacklem fl->l_start = fxdr_hyper(tl); 3705191783Srmacklem tl += 2; 3706191783Srmacklem len = fxdr_hyper(tl); 3707191783Srmacklem tl += 2; 3708191783Srmacklem if (len == NFS64BITSSET) 3709191783Srmacklem fl->l_len = 0; 3710191783Srmacklem else 3711191783Srmacklem fl->l_len = len; 3712191783Srmacklem type = fxdr_unsigned(int, *tl++); 3713191783Srmacklem if (type == NFSV4LOCKT_WRITE) 3714191783Srmacklem fl->l_type = F_WRLCK; 3715191783Srmacklem else 3716191783Srmacklem fl->l_type = F_RDLCK; 3717191783Srmacklem /* 3718191783Srmacklem * XXX For now, I have no idea what to do with the 3719191783Srmacklem * conflicting lock_owner, so I'll just set the pid == 0 3720191783Srmacklem * and skip over the lock_owner. 3721191783Srmacklem */ 3722191783Srmacklem fl->l_pid = (pid_t)0; 3723191783Srmacklem tl += 2; 3724191783Srmacklem size = fxdr_unsigned(int, *tl); 3725191783Srmacklem if (size < 0 || size > NFSV4_OPAQUELIMIT) 3726191783Srmacklem error = EBADRPC; 3727191783Srmacklem if (!error) 3728191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3729191783Srmacklem } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 3730191783Srmacklem nfscl_initiate_recovery(clp); 3731191783Srmacklemnfsmout: 3732191783Srmacklem mbuf_freem(nd->nd_mrep); 3733191783Srmacklem return (error); 3734191783Srmacklem} 3735191783Srmacklem 3736191783Srmacklem/* 3737191783Srmacklem * Lower level function that performs the LockU RPC. 3738191783Srmacklem */ 3739191783Srmacklemstatic int 3740191783Srmacklemnfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 3741191783Srmacklem struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 3742191783Srmacklem u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 3743191783Srmacklem{ 3744191783Srmacklem u_int32_t *tl; 3745191783Srmacklem int error; 3746191783Srmacklem 3747191783Srmacklem nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 3748191783Srmacklem lp->nfsl_open->nfso_fhlen, NULL); 3749191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3750191783Srmacklem *tl++ = txdr_unsigned(type); 3751191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid); 3752191783Srmacklem if (nfstest_outofseq && 3753191783Srmacklem (arc4random() % nfstest_outofseq) == 0) 3754191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid + 1); 3755191783Srmacklem tl++; 3756191783Srmacklem *tl++ = lp->nfsl_stateid.seqid; 3757191783Srmacklem *tl++ = lp->nfsl_stateid.other[0]; 3758191783Srmacklem *tl++ = lp->nfsl_stateid.other[1]; 3759191783Srmacklem *tl++ = lp->nfsl_stateid.other[2]; 3760191783Srmacklem txdr_hyper(off, tl); 3761191783Srmacklem tl += 2; 3762191783Srmacklem txdr_hyper(len, tl); 3763191783Srmacklem if (syscred) 3764191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3765191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 3766191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 3767191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 3768191783Srmacklem if (error) 3769191783Srmacklem return (error); 3770191783Srmacklem if (nd->nd_repstat == 0) { 3771191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3772191783Srmacklem lp->nfsl_stateid.seqid = *tl++; 3773191783Srmacklem lp->nfsl_stateid.other[0] = *tl++; 3774191783Srmacklem lp->nfsl_stateid.other[1] = *tl++; 3775191783Srmacklem lp->nfsl_stateid.other[2] = *tl; 3776191783Srmacklem } else if (nd->nd_repstat == NFSERR_STALESTATEID) 3777191783Srmacklem nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 3778191783Srmacklemnfsmout: 3779191783Srmacklem mbuf_freem(nd->nd_mrep); 3780191783Srmacklem return (error); 3781191783Srmacklem} 3782191783Srmacklem 3783191783Srmacklem/* 3784191783Srmacklem * The actual Lock RPC. 3785191783Srmacklem */ 3786191783SrmacklemAPPLESTATIC int 3787191783Srmacklemnfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 3788191783Srmacklem u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 3789191783Srmacklem int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 3790191783Srmacklem NFSPROC_T *p, int syscred) 3791191783Srmacklem{ 3792191783Srmacklem u_int32_t *tl; 3793191783Srmacklem int error, size; 3794223747Srmacklem uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3795191783Srmacklem 3796191783Srmacklem nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL); 3797191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3798191783Srmacklem if (type == F_RDLCK) 3799191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3800191783Srmacklem else 3801191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3802191783Srmacklem *tl++ = txdr_unsigned(reclaim); 3803191783Srmacklem txdr_hyper(off, tl); 3804191783Srmacklem tl += 2; 3805191783Srmacklem txdr_hyper(len, tl); 3806191783Srmacklem tl += 2; 3807191783Srmacklem if (newone) { 3808191783Srmacklem *tl = newnfs_true; 3809191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3810191783Srmacklem 2 * NFSX_UNSIGNED + NFSX_HYPER); 3811191783Srmacklem *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 3812191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.seqid; 3813191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 3814191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 3815191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 3816191783Srmacklem *tl++ = txdr_unsigned(lp->nfsl_seqid); 3817191783Srmacklem *tl++ = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[0]; 3818191783Srmacklem *tl = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[1]; 3819223747Srmacklem NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 3820223747Srmacklem NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 3821223747Srmacklem (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 3822191783Srmacklem } else { 3823191783Srmacklem *tl = newnfs_false; 3824191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3825191783Srmacklem *tl++ = lp->nfsl_stateid.seqid; 3826191783Srmacklem *tl++ = lp->nfsl_stateid.other[0]; 3827191783Srmacklem *tl++ = lp->nfsl_stateid.other[1]; 3828191783Srmacklem *tl++ = lp->nfsl_stateid.other[2]; 3829191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid); 3830191783Srmacklem if (nfstest_outofseq && 3831191783Srmacklem (arc4random() % nfstest_outofseq) == 0) 3832191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid + 1); 3833191783Srmacklem } 3834191783Srmacklem if (syscred) 3835191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3836191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 3837191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 3838191783Srmacklem if (error) 3839191783Srmacklem return (error); 3840191783Srmacklem if (newone) 3841191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 3842191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 3843191783Srmacklem if (nd->nd_repstat == 0) { 3844191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3845191783Srmacklem lp->nfsl_stateid.seqid = *tl++; 3846191783Srmacklem lp->nfsl_stateid.other[0] = *tl++; 3847191783Srmacklem lp->nfsl_stateid.other[1] = *tl++; 3848191783Srmacklem lp->nfsl_stateid.other[2] = *tl; 3849191783Srmacklem } else if (nd->nd_repstat == NFSERR_DENIED) { 3850191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3851191783Srmacklem size = fxdr_unsigned(int, *(tl + 7)); 3852191783Srmacklem if (size < 0 || size > NFSV4_OPAQUELIMIT) 3853191783Srmacklem error = EBADRPC; 3854191783Srmacklem if (!error) 3855191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3856191783Srmacklem } else if (nd->nd_repstat == NFSERR_STALESTATEID) 3857191783Srmacklem nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 3858191783Srmacklemnfsmout: 3859191783Srmacklem mbuf_freem(nd->nd_mrep); 3860191783Srmacklem return (error); 3861191783Srmacklem} 3862191783Srmacklem 3863191783Srmacklem/* 3864191783Srmacklem * nfs statfs rpc 3865191783Srmacklem * (always called with the vp for the mount point) 3866191783Srmacklem */ 3867191783SrmacklemAPPLESTATIC int 3868191783Srmacklemnfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 3869191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3870191783Srmacklem void *stuff) 3871191783Srmacklem{ 3872191783Srmacklem u_int32_t *tl = NULL; 3873191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3874191783Srmacklem struct nfsmount *nmp; 3875191783Srmacklem nfsattrbit_t attrbits; 3876191783Srmacklem int error; 3877191783Srmacklem 3878191783Srmacklem *attrflagp = 0; 3879191783Srmacklem nmp = VFSTONFS(vnode_mount(vp)); 3880191783Srmacklem if (NFSHASNFSV4(nmp)) { 3881191783Srmacklem /* 3882191783Srmacklem * For V4, you actually do a getattr. 3883191783Srmacklem */ 3884191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 3885191783Srmacklem NFSSTATFS_GETATTRBIT(&attrbits); 3886191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3887191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3888191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3889191783Srmacklem if (error) 3890191783Srmacklem return (error); 3891191783Srmacklem if (nd->nd_repstat == 0) { 3892191783Srmacklem error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3893191783Srmacklem NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 3894191783Srmacklem cred); 3895191783Srmacklem if (!error) { 3896191783Srmacklem nmp->nm_fsid[0] = nap->na_filesid[0]; 3897191783Srmacklem nmp->nm_fsid[1] = nap->na_filesid[1]; 3898191783Srmacklem NFSSETHASSETFSID(nmp); 3899191783Srmacklem *attrflagp = 1; 3900191783Srmacklem } 3901191783Srmacklem } else { 3902191783Srmacklem error = nd->nd_repstat; 3903191783Srmacklem } 3904191783Srmacklem if (error) 3905191783Srmacklem goto nfsmout; 3906191783Srmacklem } else { 3907191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 3908191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3909191783Srmacklem if (error) 3910191783Srmacklem return (error); 3911191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 3912191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3913191783Srmacklem if (error) 3914191783Srmacklem goto nfsmout; 3915191783Srmacklem } 3916191783Srmacklem if (nd->nd_repstat) { 3917191783Srmacklem error = nd->nd_repstat; 3918191783Srmacklem goto nfsmout; 3919191783Srmacklem } 3920191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3921191783Srmacklem NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 3922191783Srmacklem } 3923191783Srmacklem if (NFSHASNFSV3(nmp)) { 3924191783Srmacklem sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 3925191783Srmacklem sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 3926191783Srmacklem sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 3927191783Srmacklem sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 3928191783Srmacklem sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 3929191783Srmacklem sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 3930191783Srmacklem sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 3931191783Srmacklem } else if (NFSHASNFSV4(nmp) == 0) { 3932191783Srmacklem sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 3933191783Srmacklem sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 3934191783Srmacklem sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 3935191783Srmacklem sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 3936191783Srmacklem sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 3937191783Srmacklem } 3938191783Srmacklemnfsmout: 3939191783Srmacklem mbuf_freem(nd->nd_mrep); 3940191783Srmacklem return (error); 3941191783Srmacklem} 3942191783Srmacklem 3943191783Srmacklem/* 3944191783Srmacklem * nfs pathconf rpc 3945191783Srmacklem */ 3946191783SrmacklemAPPLESTATIC int 3947191783Srmacklemnfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 3948191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3949191783Srmacklem void *stuff) 3950191783Srmacklem{ 3951191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3952191783Srmacklem struct nfsmount *nmp; 3953191783Srmacklem u_int32_t *tl; 3954191783Srmacklem nfsattrbit_t attrbits; 3955191783Srmacklem int error; 3956191783Srmacklem 3957191783Srmacklem *attrflagp = 0; 3958191783Srmacklem nmp = VFSTONFS(vnode_mount(vp)); 3959191783Srmacklem if (NFSHASNFSV4(nmp)) { 3960191783Srmacklem /* 3961191783Srmacklem * For V4, you actually do a getattr. 3962191783Srmacklem */ 3963191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 3964191783Srmacklem NFSPATHCONF_GETATTRBIT(&attrbits); 3965191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3966191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3967191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3968191783Srmacklem if (error) 3969191783Srmacklem return (error); 3970191783Srmacklem if (nd->nd_repstat == 0) { 3971191783Srmacklem error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3972191783Srmacklem pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 3973191783Srmacklem cred); 3974191783Srmacklem if (!error) 3975191783Srmacklem *attrflagp = 1; 3976191783Srmacklem } else { 3977191783Srmacklem error = nd->nd_repstat; 3978191783Srmacklem } 3979191783Srmacklem } else { 3980191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 3981191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3982191783Srmacklem if (error) 3983191783Srmacklem return (error); 3984191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3985191783Srmacklem if (nd->nd_repstat && !error) 3986191783Srmacklem error = nd->nd_repstat; 3987191783Srmacklem if (!error) { 3988191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 3989191783Srmacklem pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 3990191783Srmacklem pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 3991191783Srmacklem pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 3992191783Srmacklem pc->pc_chownrestricted = 3993191783Srmacklem fxdr_unsigned(u_int32_t, *tl++); 3994191783Srmacklem pc->pc_caseinsensitive = 3995191783Srmacklem fxdr_unsigned(u_int32_t, *tl++); 3996191783Srmacklem pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 3997191783Srmacklem } 3998191783Srmacklem } 3999191783Srmacklemnfsmout: 4000191783Srmacklem mbuf_freem(nd->nd_mrep); 4001191783Srmacklem return (error); 4002191783Srmacklem} 4003191783Srmacklem 4004191783Srmacklem/* 4005191783Srmacklem * nfs version 3 fsinfo rpc call 4006191783Srmacklem */ 4007191783SrmacklemAPPLESTATIC int 4008191783Srmacklemnfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 4009191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 4010191783Srmacklem{ 4011191783Srmacklem u_int32_t *tl; 4012191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4013191783Srmacklem int error; 4014191783Srmacklem 4015191783Srmacklem *attrflagp = 0; 4016191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 4017191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4018191783Srmacklem if (error) 4019191783Srmacklem return (error); 4020191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4021191783Srmacklem if (nd->nd_repstat && !error) 4022191783Srmacklem error = nd->nd_repstat; 4023191783Srmacklem if (!error) { 4024191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 4025191783Srmacklem fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 4026191783Srmacklem fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 4027191783Srmacklem fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 4028191783Srmacklem fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 4029191783Srmacklem fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 4030191783Srmacklem fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 4031191783Srmacklem fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 4032191783Srmacklem fsp->fs_maxfilesize = fxdr_hyper(tl); 4033191783Srmacklem tl += 2; 4034191783Srmacklem fxdr_nfsv3time(tl, &fsp->fs_timedelta); 4035191783Srmacklem tl += 2; 4036191783Srmacklem fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 4037191783Srmacklem } 4038191783Srmacklemnfsmout: 4039191783Srmacklem mbuf_freem(nd->nd_mrep); 4040191783Srmacklem return (error); 4041191783Srmacklem} 4042191783Srmacklem 4043191783Srmacklem/* 4044191783Srmacklem * This function performs the Renew RPC. 4045191783Srmacklem */ 4046191783SrmacklemAPPLESTATIC int 4047191783Srmacklemnfsrpc_renew(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) 4048191783Srmacklem{ 4049191783Srmacklem u_int32_t *tl; 4050191783Srmacklem struct nfsrv_descript nfsd; 4051191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4052191783Srmacklem struct nfsmount *nmp; 4053191783Srmacklem int error; 4054191783Srmacklem 4055191783Srmacklem nmp = clp->nfsc_nmp; 4056191783Srmacklem if (nmp == NULL) 4057191783Srmacklem return (0); 4058191783Srmacklem nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL); 4059191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4060191783Srmacklem *tl++ = clp->nfsc_clientid.lval[0]; 4061191783Srmacklem *tl = clp->nfsc_clientid.lval[1]; 4062191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4063191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4064191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4065191783Srmacklem if (error) 4066191783Srmacklem return (error); 4067191783Srmacklem error = nd->nd_repstat; 4068191783Srmacklem mbuf_freem(nd->nd_mrep); 4069191783Srmacklem return (error); 4070191783Srmacklem} 4071191783Srmacklem 4072191783Srmacklem/* 4073191783Srmacklem * This function performs the Releaselockowner RPC. 4074191783Srmacklem */ 4075191783SrmacklemAPPLESTATIC int 4076191783Srmacklemnfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4077229674Srmacklem uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4078191783Srmacklem{ 4079191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4080191783Srmacklem u_int32_t *tl; 4081191783Srmacklem int error; 4082223747Srmacklem uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4083191783Srmacklem 4084191783Srmacklem nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL); 4085191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4086191783Srmacklem *tl++ = nmp->nm_clp->nfsc_clientid.lval[0]; 4087191783Srmacklem *tl = nmp->nm_clp->nfsc_clientid.lval[1]; 4088223747Srmacklem NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4089229674Srmacklem NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4090229674Srmacklem (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4091191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4092191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4093191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4094191783Srmacklem if (error) 4095191783Srmacklem return (error); 4096191783Srmacklem error = nd->nd_repstat; 4097191783Srmacklem mbuf_freem(nd->nd_mrep); 4098191783Srmacklem return (error); 4099191783Srmacklem} 4100191783Srmacklem 4101191783Srmacklem/* 4102191783Srmacklem * This function performs the Compound to get the mount pt FH. 4103191783Srmacklem */ 4104191783SrmacklemAPPLESTATIC int 4105191783Srmacklemnfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4106191783Srmacklem NFSPROC_T *p) 4107191783Srmacklem{ 4108191783Srmacklem u_int32_t *tl; 4109191783Srmacklem struct nfsrv_descript nfsd; 4110191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4111191783Srmacklem u_char *cp, *cp2; 4112191783Srmacklem int error, cnt, len, setnil; 4113191783Srmacklem u_int32_t *opcntp; 4114191783Srmacklem 4115191783Srmacklem nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp); 4116191783Srmacklem cp = dirpath; 4117191783Srmacklem cnt = 0; 4118191783Srmacklem do { 4119191783Srmacklem setnil = 0; 4120191783Srmacklem while (*cp == '/') 4121191783Srmacklem cp++; 4122191783Srmacklem cp2 = cp; 4123191783Srmacklem while (*cp2 != '\0' && *cp2 != '/') 4124191783Srmacklem cp2++; 4125191783Srmacklem if (*cp2 == '/') { 4126191783Srmacklem setnil = 1; 4127191783Srmacklem *cp2 = '\0'; 4128191783Srmacklem } 4129191783Srmacklem if (cp2 != cp) { 4130191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4131191783Srmacklem *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4132191783Srmacklem nfsm_strtom(nd, cp, strlen(cp)); 4133191783Srmacklem cnt++; 4134191783Srmacklem } 4135191783Srmacklem if (setnil) 4136191783Srmacklem *cp2++ = '/'; 4137191783Srmacklem cp = cp2; 4138191783Srmacklem } while (*cp != '\0'); 4139191783Srmacklem *opcntp = txdr_unsigned(2 + cnt); 4140191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4141191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETFH); 4142191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4143191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4144191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4145191783Srmacklem if (error) 4146191783Srmacklem return (error); 4147191783Srmacklem if (nd->nd_repstat == 0) { 4148191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4149191783Srmacklem tl += (2 + 2 * cnt); 4150191783Srmacklem if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4151191783Srmacklem len > NFSX_FHMAX) { 4152191783Srmacklem nd->nd_repstat = NFSERR_BADXDR; 4153191783Srmacklem } else { 4154191783Srmacklem nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4155191783Srmacklem if (nd->nd_repstat == 0) 4156191783Srmacklem nmp->nm_fhsize = len; 4157191783Srmacklem } 4158191783Srmacklem } 4159191783Srmacklem error = nd->nd_repstat; 4160191783Srmacklemnfsmout: 4161191783Srmacklem mbuf_freem(nd->nd_mrep); 4162191783Srmacklem return (error); 4163191783Srmacklem} 4164191783Srmacklem 4165191783Srmacklem/* 4166191783Srmacklem * This function performs the Delegreturn RPC. 4167191783Srmacklem */ 4168191783SrmacklemAPPLESTATIC int 4169191783Srmacklemnfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4170191783Srmacklem struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4171191783Srmacklem{ 4172191783Srmacklem u_int32_t *tl; 4173191783Srmacklem struct nfsrv_descript nfsd; 4174191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4175191783Srmacklem int error; 4176191783Srmacklem 4177191783Srmacklem nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4178191783Srmacklem dp->nfsdl_fhlen, NULL); 4179191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4180191783Srmacklem *tl++ = dp->nfsdl_stateid.seqid; 4181191783Srmacklem *tl++ = dp->nfsdl_stateid.other[0]; 4182191783Srmacklem *tl++ = dp->nfsdl_stateid.other[1]; 4183191783Srmacklem *tl = dp->nfsdl_stateid.other[2]; 4184191783Srmacklem if (syscred) 4185191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4186191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4187191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4188191783Srmacklem if (error) 4189191783Srmacklem return (error); 4190191783Srmacklem error = nd->nd_repstat; 4191191783Srmacklem mbuf_freem(nd->nd_mrep); 4192191783Srmacklem return (error); 4193191783Srmacklem} 4194191783Srmacklem 4195191783Srmacklem/* 4196191783Srmacklem * nfs getacl call. 4197191783Srmacklem */ 4198191783SrmacklemAPPLESTATIC int 4199191783Srmacklemnfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4200191783Srmacklem struct acl *aclp, void *stuff) 4201191783Srmacklem{ 4202191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4203191783Srmacklem int error; 4204191783Srmacklem nfsattrbit_t attrbits; 4205191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4206191783Srmacklem 4207191783Srmacklem if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4208191783Srmacklem return (EOPNOTSUPP); 4209191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4210191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 4211191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4212191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 4213191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4214191783Srmacklem if (error) 4215191783Srmacklem return (error); 4216191783Srmacklem if (!nd->nd_repstat) 4217191783Srmacklem error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4218191783Srmacklem NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4219191783Srmacklem else 4220191783Srmacklem error = nd->nd_repstat; 4221191783Srmacklem mbuf_freem(nd->nd_mrep); 4222191783Srmacklem return (error); 4223191783Srmacklem} 4224191783Srmacklem 4225191783Srmacklem/* 4226191783Srmacklem * nfs setacl call. 4227191783Srmacklem */ 4228191783SrmacklemAPPLESTATIC int 4229191783Srmacklemnfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4230191783Srmacklem struct acl *aclp, void *stuff) 4231191783Srmacklem{ 4232191783Srmacklem int error; 4233191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4234191783Srmacklem 4235191783Srmacklem if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4236191783Srmacklem return (EOPNOTSUPP); 4237191783Srmacklem error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4238191783Srmacklem return (error); 4239191783Srmacklem} 4240191783Srmacklem 4241191783Srmacklem/* 4242191783Srmacklem * nfs setacl call. 4243191783Srmacklem */ 4244191783Srmacklemstatic int 4245191783Srmacklemnfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4246191783Srmacklem struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 4247191783Srmacklem{ 4248191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4249191783Srmacklem int error; 4250191783Srmacklem nfsattrbit_t attrbits; 4251191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4252191783Srmacklem 4253191783Srmacklem if (!NFSHASNFSV4(nmp)) 4254191783Srmacklem return (EOPNOTSUPP); 4255191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 4256191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 4257191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 4258191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4259220645Srmacklem (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0, 4260220648Srmacklem &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0); 4261191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4262191783Srmacklem if (error) 4263191783Srmacklem return (error); 4264191783Srmacklem /* Don't care about the pre/postop attributes */ 4265191783Srmacklem mbuf_freem(nd->nd_mrep); 4266191783Srmacklem return (nd->nd_repstat); 4267191783Srmacklem} 4268