nfs_clrpcops.c revision 220810
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: head/sys/fs/nfsclient/nfs_clrpcops.c 220810 2011-04-19 01:09:51Z rmacklem $"); 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 46191783Srmacklem#include <fs/nfs/nfsport.h> 47191783Srmacklem 48191783Srmacklem/* 49191783Srmacklem * Global variables 50191783Srmacklem */ 51191783Srmacklemextern int nfs_numnfscbd; 52191783Srmacklemextern struct timeval nfsboottime; 53191783Srmacklemextern u_int32_t newnfs_false, newnfs_true; 54191783Srmacklemextern nfstype nfsv34_type[9]; 55191783Srmacklemextern int nfsrv_useacl; 56191783Srmacklemextern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 57191783SrmacklemNFSCLSTATEMUTEX; 58191783Srmacklemint nfstest_outofseq = 0; 59191783Srmacklemint nfscl_assumeposixlocks = 1; 60191783Srmacklemint nfscl_enablecallb = 0; 61191783Srmacklemshort nfsv4_cbport = NFSV4_CBPORT; 62191783Srmacklemint nfstest_openallsetattr = 0; 63191783Srmacklem#endif /* !APPLEKEXT */ 64191783Srmacklem 65191783Srmacklem#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 66191783Srmacklem 67191783Srmacklemstatic int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, 68191783Srmacklem struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); 69191783Srmacklemstatic int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, 70191783Srmacklem nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *); 71191783Srmacklemstatic int nfsrpc_writerpc(vnode_t , struct uio *, int *, u_char *, 72191783Srmacklem struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, 73191783Srmacklem void *); 74191783Srmacklemstatic int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, 75191783Srmacklem nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, 76191783Srmacklem struct nfsvattr *, struct nfsfh **, int *, int *, void *); 77191783Srmacklemstatic int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, 78191783Srmacklem nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, 79191783Srmacklem NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, 80191783Srmacklem int *, void *, int *); 81191783Srmacklemstatic int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, 82191783Srmacklem struct nfscllockowner *, u_int64_t, u_int64_t, 83191783Srmacklem u_int32_t, struct ucred *, NFSPROC_T *, int); 84191783Srmacklemstatic int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, 85191783Srmacklem struct acl *, nfsv4stateid_t *, void *); 86191783Srmacklem 87191783Srmacklem/* 88191783Srmacklem * nfs null call from vfs. 89191783Srmacklem */ 90191783SrmacklemAPPLESTATIC int 91191783Srmacklemnfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) 92191783Srmacklem{ 93191783Srmacklem int error; 94191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 95191783Srmacklem 96191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_NULL, vp); 97191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 98191783Srmacklem if (nd->nd_repstat && !error) 99191783Srmacklem error = nd->nd_repstat; 100191783Srmacklem mbuf_freem(nd->nd_mrep); 101191783Srmacklem return (error); 102191783Srmacklem} 103191783Srmacklem 104191783Srmacklem/* 105191783Srmacklem * nfs access rpc op. 106191783Srmacklem * For nfs version 3 and 4, use the access rpc to check accessibility. If file 107191783Srmacklem * modes are changed on the server, accesses might still fail later. 108191783Srmacklem */ 109191783SrmacklemAPPLESTATIC int 110191783Srmacklemnfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, 111191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 112191783Srmacklem{ 113191783Srmacklem int error; 114191783Srmacklem u_int32_t mode, rmode; 115191783Srmacklem 116191783Srmacklem if (acmode & VREAD) 117191783Srmacklem mode = NFSACCESS_READ; 118191783Srmacklem else 119191783Srmacklem mode = 0; 120191783Srmacklem if (vnode_vtype(vp) == VDIR) { 121191783Srmacklem if (acmode & VWRITE) 122191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | 123191783Srmacklem NFSACCESS_DELETE); 124191783Srmacklem if (acmode & VEXEC) 125191783Srmacklem mode |= NFSACCESS_LOOKUP; 126191783Srmacklem } else { 127191783Srmacklem if (acmode & VWRITE) 128191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 129191783Srmacklem if (acmode & VEXEC) 130191783Srmacklem mode |= NFSACCESS_EXECUTE; 131191783Srmacklem } 132191783Srmacklem 133191783Srmacklem /* 134191783Srmacklem * Now, just call nfsrpc_accessrpc() to do the actual RPC. 135191783Srmacklem */ 136191783Srmacklem error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode, 137191783Srmacklem NULL); 138191783Srmacklem 139191783Srmacklem /* 140191783Srmacklem * The NFS V3 spec does not clarify whether or not 141191783Srmacklem * the returned access bits can be a superset of 142191783Srmacklem * the ones requested, so... 143191783Srmacklem */ 144191783Srmacklem if (!error && (rmode & mode) != mode) 145191783Srmacklem error = EACCES; 146191783Srmacklem return (error); 147191783Srmacklem} 148191783Srmacklem 149191783Srmacklem/* 150191783Srmacklem * The actual rpc, separated out for Darwin. 151191783Srmacklem */ 152191783SrmacklemAPPLESTATIC int 153191783Srmacklemnfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, 154191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep, 155191783Srmacklem void *stuff) 156191783Srmacklem{ 157191783Srmacklem u_int32_t *tl; 158191783Srmacklem u_int32_t supported, rmode; 159191783Srmacklem int error; 160191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 161191783Srmacklem nfsattrbit_t attrbits; 162191783Srmacklem 163191783Srmacklem *attrflagp = 0; 164191783Srmacklem supported = mode; 165191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp); 166191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 167191783Srmacklem *tl = txdr_unsigned(mode); 168191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 169191783Srmacklem /* 170191783Srmacklem * And do a Getattr op. 171191783Srmacklem */ 172191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 173191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 174191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 175191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 176191783Srmacklem } 177191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 178191783Srmacklem if (error) 179191783Srmacklem return (error); 180191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 181191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 182191783Srmacklem if (error) 183191783Srmacklem goto nfsmout; 184191783Srmacklem } 185191783Srmacklem if (!nd->nd_repstat) { 186191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 187191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 188191783Srmacklem supported = fxdr_unsigned(u_int32_t, *tl++); 189191783Srmacklem } else { 190191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 191191783Srmacklem } 192191783Srmacklem rmode = fxdr_unsigned(u_int32_t, *tl); 193191783Srmacklem if (nd->nd_flag & ND_NFSV4) 194191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 195191783Srmacklem 196191783Srmacklem /* 197191783Srmacklem * It's not obvious what should be done about 198191783Srmacklem * unsupported access modes. For now, be paranoid 199191783Srmacklem * and clear the unsupported ones. 200191783Srmacklem */ 201191783Srmacklem rmode &= supported; 202191783Srmacklem *rmodep = rmode; 203191783Srmacklem } else 204191783Srmacklem error = nd->nd_repstat; 205191783Srmacklemnfsmout: 206191783Srmacklem mbuf_freem(nd->nd_mrep); 207191783Srmacklem return (error); 208191783Srmacklem} 209191783Srmacklem 210191783Srmacklem/* 211191783Srmacklem * nfs open rpc 212191783Srmacklem */ 213191783SrmacklemAPPLESTATIC int 214191783Srmacklemnfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) 215191783Srmacklem{ 216191783Srmacklem struct nfsclopen *op; 217191783Srmacklem struct nfscldeleg *dp; 218191783Srmacklem struct nfsfh *nfhp; 219191783Srmacklem struct nfsnode *np = VTONFS(vp); 220191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 221191783Srmacklem u_int32_t mode, clidrev; 222191783Srmacklem int ret, newone, error, expireret = 0, retrycnt; 223191783Srmacklem 224191783Srmacklem /* 225191783Srmacklem * For NFSv4, Open Ops are only done on Regular Files. 226191783Srmacklem */ 227191783Srmacklem if (vnode_vtype(vp) != VREG) 228191783Srmacklem return (0); 229191783Srmacklem mode = 0; 230191783Srmacklem if (amode & FREAD) 231191783Srmacklem mode |= NFSV4OPEN_ACCESSREAD; 232191783Srmacklem if (amode & FWRITE) 233191783Srmacklem mode |= NFSV4OPEN_ACCESSWRITE; 234191783Srmacklem nfhp = np->n_fhp; 235191783Srmacklem 236191783Srmacklem retrycnt = 0; 237191783Srmacklem#ifdef notdef 238191783Srmacklem{ char name[100]; int namel; 239191783Srmacklemnamel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99; 240191783Srmacklembcopy(NFS4NODENAME(np->n_v4), name, namel); 241191783Srmacklemname[namel] = '\0'; 242191783Srmacklemprintf("rpcopen p=0x%x name=%s",p->p_pid,name); 243191783Srmacklemif (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]); 244191783Srmacklemelse printf(" fhl=0\n"); 245191783Srmacklem} 246191783Srmacklem#endif 247191783Srmacklem do { 248191783Srmacklem dp = NULL; 249191783Srmacklem error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, 250191783Srmacklem cred, p, NULL, &op, &newone, &ret, 1); 251191783Srmacklem if (error) { 252191783Srmacklem return (error); 253191783Srmacklem } 254191783Srmacklem if (nmp->nm_clp != NULL) 255191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 256191783Srmacklem else 257191783Srmacklem clidrev = 0; 258191783Srmacklem if (ret == NFSCLOPEN_DOOPEN) { 259191783Srmacklem if (np->n_v4 != NULL) { 260191783Srmacklem error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data, 261191783Srmacklem np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 262191783Srmacklem np->n_fhp->nfh_len, mode, op, 263191783Srmacklem NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, 264191783Srmacklem 0, 0x0, cred, p, 0, 0); 265191783Srmacklem if (dp != NULL) { 266191783Srmacklem#ifdef APPLE 267191783Srmacklem OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); 268191783Srmacklem#else 269191783Srmacklem NFSLOCKNODE(np); 270191783Srmacklem np->n_flag &= ~NDELEGMOD; 271210034Srmacklem /* 272210034Srmacklem * Invalidate the attribute cache, so that 273210034Srmacklem * attributes that pre-date the issue of a 274210034Srmacklem * delegation are not cached, since the 275210034Srmacklem * cached attributes will remain valid while 276210034Srmacklem * the delegation is held. 277210034Srmacklem */ 278210034Srmacklem NFSINVALATTRCACHE(np); 279191783Srmacklem NFSUNLOCKNODE(np); 280191783Srmacklem#endif 281191783Srmacklem (void) nfscl_deleg(nmp->nm_mountp, 282191783Srmacklem op->nfso_own->nfsow_clp, 283191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); 284191783Srmacklem } 285191783Srmacklem } else { 286191783Srmacklem error = EIO; 287191783Srmacklem } 288191783Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 289206688Srmacklem } else if (ret == NFSCLOPEN_SETCRED) 290206688Srmacklem /* 291206688Srmacklem * This is a new local open on a delegation. It needs 292206688Srmacklem * to have credentials so that an open can be done 293206688Srmacklem * against the server during recovery. 294206688Srmacklem */ 295206688Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 296191783Srmacklem 297191783Srmacklem /* 298191783Srmacklem * nfso_opencnt is the count of how many VOP_OPEN()s have 299191783Srmacklem * been done on this Open successfully and a VOP_CLOSE() 300191783Srmacklem * is expected for each of these. 301191783Srmacklem * If error is non-zero, don't increment it, since the Open 302191783Srmacklem * hasn't succeeded yet. 303191783Srmacklem */ 304191783Srmacklem if (!error) 305191783Srmacklem op->nfso_opencnt++; 306191783Srmacklem nfscl_openrelease(op, error, newone); 307191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 308191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) { 309207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_open"); 310191783Srmacklem } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 311191783Srmacklem && clidrev != 0) { 312191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 313191783Srmacklem retrycnt++; 314191783Srmacklem } 315191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 316191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 317191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 318191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 319191783Srmacklem if (error && retrycnt >= 4) 320191783Srmacklem error = EIO; 321191783Srmacklem return (error); 322191783Srmacklem} 323191783Srmacklem 324191783Srmacklem/* 325191783Srmacklem * the actual open rpc 326191783Srmacklem */ 327191783SrmacklemAPPLESTATIC int 328191783Srmacklemnfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, 329191783Srmacklem u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 330191783Srmacklem u_int8_t *name, int namelen, struct nfscldeleg **dpp, 331191783Srmacklem int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, 332191783Srmacklem int syscred, int recursed) 333191783Srmacklem{ 334191783Srmacklem u_int32_t *tl; 335191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 336191783Srmacklem struct nfscldeleg *dp, *ndp = NULL; 337191783Srmacklem struct nfsvattr nfsva; 338191783Srmacklem u_int32_t rflags, deleg; 339191783Srmacklem nfsattrbit_t attrbits; 340191783Srmacklem int error, ret, acesize, limitby; 341191783Srmacklem 342191783Srmacklem dp = *dpp; 343191783Srmacklem *dpp = NULL; 344191783Srmacklem nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL); 345191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 346191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 347191783Srmacklem *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 348191783Srmacklem *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 349191783Srmacklem *tl++ = op->nfso_own->nfsow_clp->nfsc_clientid.lval[0]; 350191783Srmacklem *tl = op->nfso_own->nfsow_clp->nfsc_clientid.lval[1]; 351191783Srmacklem (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 352191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 353191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 354191783Srmacklem if (reclaim) { 355191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); 356191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 357191783Srmacklem *tl = txdr_unsigned(delegtype); 358191783Srmacklem } else { 359191783Srmacklem if (dp != NULL) { 360191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); 361191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 362191783Srmacklem *tl++ = dp->nfsdl_stateid.seqid; 363191783Srmacklem *tl++ = dp->nfsdl_stateid.other[0]; 364191783Srmacklem *tl++ = dp->nfsdl_stateid.other[1]; 365191783Srmacklem *tl = dp->nfsdl_stateid.other[2]; 366191783Srmacklem } else { 367191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 368191783Srmacklem } 369191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 370191783Srmacklem } 371191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 372191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 373191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 374191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 375191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 376191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 377191783Srmacklem if (syscred) 378191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 379191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 380191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 381191783Srmacklem if (error) 382191783Srmacklem return (error); 383191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 384191783Srmacklem if (!nd->nd_repstat) { 385191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 386191783Srmacklem 6 * NFSX_UNSIGNED); 387191783Srmacklem op->nfso_stateid.seqid = *tl++; 388191783Srmacklem op->nfso_stateid.other[0] = *tl++; 389191783Srmacklem op->nfso_stateid.other[1] = *tl++; 390191783Srmacklem op->nfso_stateid.other[2] = *tl; 391191783Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 392191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 393191783Srmacklem if (error) 394191783Srmacklem goto nfsmout; 395191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 396191783Srmacklem deleg = fxdr_unsigned(u_int32_t, *tl); 397191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 398191783Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 399191783Srmacklem if (!(op->nfso_own->nfsow_clp->nfsc_flags & 400191783Srmacklem NFSCLFLAGS_FIRSTDELEG)) 401191783Srmacklem op->nfso_own->nfsow_clp->nfsc_flags |= 402191783Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 403191783Srmacklem MALLOC(ndp, struct nfscldeleg *, 404191783Srmacklem sizeof (struct nfscldeleg) + newfhlen, 405191783Srmacklem M_NFSCLDELEG, M_WAITOK); 406191783Srmacklem LIST_INIT(&ndp->nfsdl_owner); 407191783Srmacklem LIST_INIT(&ndp->nfsdl_lock); 408191783Srmacklem ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 409191783Srmacklem ndp->nfsdl_fhlen = newfhlen; 410191783Srmacklem NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 411191783Srmacklem newnfs_copyincred(cred, &ndp->nfsdl_cred); 412191783Srmacklem nfscl_lockinit(&ndp->nfsdl_rwlock); 413191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 414191783Srmacklem NFSX_UNSIGNED); 415191783Srmacklem ndp->nfsdl_stateid.seqid = *tl++; 416191783Srmacklem ndp->nfsdl_stateid.other[0] = *tl++; 417191783Srmacklem ndp->nfsdl_stateid.other[1] = *tl++; 418191783Srmacklem ndp->nfsdl_stateid.other[2] = *tl++; 419191783Srmacklem ret = fxdr_unsigned(int, *tl); 420191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 421191783Srmacklem ndp->nfsdl_flags = NFSCLDL_WRITE; 422191783Srmacklem /* 423191783Srmacklem * Indicates how much the file can grow. 424191783Srmacklem */ 425191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 426191783Srmacklem 3 * NFSX_UNSIGNED); 427191783Srmacklem limitby = fxdr_unsigned(int, *tl++); 428191783Srmacklem switch (limitby) { 429191783Srmacklem case NFSV4OPEN_LIMITSIZE: 430191783Srmacklem ndp->nfsdl_sizelimit = fxdr_hyper(tl); 431191783Srmacklem break; 432191783Srmacklem case NFSV4OPEN_LIMITBLOCKS: 433191783Srmacklem ndp->nfsdl_sizelimit = 434191783Srmacklem fxdr_unsigned(u_int64_t, *tl++); 435191783Srmacklem ndp->nfsdl_sizelimit *= 436191783Srmacklem fxdr_unsigned(u_int64_t, *tl); 437191783Srmacklem break; 438191783Srmacklem default: 439191783Srmacklem error = NFSERR_BADXDR; 440191783Srmacklem goto nfsmout; 441191783Srmacklem }; 442191783Srmacklem } else { 443191783Srmacklem ndp->nfsdl_flags = NFSCLDL_READ; 444191783Srmacklem } 445191783Srmacklem if (ret) 446191783Srmacklem ndp->nfsdl_flags |= NFSCLDL_RECALL; 447191783Srmacklem error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 448191783Srmacklem &acesize, p); 449191783Srmacklem if (error) 450191783Srmacklem goto nfsmout; 451191783Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 452191783Srmacklem error = NFSERR_BADXDR; 453191783Srmacklem goto nfsmout; 454191783Srmacklem } 455191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 456191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 457191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 458191783Srmacklem NULL, NULL, NULL, p, cred); 459191783Srmacklem if (error) 460191783Srmacklem goto nfsmout; 461191783Srmacklem if (ndp != NULL) { 462191783Srmacklem ndp->nfsdl_change = nfsva.na_filerev; 463191783Srmacklem ndp->nfsdl_modtime = nfsva.na_mtime; 464191783Srmacklem ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 465191783Srmacklem } 466191783Srmacklem if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { 467191783Srmacklem do { 468191783Srmacklem ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, 469191783Srmacklem cred, p); 470191783Srmacklem if (ret == NFSERR_DELAY) 471207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_open"); 472191783Srmacklem } while (ret == NFSERR_DELAY); 473191783Srmacklem error = ret; 474191783Srmacklem } 475191783Srmacklem if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || 476191783Srmacklem nfscl_assumeposixlocks) 477191783Srmacklem op->nfso_posixlock = 1; 478191783Srmacklem else 479191783Srmacklem op->nfso_posixlock = 0; 480191783Srmacklem 481191783Srmacklem /* 482191783Srmacklem * If the server is handing out delegations, but we didn't 483191783Srmacklem * get one because an OpenConfirm was required, try the 484191783Srmacklem * Open again, to get a delegation. This is a harmless no-op, 485191783Srmacklem * from a server's point of view. 486191783Srmacklem */ 487191783Srmacklem if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && 488191783Srmacklem (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) 489191783Srmacklem && !error && dp == NULL && ndp == NULL && !recursed) { 490191783Srmacklem do { 491191783Srmacklem ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, 492191783Srmacklem newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, 493191783Srmacklem cred, p, syscred, 1); 494191783Srmacklem if (ret == NFSERR_DELAY) 495207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_open2"); 496191783Srmacklem } while (ret == NFSERR_DELAY); 497191783Srmacklem if (ret) { 498191783Srmacklem if (ndp != NULL) 499191783Srmacklem FREE((caddr_t)ndp, M_NFSCLDELEG); 500191783Srmacklem if (ret == NFSERR_STALECLIENTID || 501191783Srmacklem ret == NFSERR_STALEDONTRECOVER) 502191783Srmacklem error = ret; 503191783Srmacklem } 504191783Srmacklem } 505191783Srmacklem } 506191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 507191783Srmacklem error = nd->nd_repstat; 508191783Srmacklem if (error == NFSERR_STALECLIENTID) 509191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 510191783Srmacklemnfsmout: 511191783Srmacklem if (!error) 512191783Srmacklem *dpp = ndp; 513191783Srmacklem else if (ndp != NULL) 514191783Srmacklem FREE((caddr_t)ndp, M_NFSCLDELEG); 515191783Srmacklem mbuf_freem(nd->nd_mrep); 516191783Srmacklem return (error); 517191783Srmacklem} 518191783Srmacklem 519191783Srmacklem/* 520191783Srmacklem * open downgrade rpc 521191783Srmacklem */ 522191783SrmacklemAPPLESTATIC int 523191783Srmacklemnfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, 524191783Srmacklem struct ucred *cred, NFSPROC_T *p) 525191783Srmacklem{ 526191783Srmacklem u_int32_t *tl; 527191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 528191783Srmacklem int error; 529191783Srmacklem 530191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp); 531191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 532191783Srmacklem *tl++ = op->nfso_stateid.seqid; 533191783Srmacklem *tl++ = op->nfso_stateid.other[0]; 534191783Srmacklem *tl++ = op->nfso_stateid.other[1]; 535191783Srmacklem *tl++ = op->nfso_stateid.other[2]; 536191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 537191783Srmacklem *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 538191783Srmacklem *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 539191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 540191783Srmacklem if (error) 541191783Srmacklem return (error); 542191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 543191783Srmacklem if (!nd->nd_repstat) { 544191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 545191783Srmacklem op->nfso_stateid.seqid = *tl++; 546191783Srmacklem op->nfso_stateid.other[0] = *tl++; 547191783Srmacklem op->nfso_stateid.other[1] = *tl++; 548191783Srmacklem op->nfso_stateid.other[2] = *tl; 549191783Srmacklem } 550191783Srmacklem if (nd->nd_repstat && error == 0) 551191783Srmacklem error = nd->nd_repstat; 552191783Srmacklem if (error == NFSERR_STALESTATEID) 553191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 554191783Srmacklemnfsmout: 555191783Srmacklem mbuf_freem(nd->nd_mrep); 556191783Srmacklem return (error); 557191783Srmacklem} 558191783Srmacklem 559191783Srmacklem/* 560191783Srmacklem * V4 Close operation. 561191783Srmacklem */ 562191783SrmacklemAPPLESTATIC int 563192337Srmacklemnfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) 564191783Srmacklem{ 565191783Srmacklem struct nfsclclient *clp; 566191783Srmacklem int error; 567191783Srmacklem 568191783Srmacklem if (vnode_vtype(vp) != VREG) 569191783Srmacklem return (0); 570192337Srmacklem if (doclose) 571195510Srmacklem error = nfscl_doclose(vp, &clp, p); 572192337Srmacklem else 573195510Srmacklem error = nfscl_getclose(vp, &clp); 574191783Srmacklem if (error) 575191783Srmacklem return (error); 576191783Srmacklem 577191783Srmacklem nfscl_clientrelease(clp); 578191783Srmacklem return (0); 579191783Srmacklem} 580191783Srmacklem 581191783Srmacklem/* 582195510Srmacklem * Close the open. 583191783Srmacklem */ 584195510SrmacklemAPPLESTATIC void 585195510Srmacklemnfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p) 586191783Srmacklem{ 587191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 588191783Srmacklem struct nfscllockowner *lp; 589191783Srmacklem struct nfscllock *lop, *nlop; 590191783Srmacklem struct ucred *tcred; 591191783Srmacklem u_int64_t off = 0, len = 0; 592191783Srmacklem u_int32_t type = NFSV4LOCKT_READ; 593195510Srmacklem int error, do_unlock, trycnt; 594191783Srmacklem 595191783Srmacklem tcred = newnfs_getcred(); 596195510Srmacklem newnfs_copycred(&op->nfso_cred, tcred); 597195510Srmacklem /* 598195510Srmacklem * (Theoretically this could be done in the same 599195510Srmacklem * compound as the close, but having multiple 600195510Srmacklem * sequenced Ops in the same compound might be 601195510Srmacklem * too scary for some servers.) 602195510Srmacklem */ 603195510Srmacklem if (op->nfso_posixlock) { 604195510Srmacklem off = 0; 605195510Srmacklem len = NFS64BITSSET; 606195510Srmacklem type = NFSV4LOCKT_READ; 607195510Srmacklem } 608195510Srmacklem 609195510Srmacklem /* 610195510Srmacklem * Since this function is only called from VOP_INACTIVE(), no 611195510Srmacklem * other thread will be manipulating this Open. As such, the 612195510Srmacklem * lock lists are not being changed by other threads, so it should 613195510Srmacklem * be safe to do this without locking. 614195510Srmacklem */ 615195510Srmacklem LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 616195510Srmacklem do_unlock = 1; 617195510Srmacklem LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 618191783Srmacklem if (op->nfso_posixlock == 0) { 619195510Srmacklem off = lop->nfslo_first; 620195510Srmacklem len = lop->nfslo_end - lop->nfslo_first; 621195510Srmacklem if (lop->nfslo_type == F_WRLCK) 622195510Srmacklem type = NFSV4LOCKT_WRITE; 623195510Srmacklem else 624195510Srmacklem type = NFSV4LOCKT_READ; 625191783Srmacklem } 626195510Srmacklem if (do_unlock) { 627195510Srmacklem trycnt = 0; 628195510Srmacklem do { 629195510Srmacklem error = nfsrpc_locku(nd, nmp, lp, off, 630195510Srmacklem len, type, tcred, p, 0); 631195510Srmacklem if ((nd->nd_repstat == NFSERR_GRACE || 632195510Srmacklem nd->nd_repstat == NFSERR_DELAY) && 633195510Srmacklem error == 0) 634195510Srmacklem (void) nfs_catnap(PZERO, 635207170Srmacklem (int)nd->nd_repstat, 636195510Srmacklem "nfs_close"); 637195510Srmacklem } while ((nd->nd_repstat == NFSERR_GRACE || 638195510Srmacklem nd->nd_repstat == NFSERR_DELAY) && 639195510Srmacklem error == 0 && trycnt++ < 5); 640195510Srmacklem if (op->nfso_posixlock) 641195510Srmacklem do_unlock = 0; 642191783Srmacklem } 643191783Srmacklem nfscl_freelock(lop, 0); 644191783Srmacklem } 645195510Srmacklem } 646191783Srmacklem 647195510Srmacklem /* 648195510Srmacklem * There could be other Opens for different files on the same 649195510Srmacklem * OpenOwner, so locking is required. 650195510Srmacklem */ 651195510Srmacklem NFSLOCKCLSTATE(); 652195510Srmacklem nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 653195510Srmacklem NFSUNLOCKCLSTATE(); 654195510Srmacklem do { 655195510Srmacklem error = nfscl_tryclose(op, tcred, nmp, p); 656195510Srmacklem if (error == NFSERR_GRACE) 657207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_close"); 658195510Srmacklem } while (error == NFSERR_GRACE); 659195510Srmacklem NFSLOCKCLSTATE(); 660195510Srmacklem nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); 661195510Srmacklem 662195510Srmacklem /* 663195510Srmacklem * Move the lockowner to nfsc_defunctlockowner, 664195510Srmacklem * so the Renew thread will do the ReleaseLockOwner 665195510Srmacklem * Op on it later. There might still be other 666195510Srmacklem * opens using the same lockowner name. 667195510Srmacklem */ 668195510Srmacklem lp = LIST_FIRST(&op->nfso_lock); 669195510Srmacklem if (lp != NULL) { 670195510Srmacklem while (LIST_NEXT(lp, nfsl_list) != NULL) 671191783Srmacklem lp = LIST_NEXT(lp, nfsl_list); 672195510Srmacklem LIST_PREPEND(&nmp->nm_clp->nfsc_defunctlockowner, 673195510Srmacklem &op->nfso_lock, lp, nfsl_list); 674195510Srmacklem LIST_INIT(&op->nfso_lock); 675191783Srmacklem } 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); 1138191783Srmacklem goto nfsmout; 1139191783Srmacklem } 1140191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 1141191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1142191783Srmacklem if (*(tl + 1)) { 1143191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 1144191783Srmacklem goto nfsmout; 1145191783Srmacklem } 1146191783Srmacklem } 1147191783Srmacklem error = nfsm_getfh(nd, nfhpp); 1148191783Srmacklem if (error) 1149191783Srmacklem goto nfsmout; 1150191783Srmacklem 1151191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1152191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) 1153191783Srmacklem error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1154191783Srmacklemnfsmout: 1155191783Srmacklem mbuf_freem(nd->nd_mrep); 1156191783Srmacklem if (!error && nd->nd_repstat) 1157191783Srmacklem error = nd->nd_repstat; 1158191783Srmacklem return (error); 1159191783Srmacklem} 1160191783Srmacklem 1161191783Srmacklem/* 1162191783Srmacklem * Do a readlink rpc. 1163191783Srmacklem */ 1164191783SrmacklemAPPLESTATIC int 1165191783Srmacklemnfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, 1166191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1167191783Srmacklem{ 1168191783Srmacklem u_int32_t *tl; 1169191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1170191783Srmacklem struct nfsnode *np = VTONFS(vp); 1171191783Srmacklem nfsattrbit_t attrbits; 1172191783Srmacklem int error, len, cangetattr = 1; 1173191783Srmacklem 1174191783Srmacklem *attrflagp = 0; 1175191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READLINK, vp); 1176191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1177191783Srmacklem /* 1178191783Srmacklem * And do a Getattr op. 1179191783Srmacklem */ 1180191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1181191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1182191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1183191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1184191783Srmacklem } 1185191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1186191783Srmacklem if (error) 1187191783Srmacklem return (error); 1188191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1189191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1190191783Srmacklem if (!nd->nd_repstat && !error) { 1191191783Srmacklem NFSM_STRSIZ(len, NFS_MAXPATHLEN); 1192191783Srmacklem /* 1193191783Srmacklem * This seems weird to me, but must have been added to 1194191783Srmacklem * FreeBSD for some reason. The only thing I can think of 1195191783Srmacklem * is that there was/is some server that replies with 1196191783Srmacklem * more link data than it should? 1197191783Srmacklem */ 1198191783Srmacklem if (len == NFS_MAXPATHLEN) { 1199191783Srmacklem NFSLOCKNODE(np); 1200191783Srmacklem if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { 1201191783Srmacklem len = np->n_size; 1202191783Srmacklem cangetattr = 0; 1203191783Srmacklem } 1204191783Srmacklem NFSUNLOCKNODE(np); 1205191783Srmacklem } 1206191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 1207191783Srmacklem if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) 1208191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1209191783Srmacklem } 1210191783Srmacklem if (nd->nd_repstat && !error) 1211191783Srmacklem error = nd->nd_repstat; 1212191783Srmacklemnfsmout: 1213191783Srmacklem mbuf_freem(nd->nd_mrep); 1214191783Srmacklem return (error); 1215191783Srmacklem} 1216191783Srmacklem 1217191783Srmacklem/* 1218191783Srmacklem * Read operation. 1219191783Srmacklem */ 1220191783SrmacklemAPPLESTATIC int 1221191783Srmacklemnfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, 1222191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1223191783Srmacklem{ 1224191783Srmacklem int error, expireret = 0, retrycnt; 1225191783Srmacklem u_int32_t clidrev = 0; 1226191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1227191783Srmacklem struct nfsnode *np = VTONFS(vp); 1228191783Srmacklem struct ucred *newcred; 1229191783Srmacklem struct nfsfh *nfhp = NULL; 1230191783Srmacklem nfsv4stateid_t stateid; 1231191783Srmacklem void *lckp; 1232191783Srmacklem 1233191783Srmacklem if (nmp->nm_clp != NULL) 1234191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1235191783Srmacklem newcred = cred; 1236191783Srmacklem if (NFSHASNFSV4(nmp)) { 1237191783Srmacklem nfhp = np->n_fhp; 1238191783Srmacklem if (p == NULL) 1239191783Srmacklem newcred = NFSNEWCRED(cred); 1240191783Srmacklem } 1241191783Srmacklem retrycnt = 0; 1242191783Srmacklem do { 1243191783Srmacklem lckp = NULL; 1244191783Srmacklem if (NFSHASNFSV4(nmp)) 1245191783Srmacklem (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1246191783Srmacklem NFSV4OPEN_ACCESSREAD, newcred, p, &stateid, &lckp); 1247191783Srmacklem error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, 1248191783Srmacklem attrflagp, stuff); 1249191783Srmacklem if (error == NFSERR_STALESTATEID) 1250191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1251191783Srmacklem if (lckp != NULL) 1252191783Srmacklem nfscl_lockderef(lckp); 1253191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1254191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1255191783Srmacklem error == NFSERR_OLDSTATEID) { 1256207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_read"); 1257191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1258191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1259191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1260191783Srmacklem } 1261191783Srmacklem retrycnt++; 1262191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1263191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1264191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1265191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1266191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1267191783Srmacklem if (error && retrycnt >= 4) 1268191783Srmacklem error = EIO; 1269191783Srmacklem if (NFSHASNFSV4(nmp) && p == NULL) 1270191783Srmacklem NFSFREECRED(newcred); 1271191783Srmacklem return (error); 1272191783Srmacklem} 1273191783Srmacklem 1274191783Srmacklem/* 1275191783Srmacklem * The actual read RPC. 1276191783Srmacklem */ 1277191783Srmacklemstatic int 1278191783Srmacklemnfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, 1279191783Srmacklem nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, 1280191783Srmacklem int *attrflagp, void *stuff) 1281191783Srmacklem{ 1282191783Srmacklem u_int32_t *tl; 1283191783Srmacklem int error = 0, len, retlen, tsiz, eof = 0; 1284191783Srmacklem struct nfsrv_descript nfsd; 1285191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1286191783Srmacklem struct nfsrv_descript *nd = &nfsd; 1287220810Srmacklem int rsize; 1288191783Srmacklem 1289191783Srmacklem *attrflagp = 0; 1290191783Srmacklem tsiz = uio_uio_resid(uiop); 1291220810Srmacklem NFSLOCKMNT(nmp); 1292220810Srmacklem if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) { 1293220810Srmacklem /* XXX Needs overflow/negative check for uio_offset */ 1294220810Srmacklem NFSUNLOCKMNT(nmp); 1295191783Srmacklem return (EFBIG); 1296220810Srmacklem } 1297220810Srmacklem rsize = nmp->nm_rsize; 1298220810Srmacklem NFSUNLOCKMNT(nmp); 1299191783Srmacklem nd->nd_mrep = NULL; 1300191783Srmacklem while (tsiz > 0) { 1301191783Srmacklem *attrflagp = 0; 1302220810Srmacklem len = (tsiz > rsize) ? rsize : tsiz; 1303191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READ, vp); 1304191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1305191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1306191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1307191783Srmacklem if (nd->nd_flag & ND_NFSV2) { 1308191783Srmacklem *tl++ = txdr_unsigned(uiop->uio_offset); 1309191783Srmacklem *tl++ = txdr_unsigned(len); 1310191783Srmacklem *tl = 0; 1311191783Srmacklem } else { 1312191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1313191783Srmacklem *(tl + 2) = txdr_unsigned(len); 1314191783Srmacklem } 1315191783Srmacklem /* 1316191783Srmacklem * Since I can't do a Getattr for NFSv4 for Write, there 1317191783Srmacklem * doesn't seem any point in doing one here, either. 1318191783Srmacklem * (See the comment in nfsrpc_writerpc() for more info.) 1319191783Srmacklem */ 1320191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1321191783Srmacklem if (error) 1322191783Srmacklem return (error); 1323191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1324191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1325191783Srmacklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { 1326191783Srmacklem error = nfsm_loadattr(nd, nap); 1327191783Srmacklem if (!error) 1328191783Srmacklem *attrflagp = 1; 1329191783Srmacklem } 1330191783Srmacklem if (nd->nd_repstat || error) { 1331191783Srmacklem if (!error) 1332191783Srmacklem error = nd->nd_repstat; 1333191783Srmacklem goto nfsmout; 1334191783Srmacklem } 1335191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1336191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1337191783Srmacklem eof = fxdr_unsigned(int, *(tl + 1)); 1338191783Srmacklem } else if (nd->nd_flag & ND_NFSV4) { 1339191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1340191783Srmacklem eof = fxdr_unsigned(int, *tl); 1341191783Srmacklem } 1342220810Srmacklem NFSM_STRSIZ(retlen, rsize); 1343191783Srmacklem error = nfsm_mbufuio(nd, uiop, retlen); 1344191783Srmacklem if (error) 1345191783Srmacklem goto nfsmout; 1346191783Srmacklem mbuf_freem(nd->nd_mrep); 1347191783Srmacklem nd->nd_mrep = NULL; 1348191783Srmacklem tsiz -= retlen; 1349191783Srmacklem if (!(nd->nd_flag & ND_NFSV2)) { 1350191783Srmacklem if (eof || retlen == 0) 1351191783Srmacklem tsiz = 0; 1352191783Srmacklem } else if (retlen < len) 1353191783Srmacklem tsiz = 0; 1354191783Srmacklem } 1355191783Srmacklem return (0); 1356191783Srmacklemnfsmout: 1357191783Srmacklem if (nd->nd_mrep != NULL) 1358191783Srmacklem mbuf_freem(nd->nd_mrep); 1359191783Srmacklem return (error); 1360191783Srmacklem} 1361191783Srmacklem 1362191783Srmacklem/* 1363191783Srmacklem * nfs write operation 1364207082Srmacklem * When called_from_strategy != 0, it should return EIO for an error that 1365207082Srmacklem * indicates recovery is in progress, so that the buffer will be left 1366207082Srmacklem * dirty and be written back to the server later. If it loops around, 1367207082Srmacklem * the recovery thread could get stuck waiting for the buffer and recovery 1368207082Srmacklem * will then deadlock. 1369191783Srmacklem */ 1370191783SrmacklemAPPLESTATIC int 1371191783Srmacklemnfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, u_char *verfp, 1372191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 1373207082Srmacklem void *stuff, int called_from_strategy) 1374191783Srmacklem{ 1375191783Srmacklem int error, expireret = 0, retrycnt, nostateid; 1376191783Srmacklem u_int32_t clidrev = 0; 1377191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1378191783Srmacklem struct nfsnode *np = VTONFS(vp); 1379191783Srmacklem struct ucred *newcred; 1380191783Srmacklem struct nfsfh *nfhp = NULL; 1381191783Srmacklem nfsv4stateid_t stateid; 1382191783Srmacklem void *lckp; 1383191783Srmacklem 1384191783Srmacklem if (nmp->nm_clp != NULL) 1385191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1386191783Srmacklem newcred = cred; 1387191783Srmacklem if (NFSHASNFSV4(nmp)) { 1388191783Srmacklem if (p == NULL) 1389191783Srmacklem newcred = NFSNEWCRED(cred); 1390191783Srmacklem nfhp = np->n_fhp; 1391191783Srmacklem } 1392191783Srmacklem retrycnt = 0; 1393191783Srmacklem do { 1394191783Srmacklem lckp = NULL; 1395191783Srmacklem nostateid = 0; 1396191783Srmacklem if (NFSHASNFSV4(nmp)) { 1397191783Srmacklem (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1398191783Srmacklem NFSV4OPEN_ACCESSWRITE, newcred, p, &stateid, &lckp); 1399191783Srmacklem if (stateid.other[0] == 0 && stateid.other[1] == 0 && 1400191783Srmacklem stateid.other[2] == 0) { 1401191783Srmacklem nostateid = 1; 1402191783Srmacklem printf("stateid0 in write\n"); 1403191783Srmacklem } 1404191783Srmacklem } 1405191783Srmacklem 1406191783Srmacklem /* 1407191783Srmacklem * If there is no stateid for NFSv4, it means this is an 1408191783Srmacklem * extraneous write after close. Basically a poorly 1409191783Srmacklem * implemented buffer cache. Just don't do the write. 1410191783Srmacklem */ 1411191783Srmacklem if (nostateid) 1412191783Srmacklem error = 0; 1413191783Srmacklem else 1414191783Srmacklem error = nfsrpc_writerpc(vp, uiop, iomode, verfp, 1415191783Srmacklem newcred, &stateid, p, nap, attrflagp, stuff); 1416191783Srmacklem if (error == NFSERR_STALESTATEID) 1417191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1418191783Srmacklem if (lckp != NULL) 1419191783Srmacklem nfscl_lockderef(lckp); 1420191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1421191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1422191783Srmacklem error == NFSERR_OLDSTATEID) { 1423207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_write"); 1424191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1425191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1426191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1427191783Srmacklem } 1428191783Srmacklem retrycnt++; 1429207082Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 1430207082Srmacklem ((error == NFSERR_STALESTATEID || 1431207082Srmacklem error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || 1432191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1433191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1434191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1435207082Srmacklem if (error != 0 && (retrycnt >= 4 || 1436207082Srmacklem ((error == NFSERR_STALESTATEID || 1437207082Srmacklem error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0))) 1438191783Srmacklem error = EIO; 1439191783Srmacklem if (NFSHASNFSV4(nmp) && p == NULL) 1440191783Srmacklem NFSFREECRED(newcred); 1441191783Srmacklem return (error); 1442191783Srmacklem} 1443191783Srmacklem 1444191783Srmacklem/* 1445191783Srmacklem * The actual write RPC. 1446191783Srmacklem */ 1447191783Srmacklemstatic int 1448191783Srmacklemnfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, 1449191783Srmacklem u_char *verfp, struct ucred *cred, nfsv4stateid_t *stateidp, 1450191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1451191783Srmacklem{ 1452191783Srmacklem u_int32_t *tl; 1453191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1454191783Srmacklem struct nfsnode *np = VTONFS(vp); 1455191783Srmacklem int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; 1456191783Srmacklem int wccflag = 0, wsize; 1457191783Srmacklem int32_t backup; 1458191783Srmacklem struct nfsrv_descript nfsd; 1459191783Srmacklem struct nfsrv_descript *nd = &nfsd; 1460191783Srmacklem nfsattrbit_t attrbits; 1461191783Srmacklem 1462209120Skib KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 1463191783Srmacklem *attrflagp = 0; 1464191783Srmacklem tsiz = uio_uio_resid(uiop); 1465191783Srmacklem NFSLOCKMNT(nmp); 1466220810Srmacklem if (uiop->uio_offset + tsiz > nmp->nm_maxfilesize) { 1467191783Srmacklem NFSUNLOCKMNT(nmp); 1468191783Srmacklem return (EFBIG); 1469191783Srmacklem } 1470191783Srmacklem wsize = nmp->nm_wsize; 1471191783Srmacklem NFSUNLOCKMNT(nmp); 1472191783Srmacklem nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ 1473191783Srmacklem nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ 1474191783Srmacklem while (tsiz > 0) { 1475191783Srmacklem *attrflagp = 0; 1476191783Srmacklem len = (tsiz > wsize) ? wsize : tsiz; 1477191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); 1478191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1479191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1480191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); 1481191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1482191783Srmacklem tl += 2; 1483191783Srmacklem *tl++ = txdr_unsigned(*iomode); 1484191783Srmacklem *tl = txdr_unsigned(len); 1485191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 1486191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); 1487191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1488191783Srmacklem tl += 2; 1489191783Srmacklem *tl++ = txdr_unsigned(len); 1490191783Srmacklem *tl++ = txdr_unsigned(*iomode); 1491191783Srmacklem *tl = txdr_unsigned(len); 1492191783Srmacklem } else { 1493191783Srmacklem u_int32_t x; 1494191783Srmacklem 1495191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1496191783Srmacklem /* 1497191783Srmacklem * Not sure why someone changed this, since the 1498191783Srmacklem * RFC clearly states that "beginoffset" and 1499191783Srmacklem * "totalcount" are ignored, but it wouldn't 1500191783Srmacklem * surprise me if there's a busted server out there. 1501191783Srmacklem */ 1502191783Srmacklem /* Set both "begin" and "current" to non-garbage. */ 1503191783Srmacklem x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1504191783Srmacklem *tl++ = x; /* "begin offset" */ 1505191783Srmacklem *tl++ = x; /* "current offset" */ 1506191783Srmacklem x = txdr_unsigned(len); 1507191783Srmacklem *tl++ = x; /* total to this offset */ 1508191783Srmacklem *tl = x; /* size of this write */ 1509191783Srmacklem 1510191783Srmacklem } 1511191783Srmacklem nfsm_uiombuf(nd, uiop, len); 1512191783Srmacklem /* 1513191783Srmacklem * Although it is tempting to do a normal Getattr Op in the 1514191783Srmacklem * NFSv4 compound, the result can be a nearly hung client 1515191783Srmacklem * system if the Getattr asks for Owner and/or OwnerGroup. 1516191783Srmacklem * It occurs when the client can't map either the Owner or 1517191783Srmacklem * Owner_group name in the Getattr reply to a uid/gid. When 1518191783Srmacklem * there is a cache miss, the kernel does an upcall to the 1519191783Srmacklem * nfsuserd. Then, it can try and read the local /etc/passwd 1520191783Srmacklem * or /etc/group file. It can then block in getnewbuf(), 1521191783Srmacklem * waiting for dirty writes to be pushed to the NFS server. 1522191783Srmacklem * The only reason this doesn't result in a complete 1523191783Srmacklem * deadlock, is that the upcall times out and allows 1524191783Srmacklem * the write to complete. However, progress is so slow 1525191783Srmacklem * that it might just as well be deadlocked. 1526191783Srmacklem * So, we just get the attributes that change with each 1527191783Srmacklem * write Op. 1528191783Srmacklem * nb: nfscl_loadattrcache() needs to be told that these 1529191783Srmacklem * partial attributes from a write rpc are being 1530191783Srmacklem * passed in, via a argument flag. 1531191783Srmacklem */ 1532191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1533191783Srmacklem NFSWRITEGETATTR_ATTRBIT(&attrbits); 1534191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1535191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1536191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1537191783Srmacklem } 1538191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1539191783Srmacklem if (error) 1540191783Srmacklem return (error); 1541191783Srmacklem if (nd->nd_repstat) { 1542191783Srmacklem /* 1543191783Srmacklem * In case the rpc gets retried, roll 1544191783Srmacklem * the uio fileds changed by nfsm_uiombuf() 1545191783Srmacklem * back. 1546191783Srmacklem */ 1547191783Srmacklem uiop->uio_offset -= len; 1548191783Srmacklem uio_uio_resid_add(uiop, len); 1549191783Srmacklem uio_iov_base_add(uiop, -len); 1550191783Srmacklem uio_iov_len_add(uiop, len); 1551191783Srmacklem } 1552191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1553191783Srmacklem error = nfscl_wcc_data(nd, vp, nap, attrflagp, 1554191783Srmacklem &wccflag, stuff); 1555191783Srmacklem if (error) 1556191783Srmacklem goto nfsmout; 1557191783Srmacklem } 1558191783Srmacklem if (!nd->nd_repstat) { 1559191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1560191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1561191783Srmacklem + NFSX_VERF); 1562191783Srmacklem rlen = fxdr_unsigned(int, *tl++); 1563191783Srmacklem if (rlen == 0) { 1564191783Srmacklem error = NFSERR_IO; 1565191783Srmacklem goto nfsmout; 1566191783Srmacklem } else if (rlen < len) { 1567191783Srmacklem backup = len - rlen; 1568191783Srmacklem uio_iov_base_add(uiop, -(backup)); 1569191783Srmacklem uio_iov_len_add(uiop, backup); 1570191783Srmacklem uiop->uio_offset -= backup; 1571191783Srmacklem uio_uio_resid_add(uiop, backup); 1572191783Srmacklem len = rlen; 1573191783Srmacklem } 1574191783Srmacklem commit = fxdr_unsigned(int, *tl++); 1575191783Srmacklem 1576191783Srmacklem /* 1577191783Srmacklem * Return the lowest committment level 1578191783Srmacklem * obtained by any of the RPCs. 1579191783Srmacklem */ 1580191783Srmacklem if (committed == NFSWRITE_FILESYNC) 1581191783Srmacklem committed = commit; 1582191783Srmacklem else if (committed == NFSWRITE_DATASYNC && 1583191783Srmacklem commit == NFSWRITE_UNSTABLE) 1584191783Srmacklem committed = commit; 1585191783Srmacklem if (verfp != NULL) 1586191783Srmacklem NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF); 1587191783Srmacklem NFSLOCKMNT(nmp); 1588191783Srmacklem if (!NFSHASWRITEVERF(nmp)) { 1589191783Srmacklem NFSBCOPY((caddr_t)tl, 1590191783Srmacklem (caddr_t)&nmp->nm_verf[0], 1591191783Srmacklem NFSX_VERF); 1592191783Srmacklem NFSSETWRITEVERF(nmp); 1593191783Srmacklem } 1594191783Srmacklem NFSUNLOCKMNT(nmp); 1595191783Srmacklem } 1596191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1597191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1598191783Srmacklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 1599191783Srmacklem error = nfsm_loadattr(nd, nap); 1600191783Srmacklem if (!error) 1601191783Srmacklem *attrflagp = NFS_LATTR_NOSHRINK; 1602191783Srmacklem } 1603191783Srmacklem } else { 1604191783Srmacklem error = nd->nd_repstat; 1605191783Srmacklem } 1606191783Srmacklem if (error) 1607191783Srmacklem goto nfsmout; 1608191783Srmacklem NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4)); 1609191783Srmacklem mbuf_freem(nd->nd_mrep); 1610191783Srmacklem nd->nd_mrep = NULL; 1611191783Srmacklem tsiz -= len; 1612191783Srmacklem } 1613191783Srmacklemnfsmout: 1614191783Srmacklem if (nd->nd_mrep != NULL) 1615191783Srmacklem mbuf_freem(nd->nd_mrep); 1616191783Srmacklem *iomode = committed; 1617191783Srmacklem if (nd->nd_repstat && !error) 1618191783Srmacklem error = nd->nd_repstat; 1619191783Srmacklem return (error); 1620191783Srmacklem} 1621191783Srmacklem 1622191783Srmacklem/* 1623191783Srmacklem * nfs mknod rpc 1624191783Srmacklem * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1625191783Srmacklem * mode set to specify the file type and the size field for rdev. 1626191783Srmacklem */ 1627191783SrmacklemAPPLESTATIC int 1628191783Srmacklemnfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1629191783Srmacklem u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p, 1630191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1631191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1632191783Srmacklem{ 1633191783Srmacklem u_int32_t *tl; 1634191783Srmacklem int error = 0; 1635191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1636191783Srmacklem nfsattrbit_t attrbits; 1637191783Srmacklem 1638191783Srmacklem *nfhpp = NULL; 1639191783Srmacklem *attrflagp = 0; 1640191783Srmacklem *dattrflagp = 0; 1641191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1642191783Srmacklem return (ENAMETOOLONG); 1643191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp); 1644191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1645201345Srmacklem if (vtyp == VBLK || vtyp == VCHR) { 1646201345Srmacklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1647201345Srmacklem *tl++ = vtonfsv34_type(vtyp); 1648201345Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1649201345Srmacklem *tl = txdr_unsigned(NFSMINOR(rdev)); 1650201345Srmacklem } else { 1651201345Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1652201345Srmacklem *tl = vtonfsv34_type(vtyp); 1653201345Srmacklem } 1654191783Srmacklem } 1655191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1656191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1657191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1658191783Srmacklem *tl = vtonfsv34_type(vtyp); 1659191783Srmacklem } 1660191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1661191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 1662191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && 1663191783Srmacklem (vtyp == VCHR || vtyp == VBLK)) { 1664191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1665191783Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1666191783Srmacklem *tl = txdr_unsigned(NFSMINOR(rdev)); 1667191783Srmacklem } 1668191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1669191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1670191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1671191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1672191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1673191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1674191783Srmacklem } 1675191783Srmacklem if (nd->nd_flag & ND_NFSV2) 1676191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 1677191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 1678191783Srmacklem if (error) 1679191783Srmacklem return (error); 1680191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1681191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1682191783Srmacklem if (!nd->nd_repstat) { 1683191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1684191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1685191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1686191783Srmacklem if (error) 1687191783Srmacklem goto nfsmout; 1688191783Srmacklem } 1689191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1690191783Srmacklem if (error) 1691191783Srmacklem goto nfsmout; 1692191783Srmacklem } 1693191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1694191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1695191783Srmacklem if (!error && nd->nd_repstat) 1696191783Srmacklem error = nd->nd_repstat; 1697191783Srmacklemnfsmout: 1698191783Srmacklem mbuf_freem(nd->nd_mrep); 1699191783Srmacklem return (error); 1700191783Srmacklem} 1701191783Srmacklem 1702191783Srmacklem/* 1703191783Srmacklem * nfs file create call 1704191783Srmacklem * Mostly just call the approriate routine. (I separated out v4, so that 1705191783Srmacklem * error recovery wouldn't be as difficult.) 1706191783Srmacklem */ 1707191783SrmacklemAPPLESTATIC int 1708191783Srmacklemnfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1709191783Srmacklem nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1710191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1711191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1712191783Srmacklem{ 1713191783Srmacklem int error = 0, newone, expireret = 0, retrycnt, unlocked; 1714191783Srmacklem struct nfsclowner *owp; 1715191783Srmacklem struct nfscldeleg *dp; 1716191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp)); 1717191783Srmacklem u_int32_t clidrev; 1718191783Srmacklem 1719191783Srmacklem if (NFSHASNFSV4(nmp)) { 1720191783Srmacklem retrycnt = 0; 1721191783Srmacklem do { 1722191783Srmacklem dp = NULL; 1723191783Srmacklem error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 1724191783Srmacklem NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 1725191783Srmacklem NULL, 1); 1726191783Srmacklem if (error) 1727191783Srmacklem return (error); 1728191783Srmacklem if (nmp->nm_clp != NULL) 1729191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1730191783Srmacklem else 1731191783Srmacklem clidrev = 0; 1732191783Srmacklem error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode, 1733191783Srmacklem owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1734191783Srmacklem dstuff, &unlocked); 1735210034Srmacklem /* 1736210034Srmacklem * There is no need to invalidate cached attributes here, 1737210034Srmacklem * since new post-delegation issue attributes are always 1738210034Srmacklem * returned by nfsrpc_createv4() and these will update the 1739210034Srmacklem * attribute cache. 1740210034Srmacklem */ 1741191783Srmacklem if (dp != NULL) 1742191783Srmacklem (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 1743191783Srmacklem (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 1744191783Srmacklem nfscl_ownerrelease(owp, error, newone, unlocked); 1745191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1746191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) { 1747207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_open"); 1748191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1749191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1750191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1751191783Srmacklem retrycnt++; 1752191783Srmacklem } 1753191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1754191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1755191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1756191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1757191783Srmacklem if (error && retrycnt >= 4) 1758191783Srmacklem error = EIO; 1759191783Srmacklem } else { 1760191783Srmacklem error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 1761191783Srmacklem fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1762191783Srmacklem dstuff); 1763191783Srmacklem } 1764191783Srmacklem return (error); 1765191783Srmacklem} 1766191783Srmacklem 1767191783Srmacklem/* 1768191783Srmacklem * The create rpc for v2 and 3. 1769191783Srmacklem */ 1770191783Srmacklemstatic int 1771191783Srmacklemnfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1772191783Srmacklem nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1773191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1774191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1775191783Srmacklem{ 1776191783Srmacklem u_int32_t *tl; 1777191783Srmacklem int error = 0; 1778191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1779191783Srmacklem 1780191783Srmacklem *nfhpp = NULL; 1781191783Srmacklem *attrflagp = 0; 1782191783Srmacklem *dattrflagp = 0; 1783191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1784191783Srmacklem return (ENAMETOOLONG); 1785191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1786191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1787191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1788191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1789191783Srmacklem if (fmode & O_EXCL) { 1790191783Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 1791191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1792191783Srmacklem *tl++ = cverf.lval[0]; 1793191783Srmacklem *tl = cverf.lval[1]; 1794191783Srmacklem } else { 1795191783Srmacklem *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 1796191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 1797191783Srmacklem } 1798191783Srmacklem } else { 1799191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 1800191783Srmacklem } 1801191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 1802191783Srmacklem if (error) 1803191783Srmacklem return (error); 1804191783Srmacklem if (nd->nd_repstat == 0) { 1805191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1806191783Srmacklem if (error) 1807191783Srmacklem goto nfsmout; 1808191783Srmacklem } 1809191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1810191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1811191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 1812191783Srmacklem error = nd->nd_repstat; 1813191783Srmacklemnfsmout: 1814191783Srmacklem mbuf_freem(nd->nd_mrep); 1815191783Srmacklem return (error); 1816191783Srmacklem} 1817191783Srmacklem 1818191783Srmacklemstatic int 1819191783Srmacklemnfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1820191783Srmacklem nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 1821191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 1822191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 1823191783Srmacklem int *dattrflagp, void *dstuff, int *unlockedp) 1824191783Srmacklem{ 1825191783Srmacklem u_int32_t *tl; 1826191783Srmacklem int error = 0, deleg, newone, ret, acesize, limitby; 1827191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1828191783Srmacklem struct nfsclopen *op; 1829191783Srmacklem struct nfscldeleg *dp = NULL; 1830191783Srmacklem struct nfsnode *np; 1831191783Srmacklem struct nfsfh *nfhp; 1832191783Srmacklem nfsattrbit_t attrbits; 1833191783Srmacklem nfsv4stateid_t stateid; 1834191783Srmacklem u_int32_t rflags; 1835191783Srmacklem 1836191783Srmacklem *unlockedp = 0; 1837191783Srmacklem *nfhpp = NULL; 1838191783Srmacklem *dpp = NULL; 1839191783Srmacklem *attrflagp = 0; 1840191783Srmacklem *dattrflagp = 0; 1841191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1842191783Srmacklem return (ENAMETOOLONG); 1843191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1844191783Srmacklem /* 1845191783Srmacklem * For V4, this is actually an Open op. 1846191783Srmacklem */ 1847191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1848191783Srmacklem *tl++ = txdr_unsigned(owp->nfsow_seqid); 1849191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 1850191783Srmacklem NFSV4OPEN_ACCESSREAD); 1851191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 1852191783Srmacklem *tl++ = owp->nfsow_clp->nfsc_clientid.lval[0]; 1853191783Srmacklem *tl = owp->nfsow_clp->nfsc_clientid.lval[1]; 1854191783Srmacklem (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 1855191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1856191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 1857191783Srmacklem if (fmode & O_EXCL) { 1858191783Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 1859191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1860191783Srmacklem *tl++ = cverf.lval[0]; 1861191783Srmacklem *tl = cverf.lval[1]; 1862191783Srmacklem } else { 1863191783Srmacklem *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 1864191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 1865191783Srmacklem } 1866191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1867191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 1868191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1869191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1870191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1871191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1872191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1873191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1874191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 1875191783Srmacklem if (error) 1876191783Srmacklem return (error); 1877191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1878191783Srmacklem if (error) 1879191783Srmacklem goto nfsmout; 1880191783Srmacklem NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 1881191783Srmacklem if (nd->nd_repstat == 0) { 1882191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 1883191783Srmacklem 6 * NFSX_UNSIGNED); 1884191783Srmacklem stateid.seqid = *tl++; 1885191783Srmacklem stateid.other[0] = *tl++; 1886191783Srmacklem stateid.other[1] = *tl++; 1887191783Srmacklem stateid.other[2] = *tl; 1888191783Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 1889191783Srmacklem (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1890191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1891191783Srmacklem deleg = fxdr_unsigned(int, *tl); 1892191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 1893191783Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 1894191783Srmacklem if (!(owp->nfsow_clp->nfsc_flags & 1895191783Srmacklem NFSCLFLAGS_FIRSTDELEG)) 1896191783Srmacklem owp->nfsow_clp->nfsc_flags |= 1897191783Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 1898191783Srmacklem MALLOC(dp, struct nfscldeleg *, 1899191783Srmacklem sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 1900191783Srmacklem M_NFSCLDELEG, M_WAITOK); 1901191783Srmacklem LIST_INIT(&dp->nfsdl_owner); 1902191783Srmacklem LIST_INIT(&dp->nfsdl_lock); 1903191783Srmacklem dp->nfsdl_clp = owp->nfsow_clp; 1904191783Srmacklem newnfs_copyincred(cred, &dp->nfsdl_cred); 1905191783Srmacklem nfscl_lockinit(&dp->nfsdl_rwlock); 1906191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 1907191783Srmacklem NFSX_UNSIGNED); 1908191783Srmacklem dp->nfsdl_stateid.seqid = *tl++; 1909191783Srmacklem dp->nfsdl_stateid.other[0] = *tl++; 1910191783Srmacklem dp->nfsdl_stateid.other[1] = *tl++; 1911191783Srmacklem dp->nfsdl_stateid.other[2] = *tl++; 1912191783Srmacklem ret = fxdr_unsigned(int, *tl); 1913191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 1914191783Srmacklem dp->nfsdl_flags = NFSCLDL_WRITE; 1915191783Srmacklem /* 1916191783Srmacklem * Indicates how much the file can grow. 1917191783Srmacklem */ 1918191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 1919191783Srmacklem 3 * NFSX_UNSIGNED); 1920191783Srmacklem limitby = fxdr_unsigned(int, *tl++); 1921191783Srmacklem switch (limitby) { 1922191783Srmacklem case NFSV4OPEN_LIMITSIZE: 1923191783Srmacklem dp->nfsdl_sizelimit = fxdr_hyper(tl); 1924191783Srmacklem break; 1925191783Srmacklem case NFSV4OPEN_LIMITBLOCKS: 1926191783Srmacklem dp->nfsdl_sizelimit = 1927191783Srmacklem fxdr_unsigned(u_int64_t, *tl++); 1928191783Srmacklem dp->nfsdl_sizelimit *= 1929191783Srmacklem fxdr_unsigned(u_int64_t, *tl); 1930191783Srmacklem break; 1931191783Srmacklem default: 1932191783Srmacklem error = NFSERR_BADXDR; 1933191783Srmacklem goto nfsmout; 1934191783Srmacklem }; 1935191783Srmacklem } else { 1936191783Srmacklem dp->nfsdl_flags = NFSCLDL_READ; 1937191783Srmacklem } 1938191783Srmacklem if (ret) 1939191783Srmacklem dp->nfsdl_flags |= NFSCLDL_RECALL; 1940191783Srmacklem error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 1941191783Srmacklem &acesize, p); 1942191783Srmacklem if (error) 1943191783Srmacklem goto nfsmout; 1944191783Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 1945191783Srmacklem error = NFSERR_BADXDR; 1946191783Srmacklem goto nfsmout; 1947191783Srmacklem } 1948191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1949191783Srmacklem if (error) 1950191783Srmacklem goto nfsmout; 1951191783Srmacklem if (dp != NULL && *attrflagp) { 1952191783Srmacklem dp->nfsdl_change = nnap->na_filerev; 1953191783Srmacklem dp->nfsdl_modtime = nnap->na_mtime; 1954191783Srmacklem dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 1955191783Srmacklem } 1956191783Srmacklem /* 1957191783Srmacklem * We can now complete the Open state. 1958191783Srmacklem */ 1959191783Srmacklem nfhp = *nfhpp; 1960191783Srmacklem if (dp != NULL) { 1961191783Srmacklem dp->nfsdl_fhlen = nfhp->nfh_len; 1962191783Srmacklem NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 1963191783Srmacklem } 1964191783Srmacklem /* 1965191783Srmacklem * Get an Open structure that will be 1966191783Srmacklem * attached to the OpenOwner, acquired already. 1967191783Srmacklem */ 1968191783Srmacklem error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 1969191783Srmacklem (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 1970191783Srmacklem cred, p, NULL, &op, &newone, NULL, 0); 1971191783Srmacklem if (error) 1972191783Srmacklem goto nfsmout; 1973191783Srmacklem op->nfso_stateid = stateid; 1974191783Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 1975191783Srmacklem if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 1976191783Srmacklem do { 1977191783Srmacklem ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 1978191783Srmacklem nfhp->nfh_len, op, cred, p); 1979191783Srmacklem if (ret == NFSERR_DELAY) 1980207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_create"); 1981191783Srmacklem } while (ret == NFSERR_DELAY); 1982191783Srmacklem error = ret; 1983191783Srmacklem } 1984191783Srmacklem 1985191783Srmacklem /* 1986191783Srmacklem * If the server is handing out delegations, but we didn't 1987191783Srmacklem * get one because an OpenConfirm was required, try the 1988191783Srmacklem * Open again, to get a delegation. This is a harmless no-op, 1989191783Srmacklem * from a server's point of view. 1990191783Srmacklem */ 1991191783Srmacklem if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 1992191783Srmacklem (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 1993191783Srmacklem !error && dp == NULL) { 1994191783Srmacklem np = VTONFS(dvp); 1995191783Srmacklem do { 1996191783Srmacklem ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp, 1997191783Srmacklem np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 1998191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, 1999191783Srmacklem (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2000191783Srmacklem name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2001191783Srmacklem if (ret == NFSERR_DELAY) 2002207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2003191783Srmacklem } while (ret == NFSERR_DELAY); 2004191783Srmacklem if (ret) { 2005191783Srmacklem if (dp != NULL) 2006191783Srmacklem FREE((caddr_t)dp, M_NFSCLDELEG); 2007191783Srmacklem if (ret == NFSERR_STALECLIENTID || 2008191783Srmacklem ret == NFSERR_STALEDONTRECOVER) 2009191783Srmacklem error = ret; 2010191783Srmacklem } 2011191783Srmacklem } 2012191783Srmacklem nfscl_openrelease(op, error, newone); 2013191783Srmacklem *unlockedp = 1; 2014191783Srmacklem } 2015191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 2016191783Srmacklem error = nd->nd_repstat; 2017191783Srmacklem if (error == NFSERR_STALECLIENTID) 2018191783Srmacklem nfscl_initiate_recovery(owp->nfsow_clp); 2019191783Srmacklemnfsmout: 2020191783Srmacklem if (!error) 2021191783Srmacklem *dpp = dp; 2022191783Srmacklem else if (dp != NULL) 2023191783Srmacklem FREE((caddr_t)dp, M_NFSCLDELEG); 2024191783Srmacklem mbuf_freem(nd->nd_mrep); 2025191783Srmacklem return (error); 2026191783Srmacklem} 2027191783Srmacklem 2028191783Srmacklem/* 2029191783Srmacklem * Nfs remove rpc 2030191783Srmacklem */ 2031191783SrmacklemAPPLESTATIC int 2032191783Srmacklemnfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2033191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, 2034191783Srmacklem void *dstuff) 2035191783Srmacklem{ 2036191783Srmacklem u_int32_t *tl; 2037191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2038191783Srmacklem struct nfsnode *np; 2039191783Srmacklem struct nfsmount *nmp; 2040191783Srmacklem nfsv4stateid_t dstateid; 2041191783Srmacklem int error, ret = 0, i; 2042191783Srmacklem 2043191783Srmacklem *dattrflagp = 0; 2044191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2045191783Srmacklem return (ENAMETOOLONG); 2046191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 2047191783Srmacklemtryagain: 2048191783Srmacklem if (NFSHASNFSV4(nmp) && ret == 0) { 2049191783Srmacklem ret = nfscl_removedeleg(vp, p, &dstateid); 2050191783Srmacklem if (ret == 1) { 2051191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp); 2052191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2053191783Srmacklem NFSX_UNSIGNED); 2054191783Srmacklem *tl++ = dstateid.seqid; 2055191783Srmacklem *tl++ = dstateid.other[0]; 2056191783Srmacklem *tl++ = dstateid.other[1]; 2057191783Srmacklem *tl++ = dstateid.other[2]; 2058191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2059191783Srmacklem np = VTONFS(dvp); 2060191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2061191783Srmacklem np->n_fhp->nfh_len, 0); 2062191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2063191783Srmacklem *tl = txdr_unsigned(NFSV4OP_REMOVE); 2064191783Srmacklem } 2065191783Srmacklem } else { 2066191783Srmacklem ret = 0; 2067191783Srmacklem } 2068191783Srmacklem if (ret == 0) 2069191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp); 2070191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2071191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2072191783Srmacklem if (error) 2073191783Srmacklem return (error); 2074191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2075191783Srmacklem /* For NFSv4, parse out any Delereturn replies. */ 2076191783Srmacklem if (ret > 0 && nd->nd_repstat != 0 && 2077191783Srmacklem (nd->nd_flag & ND_NOMOREDATA)) { 2078191783Srmacklem /* 2079191783Srmacklem * If the Delegreturn failed, try again without 2080191783Srmacklem * it. The server will Recall, as required. 2081191783Srmacklem */ 2082191783Srmacklem mbuf_freem(nd->nd_mrep); 2083191783Srmacklem goto tryagain; 2084191783Srmacklem } 2085191783Srmacklem for (i = 0; i < (ret * 2); i++) { 2086191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2087191783Srmacklem ND_NFSV4) { 2088191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2089191783Srmacklem if (*(tl + 1)) 2090191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2091191783Srmacklem } 2092191783Srmacklem } 2093191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2094191783Srmacklem } 2095191783Srmacklem if (nd->nd_repstat && !error) 2096191783Srmacklem error = nd->nd_repstat; 2097191783Srmacklemnfsmout: 2098191783Srmacklem mbuf_freem(nd->nd_mrep); 2099191783Srmacklem return (error); 2100191783Srmacklem} 2101191783Srmacklem 2102191783Srmacklem/* 2103191783Srmacklem * Do an nfs rename rpc. 2104191783Srmacklem */ 2105191783SrmacklemAPPLESTATIC int 2106191783Srmacklemnfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2107191783Srmacklem vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2108191783Srmacklem NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2109191783Srmacklem int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff) 2110191783Srmacklem{ 2111191783Srmacklem u_int32_t *tl; 2112191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2113191783Srmacklem struct nfsmount *nmp; 2114191783Srmacklem struct nfsnode *np; 2115191783Srmacklem nfsattrbit_t attrbits; 2116191783Srmacklem nfsv4stateid_t fdstateid, tdstateid; 2117191783Srmacklem int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2118191783Srmacklem 2119191783Srmacklem *fattrflagp = 0; 2120191783Srmacklem *tattrflagp = 0; 2121191783Srmacklem nmp = VFSTONFS(vnode_mount(fdvp)); 2122191783Srmacklem if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2123191783Srmacklem return (ENAMETOOLONG); 2124191783Srmacklemtryagain: 2125191783Srmacklem if (NFSHASNFSV4(nmp) && ret == 0) { 2126191783Srmacklem ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2127191783Srmacklem &tdstateid, &gottd, p); 2128191783Srmacklem if (gotfd && gottd) { 2129191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp); 2130191783Srmacklem } else if (gotfd) { 2131191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp); 2132191783Srmacklem } else if (gottd) { 2133191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp); 2134191783Srmacklem } 2135191783Srmacklem if (gotfd) { 2136191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2137191783Srmacklem *tl++ = fdstateid.seqid; 2138191783Srmacklem *tl++ = fdstateid.other[0]; 2139191783Srmacklem *tl++ = fdstateid.other[1]; 2140191783Srmacklem *tl = fdstateid.other[2]; 2141191783Srmacklem if (gottd) { 2142191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2143191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2144191783Srmacklem np = VTONFS(tvp); 2145191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2146191783Srmacklem np->n_fhp->nfh_len, 0); 2147191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2148191783Srmacklem *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2149191783Srmacklem } 2150191783Srmacklem } 2151191783Srmacklem if (gottd) { 2152191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2153191783Srmacklem *tl++ = tdstateid.seqid; 2154191783Srmacklem *tl++ = tdstateid.other[0]; 2155191783Srmacklem *tl++ = tdstateid.other[1]; 2156191783Srmacklem *tl = tdstateid.other[2]; 2157191783Srmacklem } 2158191783Srmacklem if (ret > 0) { 2159191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2160191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2161191783Srmacklem np = VTONFS(fdvp); 2162191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2163191783Srmacklem np->n_fhp->nfh_len, 0); 2164191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2165191783Srmacklem *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2166191783Srmacklem } 2167191783Srmacklem } else { 2168191783Srmacklem ret = 0; 2169191783Srmacklem } 2170191783Srmacklem if (ret == 0) 2171191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp); 2172191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2173191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2174191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2175191783Srmacklem NFSWCCATTR_ATTRBIT(&attrbits); 2176191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2177191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2178191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2179191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2180191783Srmacklem VTONFS(tdvp)->n_fhp->nfh_len, 0); 2181191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2182191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2183191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2184191783Srmacklem nd->nd_flag |= ND_V4WCCATTR; 2185191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2186191783Srmacklem *tl = txdr_unsigned(NFSV4OP_RENAME); 2187191783Srmacklem } 2188191783Srmacklem (void) nfsm_strtom(nd, fnameptr, fnamelen); 2189191783Srmacklem if (!(nd->nd_flag & ND_NFSV4)) 2190191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2191191783Srmacklem VTONFS(tdvp)->n_fhp->nfh_len, 0); 2192191783Srmacklem (void) nfsm_strtom(nd, tnameptr, tnamelen); 2193191783Srmacklem error = nfscl_request(nd, fdvp, p, cred, fstuff); 2194191783Srmacklem if (error) 2195191783Srmacklem return (error); 2196191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2197191783Srmacklem /* For NFSv4, parse out any Delereturn replies. */ 2198191783Srmacklem if (ret > 0 && nd->nd_repstat != 0 && 2199191783Srmacklem (nd->nd_flag & ND_NOMOREDATA)) { 2200191783Srmacklem /* 2201191783Srmacklem * If the Delegreturn failed, try again without 2202191783Srmacklem * it. The server will Recall, as required. 2203191783Srmacklem */ 2204191783Srmacklem mbuf_freem(nd->nd_mrep); 2205191783Srmacklem goto tryagain; 2206191783Srmacklem } 2207191783Srmacklem for (i = 0; i < (ret * 2); i++) { 2208191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2209191783Srmacklem ND_NFSV4) { 2210191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2211191783Srmacklem if (*(tl + 1)) { 2212191783Srmacklem if (i == 0 && ret > 1) { 2213191783Srmacklem /* 2214191783Srmacklem * If the Delegreturn failed, try again 2215191783Srmacklem * without it. The server will Recall, as 2216191783Srmacklem * required. 2217191783Srmacklem * If ret > 1, the first iteration of this 2218191783Srmacklem * loop is the second DelegReturn result. 2219191783Srmacklem */ 2220191783Srmacklem mbuf_freem(nd->nd_mrep); 2221191783Srmacklem goto tryagain; 2222191783Srmacklem } else { 2223191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2224191783Srmacklem } 2225191783Srmacklem } 2226191783Srmacklem } 2227191783Srmacklem } 2228191783Srmacklem /* Now, the first wcc attribute reply. */ 2229191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2230191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2231191783Srmacklem if (*(tl + 1)) 2232191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2233191783Srmacklem } 2234191783Srmacklem error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, 2235191783Srmacklem fstuff); 2236191783Srmacklem /* and the second wcc attribute reply. */ 2237191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2238191783Srmacklem !error) { 2239191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2240191783Srmacklem if (*(tl + 1)) 2241191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2242191783Srmacklem } 2243191783Srmacklem if (!error) 2244191783Srmacklem error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2245191783Srmacklem NULL, tstuff); 2246191783Srmacklem } 2247191783Srmacklem if (nd->nd_repstat && !error) 2248191783Srmacklem error = nd->nd_repstat; 2249191783Srmacklemnfsmout: 2250191783Srmacklem mbuf_freem(nd->nd_mrep); 2251191783Srmacklem return (error); 2252191783Srmacklem} 2253191783Srmacklem 2254191783Srmacklem/* 2255191783Srmacklem * nfs hard link create rpc 2256191783Srmacklem */ 2257191783SrmacklemAPPLESTATIC int 2258191783Srmacklemnfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2259191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2260191783Srmacklem struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2261191783Srmacklem{ 2262191783Srmacklem u_int32_t *tl; 2263191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2264191783Srmacklem nfsattrbit_t attrbits; 2265191783Srmacklem int error = 0; 2266191783Srmacklem 2267191783Srmacklem *attrflagp = 0; 2268191783Srmacklem *dattrflagp = 0; 2269191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2270191783Srmacklem return (ENAMETOOLONG); 2271191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2272191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2273191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2274191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2275191783Srmacklem } 2276191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2277191783Srmacklem VTONFS(dvp)->n_fhp->nfh_len, 0); 2278191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2279191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2280191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2281191783Srmacklem NFSWCCATTR_ATTRBIT(&attrbits); 2282191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2283191783Srmacklem nd->nd_flag |= ND_V4WCCATTR; 2284191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2285191783Srmacklem *tl = txdr_unsigned(NFSV4OP_LINK); 2286191783Srmacklem } 2287191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2288191783Srmacklem error = nfscl_request(nd, vp, p, cred, dstuff); 2289191783Srmacklem if (error) 2290191783Srmacklem return (error); 2291191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 2292191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2293191783Srmacklem if (!error) 2294191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2295191783Srmacklem NULL, dstuff); 2296191783Srmacklem } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2297191783Srmacklem /* 2298191783Srmacklem * First, parse out the PutFH and Getattr result. 2299191783Srmacklem */ 2300191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2301191783Srmacklem if (!(*(tl + 1))) 2302191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2303191783Srmacklem if (*(tl + 1)) 2304191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2305191783Srmacklem /* 2306191783Srmacklem * Get the pre-op attributes. 2307191783Srmacklem */ 2308191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2309191783Srmacklem } 2310191783Srmacklem if (nd->nd_repstat && !error) 2311191783Srmacklem error = nd->nd_repstat; 2312191783Srmacklemnfsmout: 2313191783Srmacklem mbuf_freem(nd->nd_mrep); 2314191783Srmacklem return (error); 2315191783Srmacklem} 2316191783Srmacklem 2317191783Srmacklem/* 2318191783Srmacklem * nfs symbolic link create rpc 2319191783Srmacklem */ 2320191783SrmacklemAPPLESTATIC int 2321191783Srmacklemnfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target, 2322191783Srmacklem struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2323191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2324191783Srmacklem int *dattrflagp, void *dstuff) 2325191783Srmacklem{ 2326191783Srmacklem u_int32_t *tl; 2327191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2328191783Srmacklem struct nfsmount *nmp; 2329191783Srmacklem int slen, error = 0; 2330191783Srmacklem 2331191783Srmacklem *nfhpp = NULL; 2332191783Srmacklem *attrflagp = 0; 2333191783Srmacklem *dattrflagp = 0; 2334191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 2335191783Srmacklem slen = strlen(target); 2336191783Srmacklem if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2337191783Srmacklem return (ENAMETOOLONG); 2338191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2339191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2340191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2341191783Srmacklem *tl = txdr_unsigned(NFLNK); 2342191783Srmacklem (void) nfsm_strtom(nd, target, slen); 2343191783Srmacklem } 2344191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2345191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2346191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 2347191783Srmacklem if (!(nd->nd_flag & ND_NFSV4)) 2348191783Srmacklem (void) nfsm_strtom(nd, target, slen); 2349191783Srmacklem if (nd->nd_flag & ND_NFSV2) 2350191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2351191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2352191783Srmacklem if (error) 2353191783Srmacklem return (error); 2354191783Srmacklem if (nd->nd_flag & ND_NFSV4) 2355191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2356191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) { 2357191783Srmacklem if (!nd->nd_repstat) 2358191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2359191783Srmacklem if (!error) 2360191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2361191783Srmacklem NULL, dstuff); 2362191783Srmacklem } 2363191783Srmacklem if (nd->nd_repstat && !error) 2364191783Srmacklem error = nd->nd_repstat; 2365191783Srmacklem mbuf_freem(nd->nd_mrep); 2366191783Srmacklem /* 2367191783Srmacklem * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2368191783Srmacklem */ 2369191783Srmacklem if (error == EEXIST) 2370191783Srmacklem error = 0; 2371191783Srmacklem return (error); 2372191783Srmacklem} 2373191783Srmacklem 2374191783Srmacklem/* 2375191783Srmacklem * nfs make dir rpc 2376191783Srmacklem */ 2377191783SrmacklemAPPLESTATIC int 2378191783Srmacklemnfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2379191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2380191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2381191783Srmacklem int *dattrflagp, void *dstuff) 2382191783Srmacklem{ 2383191783Srmacklem u_int32_t *tl; 2384191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2385191783Srmacklem nfsattrbit_t attrbits; 2386191783Srmacklem int error = 0; 2387191783Srmacklem 2388191783Srmacklem *nfhpp = NULL; 2389191783Srmacklem *attrflagp = 0; 2390191783Srmacklem *dattrflagp = 0; 2391191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2392191783Srmacklem return (ENAMETOOLONG); 2393191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 2394191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2395191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2396191783Srmacklem *tl = txdr_unsigned(NFDIR); 2397191783Srmacklem } 2398191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2399191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2400191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2401191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 2402191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2403191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2404191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2405191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2406191783Srmacklem } 2407191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2408191783Srmacklem if (error) 2409191783Srmacklem return (error); 2410191783Srmacklem if (nd->nd_flag & ND_NFSV4) 2411191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2412191783Srmacklem if (!nd->nd_repstat && !error) { 2413191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2414191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2415191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2416191783Srmacklem } 2417191783Srmacklem if (!error) 2418191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2419191783Srmacklem } 2420191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) 2421191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2422191783Srmacklem if (nd->nd_repstat && !error) 2423191783Srmacklem error = nd->nd_repstat; 2424191783Srmacklemnfsmout: 2425191783Srmacklem mbuf_freem(nd->nd_mrep); 2426191783Srmacklem /* 2427191783Srmacklem * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry. 2428191783Srmacklem */ 2429191783Srmacklem if (error == EEXIST) 2430191783Srmacklem error = 0; 2431191783Srmacklem return (error); 2432191783Srmacklem} 2433191783Srmacklem 2434191783Srmacklem/* 2435191783Srmacklem * nfs remove directory call 2436191783Srmacklem */ 2437191783SrmacklemAPPLESTATIC int 2438191783Srmacklemnfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 2439191783Srmacklem NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 2440191783Srmacklem{ 2441191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2442191783Srmacklem int error = 0; 2443191783Srmacklem 2444191783Srmacklem *dattrflagp = 0; 2445191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2446191783Srmacklem return (ENAMETOOLONG); 2447191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 2448191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2449191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2450191783Srmacklem if (error) 2451191783Srmacklem return (error); 2452191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2453191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2454191783Srmacklem if (nd->nd_repstat && !error) 2455191783Srmacklem error = nd->nd_repstat; 2456191783Srmacklem mbuf_freem(nd->nd_mrep); 2457191783Srmacklem /* 2458191783Srmacklem * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2459191783Srmacklem */ 2460191783Srmacklem if (error == ENOENT) 2461191783Srmacklem error = 0; 2462191783Srmacklem return (error); 2463191783Srmacklem} 2464191783Srmacklem 2465191783Srmacklem/* 2466191783Srmacklem * Readdir rpc. 2467191783Srmacklem * Always returns with either uio_resid unchanged, if you are at the 2468191783Srmacklem * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 2469191783Srmacklem * filled in. 2470191783Srmacklem * I felt this would allow caching of directory blocks more easily 2471191783Srmacklem * than returning a pertially filled block. 2472191783Srmacklem * Directory offset cookies: 2473191783Srmacklem * Oh my, what to do with them... 2474191783Srmacklem * I can think of three ways to deal with them: 2475191783Srmacklem * 1 - have the layer above these RPCs maintain a map between logical 2476191783Srmacklem * directory byte offsets and the NFS directory offset cookies 2477191783Srmacklem * 2 - pass the opaque directory offset cookies up into userland 2478191783Srmacklem * and let the libc functions deal with them, via the system call 2479191783Srmacklem * 3 - return them to userland in the "struct dirent", so future versions 2480191783Srmacklem * of libc can use them and do whatever is necessary to amke things work 2481191783Srmacklem * above these rpc calls, in the meantime 2482191783Srmacklem * For now, I do #3 by "hiding" the directory offset cookies after the 2483191783Srmacklem * d_name field in struct dirent. This is space inside d_reclen that 2484191783Srmacklem * will be ignored by anything that doesn't know about them. 2485191783Srmacklem * The directory offset cookies are filled in as the last 8 bytes of 2486191783Srmacklem * each directory entry, after d_name. Someday, the userland libc 2487191783Srmacklem * functions may be able to use these. In the meantime, it satisfies 2488191783Srmacklem * OpenBSD's requirements for cookies being returned. 2489191783Srmacklem * If expects the directory offset cookie for the read to be in uio_offset 2490191783Srmacklem * and returns the one for the next entry after this directory block in 2491191783Srmacklem * there, as well. 2492191783Srmacklem */ 2493191783SrmacklemAPPLESTATIC int 2494191783Srmacklemnfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2495191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2496191783Srmacklem int *eofp, void *stuff) 2497191783Srmacklem{ 2498191783Srmacklem int len, left; 2499191783Srmacklem struct dirent *dp = NULL; 2500191783Srmacklem u_int32_t *tl; 2501191783Srmacklem nfsquad_t cookie, ncookie; 2502191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2503191783Srmacklem struct nfsnode *dnp = VTONFS(vp); 2504191783Srmacklem struct nfsvattr nfsva; 2505191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2506191783Srmacklem int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2507191783Srmacklem int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 2508191783Srmacklem long dotfileid, dotdotfileid = 0; 2509191783Srmacklem u_int32_t fakefileno = 0xffffffff, rderr; 2510191783Srmacklem char *cp; 2511191783Srmacklem nfsattrbit_t attrbits, dattrbits; 2512191783Srmacklem u_int32_t *tl2 = NULL; 2513191783Srmacklem size_t tresid; 2514191783Srmacklem 2515209120Skib KASSERT(uiop->uio_iovcnt == 1 && 2516209120Skib (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2517209120Skib ("nfs readdirrpc bad uio")); 2518191783Srmacklem 2519191783Srmacklem /* 2520191783Srmacklem * There is no point in reading a lot more than uio_resid, however 2521191783Srmacklem * adding one additional DIRBLKSIZ makes sense. Since uio_resid 2522191783Srmacklem * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 2523191783Srmacklem * will never make readsize > nm_readdirsize. 2524191783Srmacklem */ 2525191783Srmacklem readsize = nmp->nm_readdirsize; 2526191783Srmacklem if (readsize > uio_uio_resid(uiop)) 2527191783Srmacklem readsize = uio_uio_resid(uiop) + DIRBLKSIZ; 2528191783Srmacklem 2529191783Srmacklem *attrflagp = 0; 2530191783Srmacklem if (eofp) 2531191783Srmacklem *eofp = 0; 2532191783Srmacklem tresid = uio_uio_resid(uiop); 2533191783Srmacklem cookie.lval[0] = cookiep->nfsuquad[0]; 2534191783Srmacklem cookie.lval[1] = cookiep->nfsuquad[1]; 2535191783Srmacklem nd->nd_mrep = NULL; 2536191783Srmacklem 2537191783Srmacklem /* 2538191783Srmacklem * For NFSv4, first create the "." and ".." entries. 2539191783Srmacklem */ 2540191783Srmacklem if (NFSHASNFSV4(nmp)) { 2541191783Srmacklem reqsize = 6 * NFSX_UNSIGNED; 2542191783Srmacklem NFSGETATTR_ATTRBIT(&dattrbits); 2543191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 2544191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2545191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 2546191783Srmacklem if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2547191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID)) { 2548191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 2549191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 2550191783Srmacklem gotmnton = 1; 2551191783Srmacklem } else { 2552191783Srmacklem /* 2553191783Srmacklem * Must fake it. Use the fileno, except when the 2554191783Srmacklem * fsid is != to that of the directory. For that 2555191783Srmacklem * case, generate a fake fileno that is not the same. 2556191783Srmacklem */ 2557191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2558191783Srmacklem gotmnton = 0; 2559191783Srmacklem } 2560191783Srmacklem 2561191783Srmacklem /* 2562191783Srmacklem * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2563191783Srmacklem */ 2564191783Srmacklem if (uiop->uio_offset == 0) { 2565191783Srmacklem#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 2566191783Srmacklem error = VOP_GETATTR(vp, &nfsva.na_vattr, cred); 2567191783Srmacklem#else 2568191783Srmacklem error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p); 2569191783Srmacklem#endif 2570191783Srmacklem if (error) 2571191783Srmacklem return (error); 2572191783Srmacklem dotfileid = nfsva.na_fileid; 2573191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2574191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2575191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2576191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2577191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2578191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 2579191783Srmacklem if (error) 2580191783Srmacklem return (error); 2581191783Srmacklem if (nd->nd_repstat == 0) { 2582191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2583191783Srmacklem len = fxdr_unsigned(int, *(tl + 2)); 2584191783Srmacklem if (len > 0 && len <= NFSX_V4FHMAX) 2585191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2586191783Srmacklem else 2587191783Srmacklem error = EPERM; 2588191783Srmacklem if (!error) { 2589191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2590191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 2591191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2592191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2593191783Srmacklem NULL, NULL, NULL, p, cred); 2594191783Srmacklem if (error) { 2595191783Srmacklem dotdotfileid = dotfileid; 2596191783Srmacklem } else if (gotmnton) { 2597191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 2598191783Srmacklem dotdotfileid = nfsva.na_mntonfileno; 2599191783Srmacklem else 2600191783Srmacklem dotdotfileid = nfsva.na_fileid; 2601191783Srmacklem } else if (nfsva.na_filesid[0] == 2602191783Srmacklem dnp->n_vattr.na_filesid[0] && 2603191783Srmacklem nfsva.na_filesid[1] == 2604191783Srmacklem dnp->n_vattr.na_filesid[1]) { 2605191783Srmacklem dotdotfileid = nfsva.na_fileid; 2606191783Srmacklem } else { 2607191783Srmacklem do { 2608191783Srmacklem fakefileno--; 2609191783Srmacklem } while (fakefileno == 2610191783Srmacklem nfsva.na_fileid); 2611191783Srmacklem dotdotfileid = fakefileno; 2612191783Srmacklem } 2613191783Srmacklem } 2614191783Srmacklem } else if (nd->nd_repstat == NFSERR_NOENT) { 2615191783Srmacklem /* 2616191783Srmacklem * Lookupp returns NFSERR_NOENT when we are 2617191783Srmacklem * at the root, so just use the current dir. 2618191783Srmacklem */ 2619191783Srmacklem nd->nd_repstat = 0; 2620191783Srmacklem dotdotfileid = dotfileid; 2621191783Srmacklem } else { 2622191783Srmacklem error = nd->nd_repstat; 2623191783Srmacklem } 2624191783Srmacklem mbuf_freem(nd->nd_mrep); 2625191783Srmacklem if (error) 2626191783Srmacklem return (error); 2627191783Srmacklem nd->nd_mrep = NULL; 2628191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2629191783Srmacklem dp->d_type = DT_DIR; 2630191783Srmacklem dp->d_fileno = dotfileid; 2631191783Srmacklem dp->d_namlen = 1; 2632191783Srmacklem dp->d_name[0] = '.'; 2633191783Srmacklem dp->d_name[1] = '\0'; 2634191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2635191783Srmacklem /* 2636191783Srmacklem * Just make these offset cookie 0. 2637191783Srmacklem */ 2638191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2639191783Srmacklem *tl++ = 0; 2640191783Srmacklem *tl = 0; 2641191783Srmacklem blksiz += dp->d_reclen; 2642191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 2643191783Srmacklem uiop->uio_offset += dp->d_reclen; 2644191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 2645191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 2646191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2647191783Srmacklem dp->d_type = DT_DIR; 2648191783Srmacklem dp->d_fileno = dotdotfileid; 2649191783Srmacklem dp->d_namlen = 2; 2650191783Srmacklem dp->d_name[0] = '.'; 2651191783Srmacklem dp->d_name[1] = '.'; 2652191783Srmacklem dp->d_name[2] = '\0'; 2653191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2654191783Srmacklem /* 2655191783Srmacklem * Just make these offset cookie 0. 2656191783Srmacklem */ 2657191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2658191783Srmacklem *tl++ = 0; 2659191783Srmacklem *tl = 0; 2660191783Srmacklem blksiz += dp->d_reclen; 2661191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 2662191783Srmacklem uiop->uio_offset += dp->d_reclen; 2663191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 2664191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 2665191783Srmacklem } 2666191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 2667191783Srmacklem } else { 2668191783Srmacklem reqsize = 5 * NFSX_UNSIGNED; 2669191783Srmacklem } 2670191783Srmacklem 2671191783Srmacklem 2672191783Srmacklem /* 2673191783Srmacklem * Loop around doing readdir rpc's of size readsize. 2674191783Srmacklem * The stopping criteria is EOF or buffer full. 2675191783Srmacklem */ 2676191783Srmacklem while (more_dirs && bigenough) { 2677191783Srmacklem *attrflagp = 0; 2678191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 2679191783Srmacklem if (nd->nd_flag & ND_NFSV2) { 2680191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2681191783Srmacklem *tl++ = cookie.lval[1]; 2682191783Srmacklem *tl = txdr_unsigned(readsize); 2683191783Srmacklem } else { 2684191783Srmacklem NFSM_BUILD(tl, u_int32_t *, reqsize); 2685191783Srmacklem *tl++ = cookie.lval[0]; 2686191783Srmacklem *tl++ = cookie.lval[1]; 2687191783Srmacklem if (cookie.qval == 0) { 2688191783Srmacklem *tl++ = 0; 2689191783Srmacklem *tl++ = 0; 2690191783Srmacklem } else { 2691191783Srmacklem NFSLOCKNODE(dnp); 2692191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[0]; 2693191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[1]; 2694191783Srmacklem NFSUNLOCKNODE(dnp); 2695191783Srmacklem } 2696191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2697191783Srmacklem *tl++ = txdr_unsigned(readsize); 2698191783Srmacklem *tl = txdr_unsigned(readsize); 2699191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2700191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2701191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2702191783Srmacklem (void) nfsrv_putattrbit(nd, &dattrbits); 2703191783Srmacklem } else { 2704191783Srmacklem *tl = txdr_unsigned(readsize); 2705191783Srmacklem } 2706191783Srmacklem } 2707191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 2708191783Srmacklem if (error) 2709191783Srmacklem return (error); 2710191783Srmacklem if (!(nd->nd_flag & ND_NFSV2)) { 2711191783Srmacklem if (nd->nd_flag & ND_NFSV3) 2712191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 2713191783Srmacklem stuff); 2714191783Srmacklem if (!nd->nd_repstat && !error) { 2715191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 2716191783Srmacklem NFSLOCKNODE(dnp); 2717191783Srmacklem dnp->n_cookieverf.nfsuquad[0] = *tl++; 2718191783Srmacklem dnp->n_cookieverf.nfsuquad[1] = *tl; 2719191783Srmacklem NFSUNLOCKNODE(dnp); 2720191783Srmacklem } 2721191783Srmacklem } 2722191783Srmacklem if (nd->nd_repstat || error) { 2723191783Srmacklem if (!error) 2724191783Srmacklem error = nd->nd_repstat; 2725191783Srmacklem goto nfsmout; 2726191783Srmacklem } 2727191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2728191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 2729191783Srmacklem if (!more_dirs) 2730191783Srmacklem tryformoredirs = 0; 2731191783Srmacklem 2732191783Srmacklem /* loop thru the dir entries, doctoring them to 4bsd form */ 2733191783Srmacklem while (more_dirs && bigenough) { 2734191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2735191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2736191783Srmacklem ncookie.lval[0] = *tl++; 2737191783Srmacklem ncookie.lval[1] = *tl++; 2738191783Srmacklem len = fxdr_unsigned(int, *tl); 2739191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 2740191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2741220152Szack nfsva.na_fileid = fxdr_hyper(tl); 2742220152Szack tl += 2; 2743220152Szack len = fxdr_unsigned(int, *tl); 2744191783Srmacklem } else { 2745191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2746191783Srmacklem nfsva.na_fileid = 2747191783Srmacklem fxdr_unsigned(long, *tl++); 2748191783Srmacklem len = fxdr_unsigned(int, *tl); 2749191783Srmacklem } 2750191783Srmacklem if (len <= 0 || len > NFS_MAXNAMLEN) { 2751191783Srmacklem error = EBADRPC; 2752191783Srmacklem goto nfsmout; 2753191783Srmacklem } 2754191783Srmacklem tlen = NFSM_RNDUP(len); 2755191783Srmacklem if (tlen == len) 2756191783Srmacklem tlen += 4; /* To ensure null termination */ 2757191783Srmacklem left = DIRBLKSIZ - blksiz; 2758191783Srmacklem if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) { 2759191783Srmacklem dp->d_reclen += left; 2760191783Srmacklem uio_iov_base_add(uiop, left); 2761191783Srmacklem uio_iov_len_add(uiop, -(left)); 2762191783Srmacklem uio_uio_resid_add(uiop, -(left)); 2763191783Srmacklem uiop->uio_offset += left; 2764191783Srmacklem blksiz = 0; 2765191783Srmacklem } 2766191783Srmacklem if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 2767191783Srmacklem bigenough = 0; 2768191783Srmacklem if (bigenough) { 2769191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2770191783Srmacklem dp->d_namlen = len; 2771191783Srmacklem dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 2772191783Srmacklem dp->d_type = DT_UNKNOWN; 2773191783Srmacklem blksiz += dp->d_reclen; 2774191783Srmacklem if (blksiz == DIRBLKSIZ) 2775191783Srmacklem blksiz = 0; 2776191783Srmacklem uio_uio_resid_add(uiop, -(DIRHDSIZ)); 2777191783Srmacklem uiop->uio_offset += DIRHDSIZ; 2778191783Srmacklem uio_iov_base_add(uiop, DIRHDSIZ); 2779191783Srmacklem uio_iov_len_add(uiop, -(DIRHDSIZ)); 2780191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 2781191783Srmacklem if (error) 2782191783Srmacklem goto nfsmout; 2783191783Srmacklem cp = CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2784191783Srmacklem tlen -= len; 2785191783Srmacklem *cp = '\0'; /* null terminate */ 2786191783Srmacklem cp += tlen; /* points to cookie storage */ 2787191783Srmacklem tl2 = (u_int32_t *)cp; 2788191783Srmacklem uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 2789191783Srmacklem uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 2790191783Srmacklem uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 2791191783Srmacklem uiop->uio_offset += (tlen + NFSX_HYPER); 2792191783Srmacklem } else { 2793191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2794191783Srmacklem if (error) 2795191783Srmacklem goto nfsmout; 2796191783Srmacklem } 2797191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2798191783Srmacklem rderr = 0; 2799191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 2800191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2801191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2802191783Srmacklem NULL, NULL, &rderr, p, cred); 2803191783Srmacklem if (error) 2804191783Srmacklem goto nfsmout; 2805191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2806191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 2807191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2808191783Srmacklem ncookie.lval[0] = *tl++; 2809191783Srmacklem ncookie.lval[1] = *tl++; 2810191783Srmacklem } else { 2811191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2812191783Srmacklem ncookie.lval[0] = 0; 2813191783Srmacklem ncookie.lval[1] = *tl++; 2814191783Srmacklem } 2815191783Srmacklem if (bigenough) { 2816191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2817191783Srmacklem if (rderr) { 2818191783Srmacklem dp->d_fileno = 0; 2819191783Srmacklem } else { 2820191783Srmacklem if (gotmnton) { 2821191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 2822191783Srmacklem dp->d_fileno = nfsva.na_mntonfileno; 2823191783Srmacklem else 2824191783Srmacklem dp->d_fileno = nfsva.na_fileid; 2825191783Srmacklem } else if (nfsva.na_filesid[0] == 2826191783Srmacklem dnp->n_vattr.na_filesid[0] && 2827191783Srmacklem nfsva.na_filesid[1] == 2828191783Srmacklem dnp->n_vattr.na_filesid[1]) { 2829191783Srmacklem dp->d_fileno = nfsva.na_fileid; 2830191783Srmacklem } else { 2831191783Srmacklem do { 2832191783Srmacklem fakefileno--; 2833191783Srmacklem } while (fakefileno == 2834191783Srmacklem nfsva.na_fileid); 2835191783Srmacklem dp->d_fileno = fakefileno; 2836191783Srmacklem } 2837191783Srmacklem dp->d_type = vtonfs_dtype(nfsva.na_type); 2838191783Srmacklem } 2839191783Srmacklem } else { 2840191783Srmacklem dp->d_fileno = nfsva.na_fileid; 2841191783Srmacklem } 2842191783Srmacklem *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 2843191783Srmacklem ncookie.lval[0]; 2844191783Srmacklem *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 2845191783Srmacklem ncookie.lval[1]; 2846191783Srmacklem } 2847191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 2848191783Srmacklem } 2849191783Srmacklem /* 2850191783Srmacklem * If at end of rpc data, get the eof boolean 2851191783Srmacklem */ 2852191783Srmacklem if (!more_dirs) { 2853191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2854191783Srmacklem eof = fxdr_unsigned(int, *tl); 2855191783Srmacklem if (tryformoredirs) 2856191783Srmacklem more_dirs = !eof; 2857191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2858191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 2859191783Srmacklem stuff); 2860191783Srmacklem if (error) 2861191783Srmacklem goto nfsmout; 2862191783Srmacklem } 2863191783Srmacklem } 2864191783Srmacklem mbuf_freem(nd->nd_mrep); 2865191783Srmacklem nd->nd_mrep = NULL; 2866191783Srmacklem } 2867191783Srmacklem /* 2868191783Srmacklem * Fill last record, iff any, out to a multiple of DIRBLKSIZ 2869191783Srmacklem * by increasing d_reclen for the last record. 2870191783Srmacklem */ 2871191783Srmacklem if (blksiz > 0) { 2872191783Srmacklem left = DIRBLKSIZ - blksiz; 2873191783Srmacklem dp->d_reclen += left; 2874191783Srmacklem uio_iov_base_add(uiop, left); 2875191783Srmacklem uio_iov_len_add(uiop, -(left)); 2876191783Srmacklem uio_uio_resid_add(uiop, -(left)); 2877191783Srmacklem uiop->uio_offset += left; 2878191783Srmacklem } 2879191783Srmacklem 2880191783Srmacklem /* 2881191783Srmacklem * If returning no data, assume end of file. 2882191783Srmacklem * If not bigenough, return not end of file, since you aren't 2883191783Srmacklem * returning all the data 2884191783Srmacklem * Otherwise, return the eof flag from the server. 2885191783Srmacklem */ 2886191783Srmacklem if (eofp) { 2887191783Srmacklem if (tresid == ((size_t)(uio_uio_resid(uiop)))) 2888191783Srmacklem *eofp = 1; 2889191783Srmacklem else if (!bigenough) 2890191783Srmacklem *eofp = 0; 2891191783Srmacklem else 2892191783Srmacklem *eofp = eof; 2893191783Srmacklem } 2894191783Srmacklem 2895191783Srmacklem /* 2896191783Srmacklem * Add extra empty records to any remaining DIRBLKSIZ chunks. 2897191783Srmacklem */ 2898191783Srmacklem while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) { 2899191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2900191783Srmacklem dp->d_type = DT_UNKNOWN; 2901191783Srmacklem dp->d_fileno = 0; 2902191783Srmacklem dp->d_namlen = 0; 2903191783Srmacklem dp->d_name[0] = '\0'; 2904191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2905191783Srmacklem *tl++ = cookie.lval[0]; 2906191783Srmacklem *tl = cookie.lval[1]; 2907191783Srmacklem dp->d_reclen = DIRBLKSIZ; 2908191783Srmacklem uio_iov_base_add(uiop, DIRBLKSIZ); 2909191783Srmacklem uio_iov_len_add(uiop, -(DIRBLKSIZ)); 2910191783Srmacklem uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 2911191783Srmacklem uiop->uio_offset += DIRBLKSIZ; 2912191783Srmacklem } 2913191783Srmacklem 2914191783Srmacklemnfsmout: 2915191783Srmacklem if (nd->nd_mrep != NULL) 2916191783Srmacklem mbuf_freem(nd->nd_mrep); 2917191783Srmacklem return (error); 2918191783Srmacklem} 2919191783Srmacklem 2920191783Srmacklem#ifndef APPLE 2921191783Srmacklem/* 2922191783Srmacklem * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 2923191783Srmacklem * (Also used for NFS V4 when mount flag set.) 2924191783Srmacklem * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 2925191783Srmacklem */ 2926191783SrmacklemAPPLESTATIC int 2927191783Srmacklemnfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2928191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2929191783Srmacklem int *eofp, void *stuff) 2930191783Srmacklem{ 2931191783Srmacklem int len, left; 2932191783Srmacklem struct dirent *dp = NULL; 2933191783Srmacklem u_int32_t *tl; 2934191783Srmacklem vnode_t newvp = NULLVP; 2935191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2936191783Srmacklem struct nameidata nami, *ndp = &nami; 2937191783Srmacklem struct componentname *cnp = &ndp->ni_cnd; 2938191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2939191783Srmacklem struct nfsnode *dnp = VTONFS(vp), *np; 2940191783Srmacklem struct nfsvattr nfsva; 2941191783Srmacklem struct nfsfh *nfhp; 2942191783Srmacklem nfsquad_t cookie, ncookie; 2943191783Srmacklem int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2944191783Srmacklem int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 2945220735Srmacklem int isdotdot = 0, unlocknewvp = 0; 2946191783Srmacklem long dotfileid, dotdotfileid = 0, fileno = 0; 2947191783Srmacklem char *cp; 2948191783Srmacklem nfsattrbit_t attrbits, dattrbits; 2949191783Srmacklem size_t tresid; 2950191783Srmacklem u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr; 2951191783Srmacklem 2952209120Skib KASSERT(uiop->uio_iovcnt == 1 && 2953209120Skib (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2954209120Skib ("nfs readdirplusrpc bad uio")); 2955191783Srmacklem *attrflagp = 0; 2956191783Srmacklem if (eofp != NULL) 2957191783Srmacklem *eofp = 0; 2958191783Srmacklem ndp->ni_dvp = vp; 2959191783Srmacklem nd->nd_mrep = NULL; 2960191783Srmacklem cookie.lval[0] = cookiep->nfsuquad[0]; 2961191783Srmacklem cookie.lval[1] = cookiep->nfsuquad[1]; 2962191783Srmacklem tresid = uio_uio_resid(uiop); 2963191783Srmacklem 2964191783Srmacklem /* 2965191783Srmacklem * For NFSv4, first create the "." and ".." entries. 2966191783Srmacklem */ 2967191783Srmacklem if (NFSHASNFSV4(nmp)) { 2968191783Srmacklem NFSGETATTR_ATTRBIT(&dattrbits); 2969191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 2970191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2971191783Srmacklem if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2972191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID)) { 2973191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 2974191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 2975191783Srmacklem gotmnton = 1; 2976191783Srmacklem } else { 2977191783Srmacklem /* 2978191783Srmacklem * Must fake it. Use the fileno, except when the 2979191783Srmacklem * fsid is != to that of the directory. For that 2980191783Srmacklem * case, generate a fake fileno that is not the same. 2981191783Srmacklem */ 2982191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2983191783Srmacklem gotmnton = 0; 2984191783Srmacklem } 2985191783Srmacklem 2986191783Srmacklem /* 2987191783Srmacklem * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2988191783Srmacklem */ 2989191783Srmacklem if (uiop->uio_offset == 0) { 2990191783Srmacklem#if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 2991191783Srmacklem error = VOP_GETATTR(vp, &nfsva.na_vattr, cred); 2992191783Srmacklem#else 2993191783Srmacklem error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p); 2994191783Srmacklem#endif 2995191783Srmacklem if (error) 2996191783Srmacklem return (error); 2997191783Srmacklem dotfileid = nfsva.na_fileid; 2998191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2999191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3000191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3001191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3002191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3003191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3004191783Srmacklem if (error) 3005191783Srmacklem return (error); 3006191783Srmacklem if (nd->nd_repstat == 0) { 3007191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3008191783Srmacklem len = fxdr_unsigned(int, *(tl + 2)); 3009191783Srmacklem if (len > 0 && len <= NFSX_V4FHMAX) 3010191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3011191783Srmacklem else 3012191783Srmacklem error = EPERM; 3013191783Srmacklem if (!error) { 3014191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3015191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 3016191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3017191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3018191783Srmacklem NULL, NULL, NULL, p, cred); 3019191783Srmacklem if (error) { 3020191783Srmacklem dotdotfileid = dotfileid; 3021191783Srmacklem } else if (gotmnton) { 3022191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 3023191783Srmacklem dotdotfileid = nfsva.na_mntonfileno; 3024191783Srmacklem else 3025191783Srmacklem dotdotfileid = nfsva.na_fileid; 3026191783Srmacklem } else if (nfsva.na_filesid[0] == 3027191783Srmacklem dnp->n_vattr.na_filesid[0] && 3028191783Srmacklem nfsva.na_filesid[1] == 3029191783Srmacklem dnp->n_vattr.na_filesid[1]) { 3030191783Srmacklem dotdotfileid = nfsva.na_fileid; 3031191783Srmacklem } else { 3032191783Srmacklem do { 3033191783Srmacklem fakefileno--; 3034191783Srmacklem } while (fakefileno == 3035191783Srmacklem nfsva.na_fileid); 3036191783Srmacklem dotdotfileid = fakefileno; 3037191783Srmacklem } 3038191783Srmacklem } 3039191783Srmacklem } else if (nd->nd_repstat == NFSERR_NOENT) { 3040191783Srmacklem /* 3041191783Srmacklem * Lookupp returns NFSERR_NOENT when we are 3042191783Srmacklem * at the root, so just use the current dir. 3043191783Srmacklem */ 3044191783Srmacklem nd->nd_repstat = 0; 3045191783Srmacklem dotdotfileid = dotfileid; 3046191783Srmacklem } else { 3047191783Srmacklem error = nd->nd_repstat; 3048191783Srmacklem } 3049191783Srmacklem mbuf_freem(nd->nd_mrep); 3050191783Srmacklem if (error) 3051191783Srmacklem return (error); 3052191783Srmacklem nd->nd_mrep = NULL; 3053191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3054191783Srmacklem dp->d_type = DT_DIR; 3055191783Srmacklem dp->d_fileno = dotfileid; 3056191783Srmacklem dp->d_namlen = 1; 3057191783Srmacklem dp->d_name[0] = '.'; 3058191783Srmacklem dp->d_name[1] = '\0'; 3059191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3060191783Srmacklem /* 3061191783Srmacklem * Just make these offset cookie 0. 3062191783Srmacklem */ 3063191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3064191783Srmacklem *tl++ = 0; 3065191783Srmacklem *tl = 0; 3066191783Srmacklem blksiz += dp->d_reclen; 3067191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 3068191783Srmacklem uiop->uio_offset += dp->d_reclen; 3069191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 3070191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 3071191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3072191783Srmacklem dp->d_type = DT_DIR; 3073191783Srmacklem dp->d_fileno = dotdotfileid; 3074191783Srmacklem dp->d_namlen = 2; 3075191783Srmacklem dp->d_name[0] = '.'; 3076191783Srmacklem dp->d_name[1] = '.'; 3077191783Srmacklem dp->d_name[2] = '\0'; 3078191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3079191783Srmacklem /* 3080191783Srmacklem * Just make these offset cookie 0. 3081191783Srmacklem */ 3082191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3083191783Srmacklem *tl++ = 0; 3084191783Srmacklem *tl = 0; 3085191783Srmacklem blksiz += dp->d_reclen; 3086191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 3087191783Srmacklem uiop->uio_offset += dp->d_reclen; 3088191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 3089191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 3090191783Srmacklem } 3091191783Srmacklem NFSREADDIRPLUS_ATTRBIT(&attrbits); 3092191783Srmacklem if (gotmnton) 3093191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 3094191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 3095191783Srmacklem } 3096191783Srmacklem 3097191783Srmacklem /* 3098191783Srmacklem * Loop around doing readdir rpc's of size nm_readdirsize. 3099191783Srmacklem * The stopping criteria is EOF or buffer full. 3100191783Srmacklem */ 3101191783Srmacklem while (more_dirs && bigenough) { 3102191783Srmacklem *attrflagp = 0; 3103191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3104191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3105191783Srmacklem *tl++ = cookie.lval[0]; 3106191783Srmacklem *tl++ = cookie.lval[1]; 3107191783Srmacklem if (cookie.qval == 0) { 3108191783Srmacklem *tl++ = 0; 3109191783Srmacklem *tl++ = 0; 3110191783Srmacklem } else { 3111191783Srmacklem NFSLOCKNODE(dnp); 3112191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3113191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3114191783Srmacklem NFSUNLOCKNODE(dnp); 3115191783Srmacklem } 3116191783Srmacklem *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3117191783Srmacklem *tl = txdr_unsigned(nmp->nm_readdirsize); 3118191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3119191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3120191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3121191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3122191783Srmacklem (void) nfsrv_putattrbit(nd, &dattrbits); 3123191783Srmacklem } 3124191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3125191783Srmacklem if (error) 3126191783Srmacklem return (error); 3127191783Srmacklem if (nd->nd_flag & ND_NFSV3) 3128191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3129191783Srmacklem if (nd->nd_repstat || error) { 3130191783Srmacklem if (!error) 3131191783Srmacklem error = nd->nd_repstat; 3132191783Srmacklem goto nfsmout; 3133191783Srmacklem } 3134191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3135191783Srmacklem NFSLOCKNODE(dnp); 3136191783Srmacklem dnp->n_cookieverf.nfsuquad[0] = *tl++; 3137191783Srmacklem dnp->n_cookieverf.nfsuquad[1] = *tl++; 3138191783Srmacklem NFSUNLOCKNODE(dnp); 3139191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3140191783Srmacklem if (!more_dirs) 3141191783Srmacklem tryformoredirs = 0; 3142191783Srmacklem 3143191783Srmacklem /* loop thru the dir entries, doctoring them to 4bsd form */ 3144191783Srmacklem while (more_dirs && bigenough) { 3145191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3146191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3147191783Srmacklem ncookie.lval[0] = *tl++; 3148191783Srmacklem ncookie.lval[1] = *tl++; 3149191783Srmacklem } else { 3150191783Srmacklem fileno = fxdr_unsigned(long, *++tl); 3151191783Srmacklem tl++; 3152191783Srmacklem } 3153191783Srmacklem len = fxdr_unsigned(int, *tl); 3154191783Srmacklem if (len <= 0 || len > NFS_MAXNAMLEN) { 3155191783Srmacklem error = EBADRPC; 3156191783Srmacklem goto nfsmout; 3157191783Srmacklem } 3158191783Srmacklem tlen = NFSM_RNDUP(len); 3159191783Srmacklem if (tlen == len) 3160191783Srmacklem tlen += 4; /* To ensure null termination */ 3161191783Srmacklem left = DIRBLKSIZ - blksiz; 3162191783Srmacklem if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) { 3163191783Srmacklem dp->d_reclen += left; 3164191783Srmacklem uio_iov_base_add(uiop, left); 3165191783Srmacklem uio_iov_len_add(uiop, -(left)); 3166191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3167191783Srmacklem uiop->uio_offset += left; 3168191783Srmacklem blksiz = 0; 3169191783Srmacklem } 3170191783Srmacklem if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 3171191783Srmacklem bigenough = 0; 3172191783Srmacklem if (bigenough) { 3173191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3174191783Srmacklem dp->d_namlen = len; 3175191783Srmacklem dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 3176191783Srmacklem dp->d_type = DT_UNKNOWN; 3177191783Srmacklem blksiz += dp->d_reclen; 3178191783Srmacklem if (blksiz == DIRBLKSIZ) 3179191783Srmacklem blksiz = 0; 3180191783Srmacklem uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3181191783Srmacklem uiop->uio_offset += DIRHDSIZ; 3182191783Srmacklem uio_iov_base_add(uiop, DIRHDSIZ); 3183191783Srmacklem uio_iov_len_add(uiop, -(DIRHDSIZ)); 3184191783Srmacklem cnp->cn_nameptr = uio_iov_base(uiop); 3185191783Srmacklem cnp->cn_namelen = len; 3186191783Srmacklem NFSCNHASHZERO(cnp); 3187191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 3188191783Srmacklem if (error) 3189191783Srmacklem goto nfsmout; 3190191783Srmacklem cp = uio_iov_base(uiop); 3191191783Srmacklem tlen -= len; 3192191783Srmacklem *cp = '\0'; 3193191783Srmacklem cp += tlen; /* points to cookie storage */ 3194191783Srmacklem tl2 = (u_int32_t *)cp; 3195220735Srmacklem if (len == 2 && cnp->cn_nameptr[0] == '.' && 3196220735Srmacklem cnp->cn_nameptr[1] == '.') 3197220735Srmacklem isdotdot = 1; 3198220735Srmacklem else 3199220735Srmacklem isdotdot = 0; 3200191783Srmacklem uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3201191783Srmacklem uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3202191783Srmacklem uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3203191783Srmacklem uiop->uio_offset += (tlen + NFSX_HYPER); 3204191783Srmacklem } else { 3205191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3206191783Srmacklem if (error) 3207191783Srmacklem goto nfsmout; 3208191783Srmacklem } 3209191783Srmacklem nfhp = NULL; 3210191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 3211191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3212191783Srmacklem ncookie.lval[0] = *tl++; 3213191783Srmacklem ncookie.lval[1] = *tl++; 3214191783Srmacklem attrflag = fxdr_unsigned(int, *tl); 3215191783Srmacklem if (attrflag) { 3216191783Srmacklem error = nfsm_loadattr(nd, &nfsva); 3217191783Srmacklem if (error) 3218191783Srmacklem goto nfsmout; 3219191783Srmacklem } 3220191783Srmacklem NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3221191783Srmacklem if (*tl) { 3222191783Srmacklem error = nfsm_getfh(nd, &nfhp); 3223191783Srmacklem if (error) 3224191783Srmacklem goto nfsmout; 3225191783Srmacklem } 3226191783Srmacklem if (!attrflag && nfhp != NULL) { 3227191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3228191783Srmacklem nfhp = NULL; 3229191783Srmacklem } 3230191783Srmacklem } else { 3231191783Srmacklem rderr = 0; 3232191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 3233191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3234191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3235191783Srmacklem NULL, NULL, &rderr, p, cred); 3236191783Srmacklem if (error) 3237191783Srmacklem goto nfsmout; 3238191783Srmacklem } 3239191783Srmacklem 3240191783Srmacklem if (bigenough) { 3241191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3242191783Srmacklem if (rderr) { 3243191783Srmacklem dp->d_fileno = 0; 3244191783Srmacklem } else if (gotmnton) { 3245191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 3246191783Srmacklem dp->d_fileno = nfsva.na_mntonfileno; 3247191783Srmacklem else 3248191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3249191783Srmacklem } else if (nfsva.na_filesid[0] == 3250191783Srmacklem dnp->n_vattr.na_filesid[0] && 3251191783Srmacklem nfsva.na_filesid[1] == 3252191783Srmacklem dnp->n_vattr.na_filesid[1]) { 3253191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3254191783Srmacklem } else { 3255191783Srmacklem do { 3256191783Srmacklem fakefileno--; 3257191783Srmacklem } while (fakefileno == 3258191783Srmacklem nfsva.na_fileid); 3259191783Srmacklem dp->d_fileno = fakefileno; 3260191783Srmacklem } 3261191783Srmacklem } else { 3262191783Srmacklem dp->d_fileno = fileno; 3263191783Srmacklem } 3264191783Srmacklem *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3265191783Srmacklem ncookie.lval[0]; 3266191783Srmacklem *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3267191783Srmacklem ncookie.lval[1]; 3268191783Srmacklem 3269191783Srmacklem if (nfhp != NULL) { 3270191783Srmacklem if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3271191783Srmacklem dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3272191783Srmacklem VREF(vp); 3273191783Srmacklem newvp = vp; 3274191783Srmacklem unlocknewvp = 0; 3275191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3276191783Srmacklem np = dnp; 3277220735Srmacklem } else if (isdotdot != 0) { 3278220735Srmacklem /* 3279220735Srmacklem * Skip doing a nfscl_nget() call for "..". 3280220735Srmacklem * There's a race between acquiring the nfs 3281220735Srmacklem * node here and lookups that look for the 3282220735Srmacklem * directory being read (in the parent). 3283220735Srmacklem * It would try to get a lock on ".." here, 3284220735Srmacklem * owning the lock on the directory being 3285220735Srmacklem * read. Lookup will hold the lock on ".." 3286220735Srmacklem * and try to acquire the lock on the 3287220735Srmacklem * directory being read. 3288220735Srmacklem * If the directory is unlocked/relocked, 3289220735Srmacklem * then there is a LOR with the buflock 3290220735Srmacklem * vp is relocked. 3291220735Srmacklem */ 3292220735Srmacklem free(nfhp, M_NFSFH); 3293191783Srmacklem } else { 3294191783Srmacklem error = nfscl_nget(vnode_mount(vp), vp, 3295220732Srmacklem nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 3296191783Srmacklem if (!error) { 3297191783Srmacklem newvp = NFSTOV(np); 3298191783Srmacklem unlocknewvp = 1; 3299191783Srmacklem } 3300191783Srmacklem } 3301191783Srmacklem nfhp = NULL; 3302191783Srmacklem if (newvp != NULLVP) { 3303191783Srmacklem error = nfscl_loadattrcache(&newvp, 3304191783Srmacklem &nfsva, NULL, NULL, 0, 0); 3305191783Srmacklem if (error) { 3306191783Srmacklem if (unlocknewvp) 3307191783Srmacklem vput(newvp); 3308191783Srmacklem else 3309191783Srmacklem vrele(newvp); 3310191783Srmacklem goto nfsmout; 3311191783Srmacklem } 3312191783Srmacklem dp->d_type = 3313191783Srmacklem vtonfs_dtype(np->n_vattr.na_type); 3314191783Srmacklem ndp->ni_vp = newvp; 3315191783Srmacklem NFSCNHASH(cnp, HASHINIT); 3316191783Srmacklem if (cnp->cn_namelen <= NCHNAMLEN) { 3317212293Sjhb np->n_ctime = np->n_vattr.na_ctime; 3318191783Srmacklem cache_enter(ndp->ni_dvp,ndp->ni_vp,cnp); 3319191783Srmacklem } 3320191783Srmacklem if (unlocknewvp) 3321191783Srmacklem vput(newvp); 3322191783Srmacklem else 3323191783Srmacklem vrele(newvp); 3324191783Srmacklem newvp = NULLVP; 3325191783Srmacklem } 3326191783Srmacklem } 3327191783Srmacklem } else if (nfhp != NULL) { 3328191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3329191783Srmacklem } 3330191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3331191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3332191783Srmacklem } 3333191783Srmacklem /* 3334191783Srmacklem * If at end of rpc data, get the eof boolean 3335191783Srmacklem */ 3336191783Srmacklem if (!more_dirs) { 3337191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3338191783Srmacklem eof = fxdr_unsigned(int, *tl); 3339191783Srmacklem if (tryformoredirs) 3340191783Srmacklem more_dirs = !eof; 3341191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3342191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 3343191783Srmacklem stuff); 3344191783Srmacklem if (error) 3345191783Srmacklem goto nfsmout; 3346191783Srmacklem } 3347191783Srmacklem } 3348191783Srmacklem mbuf_freem(nd->nd_mrep); 3349191783Srmacklem nd->nd_mrep = NULL; 3350191783Srmacklem } 3351191783Srmacklem /* 3352191783Srmacklem * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3353191783Srmacklem * by increasing d_reclen for the last record. 3354191783Srmacklem */ 3355191783Srmacklem if (blksiz > 0) { 3356191783Srmacklem left = DIRBLKSIZ - blksiz; 3357191783Srmacklem dp->d_reclen += left; 3358191783Srmacklem uio_iov_base_add(uiop, left); 3359191783Srmacklem uio_iov_len_add(uiop, -(left)); 3360191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3361191783Srmacklem uiop->uio_offset += left; 3362191783Srmacklem } 3363191783Srmacklem 3364191783Srmacklem /* 3365191783Srmacklem * If returning no data, assume end of file. 3366191783Srmacklem * If not bigenough, return not end of file, since you aren't 3367191783Srmacklem * returning all the data 3368191783Srmacklem * Otherwise, return the eof flag from the server. 3369191783Srmacklem */ 3370191783Srmacklem if (eofp != NULL) { 3371191783Srmacklem if (tresid == uio_uio_resid(uiop)) 3372191783Srmacklem *eofp = 1; 3373191783Srmacklem else if (!bigenough) 3374191783Srmacklem *eofp = 0; 3375191783Srmacklem else 3376191783Srmacklem *eofp = eof; 3377191783Srmacklem } 3378191783Srmacklem 3379191783Srmacklem /* 3380191783Srmacklem * Add extra empty records to any remaining DIRBLKSIZ chunks. 3381191783Srmacklem */ 3382191783Srmacklem while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3383191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3384191783Srmacklem dp->d_type = DT_UNKNOWN; 3385191783Srmacklem dp->d_fileno = 0; 3386191783Srmacklem dp->d_namlen = 0; 3387191783Srmacklem dp->d_name[0] = '\0'; 3388191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3389191783Srmacklem *tl++ = cookie.lval[0]; 3390191783Srmacklem *tl = cookie.lval[1]; 3391191783Srmacklem dp->d_reclen = DIRBLKSIZ; 3392191783Srmacklem uio_iov_base_add(uiop, DIRBLKSIZ); 3393191783Srmacklem uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3394191783Srmacklem uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3395191783Srmacklem uiop->uio_offset += DIRBLKSIZ; 3396191783Srmacklem } 3397191783Srmacklem 3398191783Srmacklemnfsmout: 3399191783Srmacklem if (nd->nd_mrep != NULL) 3400191783Srmacklem mbuf_freem(nd->nd_mrep); 3401191783Srmacklem return (error); 3402191783Srmacklem} 3403191783Srmacklem#endif /* !APPLE */ 3404191783Srmacklem 3405191783Srmacklem/* 3406191783Srmacklem * Nfs commit rpc 3407191783Srmacklem */ 3408191783SrmacklemAPPLESTATIC int 3409191783Srmacklemnfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 3410191783Srmacklem NFSPROC_T *p, u_char *verfp, struct nfsvattr *nap, int *attrflagp, 3411191783Srmacklem void *stuff) 3412191783Srmacklem{ 3413191783Srmacklem u_int32_t *tl; 3414191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3415191783Srmacklem nfsattrbit_t attrbits; 3416191783Srmacklem int error; 3417191783Srmacklem 3418191783Srmacklem *attrflagp = 0; 3419191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 3420191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3421191783Srmacklem txdr_hyper(offset, tl); 3422191783Srmacklem tl += 2; 3423191783Srmacklem *tl = txdr_unsigned(cnt); 3424191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3425191783Srmacklem /* 3426191783Srmacklem * And do a Getattr op. 3427191783Srmacklem */ 3428191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3429191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3430191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 3431191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3432191783Srmacklem } 3433191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3434191783Srmacklem if (error) 3435191783Srmacklem return (error); 3436191783Srmacklem error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 3437191783Srmacklem if (!error && !nd->nd_repstat) { 3438191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3439191783Srmacklem NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF); 3440191783Srmacklem if (nd->nd_flag & ND_NFSV4) 3441191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3442191783Srmacklem } 3443191783Srmacklemnfsmout: 3444191783Srmacklem if (!error && nd->nd_repstat) 3445191783Srmacklem error = nd->nd_repstat; 3446191783Srmacklem mbuf_freem(nd->nd_mrep); 3447191783Srmacklem return (error); 3448191783Srmacklem} 3449191783Srmacklem 3450191783Srmacklem/* 3451191783Srmacklem * NFS byte range lock rpc. 3452191783Srmacklem * (Mostly just calls one of the three lower level RPC routines.) 3453191783Srmacklem */ 3454191783SrmacklemAPPLESTATIC int 3455191783Srmacklemnfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 3456191783Srmacklem int reclaim, struct ucred *cred, NFSPROC_T *p) 3457191783Srmacklem{ 3458191783Srmacklem struct nfscllockowner *lp; 3459191783Srmacklem struct nfsclclient *clp; 3460191783Srmacklem struct nfsfh *nfhp; 3461191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3462191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3463191783Srmacklem u_int64_t off, len; 3464191783Srmacklem off_t start, end; 3465191783Srmacklem u_int32_t clidrev = 0; 3466191783Srmacklem int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 3467191783Srmacklem int callcnt, dorpc; 3468191783Srmacklem 3469191783Srmacklem /* 3470191783Srmacklem * Convert the flock structure into a start and end and do POSIX 3471191783Srmacklem * bounds checking. 3472191783Srmacklem */ 3473191783Srmacklem switch (fl->l_whence) { 3474191783Srmacklem case SEEK_SET: 3475191783Srmacklem case SEEK_CUR: 3476191783Srmacklem /* 3477191783Srmacklem * Caller is responsible for adding any necessary offset 3478191783Srmacklem * when SEEK_CUR is used. 3479191783Srmacklem */ 3480191783Srmacklem start = fl->l_start; 3481191783Srmacklem off = fl->l_start; 3482191783Srmacklem break; 3483191783Srmacklem case SEEK_END: 3484191783Srmacklem start = size + fl->l_start; 3485191783Srmacklem off = size + fl->l_start; 3486191783Srmacklem break; 3487191783Srmacklem default: 3488191783Srmacklem return (EINVAL); 3489191783Srmacklem }; 3490191783Srmacklem if (start < 0) 3491191783Srmacklem return (EINVAL); 3492191783Srmacklem if (fl->l_len != 0) { 3493191783Srmacklem end = start + fl->l_len - 1; 3494191783Srmacklem if (end < start) 3495191783Srmacklem return (EINVAL); 3496191783Srmacklem } 3497191783Srmacklem 3498191783Srmacklem len = fl->l_len; 3499191783Srmacklem if (len == 0) 3500191783Srmacklem len = NFS64BITSSET; 3501191783Srmacklem retrycnt = 0; 3502191783Srmacklem do { 3503191783Srmacklem nd->nd_repstat = 0; 3504191783Srmacklem if (op == F_GETLK) { 3505191783Srmacklem error = nfscl_getcl(vp, cred, p, &clp); 3506191783Srmacklem if (error) 3507191783Srmacklem return (error); 3508191783Srmacklem error = nfscl_lockt(vp, clp, off, len, fl, p); 3509191783Srmacklem if (!error) { 3510191783Srmacklem clidrev = clp->nfsc_clientidrev; 3511191783Srmacklem error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 3512191783Srmacklem p); 3513191783Srmacklem } else if (error == -1) { 3514191783Srmacklem error = 0; 3515191783Srmacklem } 3516191783Srmacklem nfscl_clientrelease(clp); 3517191783Srmacklem } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 3518191783Srmacklem /* 3519191783Srmacklem * We must loop around for all lockowner cases. 3520191783Srmacklem */ 3521191783Srmacklem callcnt = 0; 3522191783Srmacklem error = nfscl_getcl(vp, cred, p, &clp); 3523191783Srmacklem if (error) 3524191783Srmacklem return (error); 3525191783Srmacklem do { 3526191783Srmacklem error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 3527191783Srmacklem clp, &lp, &dorpc); 3528191783Srmacklem /* 3529191783Srmacklem * If it returns a NULL lp, we're done. 3530191783Srmacklem */ 3531191783Srmacklem if (lp == NULL) { 3532191783Srmacklem if (callcnt == 0) 3533191783Srmacklem nfscl_clientrelease(clp); 3534191783Srmacklem else 3535191783Srmacklem nfscl_releasealllocks(clp, vp, p); 3536191783Srmacklem return (error); 3537191783Srmacklem } 3538191783Srmacklem if (nmp->nm_clp != NULL) 3539191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 3540191783Srmacklem else 3541191783Srmacklem clidrev = 0; 3542191783Srmacklem /* 3543191783Srmacklem * If the server doesn't support Posix lock semantics, 3544191783Srmacklem * only allow locks on the entire file, since it won't 3545191783Srmacklem * handle overlapping byte ranges. 3546191783Srmacklem * There might still be a problem when a lock 3547191783Srmacklem * upgrade/downgrade (read<->write) occurs, since the 3548191783Srmacklem * server "might" expect an unlock first? 3549191783Srmacklem */ 3550191783Srmacklem if (dorpc && (lp->nfsl_open->nfso_posixlock || 3551191783Srmacklem (off == 0 && len == NFS64BITSSET))) { 3552191783Srmacklem /* 3553191783Srmacklem * Since the lock records will go away, we must 3554191783Srmacklem * wait for grace and delay here. 3555191783Srmacklem */ 3556191783Srmacklem do { 3557191783Srmacklem error = nfsrpc_locku(nd, nmp, lp, off, len, 3558191783Srmacklem NFSV4LOCKT_READ, cred, p, 0); 3559191783Srmacklem if ((nd->nd_repstat == NFSERR_GRACE || 3560191783Srmacklem nd->nd_repstat == NFSERR_DELAY) && 3561191783Srmacklem error == 0) 3562207170Srmacklem (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3563207170Srmacklem "nfs_advlock"); 3564191783Srmacklem } while ((nd->nd_repstat == NFSERR_GRACE || 3565191783Srmacklem nd->nd_repstat == NFSERR_DELAY) && error == 0); 3566191783Srmacklem } 3567191783Srmacklem callcnt++; 3568191783Srmacklem } while (error == 0 && nd->nd_repstat == 0); 3569191783Srmacklem nfscl_releasealllocks(clp, vp, p); 3570191783Srmacklem } else if (op == F_SETLK) { 3571191783Srmacklem error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 3572191783Srmacklem NULL, 0, NULL, NULL, &lp, &newone, &donelocally); 3573191783Srmacklem if (error || donelocally) { 3574191783Srmacklem return (error); 3575191783Srmacklem } 3576191783Srmacklem if (nmp->nm_clp != NULL) 3577191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 3578191783Srmacklem else 3579191783Srmacklem clidrev = 0; 3580191783Srmacklem nfhp = VTONFS(vp)->n_fhp; 3581191783Srmacklem if (!lp->nfsl_open->nfso_posixlock && 3582191783Srmacklem (off != 0 || len != NFS64BITSSET)) { 3583191783Srmacklem error = EINVAL; 3584191783Srmacklem } else { 3585191783Srmacklem error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 3586191783Srmacklem nfhp->nfh_len, lp, newone, reclaim, off, 3587191783Srmacklem len, fl->l_type, cred, p, 0); 3588191783Srmacklem } 3589191783Srmacklem if (!error) 3590191783Srmacklem error = nd->nd_repstat; 3591191783Srmacklem nfscl_lockrelease(lp, error, newone); 3592191783Srmacklem } else { 3593191783Srmacklem error = EINVAL; 3594191783Srmacklem } 3595191783Srmacklem if (!error) 3596191783Srmacklem error = nd->nd_repstat; 3597191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 3598191783Srmacklem error == NFSERR_STALEDONTRECOVER || 3599191783Srmacklem error == NFSERR_STALECLIENTID || error == NFSERR_DELAY) { 3600207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_advlock"); 3601191783Srmacklem } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 3602191783Srmacklem && clidrev != 0) { 3603191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 3604191783Srmacklem retrycnt++; 3605191783Srmacklem } 3606191783Srmacklem } while (error == NFSERR_GRACE || 3607191783Srmacklem error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3608191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 3609191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 3610191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 3611191783Srmacklem if (error && retrycnt >= 4) 3612191783Srmacklem error = EIO; 3613191783Srmacklem return (error); 3614191783Srmacklem} 3615191783Srmacklem 3616191783Srmacklem/* 3617191783Srmacklem * The lower level routine for the LockT case. 3618191783Srmacklem */ 3619191783SrmacklemAPPLESTATIC int 3620191783Srmacklemnfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 3621191783Srmacklem struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 3622191783Srmacklem struct ucred *cred, NFSPROC_T *p) 3623191783Srmacklem{ 3624191783Srmacklem u_int32_t *tl; 3625191783Srmacklem int error, type, size; 3626191783Srmacklem u_int8_t own[NFSV4CL_LOCKNAMELEN]; 3627191783Srmacklem 3628191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 3629191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3630191783Srmacklem if (fl->l_type == F_RDLCK) 3631191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3632191783Srmacklem else 3633191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3634191783Srmacklem txdr_hyper(off, tl); 3635191783Srmacklem tl += 2; 3636191783Srmacklem txdr_hyper(len, tl); 3637191783Srmacklem tl += 2; 3638191783Srmacklem *tl++ = clp->nfsc_clientid.lval[0]; 3639191783Srmacklem *tl = clp->nfsc_clientid.lval[1]; 3640191783Srmacklem nfscl_filllockowner(p, own); 3641191783Srmacklem (void) nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN); 3642191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 3643191783Srmacklem if (error) 3644191783Srmacklem return (error); 3645191783Srmacklem if (nd->nd_repstat == 0) { 3646191783Srmacklem fl->l_type = F_UNLCK; 3647191783Srmacklem } else if (nd->nd_repstat == NFSERR_DENIED) { 3648191783Srmacklem nd->nd_repstat = 0; 3649191783Srmacklem fl->l_whence = SEEK_SET; 3650191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3651191783Srmacklem fl->l_start = fxdr_hyper(tl); 3652191783Srmacklem tl += 2; 3653191783Srmacklem len = fxdr_hyper(tl); 3654191783Srmacklem tl += 2; 3655191783Srmacklem if (len == NFS64BITSSET) 3656191783Srmacklem fl->l_len = 0; 3657191783Srmacklem else 3658191783Srmacklem fl->l_len = len; 3659191783Srmacklem type = fxdr_unsigned(int, *tl++); 3660191783Srmacklem if (type == NFSV4LOCKT_WRITE) 3661191783Srmacklem fl->l_type = F_WRLCK; 3662191783Srmacklem else 3663191783Srmacklem fl->l_type = F_RDLCK; 3664191783Srmacklem /* 3665191783Srmacklem * XXX For now, I have no idea what to do with the 3666191783Srmacklem * conflicting lock_owner, so I'll just set the pid == 0 3667191783Srmacklem * and skip over the lock_owner. 3668191783Srmacklem */ 3669191783Srmacklem fl->l_pid = (pid_t)0; 3670191783Srmacklem tl += 2; 3671191783Srmacklem size = fxdr_unsigned(int, *tl); 3672191783Srmacklem if (size < 0 || size > NFSV4_OPAQUELIMIT) 3673191783Srmacklem error = EBADRPC; 3674191783Srmacklem if (!error) 3675191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3676191783Srmacklem } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 3677191783Srmacklem nfscl_initiate_recovery(clp); 3678191783Srmacklemnfsmout: 3679191783Srmacklem mbuf_freem(nd->nd_mrep); 3680191783Srmacklem return (error); 3681191783Srmacklem} 3682191783Srmacklem 3683191783Srmacklem/* 3684191783Srmacklem * Lower level function that performs the LockU RPC. 3685191783Srmacklem */ 3686191783Srmacklemstatic int 3687191783Srmacklemnfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 3688191783Srmacklem struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 3689191783Srmacklem u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 3690191783Srmacklem{ 3691191783Srmacklem u_int32_t *tl; 3692191783Srmacklem int error; 3693191783Srmacklem 3694191783Srmacklem nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 3695191783Srmacklem lp->nfsl_open->nfso_fhlen, NULL); 3696191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3697191783Srmacklem *tl++ = txdr_unsigned(type); 3698191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid); 3699191783Srmacklem if (nfstest_outofseq && 3700191783Srmacklem (arc4random() % nfstest_outofseq) == 0) 3701191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid + 1); 3702191783Srmacklem tl++; 3703191783Srmacklem *tl++ = lp->nfsl_stateid.seqid; 3704191783Srmacklem *tl++ = lp->nfsl_stateid.other[0]; 3705191783Srmacklem *tl++ = lp->nfsl_stateid.other[1]; 3706191783Srmacklem *tl++ = lp->nfsl_stateid.other[2]; 3707191783Srmacklem txdr_hyper(off, tl); 3708191783Srmacklem tl += 2; 3709191783Srmacklem txdr_hyper(len, tl); 3710191783Srmacklem if (syscred) 3711191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3712191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 3713191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 3714191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 3715191783Srmacklem if (error) 3716191783Srmacklem return (error); 3717191783Srmacklem if (nd->nd_repstat == 0) { 3718191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3719191783Srmacklem lp->nfsl_stateid.seqid = *tl++; 3720191783Srmacklem lp->nfsl_stateid.other[0] = *tl++; 3721191783Srmacklem lp->nfsl_stateid.other[1] = *tl++; 3722191783Srmacklem lp->nfsl_stateid.other[2] = *tl; 3723191783Srmacklem } else if (nd->nd_repstat == NFSERR_STALESTATEID) 3724191783Srmacklem nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 3725191783Srmacklemnfsmout: 3726191783Srmacklem mbuf_freem(nd->nd_mrep); 3727191783Srmacklem return (error); 3728191783Srmacklem} 3729191783Srmacklem 3730191783Srmacklem/* 3731191783Srmacklem * The actual Lock RPC. 3732191783Srmacklem */ 3733191783SrmacklemAPPLESTATIC int 3734191783Srmacklemnfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 3735191783Srmacklem u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 3736191783Srmacklem int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 3737191783Srmacklem NFSPROC_T *p, int syscred) 3738191783Srmacklem{ 3739191783Srmacklem u_int32_t *tl; 3740191783Srmacklem int error, size; 3741191783Srmacklem 3742191783Srmacklem nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL); 3743191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3744191783Srmacklem if (type == F_RDLCK) 3745191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3746191783Srmacklem else 3747191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3748191783Srmacklem *tl++ = txdr_unsigned(reclaim); 3749191783Srmacklem txdr_hyper(off, tl); 3750191783Srmacklem tl += 2; 3751191783Srmacklem txdr_hyper(len, tl); 3752191783Srmacklem tl += 2; 3753191783Srmacklem if (newone) { 3754191783Srmacklem *tl = newnfs_true; 3755191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3756191783Srmacklem 2 * NFSX_UNSIGNED + NFSX_HYPER); 3757191783Srmacklem *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 3758191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.seqid; 3759191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 3760191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 3761191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 3762191783Srmacklem *tl++ = txdr_unsigned(lp->nfsl_seqid); 3763191783Srmacklem *tl++ = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[0]; 3764191783Srmacklem *tl = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[1]; 3765191783Srmacklem (void) nfsm_strtom(nd, lp->nfsl_owner, NFSV4CL_LOCKNAMELEN); 3766191783Srmacklem } else { 3767191783Srmacklem *tl = newnfs_false; 3768191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3769191783Srmacklem *tl++ = lp->nfsl_stateid.seqid; 3770191783Srmacklem *tl++ = lp->nfsl_stateid.other[0]; 3771191783Srmacklem *tl++ = lp->nfsl_stateid.other[1]; 3772191783Srmacklem *tl++ = lp->nfsl_stateid.other[2]; 3773191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid); 3774191783Srmacklem if (nfstest_outofseq && 3775191783Srmacklem (arc4random() % nfstest_outofseq) == 0) 3776191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid + 1); 3777191783Srmacklem } 3778191783Srmacklem if (syscred) 3779191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3780191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 3781191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 3782191783Srmacklem if (error) 3783191783Srmacklem return (error); 3784191783Srmacklem if (newone) 3785191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 3786191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 3787191783Srmacklem if (nd->nd_repstat == 0) { 3788191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3789191783Srmacklem lp->nfsl_stateid.seqid = *tl++; 3790191783Srmacklem lp->nfsl_stateid.other[0] = *tl++; 3791191783Srmacklem lp->nfsl_stateid.other[1] = *tl++; 3792191783Srmacklem lp->nfsl_stateid.other[2] = *tl; 3793191783Srmacklem } else if (nd->nd_repstat == NFSERR_DENIED) { 3794191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3795191783Srmacklem size = fxdr_unsigned(int, *(tl + 7)); 3796191783Srmacklem if (size < 0 || size > NFSV4_OPAQUELIMIT) 3797191783Srmacklem error = EBADRPC; 3798191783Srmacklem if (!error) 3799191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3800191783Srmacklem } else if (nd->nd_repstat == NFSERR_STALESTATEID) 3801191783Srmacklem nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 3802191783Srmacklemnfsmout: 3803191783Srmacklem mbuf_freem(nd->nd_mrep); 3804191783Srmacklem return (error); 3805191783Srmacklem} 3806191783Srmacklem 3807191783Srmacklem/* 3808191783Srmacklem * nfs statfs rpc 3809191783Srmacklem * (always called with the vp for the mount point) 3810191783Srmacklem */ 3811191783SrmacklemAPPLESTATIC int 3812191783Srmacklemnfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 3813191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3814191783Srmacklem void *stuff) 3815191783Srmacklem{ 3816191783Srmacklem u_int32_t *tl = NULL; 3817191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3818191783Srmacklem struct nfsmount *nmp; 3819191783Srmacklem nfsattrbit_t attrbits; 3820191783Srmacklem int error; 3821191783Srmacklem 3822191783Srmacklem *attrflagp = 0; 3823191783Srmacklem nmp = VFSTONFS(vnode_mount(vp)); 3824191783Srmacklem if (NFSHASNFSV4(nmp)) { 3825191783Srmacklem /* 3826191783Srmacklem * For V4, you actually do a getattr. 3827191783Srmacklem */ 3828191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 3829191783Srmacklem NFSSTATFS_GETATTRBIT(&attrbits); 3830191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3831191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3832191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3833191783Srmacklem if (error) 3834191783Srmacklem return (error); 3835191783Srmacklem if (nd->nd_repstat == 0) { 3836191783Srmacklem error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3837191783Srmacklem NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 3838191783Srmacklem cred); 3839191783Srmacklem if (!error) { 3840191783Srmacklem nmp->nm_fsid[0] = nap->na_filesid[0]; 3841191783Srmacklem nmp->nm_fsid[1] = nap->na_filesid[1]; 3842191783Srmacklem NFSSETHASSETFSID(nmp); 3843191783Srmacklem *attrflagp = 1; 3844191783Srmacklem } 3845191783Srmacklem } else { 3846191783Srmacklem error = nd->nd_repstat; 3847191783Srmacklem } 3848191783Srmacklem if (error) 3849191783Srmacklem goto nfsmout; 3850191783Srmacklem } else { 3851191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 3852191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3853191783Srmacklem if (error) 3854191783Srmacklem return (error); 3855191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 3856191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3857191783Srmacklem if (error) 3858191783Srmacklem goto nfsmout; 3859191783Srmacklem } 3860191783Srmacklem if (nd->nd_repstat) { 3861191783Srmacklem error = nd->nd_repstat; 3862191783Srmacklem goto nfsmout; 3863191783Srmacklem } 3864191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3865191783Srmacklem NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 3866191783Srmacklem } 3867191783Srmacklem if (NFSHASNFSV3(nmp)) { 3868191783Srmacklem sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 3869191783Srmacklem sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 3870191783Srmacklem sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 3871191783Srmacklem sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 3872191783Srmacklem sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 3873191783Srmacklem sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 3874191783Srmacklem sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 3875191783Srmacklem } else if (NFSHASNFSV4(nmp) == 0) { 3876191783Srmacklem sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 3877191783Srmacklem sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 3878191783Srmacklem sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 3879191783Srmacklem sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 3880191783Srmacklem sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 3881191783Srmacklem } 3882191783Srmacklemnfsmout: 3883191783Srmacklem mbuf_freem(nd->nd_mrep); 3884191783Srmacklem return (error); 3885191783Srmacklem} 3886191783Srmacklem 3887191783Srmacklem/* 3888191783Srmacklem * nfs pathconf rpc 3889191783Srmacklem */ 3890191783SrmacklemAPPLESTATIC int 3891191783Srmacklemnfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 3892191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3893191783Srmacklem void *stuff) 3894191783Srmacklem{ 3895191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3896191783Srmacklem struct nfsmount *nmp; 3897191783Srmacklem u_int32_t *tl; 3898191783Srmacklem nfsattrbit_t attrbits; 3899191783Srmacklem int error; 3900191783Srmacklem 3901191783Srmacklem *attrflagp = 0; 3902191783Srmacklem nmp = VFSTONFS(vnode_mount(vp)); 3903191783Srmacklem if (NFSHASNFSV4(nmp)) { 3904191783Srmacklem /* 3905191783Srmacklem * For V4, you actually do a getattr. 3906191783Srmacklem */ 3907191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 3908191783Srmacklem NFSPATHCONF_GETATTRBIT(&attrbits); 3909191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3910191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 3911191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3912191783Srmacklem if (error) 3913191783Srmacklem return (error); 3914191783Srmacklem if (nd->nd_repstat == 0) { 3915191783Srmacklem error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3916191783Srmacklem pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 3917191783Srmacklem cred); 3918191783Srmacklem if (!error) 3919191783Srmacklem *attrflagp = 1; 3920191783Srmacklem } else { 3921191783Srmacklem error = nd->nd_repstat; 3922191783Srmacklem } 3923191783Srmacklem } else { 3924191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 3925191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3926191783Srmacklem if (error) 3927191783Srmacklem return (error); 3928191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3929191783Srmacklem if (nd->nd_repstat && !error) 3930191783Srmacklem error = nd->nd_repstat; 3931191783Srmacklem if (!error) { 3932191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 3933191783Srmacklem pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 3934191783Srmacklem pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 3935191783Srmacklem pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 3936191783Srmacklem pc->pc_chownrestricted = 3937191783Srmacklem fxdr_unsigned(u_int32_t, *tl++); 3938191783Srmacklem pc->pc_caseinsensitive = 3939191783Srmacklem fxdr_unsigned(u_int32_t, *tl++); 3940191783Srmacklem pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 3941191783Srmacklem } 3942191783Srmacklem } 3943191783Srmacklemnfsmout: 3944191783Srmacklem mbuf_freem(nd->nd_mrep); 3945191783Srmacklem return (error); 3946191783Srmacklem} 3947191783Srmacklem 3948191783Srmacklem/* 3949191783Srmacklem * nfs version 3 fsinfo rpc call 3950191783Srmacklem */ 3951191783SrmacklemAPPLESTATIC int 3952191783Srmacklemnfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 3953191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 3954191783Srmacklem{ 3955191783Srmacklem u_int32_t *tl; 3956191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3957191783Srmacklem int error; 3958191783Srmacklem 3959191783Srmacklem *attrflagp = 0; 3960191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 3961191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3962191783Srmacklem if (error) 3963191783Srmacklem return (error); 3964191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3965191783Srmacklem if (nd->nd_repstat && !error) 3966191783Srmacklem error = nd->nd_repstat; 3967191783Srmacklem if (!error) { 3968191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 3969191783Srmacklem fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 3970191783Srmacklem fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 3971191783Srmacklem fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 3972191783Srmacklem fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 3973191783Srmacklem fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 3974191783Srmacklem fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 3975191783Srmacklem fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 3976191783Srmacklem fsp->fs_maxfilesize = fxdr_hyper(tl); 3977191783Srmacklem tl += 2; 3978191783Srmacklem fxdr_nfsv3time(tl, &fsp->fs_timedelta); 3979191783Srmacklem tl += 2; 3980191783Srmacklem fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 3981191783Srmacklem } 3982191783Srmacklemnfsmout: 3983191783Srmacklem mbuf_freem(nd->nd_mrep); 3984191783Srmacklem return (error); 3985191783Srmacklem} 3986191783Srmacklem 3987191783Srmacklem/* 3988191783Srmacklem * This function performs the Renew RPC. 3989191783Srmacklem */ 3990191783SrmacklemAPPLESTATIC int 3991191783Srmacklemnfsrpc_renew(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) 3992191783Srmacklem{ 3993191783Srmacklem u_int32_t *tl; 3994191783Srmacklem struct nfsrv_descript nfsd; 3995191783Srmacklem struct nfsrv_descript *nd = &nfsd; 3996191783Srmacklem struct nfsmount *nmp; 3997191783Srmacklem int error; 3998191783Srmacklem 3999191783Srmacklem nmp = clp->nfsc_nmp; 4000191783Srmacklem if (nmp == NULL) 4001191783Srmacklem return (0); 4002191783Srmacklem nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL); 4003191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4004191783Srmacklem *tl++ = clp->nfsc_clientid.lval[0]; 4005191783Srmacklem *tl = clp->nfsc_clientid.lval[1]; 4006191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4007191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4008191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4009191783Srmacklem if (error) 4010191783Srmacklem return (error); 4011191783Srmacklem error = nd->nd_repstat; 4012191783Srmacklem mbuf_freem(nd->nd_mrep); 4013191783Srmacklem return (error); 4014191783Srmacklem} 4015191783Srmacklem 4016191783Srmacklem/* 4017191783Srmacklem * This function performs the Releaselockowner RPC. 4018191783Srmacklem */ 4019191783SrmacklemAPPLESTATIC int 4020191783Srmacklemnfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4021191783Srmacklem struct ucred *cred, NFSPROC_T *p) 4022191783Srmacklem{ 4023191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4024191783Srmacklem u_int32_t *tl; 4025191783Srmacklem int error; 4026191783Srmacklem 4027191783Srmacklem nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL); 4028191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4029191783Srmacklem *tl++ = nmp->nm_clp->nfsc_clientid.lval[0]; 4030191783Srmacklem *tl = nmp->nm_clp->nfsc_clientid.lval[1]; 4031191783Srmacklem (void) nfsm_strtom(nd, lp->nfsl_owner, NFSV4CL_LOCKNAMELEN); 4032191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4033191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4034191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4035191783Srmacklem if (error) 4036191783Srmacklem return (error); 4037191783Srmacklem error = nd->nd_repstat; 4038191783Srmacklem mbuf_freem(nd->nd_mrep); 4039191783Srmacklem return (error); 4040191783Srmacklem} 4041191783Srmacklem 4042191783Srmacklem/* 4043191783Srmacklem * This function performs the Compound to get the mount pt FH. 4044191783Srmacklem */ 4045191783SrmacklemAPPLESTATIC int 4046191783Srmacklemnfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4047191783Srmacklem NFSPROC_T *p) 4048191783Srmacklem{ 4049191783Srmacklem u_int32_t *tl; 4050191783Srmacklem struct nfsrv_descript nfsd; 4051191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4052191783Srmacklem u_char *cp, *cp2; 4053191783Srmacklem int error, cnt, len, setnil; 4054191783Srmacklem u_int32_t *opcntp; 4055191783Srmacklem 4056191783Srmacklem nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp); 4057191783Srmacklem cp = dirpath; 4058191783Srmacklem cnt = 0; 4059191783Srmacklem do { 4060191783Srmacklem setnil = 0; 4061191783Srmacklem while (*cp == '/') 4062191783Srmacklem cp++; 4063191783Srmacklem cp2 = cp; 4064191783Srmacklem while (*cp2 != '\0' && *cp2 != '/') 4065191783Srmacklem cp2++; 4066191783Srmacklem if (*cp2 == '/') { 4067191783Srmacklem setnil = 1; 4068191783Srmacklem *cp2 = '\0'; 4069191783Srmacklem } 4070191783Srmacklem if (cp2 != cp) { 4071191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4072191783Srmacklem *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4073191783Srmacklem nfsm_strtom(nd, cp, strlen(cp)); 4074191783Srmacklem cnt++; 4075191783Srmacklem } 4076191783Srmacklem if (setnil) 4077191783Srmacklem *cp2++ = '/'; 4078191783Srmacklem cp = cp2; 4079191783Srmacklem } while (*cp != '\0'); 4080191783Srmacklem *opcntp = txdr_unsigned(2 + cnt); 4081191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4082191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETFH); 4083191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4084191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4085191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4086191783Srmacklem if (error) 4087191783Srmacklem return (error); 4088191783Srmacklem if (nd->nd_repstat == 0) { 4089191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4090191783Srmacklem tl += (2 + 2 * cnt); 4091191783Srmacklem if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4092191783Srmacklem len > NFSX_FHMAX) { 4093191783Srmacklem nd->nd_repstat = NFSERR_BADXDR; 4094191783Srmacklem } else { 4095191783Srmacklem nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4096191783Srmacklem if (nd->nd_repstat == 0) 4097191783Srmacklem nmp->nm_fhsize = len; 4098191783Srmacklem } 4099191783Srmacklem } 4100191783Srmacklem error = nd->nd_repstat; 4101191783Srmacklemnfsmout: 4102191783Srmacklem mbuf_freem(nd->nd_mrep); 4103191783Srmacklem return (error); 4104191783Srmacklem} 4105191783Srmacklem 4106191783Srmacklem/* 4107191783Srmacklem * This function performs the Delegreturn RPC. 4108191783Srmacklem */ 4109191783SrmacklemAPPLESTATIC int 4110191783Srmacklemnfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4111191783Srmacklem struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4112191783Srmacklem{ 4113191783Srmacklem u_int32_t *tl; 4114191783Srmacklem struct nfsrv_descript nfsd; 4115191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4116191783Srmacklem int error; 4117191783Srmacklem 4118191783Srmacklem nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4119191783Srmacklem dp->nfsdl_fhlen, NULL); 4120191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4121191783Srmacklem *tl++ = dp->nfsdl_stateid.seqid; 4122191783Srmacklem *tl++ = dp->nfsdl_stateid.other[0]; 4123191783Srmacklem *tl++ = dp->nfsdl_stateid.other[1]; 4124191783Srmacklem *tl = dp->nfsdl_stateid.other[2]; 4125191783Srmacklem if (syscred) 4126191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4127191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4128191783Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL); 4129191783Srmacklem if (error) 4130191783Srmacklem return (error); 4131191783Srmacklem error = nd->nd_repstat; 4132191783Srmacklem mbuf_freem(nd->nd_mrep); 4133191783Srmacklem return (error); 4134191783Srmacklem} 4135191783Srmacklem 4136191783Srmacklem/* 4137191783Srmacklem * nfs getacl call. 4138191783Srmacklem */ 4139191783SrmacklemAPPLESTATIC int 4140191783Srmacklemnfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4141191783Srmacklem struct acl *aclp, void *stuff) 4142191783Srmacklem{ 4143191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4144191783Srmacklem int error; 4145191783Srmacklem nfsattrbit_t attrbits; 4146191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4147191783Srmacklem 4148191783Srmacklem if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4149191783Srmacklem return (EOPNOTSUPP); 4150191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4151191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 4152191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4153191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 4154191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4155191783Srmacklem if (error) 4156191783Srmacklem return (error); 4157191783Srmacklem if (!nd->nd_repstat) 4158191783Srmacklem error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4159191783Srmacklem NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4160191783Srmacklem else 4161191783Srmacklem error = nd->nd_repstat; 4162191783Srmacklem mbuf_freem(nd->nd_mrep); 4163191783Srmacklem return (error); 4164191783Srmacklem} 4165191783Srmacklem 4166191783Srmacklem/* 4167191783Srmacklem * nfs setacl call. 4168191783Srmacklem */ 4169191783SrmacklemAPPLESTATIC int 4170191783Srmacklemnfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4171191783Srmacklem struct acl *aclp, void *stuff) 4172191783Srmacklem{ 4173191783Srmacklem int error; 4174191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4175191783Srmacklem 4176191783Srmacklem if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4177191783Srmacklem return (EOPNOTSUPP); 4178191783Srmacklem error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4179191783Srmacklem return (error); 4180191783Srmacklem} 4181191783Srmacklem 4182191783Srmacklem/* 4183191783Srmacklem * nfs setacl call. 4184191783Srmacklem */ 4185191783Srmacklemstatic int 4186191783Srmacklemnfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4187191783Srmacklem struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 4188191783Srmacklem{ 4189191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4190191783Srmacklem int error; 4191191783Srmacklem nfsattrbit_t attrbits; 4192191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4193191783Srmacklem 4194191783Srmacklem if (!NFSHASNFSV4(nmp)) 4195191783Srmacklem return (EOPNOTSUPP); 4196191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 4197191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 4198191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 4199191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4200220645Srmacklem (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0, 4201220648Srmacklem &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0); 4202191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4203191783Srmacklem if (error) 4204191783Srmacklem return (error); 4205191783Srmacklem /* Don't care about the pre/postop attributes */ 4206191783Srmacklem mbuf_freem(nd->nd_mrep); 4207191783Srmacklem return (nd->nd_repstat); 4208191783Srmacklem} 4209