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: stable/11/sys/fs/nfsclient/nfs_clrpcops.c 361236 2020-05-19 01:43:00Z freqlabs $"); 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 45229802Srmacklem#include "opt_inet6.h" 46229802Srmacklem 47191783Srmacklem#include <fs/nfs/nfsport.h> 48285066Srmacklem#include <sys/sysctl.h> 49191783Srmacklem 50285066SrmacklemSYSCTL_DECL(_vfs_nfs); 51285066Srmacklem 52285066Srmacklemstatic int nfsignore_eexist = 0; 53285066SrmacklemSYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW, 54285066Srmacklem &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink"); 55285066Srmacklem 56191783Srmacklem/* 57191783Srmacklem * Global variables 58191783Srmacklem */ 59191783Srmacklemextern int nfs_numnfscbd; 60191783Srmacklemextern struct timeval nfsboottime; 61191783Srmacklemextern u_int32_t newnfs_false, newnfs_true; 62191783Srmacklemextern nfstype nfsv34_type[9]; 63191783Srmacklemextern int nfsrv_useacl; 64191783Srmacklemextern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 65240289Srmacklemextern int nfscl_debuglevel; 66191783SrmacklemNFSCLSTATEMUTEX; 67191783Srmacklemint nfstest_outofseq = 0; 68191783Srmacklemint nfscl_assumeposixlocks = 1; 69191783Srmacklemint nfscl_enablecallb = 0; 70191783Srmacklemshort nfsv4_cbport = NFSV4_CBPORT; 71191783Srmacklemint nfstest_openallsetattr = 0; 72191783Srmacklem 73191783Srmacklem#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 74191783Srmacklem 75244042Srmacklem/* 76244042Srmacklem * nfscl_getsameserver() can return one of three values: 77244042Srmacklem * NFSDSP_USETHISSESSION - Use this session for the DS. 78244042Srmacklem * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new 79244042Srmacklem * session. 80244042Srmacklem * NFSDSP_NOTFOUND - No matching server was found. 81244042Srmacklem */ 82244042Srmacklemenum nfsclds_state { 83244042Srmacklem NFSDSP_USETHISSESSION = 0, 84244042Srmacklem NFSDSP_SEQTHISSESSION = 1, 85244042Srmacklem NFSDSP_NOTFOUND = 2, 86244042Srmacklem}; 87244042Srmacklem 88191783Srmacklemstatic int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, 89191783Srmacklem struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); 90191783Srmacklemstatic int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, 91191783Srmacklem nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *); 92222289Srmacklemstatic int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, 93191783Srmacklem struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, 94191783Srmacklem void *); 95191783Srmacklemstatic int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, 96191783Srmacklem nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, 97191783Srmacklem struct nfsvattr *, struct nfsfh **, int *, int *, void *); 98191783Srmacklemstatic int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, 99191783Srmacklem nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, 100191783Srmacklem NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, 101191783Srmacklem int *, void *, int *); 102191783Srmacklemstatic int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, 103191783Srmacklem struct nfscllockowner *, u_int64_t, u_int64_t, 104191783Srmacklem u_int32_t, struct ucred *, NFSPROC_T *, int); 105191783Srmacklemstatic int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, 106191783Srmacklem struct acl *, nfsv4stateid_t *, void *); 107244042Srmacklemstatic int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int, 108244042Srmacklem uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **, 109244042Srmacklem struct ucred *, NFSPROC_T *); 110244042Srmacklemstatic int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_storage *, 111244042Srmacklem struct nfsclds **, NFSPROC_T *); 112244042Srmacklemstatic void nfscl_initsessionslots(struct nfsclsession *); 113244042Srmacklemstatic int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *, 114244042Srmacklem nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, 115321029Srmacklem struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *, 116321029Srmacklem NFSPROC_T *); 117244042Srmacklemstatic int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *, 118244042Srmacklem struct nfsclds *, uint64_t, int, struct nfsfh *, struct ucred *, 119244042Srmacklem NFSPROC_T *); 120244042Srmacklemstatic int nfsrpc_writeds(vnode_t, struct uio *, int *, int *, 121244042Srmacklem nfsv4stateid_t *, struct nfsclds *, uint64_t, int, 122244042Srmacklem struct nfsfh *, int, struct ucred *, NFSPROC_T *); 123244042Srmacklemstatic enum nfsclds_state nfscl_getsameserver(struct nfsmount *, 124244042Srmacklem struct nfsclds *, struct nfsclds **); 125244042Srmacklemstatic int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, 126321029Srmacklem struct nfsfh *, struct ucred *, NFSPROC_T *); 127320998Srmacklemstatic void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t, 128320998Srmacklem uint64_t, uint64_t, nfsv4stateid_t *, int, int); 129320998Srmacklemstatic int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *, 130320998Srmacklem int *, struct nfsclflayouthead *); 131320998Srmacklemstatic int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *, 132320998Srmacklem int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, 133320998Srmacklem struct nfscldeleg **, struct ucred *, NFSPROC_T *); 134320998Srmacklemstatic int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *, 135320998Srmacklem nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, 136320998Srmacklem struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, 137320998Srmacklem struct nfsfh **, int *, int *, void *, int *); 138320998Srmacklemstatic int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *, 139320998Srmacklem int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, 140320998Srmacklem struct nfscldeleg **, nfsv4stateid_t *, int, int, int *, 141320998Srmacklem struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *); 142320998Srmacklemstatic int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *, 143320998Srmacklem nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, 144320998Srmacklem struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, 145320998Srmacklem struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *, 146320998Srmacklem int, int, int *, struct nfsclflayouthead *, int *); 147320998Srmacklemstatic int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *, 148320998Srmacklem int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **, 149320998Srmacklem struct nfsclflayouthead *, int, int *, struct ucred *, NFSPROC_T *); 150191783Srmacklem 151191783Srmacklem/* 152191783Srmacklem * nfs null call from vfs. 153191783Srmacklem */ 154361236Sfreqlabsint 155191783Srmacklemnfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) 156191783Srmacklem{ 157191783Srmacklem int error; 158191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 159191783Srmacklem 160191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_NULL, vp); 161191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 162191783Srmacklem if (nd->nd_repstat && !error) 163191783Srmacklem error = nd->nd_repstat; 164191783Srmacklem mbuf_freem(nd->nd_mrep); 165191783Srmacklem return (error); 166191783Srmacklem} 167191783Srmacklem 168191783Srmacklem/* 169191783Srmacklem * nfs access rpc op. 170191783Srmacklem * For nfs version 3 and 4, use the access rpc to check accessibility. If file 171191783Srmacklem * modes are changed on the server, accesses might still fail later. 172191783Srmacklem */ 173361236Sfreqlabsint 174191783Srmacklemnfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, 175191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 176191783Srmacklem{ 177191783Srmacklem int error; 178191783Srmacklem u_int32_t mode, rmode; 179191783Srmacklem 180191783Srmacklem if (acmode & VREAD) 181191783Srmacklem mode = NFSACCESS_READ; 182191783Srmacklem else 183191783Srmacklem mode = 0; 184191783Srmacklem if (vnode_vtype(vp) == VDIR) { 185191783Srmacklem if (acmode & VWRITE) 186191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | 187191783Srmacklem NFSACCESS_DELETE); 188191783Srmacklem if (acmode & VEXEC) 189191783Srmacklem mode |= NFSACCESS_LOOKUP; 190191783Srmacklem } else { 191191783Srmacklem if (acmode & VWRITE) 192191783Srmacklem mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 193191783Srmacklem if (acmode & VEXEC) 194191783Srmacklem mode |= NFSACCESS_EXECUTE; 195191783Srmacklem } 196191783Srmacklem 197191783Srmacklem /* 198191783Srmacklem * Now, just call nfsrpc_accessrpc() to do the actual RPC. 199191783Srmacklem */ 200191783Srmacklem error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode, 201191783Srmacklem NULL); 202191783Srmacklem 203191783Srmacklem /* 204191783Srmacklem * The NFS V3 spec does not clarify whether or not 205191783Srmacklem * the returned access bits can be a superset of 206191783Srmacklem * the ones requested, so... 207191783Srmacklem */ 208191783Srmacklem if (!error && (rmode & mode) != mode) 209191783Srmacklem error = EACCES; 210191783Srmacklem return (error); 211191783Srmacklem} 212191783Srmacklem 213191783Srmacklem/* 214191783Srmacklem * The actual rpc, separated out for Darwin. 215191783Srmacklem */ 216361236Sfreqlabsint 217191783Srmacklemnfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, 218191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep, 219191783Srmacklem void *stuff) 220191783Srmacklem{ 221191783Srmacklem u_int32_t *tl; 222191783Srmacklem u_int32_t supported, rmode; 223191783Srmacklem int error; 224191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 225191783Srmacklem nfsattrbit_t attrbits; 226191783Srmacklem 227191783Srmacklem *attrflagp = 0; 228191783Srmacklem supported = mode; 229191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp); 230191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 231191783Srmacklem *tl = txdr_unsigned(mode); 232191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 233191783Srmacklem /* 234191783Srmacklem * And do a Getattr op. 235191783Srmacklem */ 236191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 237191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 238191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 239191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 240191783Srmacklem } 241191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 242191783Srmacklem if (error) 243191783Srmacklem return (error); 244191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 245191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 246191783Srmacklem if (error) 247191783Srmacklem goto nfsmout; 248191783Srmacklem } 249191783Srmacklem if (!nd->nd_repstat) { 250191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 251191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 252191783Srmacklem supported = fxdr_unsigned(u_int32_t, *tl++); 253191783Srmacklem } else { 254191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 255191783Srmacklem } 256191783Srmacklem rmode = fxdr_unsigned(u_int32_t, *tl); 257191783Srmacklem if (nd->nd_flag & ND_NFSV4) 258191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 259191783Srmacklem 260191783Srmacklem /* 261191783Srmacklem * It's not obvious what should be done about 262191783Srmacklem * unsupported access modes. For now, be paranoid 263191783Srmacklem * and clear the unsupported ones. 264191783Srmacklem */ 265191783Srmacklem rmode &= supported; 266191783Srmacklem *rmodep = rmode; 267191783Srmacklem } else 268191783Srmacklem error = nd->nd_repstat; 269191783Srmacklemnfsmout: 270191783Srmacklem mbuf_freem(nd->nd_mrep); 271191783Srmacklem return (error); 272191783Srmacklem} 273191783Srmacklem 274191783Srmacklem/* 275191783Srmacklem * nfs open rpc 276191783Srmacklem */ 277361236Sfreqlabsint 278191783Srmacklemnfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) 279191783Srmacklem{ 280191783Srmacklem struct nfsclopen *op; 281191783Srmacklem struct nfscldeleg *dp; 282191783Srmacklem struct nfsfh *nfhp; 283191783Srmacklem struct nfsnode *np = VTONFS(vp); 284191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 285191783Srmacklem u_int32_t mode, clidrev; 286191783Srmacklem int ret, newone, error, expireret = 0, retrycnt; 287191783Srmacklem 288191783Srmacklem /* 289191783Srmacklem * For NFSv4, Open Ops are only done on Regular Files. 290191783Srmacklem */ 291191783Srmacklem if (vnode_vtype(vp) != VREG) 292191783Srmacklem return (0); 293191783Srmacklem mode = 0; 294191783Srmacklem if (amode & FREAD) 295191783Srmacklem mode |= NFSV4OPEN_ACCESSREAD; 296191783Srmacklem if (amode & FWRITE) 297191783Srmacklem mode |= NFSV4OPEN_ACCESSWRITE; 298191783Srmacklem nfhp = np->n_fhp; 299191783Srmacklem 300191783Srmacklem retrycnt = 0; 301191783Srmacklem#ifdef notdef 302191783Srmacklem{ char name[100]; int namel; 303191783Srmacklemnamel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99; 304191783Srmacklembcopy(NFS4NODENAME(np->n_v4), name, namel); 305191783Srmacklemname[namel] = '\0'; 306191783Srmacklemprintf("rpcopen p=0x%x name=%s",p->p_pid,name); 307191783Srmacklemif (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]); 308191783Srmacklemelse printf(" fhl=0\n"); 309191783Srmacklem} 310191783Srmacklem#endif 311191783Srmacklem do { 312191783Srmacklem dp = NULL; 313191783Srmacklem error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, 314191783Srmacklem cred, p, NULL, &op, &newone, &ret, 1); 315191783Srmacklem if (error) { 316191783Srmacklem return (error); 317191783Srmacklem } 318191783Srmacklem if (nmp->nm_clp != NULL) 319191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 320191783Srmacklem else 321191783Srmacklem clidrev = 0; 322191783Srmacklem if (ret == NFSCLOPEN_DOOPEN) { 323191783Srmacklem if (np->n_v4 != NULL) { 324320998Srmacklem /* 325320998Srmacklem * For the first attempt, try and get a layout, if 326320998Srmacklem * pNFS is enabled for the mount. 327320998Srmacklem */ 328320998Srmacklem if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || 329320998Srmacklem nfs_numnfscbd == 0 || 330320998Srmacklem (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0) 331320998Srmacklem error = nfsrpc_openrpc(nmp, vp, 332320998Srmacklem np->n_v4->n4_data, 333320998Srmacklem np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 334320998Srmacklem np->n_fhp->nfh_len, mode, op, 335320998Srmacklem NFS4NODENAME(np->n_v4), 336320998Srmacklem np->n_v4->n4_namelen, 337320998Srmacklem &dp, 0, 0x0, cred, p, 0, 0); 338320998Srmacklem else 339320998Srmacklem error = nfsrpc_getopenlayout(nmp, vp, 340320998Srmacklem np->n_v4->n4_data, 341320998Srmacklem np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 342320998Srmacklem np->n_fhp->nfh_len, mode, op, 343320998Srmacklem NFS4NODENAME(np->n_v4), 344320998Srmacklem np->n_v4->n4_namelen, &dp, cred, p); 345191783Srmacklem if (dp != NULL) { 346191783Srmacklem#ifdef APPLE 347191783Srmacklem OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); 348191783Srmacklem#else 349191783Srmacklem NFSLOCKNODE(np); 350191783Srmacklem np->n_flag &= ~NDELEGMOD; 351210034Srmacklem /* 352210034Srmacklem * Invalidate the attribute cache, so that 353210034Srmacklem * attributes that pre-date the issue of a 354210034Srmacklem * delegation are not cached, since the 355210034Srmacklem * cached attributes will remain valid while 356210034Srmacklem * the delegation is held. 357210034Srmacklem */ 358210034Srmacklem NFSINVALATTRCACHE(np); 359191783Srmacklem NFSUNLOCKNODE(np); 360191783Srmacklem#endif 361191783Srmacklem (void) nfscl_deleg(nmp->nm_mountp, 362191783Srmacklem op->nfso_own->nfsow_clp, 363191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); 364191783Srmacklem } 365191783Srmacklem } else { 366191783Srmacklem error = EIO; 367191783Srmacklem } 368191783Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 369206688Srmacklem } else if (ret == NFSCLOPEN_SETCRED) 370206688Srmacklem /* 371206688Srmacklem * This is a new local open on a delegation. It needs 372206688Srmacklem * to have credentials so that an open can be done 373206688Srmacklem * against the server during recovery. 374206688Srmacklem */ 375206688Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 376191783Srmacklem 377191783Srmacklem /* 378191783Srmacklem * nfso_opencnt is the count of how many VOP_OPEN()s have 379191783Srmacklem * been done on this Open successfully and a VOP_CLOSE() 380191783Srmacklem * is expected for each of these. 381191783Srmacklem * If error is non-zero, don't increment it, since the Open 382191783Srmacklem * hasn't succeeded yet. 383191783Srmacklem */ 384191783Srmacklem if (!error) 385191783Srmacklem op->nfso_opencnt++; 386317520Srmacklem nfscl_openrelease(nmp, op, error, newone); 387191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 388244042Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 389244042Srmacklem error == NFSERR_BADSESSION) { 390207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_open"); 391191783Srmacklem } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 392191783Srmacklem && clidrev != 0) { 393191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 394191783Srmacklem retrycnt++; 395191783Srmacklem } 396191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 397191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 398244042Srmacklem error == NFSERR_BADSESSION || 399191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 400191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 401191783Srmacklem if (error && retrycnt >= 4) 402191783Srmacklem error = EIO; 403191783Srmacklem return (error); 404191783Srmacklem} 405191783Srmacklem 406191783Srmacklem/* 407191783Srmacklem * the actual open rpc 408191783Srmacklem */ 409361236Sfreqlabsint 410191783Srmacklemnfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, 411191783Srmacklem u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 412191783Srmacklem u_int8_t *name, int namelen, struct nfscldeleg **dpp, 413191783Srmacklem int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, 414191783Srmacklem int syscred, int recursed) 415191783Srmacklem{ 416191783Srmacklem u_int32_t *tl; 417191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 418191783Srmacklem struct nfscldeleg *dp, *ndp = NULL; 419191783Srmacklem struct nfsvattr nfsva; 420191783Srmacklem u_int32_t rflags, deleg; 421191783Srmacklem nfsattrbit_t attrbits; 422191783Srmacklem int error, ret, acesize, limitby; 423317393Srmacklem struct nfsclsession *tsep; 424191783Srmacklem 425191783Srmacklem dp = *dpp; 426191783Srmacklem *dpp = NULL; 427244042Srmacklem nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL); 428191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 429191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 430191783Srmacklem *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 431191783Srmacklem *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 432317393Srmacklem tsep = nfsmnt_mdssession(nmp); 433317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 434317393Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 435191783Srmacklem (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 436191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 437191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 438191783Srmacklem if (reclaim) { 439191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); 440191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 441191783Srmacklem *tl = txdr_unsigned(delegtype); 442191783Srmacklem } else { 443191783Srmacklem if (dp != NULL) { 444191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); 445191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 446244042Srmacklem if (NFSHASNFSV4N(nmp)) 447244042Srmacklem *tl++ = 0; 448244042Srmacklem else 449244042Srmacklem *tl++ = dp->nfsdl_stateid.seqid; 450191783Srmacklem *tl++ = dp->nfsdl_stateid.other[0]; 451191783Srmacklem *tl++ = dp->nfsdl_stateid.other[1]; 452191783Srmacklem *tl = dp->nfsdl_stateid.other[2]; 453191783Srmacklem } else { 454191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 455191783Srmacklem } 456191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 457191783Srmacklem } 458191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 459191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 460191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 461191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 462191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 463191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 464191783Srmacklem if (syscred) 465191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 466191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 467244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 468191783Srmacklem if (error) 469191783Srmacklem return (error); 470191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 471191783Srmacklem if (!nd->nd_repstat) { 472191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 473191783Srmacklem 6 * NFSX_UNSIGNED); 474191783Srmacklem op->nfso_stateid.seqid = *tl++; 475191783Srmacklem op->nfso_stateid.other[0] = *tl++; 476191783Srmacklem op->nfso_stateid.other[1] = *tl++; 477191783Srmacklem op->nfso_stateid.other[2] = *tl; 478191783Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 479191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 480191783Srmacklem if (error) 481191783Srmacklem goto nfsmout; 482191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 483191783Srmacklem deleg = fxdr_unsigned(u_int32_t, *tl); 484191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 485191783Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 486191783Srmacklem if (!(op->nfso_own->nfsow_clp->nfsc_flags & 487191783Srmacklem NFSCLFLAGS_FIRSTDELEG)) 488191783Srmacklem op->nfso_own->nfsow_clp->nfsc_flags |= 489191783Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 490191783Srmacklem MALLOC(ndp, struct nfscldeleg *, 491191783Srmacklem sizeof (struct nfscldeleg) + newfhlen, 492191783Srmacklem M_NFSCLDELEG, M_WAITOK); 493191783Srmacklem LIST_INIT(&ndp->nfsdl_owner); 494191783Srmacklem LIST_INIT(&ndp->nfsdl_lock); 495191783Srmacklem ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 496191783Srmacklem ndp->nfsdl_fhlen = newfhlen; 497191783Srmacklem NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 498191783Srmacklem newnfs_copyincred(cred, &ndp->nfsdl_cred); 499191783Srmacklem nfscl_lockinit(&ndp->nfsdl_rwlock); 500191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 501191783Srmacklem NFSX_UNSIGNED); 502191783Srmacklem ndp->nfsdl_stateid.seqid = *tl++; 503191783Srmacklem ndp->nfsdl_stateid.other[0] = *tl++; 504191783Srmacklem ndp->nfsdl_stateid.other[1] = *tl++; 505191783Srmacklem ndp->nfsdl_stateid.other[2] = *tl++; 506191783Srmacklem ret = fxdr_unsigned(int, *tl); 507191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 508191783Srmacklem ndp->nfsdl_flags = NFSCLDL_WRITE; 509191783Srmacklem /* 510191783Srmacklem * Indicates how much the file can grow. 511191783Srmacklem */ 512191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 513191783Srmacklem 3 * NFSX_UNSIGNED); 514191783Srmacklem limitby = fxdr_unsigned(int, *tl++); 515191783Srmacklem switch (limitby) { 516191783Srmacklem case NFSV4OPEN_LIMITSIZE: 517191783Srmacklem ndp->nfsdl_sizelimit = fxdr_hyper(tl); 518191783Srmacklem break; 519191783Srmacklem case NFSV4OPEN_LIMITBLOCKS: 520191783Srmacklem ndp->nfsdl_sizelimit = 521191783Srmacklem fxdr_unsigned(u_int64_t, *tl++); 522191783Srmacklem ndp->nfsdl_sizelimit *= 523191783Srmacklem fxdr_unsigned(u_int64_t, *tl); 524191783Srmacklem break; 525191783Srmacklem default: 526191783Srmacklem error = NFSERR_BADXDR; 527191783Srmacklem goto nfsmout; 528297793Spfg } 529191783Srmacklem } else { 530191783Srmacklem ndp->nfsdl_flags = NFSCLDL_READ; 531191783Srmacklem } 532191783Srmacklem if (ret) 533191783Srmacklem ndp->nfsdl_flags |= NFSCLDL_RECALL; 534191783Srmacklem error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 535191783Srmacklem &acesize, p); 536191783Srmacklem if (error) 537191783Srmacklem goto nfsmout; 538191783Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 539191783Srmacklem error = NFSERR_BADXDR; 540191783Srmacklem goto nfsmout; 541191783Srmacklem } 542191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 543191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 544191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 545191783Srmacklem NULL, NULL, NULL, p, cred); 546191783Srmacklem if (error) 547191783Srmacklem goto nfsmout; 548191783Srmacklem if (ndp != NULL) { 549191783Srmacklem ndp->nfsdl_change = nfsva.na_filerev; 550191783Srmacklem ndp->nfsdl_modtime = nfsva.na_mtime; 551191783Srmacklem ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 552191783Srmacklem } 553191783Srmacklem if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { 554191783Srmacklem do { 555191783Srmacklem ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, 556191783Srmacklem cred, p); 557191783Srmacklem if (ret == NFSERR_DELAY) 558207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_open"); 559191783Srmacklem } while (ret == NFSERR_DELAY); 560191783Srmacklem error = ret; 561191783Srmacklem } 562191783Srmacklem if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || 563191783Srmacklem nfscl_assumeposixlocks) 564191783Srmacklem op->nfso_posixlock = 1; 565191783Srmacklem else 566191783Srmacklem op->nfso_posixlock = 0; 567191783Srmacklem 568191783Srmacklem /* 569191783Srmacklem * If the server is handing out delegations, but we didn't 570191783Srmacklem * get one because an OpenConfirm was required, try the 571191783Srmacklem * Open again, to get a delegation. This is a harmless no-op, 572191783Srmacklem * from a server's point of view. 573191783Srmacklem */ 574191783Srmacklem if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && 575191783Srmacklem (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) 576191783Srmacklem && !error && dp == NULL && ndp == NULL && !recursed) { 577191783Srmacklem do { 578191783Srmacklem ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, 579191783Srmacklem newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, 580191783Srmacklem cred, p, syscred, 1); 581191783Srmacklem if (ret == NFSERR_DELAY) 582207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_open2"); 583191783Srmacklem } while (ret == NFSERR_DELAY); 584191783Srmacklem if (ret) { 585281770Spfg if (ndp != NULL) { 586191783Srmacklem FREE((caddr_t)ndp, M_NFSCLDELEG); 587281770Spfg ndp = NULL; 588281770Spfg } 589191783Srmacklem if (ret == NFSERR_STALECLIENTID || 590244042Srmacklem ret == NFSERR_STALEDONTRECOVER || 591244042Srmacklem ret == NFSERR_BADSESSION) 592191783Srmacklem error = ret; 593191783Srmacklem } 594191783Srmacklem } 595191783Srmacklem } 596191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 597191783Srmacklem error = nd->nd_repstat; 598317393Srmacklem if (error == NFSERR_STALECLIENTID) 599191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 600191783Srmacklemnfsmout: 601191783Srmacklem if (!error) 602191783Srmacklem *dpp = ndp; 603191783Srmacklem else if (ndp != NULL) 604191783Srmacklem FREE((caddr_t)ndp, M_NFSCLDELEG); 605191783Srmacklem mbuf_freem(nd->nd_mrep); 606191783Srmacklem return (error); 607191783Srmacklem} 608191783Srmacklem 609191783Srmacklem/* 610191783Srmacklem * open downgrade rpc 611191783Srmacklem */ 612361236Sfreqlabsint 613191783Srmacklemnfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, 614191783Srmacklem struct ucred *cred, NFSPROC_T *p) 615191783Srmacklem{ 616191783Srmacklem u_int32_t *tl; 617191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 618191783Srmacklem int error; 619191783Srmacklem 620191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp); 621191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 622244042Srmacklem if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp)))) 623244042Srmacklem *tl++ = 0; 624244042Srmacklem else 625244042Srmacklem *tl++ = op->nfso_stateid.seqid; 626191783Srmacklem *tl++ = op->nfso_stateid.other[0]; 627191783Srmacklem *tl++ = op->nfso_stateid.other[1]; 628191783Srmacklem *tl++ = op->nfso_stateid.other[2]; 629191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 630191783Srmacklem *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 631191783Srmacklem *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 632191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 633191783Srmacklem if (error) 634191783Srmacklem return (error); 635191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 636191783Srmacklem if (!nd->nd_repstat) { 637191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 638191783Srmacklem op->nfso_stateid.seqid = *tl++; 639191783Srmacklem op->nfso_stateid.other[0] = *tl++; 640191783Srmacklem op->nfso_stateid.other[1] = *tl++; 641191783Srmacklem op->nfso_stateid.other[2] = *tl; 642191783Srmacklem } 643191783Srmacklem if (nd->nd_repstat && error == 0) 644191783Srmacklem error = nd->nd_repstat; 645317393Srmacklem if (error == NFSERR_STALESTATEID) 646191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 647191783Srmacklemnfsmout: 648191783Srmacklem mbuf_freem(nd->nd_mrep); 649191783Srmacklem return (error); 650191783Srmacklem} 651191783Srmacklem 652191783Srmacklem/* 653191783Srmacklem * V4 Close operation. 654191783Srmacklem */ 655361236Sfreqlabsint 656192337Srmacklemnfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) 657191783Srmacklem{ 658191783Srmacklem struct nfsclclient *clp; 659191783Srmacklem int error; 660191783Srmacklem 661191783Srmacklem if (vnode_vtype(vp) != VREG) 662191783Srmacklem return (0); 663192337Srmacklem if (doclose) 664195510Srmacklem error = nfscl_doclose(vp, &clp, p); 665192337Srmacklem else 666195510Srmacklem error = nfscl_getclose(vp, &clp); 667191783Srmacklem if (error) 668191783Srmacklem return (error); 669191783Srmacklem 670191783Srmacklem nfscl_clientrelease(clp); 671191783Srmacklem return (0); 672191783Srmacklem} 673191783Srmacklem 674191783Srmacklem/* 675195510Srmacklem * Close the open. 676191783Srmacklem */ 677361236Sfreqlabsvoid 678195510Srmacklemnfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p) 679191783Srmacklem{ 680191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 681223747Srmacklem struct nfscllockowner *lp, *nlp; 682191783Srmacklem struct nfscllock *lop, *nlop; 683191783Srmacklem struct ucred *tcred; 684191783Srmacklem u_int64_t off = 0, len = 0; 685191783Srmacklem u_int32_t type = NFSV4LOCKT_READ; 686195510Srmacklem int error, do_unlock, trycnt; 687191783Srmacklem 688191783Srmacklem tcred = newnfs_getcred(); 689195510Srmacklem newnfs_copycred(&op->nfso_cred, tcred); 690195510Srmacklem /* 691195510Srmacklem * (Theoretically this could be done in the same 692195510Srmacklem * compound as the close, but having multiple 693195510Srmacklem * sequenced Ops in the same compound might be 694195510Srmacklem * too scary for some servers.) 695195510Srmacklem */ 696195510Srmacklem if (op->nfso_posixlock) { 697195510Srmacklem off = 0; 698195510Srmacklem len = NFS64BITSSET; 699195510Srmacklem type = NFSV4LOCKT_READ; 700195510Srmacklem } 701195510Srmacklem 702195510Srmacklem /* 703195510Srmacklem * Since this function is only called from VOP_INACTIVE(), no 704195510Srmacklem * other thread will be manipulating this Open. As such, the 705195510Srmacklem * lock lists are not being changed by other threads, so it should 706195510Srmacklem * be safe to do this without locking. 707195510Srmacklem */ 708195510Srmacklem LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 709195510Srmacklem do_unlock = 1; 710195510Srmacklem LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 711191783Srmacklem if (op->nfso_posixlock == 0) { 712195510Srmacklem off = lop->nfslo_first; 713195510Srmacklem len = lop->nfslo_end - lop->nfslo_first; 714195510Srmacklem if (lop->nfslo_type == F_WRLCK) 715195510Srmacklem type = NFSV4LOCKT_WRITE; 716195510Srmacklem else 717195510Srmacklem type = NFSV4LOCKT_READ; 718191783Srmacklem } 719195510Srmacklem if (do_unlock) { 720195510Srmacklem trycnt = 0; 721195510Srmacklem do { 722195510Srmacklem error = nfsrpc_locku(nd, nmp, lp, off, 723195510Srmacklem len, type, tcred, p, 0); 724195510Srmacklem if ((nd->nd_repstat == NFSERR_GRACE || 725195510Srmacklem nd->nd_repstat == NFSERR_DELAY) && 726195510Srmacklem error == 0) 727195510Srmacklem (void) nfs_catnap(PZERO, 728207170Srmacklem (int)nd->nd_repstat, 729195510Srmacklem "nfs_close"); 730195510Srmacklem } while ((nd->nd_repstat == NFSERR_GRACE || 731195510Srmacklem nd->nd_repstat == NFSERR_DELAY) && 732195510Srmacklem error == 0 && trycnt++ < 5); 733195510Srmacklem if (op->nfso_posixlock) 734195510Srmacklem do_unlock = 0; 735191783Srmacklem } 736191783Srmacklem nfscl_freelock(lop, 0); 737191783Srmacklem } 738223747Srmacklem /* 739223747Srmacklem * Do a ReleaseLockOwner. 740223747Srmacklem * The lock owner name nfsl_owner may be used by other opens for 741223747Srmacklem * other files but the lock_owner4 name that nfsrpc_rellockown() 742223747Srmacklem * puts on the wire has the file handle for this file appended 743223747Srmacklem * to it, so it can be done now. 744223747Srmacklem */ 745227760Srmacklem (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh, 746227760Srmacklem lp->nfsl_open->nfso_fhlen, tcred, p); 747195510Srmacklem } 748191783Srmacklem 749195510Srmacklem /* 750195510Srmacklem * There could be other Opens for different files on the same 751195510Srmacklem * OpenOwner, so locking is required. 752195510Srmacklem */ 753195510Srmacklem NFSLOCKCLSTATE(); 754195510Srmacklem nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 755195510Srmacklem NFSUNLOCKCLSTATE(); 756195510Srmacklem do { 757195510Srmacklem error = nfscl_tryclose(op, tcred, nmp, p); 758195510Srmacklem if (error == NFSERR_GRACE) 759207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_close"); 760195510Srmacklem } while (error == NFSERR_GRACE); 761195510Srmacklem NFSLOCKCLSTATE(); 762195510Srmacklem nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); 763195510Srmacklem 764223747Srmacklem LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) 765223747Srmacklem nfscl_freelockowner(lp, 0); 766195510Srmacklem nfscl_freeopen(op, 0); 767195510Srmacklem NFSUNLOCKCLSTATE(); 768191783Srmacklem NFSFREECRED(tcred); 769191783Srmacklem} 770191783Srmacklem 771191783Srmacklem/* 772191783Srmacklem * The actual Close RPC. 773191783Srmacklem */ 774361236Sfreqlabsint 775191783Srmacklemnfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp, 776191783Srmacklem struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p, 777191783Srmacklem int syscred) 778191783Srmacklem{ 779191783Srmacklem u_int32_t *tl; 780191783Srmacklem int error; 781191783Srmacklem 782191783Srmacklem nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh, 783244042Srmacklem op->nfso_fhlen, NULL, NULL); 784191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 785191783Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 786244042Srmacklem if (NFSHASNFSV4N(nmp)) 787244042Srmacklem *tl++ = 0; 788244042Srmacklem else 789244042Srmacklem *tl++ = op->nfso_stateid.seqid; 790191783Srmacklem *tl++ = op->nfso_stateid.other[0]; 791191783Srmacklem *tl++ = op->nfso_stateid.other[1]; 792191783Srmacklem *tl = op->nfso_stateid.other[2]; 793191783Srmacklem if (syscred) 794191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 795191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 796244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 797191783Srmacklem if (error) 798191783Srmacklem return (error); 799191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 800191783Srmacklem if (nd->nd_repstat == 0) 801191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 802191783Srmacklem error = nd->nd_repstat; 803317393Srmacklem if (error == NFSERR_STALESTATEID) 804191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 805191783Srmacklemnfsmout: 806191783Srmacklem mbuf_freem(nd->nd_mrep); 807191783Srmacklem return (error); 808191783Srmacklem} 809191783Srmacklem 810191783Srmacklem/* 811191783Srmacklem * V4 Open Confirm RPC. 812191783Srmacklem */ 813361236Sfreqlabsint 814191783Srmacklemnfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen, 815191783Srmacklem struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) 816191783Srmacklem{ 817191783Srmacklem u_int32_t *tl; 818191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 819244042Srmacklem struct nfsmount *nmp; 820191783Srmacklem int error; 821191783Srmacklem 822244042Srmacklem nmp = VFSTONFS(vnode_mount(vp)); 823244042Srmacklem if (NFSHASNFSV4N(nmp)) 824244042Srmacklem return (0); /* No confirmation for NFSv4.1. */ 825244042Srmacklem nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL); 826191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 827191783Srmacklem *tl++ = op->nfso_stateid.seqid; 828191783Srmacklem *tl++ = op->nfso_stateid.other[0]; 829191783Srmacklem *tl++ = op->nfso_stateid.other[1]; 830191783Srmacklem *tl++ = op->nfso_stateid.other[2]; 831191783Srmacklem *tl = txdr_unsigned(op->nfso_own->nfsow_seqid); 832191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 833191783Srmacklem if (error) 834191783Srmacklem return (error); 835191783Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 836191783Srmacklem if (!nd->nd_repstat) { 837191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 838191783Srmacklem op->nfso_stateid.seqid = *tl++; 839191783Srmacklem op->nfso_stateid.other[0] = *tl++; 840191783Srmacklem op->nfso_stateid.other[1] = *tl++; 841191783Srmacklem op->nfso_stateid.other[2] = *tl; 842191783Srmacklem } 843191783Srmacklem error = nd->nd_repstat; 844317393Srmacklem if (error == NFSERR_STALESTATEID) 845191783Srmacklem nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 846191783Srmacklemnfsmout: 847191783Srmacklem mbuf_freem(nd->nd_mrep); 848191783Srmacklem return (error); 849191783Srmacklem} 850191783Srmacklem 851191783Srmacklem/* 852191783Srmacklem * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs() 853191783Srmacklem * when a mount has just occurred and when the server replies NFSERR_EXPIRED. 854191783Srmacklem */ 855361236Sfreqlabsint 856244042Srmacklemnfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim, 857191783Srmacklem struct ucred *cred, NFSPROC_T *p) 858191783Srmacklem{ 859191783Srmacklem u_int32_t *tl; 860191783Srmacklem struct nfsrv_descript nfsd; 861191783Srmacklem struct nfsrv_descript *nd = &nfsd; 862191783Srmacklem nfsattrbit_t attrbits; 863191783Srmacklem u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9]; 864191783Srmacklem u_short port; 865195825Srmacklem int error, isinet6 = 0, callblen; 866191783Srmacklem nfsquad_t confirm; 867191783Srmacklem u_int32_t lease; 868191783Srmacklem static u_int32_t rev = 0; 869317393Srmacklem struct nfsclds *dsp; 870294084Smelifaro struct in6_addr a6; 871317393Srmacklem struct nfsclsession *tsep; 872191783Srmacklem 873191783Srmacklem if (nfsboottime.tv_sec == 0) 874191783Srmacklem NFSSETBOOTTIME(nfsboottime); 875244042Srmacklem clp->nfsc_rev = rev++; 876244042Srmacklem if (NFSHASNFSV4N(nmp)) { 877317393Srmacklem /* 878317393Srmacklem * Either there was no previous session or the 879317393Srmacklem * previous session has failed, so... 880317393Srmacklem * do an ExchangeID followed by the CreateSession. 881317393Srmacklem */ 882244042Srmacklem error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 883244042Srmacklem NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p); 884244042Srmacklem NFSCL_DEBUG(1, "aft exch=%d\n", error); 885317393Srmacklem if (error == 0) 886244042Srmacklem error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 887244042Srmacklem &nmp->nm_sockreq, 888244042Srmacklem dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p); 889317393Srmacklem if (error == 0) { 890317393Srmacklem NFSLOCKMNT(nmp); 891317393Srmacklem /* 892317393Srmacklem * The old sessions cannot be safely free'd 893317393Srmacklem * here, since they may still be used by 894317393Srmacklem * in-progress RPCs. 895317393Srmacklem */ 896317393Srmacklem tsep = NULL; 897317393Srmacklem if (TAILQ_FIRST(&nmp->nm_sess) != NULL) 898317393Srmacklem tsep = NFSMNT_MDSSESSION(nmp); 899317393Srmacklem TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, 900317393Srmacklem nfsclds_list); 901317393Srmacklem /* 902317393Srmacklem * Wake up RPCs waiting for a slot on the 903317393Srmacklem * old session. These will then fail with 904317393Srmacklem * NFSERR_BADSESSION and be retried with the 905317393Srmacklem * new session by nfsv4_setsequence(). 906317393Srmacklem * Also wakeup() processes waiting for the 907317393Srmacklem * new session. 908317393Srmacklem */ 909317393Srmacklem if (tsep != NULL) 910317393Srmacklem wakeup(&tsep->nfsess_slots); 911317393Srmacklem wakeup(&nmp->nm_sess); 912317393Srmacklem NFSUNLOCKMNT(nmp); 913317393Srmacklem } else 914317393Srmacklem nfscl_freenfsclds(dsp); 915317393Srmacklem NFSCL_DEBUG(1, "aft createsess=%d\n", error); 916244042Srmacklem if (error == 0 && reclaim == 0) { 917244042Srmacklem error = nfsrpc_reclaimcomplete(nmp, cred, p); 918244042Srmacklem NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error); 919244042Srmacklem if (error == NFSERR_COMPLETEALREADY || 920244042Srmacklem error == NFSERR_NOTSUPP) 921244042Srmacklem /* Ignore this error. */ 922244042Srmacklem error = 0; 923244042Srmacklem } 924244042Srmacklem return (error); 925244042Srmacklem } 926244042Srmacklem 927244042Srmacklem /* 928244042Srmacklem * Allocate a single session structure for NFSv4.0, because some of 929244042Srmacklem * the fields are used by NFSv4.0 although it doesn't do a session. 930244042Srmacklem */ 931244042Srmacklem dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO); 932244042Srmacklem mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 933244042Srmacklem mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); 934244042Srmacklem NFSLOCKMNT(nmp); 935244042Srmacklem TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list); 936317393Srmacklem tsep = NFSMNT_MDSSESSION(nmp); 937244042Srmacklem NFSUNLOCKMNT(nmp); 938244042Srmacklem 939244042Srmacklem nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL); 940191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 941191783Srmacklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); 942244042Srmacklem *tl = txdr_unsigned(clp->nfsc_rev); 943191783Srmacklem (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 944191783Srmacklem 945191783Srmacklem /* 946191783Srmacklem * set up the callback address 947191783Srmacklem */ 948191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 949191783Srmacklem *tl = txdr_unsigned(NFS_CALLBCKPROG); 950191783Srmacklem callblen = strlen(nfsv4_callbackaddr); 951191783Srmacklem if (callblen == 0) 952294084Smelifaro cp = nfscl_getmyip(nmp, &a6, &isinet6); 953191783Srmacklem if (nfscl_enablecallb && nfs_numnfscbd > 0 && 954191783Srmacklem (callblen > 0 || cp != NULL)) { 955191783Srmacklem port = htons(nfsv4_cbport); 956191783Srmacklem cp2 = (u_int8_t *)&port; 957191783Srmacklem#ifdef INET6 958191783Srmacklem if ((callblen > 0 && 959191783Srmacklem strchr(nfsv4_callbackaddr, ':')) || isinet6) { 960191783Srmacklem char ip6buf[INET6_ADDRSTRLEN], *ip6add; 961191783Srmacklem 962191783Srmacklem (void) nfsm_strtom(nd, "tcp6", 4); 963191783Srmacklem if (callblen == 0) { 964191783Srmacklem ip6_sprintf(ip6buf, (struct in6_addr *)cp); 965191783Srmacklem ip6add = ip6buf; 966191783Srmacklem } else { 967191783Srmacklem ip6add = nfsv4_callbackaddr; 968191783Srmacklem } 969191783Srmacklem snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", 970191783Srmacklem ip6add, cp2[0], cp2[1]); 971191783Srmacklem } else 972191783Srmacklem#endif 973191783Srmacklem { 974191783Srmacklem (void) nfsm_strtom(nd, "tcp", 3); 975191783Srmacklem if (callblen == 0) 976191783Srmacklem snprintf(addr, INET6_ADDRSTRLEN + 9, 977191783Srmacklem "%d.%d.%d.%d.%d.%d", cp[0], cp[1], 978191783Srmacklem cp[2], cp[3], cp2[0], cp2[1]); 979191783Srmacklem else 980191783Srmacklem snprintf(addr, INET6_ADDRSTRLEN + 9, 981191783Srmacklem "%s.%d.%d", nfsv4_callbackaddr, 982191783Srmacklem cp2[0], cp2[1]); 983191783Srmacklem } 984191783Srmacklem (void) nfsm_strtom(nd, addr, strlen(addr)); 985191783Srmacklem } else { 986191783Srmacklem (void) nfsm_strtom(nd, "tcp", 3); 987191783Srmacklem (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11); 988191783Srmacklem } 989191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 990191783Srmacklem *tl = txdr_unsigned(clp->nfsc_cbident); 991191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 992191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 993244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 994191783Srmacklem if (error) 995191783Srmacklem return (error); 996191783Srmacklem if (nd->nd_repstat == 0) { 997191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 998317393Srmacklem tsep->nfsess_clientid.lval[0] = *tl++; 999317393Srmacklem tsep->nfsess_clientid.lval[1] = *tl++; 1000191783Srmacklem confirm.lval[0] = *tl++; 1001191783Srmacklem confirm.lval[1] = *tl; 1002191783Srmacklem mbuf_freem(nd->nd_mrep); 1003191783Srmacklem nd->nd_mrep = NULL; 1004191783Srmacklem 1005191783Srmacklem /* 1006191783Srmacklem * and confirm it. 1007191783Srmacklem */ 1008244042Srmacklem nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL, 1009244042Srmacklem NULL); 1010191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1011317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 1012317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[1]; 1013191783Srmacklem *tl++ = confirm.lval[0]; 1014191783Srmacklem *tl = confirm.lval[1]; 1015191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 1016191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 1017244042Srmacklem cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1018191783Srmacklem if (error) 1019191783Srmacklem return (error); 1020191783Srmacklem mbuf_freem(nd->nd_mrep); 1021191783Srmacklem nd->nd_mrep = NULL; 1022191783Srmacklem if (nd->nd_repstat == 0) { 1023191783Srmacklem nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh, 1024244042Srmacklem nmp->nm_fhsize, NULL, NULL); 1025191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 1026191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 1027191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1028191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 1029191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 1030244042Srmacklem cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1031191783Srmacklem if (error) 1032191783Srmacklem return (error); 1033191783Srmacklem if (nd->nd_repstat == 0) { 1034191783Srmacklem error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL, 1035191783Srmacklem NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred); 1036191783Srmacklem if (error) 1037191783Srmacklem goto nfsmout; 1038191783Srmacklem clp->nfsc_renew = NFSCL_RENEW(lease); 1039191783Srmacklem clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 1040191783Srmacklem clp->nfsc_clientidrev++; 1041191783Srmacklem if (clp->nfsc_clientidrev == 0) 1042191783Srmacklem clp->nfsc_clientidrev++; 1043191783Srmacklem } 1044191783Srmacklem } 1045191783Srmacklem } 1046191783Srmacklem error = nd->nd_repstat; 1047191783Srmacklemnfsmout: 1048191783Srmacklem mbuf_freem(nd->nd_mrep); 1049191783Srmacklem return (error); 1050191783Srmacklem} 1051191783Srmacklem 1052191783Srmacklem/* 1053191783Srmacklem * nfs getattr call. 1054191783Srmacklem */ 1055361236Sfreqlabsint 1056191783Srmacklemnfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 1057191783Srmacklem struct nfsvattr *nap, void *stuff) 1058191783Srmacklem{ 1059191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1060191783Srmacklem int error; 1061191783Srmacklem nfsattrbit_t attrbits; 1062191783Srmacklem 1063191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 1064191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1065191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1066191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1067191783Srmacklem } 1068191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1069191783Srmacklem if (error) 1070191783Srmacklem return (error); 1071191783Srmacklem if (!nd->nd_repstat) 1072191783Srmacklem error = nfsm_loadattr(nd, nap); 1073191783Srmacklem else 1074191783Srmacklem error = nd->nd_repstat; 1075191783Srmacklem mbuf_freem(nd->nd_mrep); 1076191783Srmacklem return (error); 1077191783Srmacklem} 1078191783Srmacklem 1079191783Srmacklem/* 1080191783Srmacklem * nfs getattr call with non-vnode arguemnts. 1081191783Srmacklem */ 1082361236Sfreqlabsint 1083191783Srmacklemnfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, 1084244042Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp, 1085244042Srmacklem uint32_t *leasep) 1086191783Srmacklem{ 1087191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1088191783Srmacklem int error, vers = NFS_VER2; 1089191783Srmacklem nfsattrbit_t attrbits; 1090191783Srmacklem 1091244042Srmacklem nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL); 1092191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1093191783Srmacklem vers = NFS_VER4; 1094191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1095244042Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 1096191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1097191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 1098191783Srmacklem vers = NFS_VER3; 1099191783Srmacklem } 1100191783Srmacklem if (syscred) 1101191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 1102191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 1103244042Srmacklem NFS_PROG, vers, NULL, 1, xidp, NULL); 1104191783Srmacklem if (error) 1105191783Srmacklem return (error); 1106244042Srmacklem if (nd->nd_repstat == 0) { 1107244042Srmacklem if ((nd->nd_flag & ND_NFSV4) != 0) 1108244042Srmacklem error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 1109244042Srmacklem NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL, 1110244042Srmacklem NULL, NULL); 1111244042Srmacklem else 1112244042Srmacklem error = nfsm_loadattr(nd, nap); 1113244042Srmacklem } else 1114191783Srmacklem error = nd->nd_repstat; 1115191783Srmacklem mbuf_freem(nd->nd_mrep); 1116191783Srmacklem return (error); 1117191783Srmacklem} 1118191783Srmacklem 1119191783Srmacklem/* 1120191783Srmacklem * Do an nfs setattr operation. 1121191783Srmacklem */ 1122361236Sfreqlabsint 1123191783Srmacklemnfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, 1124191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp, 1125191783Srmacklem void *stuff) 1126191783Srmacklem{ 1127191783Srmacklem int error, expireret = 0, openerr, retrycnt; 1128191783Srmacklem u_int32_t clidrev = 0, mode; 1129191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1130191783Srmacklem struct nfsfh *nfhp; 1131191783Srmacklem nfsv4stateid_t stateid; 1132191783Srmacklem void *lckp; 1133191783Srmacklem 1134191783Srmacklem if (nmp->nm_clp != NULL) 1135191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1136191783Srmacklem if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size)) 1137191783Srmacklem mode = NFSV4OPEN_ACCESSWRITE; 1138191783Srmacklem else 1139191783Srmacklem mode = NFSV4OPEN_ACCESSREAD; 1140191783Srmacklem retrycnt = 0; 1141191783Srmacklem do { 1142191783Srmacklem lckp = NULL; 1143191783Srmacklem openerr = 1; 1144191783Srmacklem if (NFSHASNFSV4(nmp)) { 1145191783Srmacklem nfhp = VTONFS(vp)->n_fhp; 1146191783Srmacklem error = nfscl_getstateid(vp, nfhp->nfh_fh, 1147244042Srmacklem nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp); 1148191783Srmacklem if (error && vnode_vtype(vp) == VREG && 1149191783Srmacklem (mode == NFSV4OPEN_ACCESSWRITE || 1150191783Srmacklem nfstest_openallsetattr)) { 1151191783Srmacklem /* 1152191783Srmacklem * No Open stateid, so try and open the file 1153191783Srmacklem * now. 1154191783Srmacklem */ 1155191783Srmacklem if (mode == NFSV4OPEN_ACCESSWRITE) 1156191783Srmacklem openerr = nfsrpc_open(vp, FWRITE, cred, 1157191783Srmacklem p); 1158191783Srmacklem else 1159191783Srmacklem openerr = nfsrpc_open(vp, FREAD, cred, 1160191783Srmacklem p); 1161191783Srmacklem if (!openerr) 1162191783Srmacklem (void) nfscl_getstateid(vp, 1163191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, 1164244042Srmacklem mode, 0, cred, p, &stateid, &lckp); 1165191783Srmacklem } 1166191783Srmacklem } 1167191783Srmacklem if (vap != NULL) 1168191783Srmacklem error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p, 1169191783Srmacklem rnap, attrflagp, stuff); 1170191783Srmacklem else 1171191783Srmacklem error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid, 1172191783Srmacklem stuff); 1173317983Srmacklem if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) { 1174317983Srmacklem NFSLOCKMNT(nmp); 1175317983Srmacklem nmp->nm_state |= NFSSTA_OPENMODE; 1176317983Srmacklem NFSUNLOCKMNT(nmp); 1177317983Srmacklem } 1178317393Srmacklem if (error == NFSERR_STALESTATEID) 1179191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1180191783Srmacklem if (lckp != NULL) 1181191783Srmacklem nfscl_lockderef(lckp); 1182191783Srmacklem if (!openerr) 1183192337Srmacklem (void) nfsrpc_close(vp, 0, p); 1184191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1185191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1186244042Srmacklem error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1187207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_setattr"); 1188191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1189191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1190191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1191191783Srmacklem } 1192191783Srmacklem retrycnt++; 1193191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1194191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1195244042Srmacklem error == NFSERR_BADSESSION || 1196191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1197191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1198317983Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4) || 1199317983Srmacklem (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD && 1200317983Srmacklem retrycnt < 4)); 1201191783Srmacklem if (error && retrycnt >= 4) 1202191783Srmacklem error = EIO; 1203191783Srmacklem return (error); 1204191783Srmacklem} 1205191783Srmacklem 1206191783Srmacklemstatic int 1207191783Srmacklemnfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, 1208191783Srmacklem nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 1209191783Srmacklem struct nfsvattr *rnap, int *attrflagp, void *stuff) 1210191783Srmacklem{ 1211191783Srmacklem u_int32_t *tl; 1212191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1213191783Srmacklem int error; 1214191783Srmacklem nfsattrbit_t attrbits; 1215191783Srmacklem 1216191783Srmacklem *attrflagp = 0; 1217191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp); 1218191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1219191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1220191783Srmacklem vap->va_type = vnode_vtype(vp); 1221191783Srmacklem nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0); 1222191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1223191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1224191783Srmacklem *tl = newnfs_false; 1225191783Srmacklem } else if (nd->nd_flag & ND_NFSV4) { 1226191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1227191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1228191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1229191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1230191783Srmacklem } 1231191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1232191783Srmacklem if (error) 1233191783Srmacklem return (error); 1234191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1235191783Srmacklem error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff); 1236317405Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error) 1237191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1238191783Srmacklem if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error) 1239191783Srmacklem error = nfscl_postop_attr(nd, rnap, attrflagp, stuff); 1240191783Srmacklem mbuf_freem(nd->nd_mrep); 1241191783Srmacklem if (nd->nd_repstat && !error) 1242191783Srmacklem error = nd->nd_repstat; 1243191783Srmacklem return (error); 1244191783Srmacklem} 1245191783Srmacklem 1246191783Srmacklem/* 1247191783Srmacklem * nfs lookup rpc 1248191783Srmacklem */ 1249361236Sfreqlabsint 1250191783Srmacklemnfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, 1251191783Srmacklem NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, 1252191783Srmacklem struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff) 1253191783Srmacklem{ 1254191783Srmacklem u_int32_t *tl; 1255191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1256191783Srmacklem struct nfsmount *nmp; 1257191783Srmacklem struct nfsnode *np; 1258191783Srmacklem struct nfsfh *nfhp; 1259191783Srmacklem nfsattrbit_t attrbits; 1260191783Srmacklem int error = 0, lookupp = 0; 1261191783Srmacklem 1262191783Srmacklem *attrflagp = 0; 1263191783Srmacklem *dattrflagp = 0; 1264191783Srmacklem if (vnode_vtype(dvp) != VDIR) 1265191783Srmacklem return (ENOTDIR); 1266191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 1267191783Srmacklem if (len > NFS_MAXNAMLEN) 1268191783Srmacklem return (ENAMETOOLONG); 1269191783Srmacklem if (NFSHASNFSV4(nmp) && len == 1 && 1270191783Srmacklem name[0] == '.') { 1271191783Srmacklem /* 1272191783Srmacklem * Just return the current dir's fh. 1273191783Srmacklem */ 1274191783Srmacklem np = VTONFS(dvp); 1275191783Srmacklem MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1276191783Srmacklem np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1277191783Srmacklem nfhp->nfh_len = np->n_fhp->nfh_len; 1278191783Srmacklem NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1279191783Srmacklem *nfhpp = nfhp; 1280191783Srmacklem return (0); 1281191783Srmacklem } 1282191783Srmacklem if (NFSHASNFSV4(nmp) && len == 2 && 1283191783Srmacklem name[0] == '.' && name[1] == '.') { 1284191783Srmacklem lookupp = 1; 1285191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp); 1286191783Srmacklem } else { 1287191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp); 1288191783Srmacklem (void) nfsm_strtom(nd, name, len); 1289191783Srmacklem } 1290191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1291191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1292191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1293191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1294191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1295191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1296191783Srmacklem } 1297191783Srmacklem error = nfscl_request(nd, dvp, p, cred, stuff); 1298191783Srmacklem if (error) 1299191783Srmacklem return (error); 1300191783Srmacklem if (nd->nd_repstat) { 1301191783Srmacklem /* 1302191783Srmacklem * When an NFSv4 Lookupp returns ENOENT, it means that 1303191783Srmacklem * the lookup is at the root of an fs, so return this dir. 1304191783Srmacklem */ 1305191783Srmacklem if (nd->nd_repstat == NFSERR_NOENT && lookupp) { 1306191783Srmacklem np = VTONFS(dvp); 1307191783Srmacklem MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1308191783Srmacklem np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1309191783Srmacklem nfhp->nfh_len = np->n_fhp->nfh_len; 1310191783Srmacklem NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1311191783Srmacklem *nfhpp = nfhp; 1312191783Srmacklem mbuf_freem(nd->nd_mrep); 1313191783Srmacklem return (0); 1314191783Srmacklem } 1315191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1316191783Srmacklem error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1317264672Srmacklem else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 1318264672Srmacklem ND_NFSV4) { 1319264672Srmacklem /* Load the directory attributes. */ 1320264672Srmacklem error = nfsm_loadattr(nd, dnap); 1321264672Srmacklem if (error == 0) 1322264672Srmacklem *dattrflagp = 1; 1323264672Srmacklem } 1324191783Srmacklem goto nfsmout; 1325191783Srmacklem } 1326191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 1327264672Srmacklem /* Load the directory attributes. */ 1328264672Srmacklem error = nfsm_loadattr(nd, dnap); 1329264672Srmacklem if (error != 0) 1330191783Srmacklem goto nfsmout; 1331264672Srmacklem *dattrflagp = 1; 1332264672Srmacklem /* Skip over the Lookup and GetFH operation status values. */ 1333264672Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1334191783Srmacklem } 1335191783Srmacklem error = nfsm_getfh(nd, nfhpp); 1336191783Srmacklem if (error) 1337191783Srmacklem goto nfsmout; 1338191783Srmacklem 1339191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1340191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) 1341191783Srmacklem error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1342191783Srmacklemnfsmout: 1343191783Srmacklem mbuf_freem(nd->nd_mrep); 1344191783Srmacklem if (!error && nd->nd_repstat) 1345191783Srmacklem error = nd->nd_repstat; 1346191783Srmacklem return (error); 1347191783Srmacklem} 1348191783Srmacklem 1349191783Srmacklem/* 1350191783Srmacklem * Do a readlink rpc. 1351191783Srmacklem */ 1352361236Sfreqlabsint 1353191783Srmacklemnfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, 1354191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1355191783Srmacklem{ 1356191783Srmacklem u_int32_t *tl; 1357191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1358191783Srmacklem struct nfsnode *np = VTONFS(vp); 1359191783Srmacklem nfsattrbit_t attrbits; 1360191783Srmacklem int error, len, cangetattr = 1; 1361191783Srmacklem 1362191783Srmacklem *attrflagp = 0; 1363191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READLINK, vp); 1364191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1365191783Srmacklem /* 1366191783Srmacklem * And do a Getattr op. 1367191783Srmacklem */ 1368191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1369191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1370191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1371191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1372191783Srmacklem } 1373191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1374191783Srmacklem if (error) 1375191783Srmacklem return (error); 1376191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1377191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1378191783Srmacklem if (!nd->nd_repstat && !error) { 1379191783Srmacklem NFSM_STRSIZ(len, NFS_MAXPATHLEN); 1380191783Srmacklem /* 1381191783Srmacklem * This seems weird to me, but must have been added to 1382191783Srmacklem * FreeBSD for some reason. The only thing I can think of 1383191783Srmacklem * is that there was/is some server that replies with 1384191783Srmacklem * more link data than it should? 1385191783Srmacklem */ 1386191783Srmacklem if (len == NFS_MAXPATHLEN) { 1387191783Srmacklem NFSLOCKNODE(np); 1388191783Srmacklem if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { 1389191783Srmacklem len = np->n_size; 1390191783Srmacklem cangetattr = 0; 1391191783Srmacklem } 1392191783Srmacklem NFSUNLOCKNODE(np); 1393191783Srmacklem } 1394191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 1395191783Srmacklem if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) 1396191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1397191783Srmacklem } 1398191783Srmacklem if (nd->nd_repstat && !error) 1399191783Srmacklem error = nd->nd_repstat; 1400191783Srmacklemnfsmout: 1401191783Srmacklem mbuf_freem(nd->nd_mrep); 1402191783Srmacklem return (error); 1403191783Srmacklem} 1404191783Srmacklem 1405191783Srmacklem/* 1406191783Srmacklem * Read operation. 1407191783Srmacklem */ 1408361236Sfreqlabsint 1409191783Srmacklemnfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, 1410191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1411191783Srmacklem{ 1412191783Srmacklem int error, expireret = 0, retrycnt; 1413191783Srmacklem u_int32_t clidrev = 0; 1414191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1415191783Srmacklem struct nfsnode *np = VTONFS(vp); 1416191783Srmacklem struct ucred *newcred; 1417191783Srmacklem struct nfsfh *nfhp = NULL; 1418191783Srmacklem nfsv4stateid_t stateid; 1419191783Srmacklem void *lckp; 1420191783Srmacklem 1421191783Srmacklem if (nmp->nm_clp != NULL) 1422191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1423191783Srmacklem newcred = cred; 1424191783Srmacklem if (NFSHASNFSV4(nmp)) { 1425191783Srmacklem nfhp = np->n_fhp; 1426228827Srmacklem newcred = NFSNEWCRED(cred); 1427191783Srmacklem } 1428191783Srmacklem retrycnt = 0; 1429191783Srmacklem do { 1430191783Srmacklem lckp = NULL; 1431191783Srmacklem if (NFSHASNFSV4(nmp)) 1432191783Srmacklem (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1433244042Srmacklem NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid, 1434244042Srmacklem &lckp); 1435191783Srmacklem error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, 1436191783Srmacklem attrflagp, stuff); 1437317983Srmacklem if (error == NFSERR_OPENMODE) { 1438317983Srmacklem NFSLOCKMNT(nmp); 1439317983Srmacklem nmp->nm_state |= NFSSTA_OPENMODE; 1440317983Srmacklem NFSUNLOCKMNT(nmp); 1441317983Srmacklem } 1442317393Srmacklem if (error == NFSERR_STALESTATEID) 1443191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1444191783Srmacklem if (lckp != NULL) 1445191783Srmacklem nfscl_lockderef(lckp); 1446191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1447191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1448244042Srmacklem error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1449207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_read"); 1450191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1451191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1452191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1453191783Srmacklem } 1454191783Srmacklem retrycnt++; 1455191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1456191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1457244042Srmacklem error == NFSERR_BADSESSION || 1458191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1459191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1460317983Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4) || 1461317983Srmacklem (error == NFSERR_OPENMODE && retrycnt < 4)); 1462191783Srmacklem if (error && retrycnt >= 4) 1463191783Srmacklem error = EIO; 1464228827Srmacklem if (NFSHASNFSV4(nmp)) 1465191783Srmacklem NFSFREECRED(newcred); 1466191783Srmacklem return (error); 1467191783Srmacklem} 1468191783Srmacklem 1469191783Srmacklem/* 1470191783Srmacklem * The actual read RPC. 1471191783Srmacklem */ 1472191783Srmacklemstatic int 1473191783Srmacklemnfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, 1474191783Srmacklem nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, 1475191783Srmacklem int *attrflagp, void *stuff) 1476191783Srmacklem{ 1477191783Srmacklem u_int32_t *tl; 1478191783Srmacklem int error = 0, len, retlen, tsiz, eof = 0; 1479191783Srmacklem struct nfsrv_descript nfsd; 1480191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1481191783Srmacklem struct nfsrv_descript *nd = &nfsd; 1482220810Srmacklem int rsize; 1483220876Srmacklem off_t tmp_off; 1484191783Srmacklem 1485191783Srmacklem *attrflagp = 0; 1486191783Srmacklem tsiz = uio_uio_resid(uiop); 1487220876Srmacklem tmp_off = uiop->uio_offset + tsiz; 1488220810Srmacklem NFSLOCKMNT(nmp); 1489220876Srmacklem if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1490220810Srmacklem NFSUNLOCKMNT(nmp); 1491191783Srmacklem return (EFBIG); 1492220810Srmacklem } 1493220810Srmacklem rsize = nmp->nm_rsize; 1494220810Srmacklem NFSUNLOCKMNT(nmp); 1495191783Srmacklem nd->nd_mrep = NULL; 1496191783Srmacklem while (tsiz > 0) { 1497191783Srmacklem *attrflagp = 0; 1498220810Srmacklem len = (tsiz > rsize) ? rsize : tsiz; 1499191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READ, vp); 1500191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1501191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1502191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1503191783Srmacklem if (nd->nd_flag & ND_NFSV2) { 1504191783Srmacklem *tl++ = txdr_unsigned(uiop->uio_offset); 1505191783Srmacklem *tl++ = txdr_unsigned(len); 1506191783Srmacklem *tl = 0; 1507191783Srmacklem } else { 1508191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1509191783Srmacklem *(tl + 2) = txdr_unsigned(len); 1510191783Srmacklem } 1511191783Srmacklem /* 1512191783Srmacklem * Since I can't do a Getattr for NFSv4 for Write, there 1513191783Srmacklem * doesn't seem any point in doing one here, either. 1514191783Srmacklem * (See the comment in nfsrpc_writerpc() for more info.) 1515191783Srmacklem */ 1516191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1517191783Srmacklem if (error) 1518191783Srmacklem return (error); 1519191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1520191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1521191783Srmacklem } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { 1522191783Srmacklem error = nfsm_loadattr(nd, nap); 1523191783Srmacklem if (!error) 1524191783Srmacklem *attrflagp = 1; 1525191783Srmacklem } 1526191783Srmacklem if (nd->nd_repstat || error) { 1527191783Srmacklem if (!error) 1528191783Srmacklem error = nd->nd_repstat; 1529191783Srmacklem goto nfsmout; 1530191783Srmacklem } 1531191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1532191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1533191783Srmacklem eof = fxdr_unsigned(int, *(tl + 1)); 1534191783Srmacklem } else if (nd->nd_flag & ND_NFSV4) { 1535191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1536191783Srmacklem eof = fxdr_unsigned(int, *tl); 1537191783Srmacklem } 1538245977Skib NFSM_STRSIZ(retlen, len); 1539191783Srmacklem error = nfsm_mbufuio(nd, uiop, retlen); 1540191783Srmacklem if (error) 1541191783Srmacklem goto nfsmout; 1542191783Srmacklem mbuf_freem(nd->nd_mrep); 1543191783Srmacklem nd->nd_mrep = NULL; 1544191783Srmacklem tsiz -= retlen; 1545191783Srmacklem if (!(nd->nd_flag & ND_NFSV2)) { 1546191783Srmacklem if (eof || retlen == 0) 1547191783Srmacklem tsiz = 0; 1548191783Srmacklem } else if (retlen < len) 1549191783Srmacklem tsiz = 0; 1550191783Srmacklem } 1551191783Srmacklem return (0); 1552191783Srmacklemnfsmout: 1553191783Srmacklem if (nd->nd_mrep != NULL) 1554191783Srmacklem mbuf_freem(nd->nd_mrep); 1555191783Srmacklem return (error); 1556191783Srmacklem} 1557191783Srmacklem 1558191783Srmacklem/* 1559191783Srmacklem * nfs write operation 1560207082Srmacklem * When called_from_strategy != 0, it should return EIO for an error that 1561207082Srmacklem * indicates recovery is in progress, so that the buffer will be left 1562207082Srmacklem * dirty and be written back to the server later. If it loops around, 1563207082Srmacklem * the recovery thread could get stuck waiting for the buffer and recovery 1564207082Srmacklem * will then deadlock. 1565191783Srmacklem */ 1566361236Sfreqlabsint 1567222289Srmacklemnfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 1568191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 1569207082Srmacklem void *stuff, int called_from_strategy) 1570191783Srmacklem{ 1571191783Srmacklem int error, expireret = 0, retrycnt, nostateid; 1572191783Srmacklem u_int32_t clidrev = 0; 1573191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1574191783Srmacklem struct nfsnode *np = VTONFS(vp); 1575191783Srmacklem struct ucred *newcred; 1576191783Srmacklem struct nfsfh *nfhp = NULL; 1577191783Srmacklem nfsv4stateid_t stateid; 1578191783Srmacklem void *lckp; 1579191783Srmacklem 1580222289Srmacklem *must_commit = 0; 1581191783Srmacklem if (nmp->nm_clp != NULL) 1582191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1583191783Srmacklem newcred = cred; 1584191783Srmacklem if (NFSHASNFSV4(nmp)) { 1585228827Srmacklem newcred = NFSNEWCRED(cred); 1586191783Srmacklem nfhp = np->n_fhp; 1587191783Srmacklem } 1588191783Srmacklem retrycnt = 0; 1589191783Srmacklem do { 1590191783Srmacklem lckp = NULL; 1591191783Srmacklem nostateid = 0; 1592191783Srmacklem if (NFSHASNFSV4(nmp)) { 1593191783Srmacklem (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1594244042Srmacklem NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid, 1595244042Srmacklem &lckp); 1596191783Srmacklem if (stateid.other[0] == 0 && stateid.other[1] == 0 && 1597191783Srmacklem stateid.other[2] == 0) { 1598191783Srmacklem nostateid = 1; 1599240289Srmacklem NFSCL_DEBUG(1, "stateid0 in write\n"); 1600191783Srmacklem } 1601191783Srmacklem } 1602191783Srmacklem 1603191783Srmacklem /* 1604191783Srmacklem * If there is no stateid for NFSv4, it means this is an 1605191783Srmacklem * extraneous write after close. Basically a poorly 1606191783Srmacklem * implemented buffer cache. Just don't do the write. 1607191783Srmacklem */ 1608191783Srmacklem if (nostateid) 1609191783Srmacklem error = 0; 1610191783Srmacklem else 1611222289Srmacklem error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, 1612191783Srmacklem newcred, &stateid, p, nap, attrflagp, stuff); 1613317393Srmacklem if (error == NFSERR_STALESTATEID) 1614191783Srmacklem nfscl_initiate_recovery(nmp->nm_clp); 1615191783Srmacklem if (lckp != NULL) 1616191783Srmacklem nfscl_lockderef(lckp); 1617191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1618191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1619244042Srmacklem error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1620207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_write"); 1621191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1622191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1623191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1624191783Srmacklem } 1625191783Srmacklem retrycnt++; 1626207082Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 1627244042Srmacklem ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1628207082Srmacklem error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || 1629191783Srmacklem (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1630191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1631191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1632207082Srmacklem if (error != 0 && (retrycnt >= 4 || 1633244042Srmacklem ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1634207082Srmacklem error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0))) 1635191783Srmacklem error = EIO; 1636228827Srmacklem if (NFSHASNFSV4(nmp)) 1637191783Srmacklem NFSFREECRED(newcred); 1638191783Srmacklem return (error); 1639191783Srmacklem} 1640191783Srmacklem 1641191783Srmacklem/* 1642191783Srmacklem * The actual write RPC. 1643191783Srmacklem */ 1644191783Srmacklemstatic int 1645191783Srmacklemnfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, 1646222289Srmacklem int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, 1647191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1648191783Srmacklem{ 1649191783Srmacklem u_int32_t *tl; 1650191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1651191783Srmacklem struct nfsnode *np = VTONFS(vp); 1652191783Srmacklem int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; 1653191783Srmacklem int wccflag = 0, wsize; 1654191783Srmacklem int32_t backup; 1655191783Srmacklem struct nfsrv_descript nfsd; 1656191783Srmacklem struct nfsrv_descript *nd = &nfsd; 1657191783Srmacklem nfsattrbit_t attrbits; 1658220876Srmacklem off_t tmp_off; 1659191783Srmacklem 1660209120Skib KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 1661191783Srmacklem *attrflagp = 0; 1662191783Srmacklem tsiz = uio_uio_resid(uiop); 1663220876Srmacklem tmp_off = uiop->uio_offset + tsiz; 1664191783Srmacklem NFSLOCKMNT(nmp); 1665220876Srmacklem if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1666191783Srmacklem NFSUNLOCKMNT(nmp); 1667191783Srmacklem return (EFBIG); 1668191783Srmacklem } 1669191783Srmacklem wsize = nmp->nm_wsize; 1670191783Srmacklem NFSUNLOCKMNT(nmp); 1671191783Srmacklem nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ 1672191783Srmacklem nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ 1673191783Srmacklem while (tsiz > 0) { 1674191783Srmacklem *attrflagp = 0; 1675191783Srmacklem len = (tsiz > wsize) ? wsize : tsiz; 1676191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); 1677191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1678191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1679191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); 1680191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1681191783Srmacklem tl += 2; 1682191783Srmacklem *tl++ = txdr_unsigned(*iomode); 1683191783Srmacklem *tl = txdr_unsigned(len); 1684191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 1685191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); 1686191783Srmacklem txdr_hyper(uiop->uio_offset, tl); 1687191783Srmacklem tl += 2; 1688191783Srmacklem *tl++ = txdr_unsigned(len); 1689191783Srmacklem *tl++ = txdr_unsigned(*iomode); 1690191783Srmacklem *tl = txdr_unsigned(len); 1691191783Srmacklem } else { 1692191783Srmacklem u_int32_t x; 1693191783Srmacklem 1694191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1695191783Srmacklem /* 1696191783Srmacklem * Not sure why someone changed this, since the 1697191783Srmacklem * RFC clearly states that "beginoffset" and 1698191783Srmacklem * "totalcount" are ignored, but it wouldn't 1699191783Srmacklem * surprise me if there's a busted server out there. 1700191783Srmacklem */ 1701191783Srmacklem /* Set both "begin" and "current" to non-garbage. */ 1702191783Srmacklem x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1703191783Srmacklem *tl++ = x; /* "begin offset" */ 1704191783Srmacklem *tl++ = x; /* "current offset" */ 1705191783Srmacklem x = txdr_unsigned(len); 1706191783Srmacklem *tl++ = x; /* total to this offset */ 1707191783Srmacklem *tl = x; /* size of this write */ 1708191783Srmacklem 1709191783Srmacklem } 1710191783Srmacklem nfsm_uiombuf(nd, uiop, len); 1711191783Srmacklem /* 1712191783Srmacklem * Although it is tempting to do a normal Getattr Op in the 1713191783Srmacklem * NFSv4 compound, the result can be a nearly hung client 1714191783Srmacklem * system if the Getattr asks for Owner and/or OwnerGroup. 1715191783Srmacklem * It occurs when the client can't map either the Owner or 1716191783Srmacklem * Owner_group name in the Getattr reply to a uid/gid. When 1717191783Srmacklem * there is a cache miss, the kernel does an upcall to the 1718191783Srmacklem * nfsuserd. Then, it can try and read the local /etc/passwd 1719191783Srmacklem * or /etc/group file. It can then block in getnewbuf(), 1720191783Srmacklem * waiting for dirty writes to be pushed to the NFS server. 1721191783Srmacklem * The only reason this doesn't result in a complete 1722191783Srmacklem * deadlock, is that the upcall times out and allows 1723191783Srmacklem * the write to complete. However, progress is so slow 1724191783Srmacklem * that it might just as well be deadlocked. 1725223657Srmacklem * As such, we get the rest of the attributes, but not 1726223657Srmacklem * Owner or Owner_group. 1727191783Srmacklem * nb: nfscl_loadattrcache() needs to be told that these 1728191783Srmacklem * partial attributes from a write rpc are being 1729191783Srmacklem * passed in, via a argument flag. 1730191783Srmacklem */ 1731191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1732191783Srmacklem NFSWRITEGETATTR_ATTRBIT(&attrbits); 1733191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1734191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1735191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1736191783Srmacklem } 1737191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 1738191783Srmacklem if (error) 1739191783Srmacklem return (error); 1740191783Srmacklem if (nd->nd_repstat) { 1741191783Srmacklem /* 1742191783Srmacklem * In case the rpc gets retried, roll 1743191783Srmacklem * the uio fileds changed by nfsm_uiombuf() 1744191783Srmacklem * back. 1745191783Srmacklem */ 1746191783Srmacklem uiop->uio_offset -= len; 1747191783Srmacklem uio_uio_resid_add(uiop, len); 1748191783Srmacklem uio_iov_base_add(uiop, -len); 1749191783Srmacklem uio_iov_len_add(uiop, len); 1750191783Srmacklem } 1751191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1752191783Srmacklem error = nfscl_wcc_data(nd, vp, nap, attrflagp, 1753191783Srmacklem &wccflag, stuff); 1754191783Srmacklem if (error) 1755191783Srmacklem goto nfsmout; 1756191783Srmacklem } 1757191783Srmacklem if (!nd->nd_repstat) { 1758191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1759191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1760191783Srmacklem + NFSX_VERF); 1761191783Srmacklem rlen = fxdr_unsigned(int, *tl++); 1762191783Srmacklem if (rlen == 0) { 1763191783Srmacklem error = NFSERR_IO; 1764191783Srmacklem goto nfsmout; 1765191783Srmacklem } else if (rlen < len) { 1766191783Srmacklem backup = len - rlen; 1767191783Srmacklem uio_iov_base_add(uiop, -(backup)); 1768191783Srmacklem uio_iov_len_add(uiop, backup); 1769191783Srmacklem uiop->uio_offset -= backup; 1770191783Srmacklem uio_uio_resid_add(uiop, backup); 1771191783Srmacklem len = rlen; 1772191783Srmacklem } 1773191783Srmacklem commit = fxdr_unsigned(int, *tl++); 1774191783Srmacklem 1775191783Srmacklem /* 1776298788Spfg * Return the lowest commitment level 1777191783Srmacklem * obtained by any of the RPCs. 1778191783Srmacklem */ 1779191783Srmacklem if (committed == NFSWRITE_FILESYNC) 1780191783Srmacklem committed = commit; 1781191783Srmacklem else if (committed == NFSWRITE_DATASYNC && 1782191783Srmacklem commit == NFSWRITE_UNSTABLE) 1783191783Srmacklem committed = commit; 1784191783Srmacklem NFSLOCKMNT(nmp); 1785191783Srmacklem if (!NFSHASWRITEVERF(nmp)) { 1786191783Srmacklem NFSBCOPY((caddr_t)tl, 1787191783Srmacklem (caddr_t)&nmp->nm_verf[0], 1788191783Srmacklem NFSX_VERF); 1789191783Srmacklem NFSSETWRITEVERF(nmp); 1790222289Srmacklem } else if (NFSBCMP(tl, nmp->nm_verf, 1791222289Srmacklem NFSX_VERF)) { 1792222289Srmacklem *must_commit = 1; 1793222289Srmacklem NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 1794191783Srmacklem } 1795191783Srmacklem NFSUNLOCKMNT(nmp); 1796191783Srmacklem } 1797191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1798191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1799191783Srmacklem if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 1800191783Srmacklem error = nfsm_loadattr(nd, nap); 1801191783Srmacklem if (!error) 1802191783Srmacklem *attrflagp = NFS_LATTR_NOSHRINK; 1803191783Srmacklem } 1804191783Srmacklem } else { 1805191783Srmacklem error = nd->nd_repstat; 1806191783Srmacklem } 1807191783Srmacklem if (error) 1808191783Srmacklem goto nfsmout; 1809297837Srmacklem NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4)); 1810191783Srmacklem mbuf_freem(nd->nd_mrep); 1811191783Srmacklem nd->nd_mrep = NULL; 1812191783Srmacklem tsiz -= len; 1813191783Srmacklem } 1814191783Srmacklemnfsmout: 1815191783Srmacklem if (nd->nd_mrep != NULL) 1816191783Srmacklem mbuf_freem(nd->nd_mrep); 1817191783Srmacklem *iomode = committed; 1818191783Srmacklem if (nd->nd_repstat && !error) 1819191783Srmacklem error = nd->nd_repstat; 1820191783Srmacklem return (error); 1821191783Srmacklem} 1822191783Srmacklem 1823191783Srmacklem/* 1824191783Srmacklem * nfs mknod rpc 1825191783Srmacklem * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1826191783Srmacklem * mode set to specify the file type and the size field for rdev. 1827191783Srmacklem */ 1828361236Sfreqlabsint 1829191783Srmacklemnfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1830191783Srmacklem u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p, 1831191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1832191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1833191783Srmacklem{ 1834191783Srmacklem u_int32_t *tl; 1835191783Srmacklem int error = 0; 1836191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1837191783Srmacklem nfsattrbit_t attrbits; 1838191783Srmacklem 1839191783Srmacklem *nfhpp = NULL; 1840191783Srmacklem *attrflagp = 0; 1841191783Srmacklem *dattrflagp = 0; 1842191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1843191783Srmacklem return (ENAMETOOLONG); 1844191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp); 1845191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1846201345Srmacklem if (vtyp == VBLK || vtyp == VCHR) { 1847201345Srmacklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1848201345Srmacklem *tl++ = vtonfsv34_type(vtyp); 1849201345Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1850201345Srmacklem *tl = txdr_unsigned(NFSMINOR(rdev)); 1851201345Srmacklem } else { 1852201345Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1853201345Srmacklem *tl = vtonfsv34_type(vtyp); 1854201345Srmacklem } 1855191783Srmacklem } 1856191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1857191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1858191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1859191783Srmacklem *tl = vtonfsv34_type(vtyp); 1860191783Srmacklem } 1861191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1862191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 1863191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && 1864191783Srmacklem (vtyp == VCHR || vtyp == VBLK)) { 1865191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1866191783Srmacklem *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1867191783Srmacklem *tl = txdr_unsigned(NFSMINOR(rdev)); 1868191783Srmacklem } 1869191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1870191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 1871191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1872191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1873191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 1874191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 1875191783Srmacklem } 1876191783Srmacklem if (nd->nd_flag & ND_NFSV2) 1877191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 1878191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 1879191783Srmacklem if (error) 1880191783Srmacklem return (error); 1881191783Srmacklem if (nd->nd_flag & ND_NFSV4) 1882191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1883191783Srmacklem if (!nd->nd_repstat) { 1884191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 1885191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1886191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1887191783Srmacklem if (error) 1888191783Srmacklem goto nfsmout; 1889191783Srmacklem } 1890191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1891191783Srmacklem if (error) 1892191783Srmacklem goto nfsmout; 1893191783Srmacklem } 1894191783Srmacklem if (nd->nd_flag & ND_NFSV3) 1895191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1896191783Srmacklem if (!error && nd->nd_repstat) 1897191783Srmacklem error = nd->nd_repstat; 1898191783Srmacklemnfsmout: 1899191783Srmacklem mbuf_freem(nd->nd_mrep); 1900191783Srmacklem return (error); 1901191783Srmacklem} 1902191783Srmacklem 1903191783Srmacklem/* 1904191783Srmacklem * nfs file create call 1905191783Srmacklem * Mostly just call the approriate routine. (I separated out v4, so that 1906191783Srmacklem * error recovery wouldn't be as difficult.) 1907191783Srmacklem */ 1908361236Sfreqlabsint 1909191783Srmacklemnfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1910191783Srmacklem nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1911191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1912191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1913191783Srmacklem{ 1914191783Srmacklem int error = 0, newone, expireret = 0, retrycnt, unlocked; 1915191783Srmacklem struct nfsclowner *owp; 1916191783Srmacklem struct nfscldeleg *dp; 1917191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp)); 1918191783Srmacklem u_int32_t clidrev; 1919191783Srmacklem 1920191783Srmacklem if (NFSHASNFSV4(nmp)) { 1921191783Srmacklem retrycnt = 0; 1922191783Srmacklem do { 1923191783Srmacklem dp = NULL; 1924191783Srmacklem error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 1925191783Srmacklem NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 1926191783Srmacklem NULL, 1); 1927191783Srmacklem if (error) 1928191783Srmacklem return (error); 1929191783Srmacklem if (nmp->nm_clp != NULL) 1930191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 1931191783Srmacklem else 1932191783Srmacklem clidrev = 0; 1933320998Srmacklem if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || 1934320998Srmacklem nfs_numnfscbd == 0 || retrycnt > 0) 1935320998Srmacklem error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, 1936320998Srmacklem fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 1937320998Srmacklem attrflagp, dattrflagp, dstuff, &unlocked); 1938320998Srmacklem else 1939320998Srmacklem error = nfsrpc_getcreatelayout(dvp, name, namelen, vap, 1940320998Srmacklem cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 1941320998Srmacklem attrflagp, dattrflagp, dstuff, &unlocked); 1942210034Srmacklem /* 1943210034Srmacklem * There is no need to invalidate cached attributes here, 1944210034Srmacklem * since new post-delegation issue attributes are always 1945210034Srmacklem * returned by nfsrpc_createv4() and these will update the 1946210034Srmacklem * attribute cache. 1947210034Srmacklem */ 1948191783Srmacklem if (dp != NULL) 1949191783Srmacklem (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 1950191783Srmacklem (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 1951317520Srmacklem nfscl_ownerrelease(nmp, owp, error, newone, unlocked); 1952191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1953244042Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1954244042Srmacklem error == NFSERR_BADSESSION) { 1955207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_open"); 1956191783Srmacklem } else if ((error == NFSERR_EXPIRED || 1957191783Srmacklem error == NFSERR_BADSTATEID) && clidrev != 0) { 1958191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1959191783Srmacklem retrycnt++; 1960191783Srmacklem } 1961191783Srmacklem } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1962191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1963244042Srmacklem error == NFSERR_BADSESSION || 1964191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1965191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 1966191783Srmacklem if (error && retrycnt >= 4) 1967191783Srmacklem error = EIO; 1968191783Srmacklem } else { 1969191783Srmacklem error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 1970191783Srmacklem fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1971191783Srmacklem dstuff); 1972191783Srmacklem } 1973191783Srmacklem return (error); 1974191783Srmacklem} 1975191783Srmacklem 1976191783Srmacklem/* 1977191783Srmacklem * The create rpc for v2 and 3. 1978191783Srmacklem */ 1979191783Srmacklemstatic int 1980191783Srmacklemnfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1981191783Srmacklem nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1982191783Srmacklem struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1983191783Srmacklem int *attrflagp, int *dattrflagp, void *dstuff) 1984191783Srmacklem{ 1985191783Srmacklem u_int32_t *tl; 1986191783Srmacklem int error = 0; 1987191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 1988191783Srmacklem 1989191783Srmacklem *nfhpp = NULL; 1990191783Srmacklem *attrflagp = 0; 1991191783Srmacklem *dattrflagp = 0; 1992191783Srmacklem if (namelen > NFS_MAXNAMLEN) 1993191783Srmacklem return (ENAMETOOLONG); 1994191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1995191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 1996191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 1997191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1998191783Srmacklem if (fmode & O_EXCL) { 1999191783Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2000191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2001191783Srmacklem *tl++ = cverf.lval[0]; 2002191783Srmacklem *tl = cverf.lval[1]; 2003191783Srmacklem } else { 2004191783Srmacklem *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2005191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 2006191783Srmacklem } 2007191783Srmacklem } else { 2008191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 2009191783Srmacklem } 2010191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2011191783Srmacklem if (error) 2012191783Srmacklem return (error); 2013191783Srmacklem if (nd->nd_repstat == 0) { 2014191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2015191783Srmacklem if (error) 2016191783Srmacklem goto nfsmout; 2017191783Srmacklem } 2018191783Srmacklem if (nd->nd_flag & ND_NFSV3) 2019191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2020191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 2021191783Srmacklem error = nd->nd_repstat; 2022191783Srmacklemnfsmout: 2023191783Srmacklem mbuf_freem(nd->nd_mrep); 2024191783Srmacklem return (error); 2025191783Srmacklem} 2026191783Srmacklem 2027191783Srmacklemstatic int 2028191783Srmacklemnfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2029191783Srmacklem nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 2030191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2031191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2032191783Srmacklem int *dattrflagp, void *dstuff, int *unlockedp) 2033191783Srmacklem{ 2034191783Srmacklem u_int32_t *tl; 2035191783Srmacklem int error = 0, deleg, newone, ret, acesize, limitby; 2036191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2037191783Srmacklem struct nfsclopen *op; 2038191783Srmacklem struct nfscldeleg *dp = NULL; 2039191783Srmacklem struct nfsnode *np; 2040191783Srmacklem struct nfsfh *nfhp; 2041191783Srmacklem nfsattrbit_t attrbits; 2042191783Srmacklem nfsv4stateid_t stateid; 2043191783Srmacklem u_int32_t rflags; 2044244042Srmacklem struct nfsmount *nmp; 2045317393Srmacklem struct nfsclsession *tsep; 2046191783Srmacklem 2047244042Srmacklem nmp = VFSTONFS(dvp->v_mount); 2048264681Srmacklem np = VTONFS(dvp); 2049191783Srmacklem *unlockedp = 0; 2050191783Srmacklem *nfhpp = NULL; 2051191783Srmacklem *dpp = NULL; 2052191783Srmacklem *attrflagp = 0; 2053191783Srmacklem *dattrflagp = 0; 2054191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2055191783Srmacklem return (ENAMETOOLONG); 2056191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 2057191783Srmacklem /* 2058191783Srmacklem * For V4, this is actually an Open op. 2059191783Srmacklem */ 2060191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2061191783Srmacklem *tl++ = txdr_unsigned(owp->nfsow_seqid); 2062191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 2063191783Srmacklem NFSV4OPEN_ACCESSREAD); 2064191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 2065317393Srmacklem tsep = nfsmnt_mdssession(nmp); 2066317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 2067317393Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 2068191783Srmacklem (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 2069191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2070191783Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 2071191783Srmacklem if (fmode & O_EXCL) { 2072244042Srmacklem if (NFSHASNFSV4N(nmp)) { 2073244042Srmacklem if (NFSHASSESSPERSIST(nmp)) { 2074244042Srmacklem /* Use GUARDED for persistent sessions. */ 2075244042Srmacklem *tl = txdr_unsigned(NFSCREATE_GUARDED); 2076244042Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 2077244042Srmacklem } else { 2078244042Srmacklem /* Otherwise, use EXCLUSIVE4_1. */ 2079244042Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 2080244042Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2081244042Srmacklem *tl++ = cverf.lval[0]; 2082244042Srmacklem *tl = cverf.lval[1]; 2083244042Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 2084244042Srmacklem } 2085244042Srmacklem } else { 2086244042Srmacklem /* NFSv4.0 */ 2087244042Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2088244042Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2089244042Srmacklem *tl++ = cverf.lval[0]; 2090244042Srmacklem *tl = cverf.lval[1]; 2091244042Srmacklem } 2092191783Srmacklem } else { 2093191783Srmacklem *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2094191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 2095191783Srmacklem } 2096191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2097191783Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 2098191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2099264681Srmacklem /* Get the new file's handle and attributes. */ 2100191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2101191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2102191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2103191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 2104191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2105264681Srmacklem /* Get the directory's post-op attributes. */ 2106264681Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2107264681Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2108264681Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 2109264681Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2110264681Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2111264681Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2112191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2113191783Srmacklem if (error) 2114191783Srmacklem return (error); 2115191783Srmacklem NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 2116191783Srmacklem if (nd->nd_repstat == 0) { 2117191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2118191783Srmacklem 6 * NFSX_UNSIGNED); 2119191783Srmacklem stateid.seqid = *tl++; 2120191783Srmacklem stateid.other[0] = *tl++; 2121191783Srmacklem stateid.other[1] = *tl++; 2122191783Srmacklem stateid.other[2] = *tl; 2123191783Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 2124191783Srmacklem (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2125191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2126191783Srmacklem deleg = fxdr_unsigned(int, *tl); 2127191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 2128191783Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 2129191783Srmacklem if (!(owp->nfsow_clp->nfsc_flags & 2130191783Srmacklem NFSCLFLAGS_FIRSTDELEG)) 2131191783Srmacklem owp->nfsow_clp->nfsc_flags |= 2132191783Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 2133191783Srmacklem MALLOC(dp, struct nfscldeleg *, 2134191783Srmacklem sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 2135191783Srmacklem M_NFSCLDELEG, M_WAITOK); 2136191783Srmacklem LIST_INIT(&dp->nfsdl_owner); 2137191783Srmacklem LIST_INIT(&dp->nfsdl_lock); 2138191783Srmacklem dp->nfsdl_clp = owp->nfsow_clp; 2139191783Srmacklem newnfs_copyincred(cred, &dp->nfsdl_cred); 2140191783Srmacklem nfscl_lockinit(&dp->nfsdl_rwlock); 2141191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2142191783Srmacklem NFSX_UNSIGNED); 2143191783Srmacklem dp->nfsdl_stateid.seqid = *tl++; 2144191783Srmacklem dp->nfsdl_stateid.other[0] = *tl++; 2145191783Srmacklem dp->nfsdl_stateid.other[1] = *tl++; 2146191783Srmacklem dp->nfsdl_stateid.other[2] = *tl++; 2147191783Srmacklem ret = fxdr_unsigned(int, *tl); 2148191783Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 2149191783Srmacklem dp->nfsdl_flags = NFSCLDL_WRITE; 2150191783Srmacklem /* 2151191783Srmacklem * Indicates how much the file can grow. 2152191783Srmacklem */ 2153191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2154191783Srmacklem 3 * NFSX_UNSIGNED); 2155191783Srmacklem limitby = fxdr_unsigned(int, *tl++); 2156191783Srmacklem switch (limitby) { 2157191783Srmacklem case NFSV4OPEN_LIMITSIZE: 2158191783Srmacklem dp->nfsdl_sizelimit = fxdr_hyper(tl); 2159191783Srmacklem break; 2160191783Srmacklem case NFSV4OPEN_LIMITBLOCKS: 2161191783Srmacklem dp->nfsdl_sizelimit = 2162191783Srmacklem fxdr_unsigned(u_int64_t, *tl++); 2163191783Srmacklem dp->nfsdl_sizelimit *= 2164191783Srmacklem fxdr_unsigned(u_int64_t, *tl); 2165191783Srmacklem break; 2166191783Srmacklem default: 2167191783Srmacklem error = NFSERR_BADXDR; 2168191783Srmacklem goto nfsmout; 2169297793Spfg } 2170191783Srmacklem } else { 2171191783Srmacklem dp->nfsdl_flags = NFSCLDL_READ; 2172191783Srmacklem } 2173191783Srmacklem if (ret) 2174191783Srmacklem dp->nfsdl_flags |= NFSCLDL_RECALL; 2175191783Srmacklem error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 2176191783Srmacklem &acesize, p); 2177191783Srmacklem if (error) 2178191783Srmacklem goto nfsmout; 2179191783Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 2180191783Srmacklem error = NFSERR_BADXDR; 2181191783Srmacklem goto nfsmout; 2182191783Srmacklem } 2183191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2184191783Srmacklem if (error) 2185191783Srmacklem goto nfsmout; 2186264681Srmacklem /* Get rid of the PutFH and Getattr status values. */ 2187264681Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2188264681Srmacklem /* Load the directory attributes. */ 2189264681Srmacklem error = nfsm_loadattr(nd, dnap); 2190264681Srmacklem if (error) 2191264681Srmacklem goto nfsmout; 2192264681Srmacklem *dattrflagp = 1; 2193191783Srmacklem if (dp != NULL && *attrflagp) { 2194191783Srmacklem dp->nfsdl_change = nnap->na_filerev; 2195191783Srmacklem dp->nfsdl_modtime = nnap->na_mtime; 2196191783Srmacklem dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 2197191783Srmacklem } 2198191783Srmacklem /* 2199191783Srmacklem * We can now complete the Open state. 2200191783Srmacklem */ 2201191783Srmacklem nfhp = *nfhpp; 2202191783Srmacklem if (dp != NULL) { 2203191783Srmacklem dp->nfsdl_fhlen = nfhp->nfh_len; 2204191783Srmacklem NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 2205191783Srmacklem } 2206191783Srmacklem /* 2207191783Srmacklem * Get an Open structure that will be 2208191783Srmacklem * attached to the OpenOwner, acquired already. 2209191783Srmacklem */ 2210191783Srmacklem error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 2211191783Srmacklem (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 2212191783Srmacklem cred, p, NULL, &op, &newone, NULL, 0); 2213191783Srmacklem if (error) 2214191783Srmacklem goto nfsmout; 2215191783Srmacklem op->nfso_stateid = stateid; 2216191783Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 2217191783Srmacklem if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 2218191783Srmacklem do { 2219191783Srmacklem ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 2220191783Srmacklem nfhp->nfh_len, op, cred, p); 2221191783Srmacklem if (ret == NFSERR_DELAY) 2222207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_create"); 2223191783Srmacklem } while (ret == NFSERR_DELAY); 2224191783Srmacklem error = ret; 2225191783Srmacklem } 2226191783Srmacklem 2227191783Srmacklem /* 2228191783Srmacklem * If the server is handing out delegations, but we didn't 2229191783Srmacklem * get one because an OpenConfirm was required, try the 2230191783Srmacklem * Open again, to get a delegation. This is a harmless no-op, 2231191783Srmacklem * from a server's point of view. 2232191783Srmacklem */ 2233191783Srmacklem if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 2234191783Srmacklem (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 2235191783Srmacklem !error && dp == NULL) { 2236191783Srmacklem do { 2237191783Srmacklem ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp, 2238191783Srmacklem np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 2239191783Srmacklem nfhp->nfh_fh, nfhp->nfh_len, 2240191783Srmacklem (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2241191783Srmacklem name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2242191783Srmacklem if (ret == NFSERR_DELAY) 2243207170Srmacklem (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2244191783Srmacklem } while (ret == NFSERR_DELAY); 2245191783Srmacklem if (ret) { 2246281756Spfg if (dp != NULL) { 2247191783Srmacklem FREE((caddr_t)dp, M_NFSCLDELEG); 2248281756Spfg dp = NULL; 2249281756Spfg } 2250191783Srmacklem if (ret == NFSERR_STALECLIENTID || 2251244042Srmacklem ret == NFSERR_STALEDONTRECOVER || 2252244042Srmacklem ret == NFSERR_BADSESSION) 2253191783Srmacklem error = ret; 2254191783Srmacklem } 2255191783Srmacklem } 2256317520Srmacklem nfscl_openrelease(nmp, op, error, newone); 2257191783Srmacklem *unlockedp = 1; 2258191783Srmacklem } 2259191783Srmacklem if (nd->nd_repstat != 0 && error == 0) 2260191783Srmacklem error = nd->nd_repstat; 2261317393Srmacklem if (error == NFSERR_STALECLIENTID) 2262191783Srmacklem nfscl_initiate_recovery(owp->nfsow_clp); 2263191783Srmacklemnfsmout: 2264191783Srmacklem if (!error) 2265191783Srmacklem *dpp = dp; 2266191783Srmacklem else if (dp != NULL) 2267191783Srmacklem FREE((caddr_t)dp, M_NFSCLDELEG); 2268191783Srmacklem mbuf_freem(nd->nd_mrep); 2269191783Srmacklem return (error); 2270191783Srmacklem} 2271191783Srmacklem 2272191783Srmacklem/* 2273191783Srmacklem * Nfs remove rpc 2274191783Srmacklem */ 2275361236Sfreqlabsint 2276191783Srmacklemnfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2277191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, 2278191783Srmacklem void *dstuff) 2279191783Srmacklem{ 2280191783Srmacklem u_int32_t *tl; 2281191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2282191783Srmacklem struct nfsnode *np; 2283191783Srmacklem struct nfsmount *nmp; 2284191783Srmacklem nfsv4stateid_t dstateid; 2285191783Srmacklem int error, ret = 0, i; 2286191783Srmacklem 2287191783Srmacklem *dattrflagp = 0; 2288191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2289191783Srmacklem return (ENAMETOOLONG); 2290191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 2291191783Srmacklemtryagain: 2292191783Srmacklem if (NFSHASNFSV4(nmp) && ret == 0) { 2293191783Srmacklem ret = nfscl_removedeleg(vp, p, &dstateid); 2294191783Srmacklem if (ret == 1) { 2295191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp); 2296191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2297191783Srmacklem NFSX_UNSIGNED); 2298244042Srmacklem if (NFSHASNFSV4N(nmp)) 2299244042Srmacklem *tl++ = 0; 2300244042Srmacklem else 2301244042Srmacklem *tl++ = dstateid.seqid; 2302191783Srmacklem *tl++ = dstateid.other[0]; 2303191783Srmacklem *tl++ = dstateid.other[1]; 2304191783Srmacklem *tl++ = dstateid.other[2]; 2305191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2306191783Srmacklem np = VTONFS(dvp); 2307191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2308191783Srmacklem np->n_fhp->nfh_len, 0); 2309191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2310191783Srmacklem *tl = txdr_unsigned(NFSV4OP_REMOVE); 2311191783Srmacklem } 2312191783Srmacklem } else { 2313191783Srmacklem ret = 0; 2314191783Srmacklem } 2315191783Srmacklem if (ret == 0) 2316191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp); 2317191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2318191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2319191783Srmacklem if (error) 2320191783Srmacklem return (error); 2321191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2322191783Srmacklem /* For NFSv4, parse out any Delereturn replies. */ 2323191783Srmacklem if (ret > 0 && nd->nd_repstat != 0 && 2324191783Srmacklem (nd->nd_flag & ND_NOMOREDATA)) { 2325191783Srmacklem /* 2326191783Srmacklem * If the Delegreturn failed, try again without 2327191783Srmacklem * it. The server will Recall, as required. 2328191783Srmacklem */ 2329191783Srmacklem mbuf_freem(nd->nd_mrep); 2330191783Srmacklem goto tryagain; 2331191783Srmacklem } 2332191783Srmacklem for (i = 0; i < (ret * 2); i++) { 2333191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2334191783Srmacklem ND_NFSV4) { 2335191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2336191783Srmacklem if (*(tl + 1)) 2337191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2338191783Srmacklem } 2339191783Srmacklem } 2340191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2341191783Srmacklem } 2342191783Srmacklem if (nd->nd_repstat && !error) 2343191783Srmacklem error = nd->nd_repstat; 2344191783Srmacklemnfsmout: 2345191783Srmacklem mbuf_freem(nd->nd_mrep); 2346191783Srmacklem return (error); 2347191783Srmacklem} 2348191783Srmacklem 2349191783Srmacklem/* 2350191783Srmacklem * Do an nfs rename rpc. 2351191783Srmacklem */ 2352361236Sfreqlabsint 2353191783Srmacklemnfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2354191783Srmacklem vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2355191783Srmacklem NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2356191783Srmacklem int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff) 2357191783Srmacklem{ 2358191783Srmacklem u_int32_t *tl; 2359191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2360191783Srmacklem struct nfsmount *nmp; 2361191783Srmacklem struct nfsnode *np; 2362191783Srmacklem nfsattrbit_t attrbits; 2363191783Srmacklem nfsv4stateid_t fdstateid, tdstateid; 2364191783Srmacklem int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2365191783Srmacklem 2366191783Srmacklem *fattrflagp = 0; 2367191783Srmacklem *tattrflagp = 0; 2368191783Srmacklem nmp = VFSTONFS(vnode_mount(fdvp)); 2369191783Srmacklem if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2370191783Srmacklem return (ENAMETOOLONG); 2371191783Srmacklemtryagain: 2372191783Srmacklem if (NFSHASNFSV4(nmp) && ret == 0) { 2373191783Srmacklem ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2374191783Srmacklem &tdstateid, &gottd, p); 2375191783Srmacklem if (gotfd && gottd) { 2376191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp); 2377191783Srmacklem } else if (gotfd) { 2378191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp); 2379191783Srmacklem } else if (gottd) { 2380191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp); 2381191783Srmacklem } 2382191783Srmacklem if (gotfd) { 2383191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2384244042Srmacklem if (NFSHASNFSV4N(nmp)) 2385244042Srmacklem *tl++ = 0; 2386244042Srmacklem else 2387244042Srmacklem *tl++ = fdstateid.seqid; 2388191783Srmacklem *tl++ = fdstateid.other[0]; 2389191783Srmacklem *tl++ = fdstateid.other[1]; 2390191783Srmacklem *tl = fdstateid.other[2]; 2391191783Srmacklem if (gottd) { 2392191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2393191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2394191783Srmacklem np = VTONFS(tvp); 2395191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2396191783Srmacklem np->n_fhp->nfh_len, 0); 2397191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2398191783Srmacklem *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2399191783Srmacklem } 2400191783Srmacklem } 2401191783Srmacklem if (gottd) { 2402191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2403244042Srmacklem if (NFSHASNFSV4N(nmp)) 2404244042Srmacklem *tl++ = 0; 2405244042Srmacklem else 2406244042Srmacklem *tl++ = tdstateid.seqid; 2407191783Srmacklem *tl++ = tdstateid.other[0]; 2408191783Srmacklem *tl++ = tdstateid.other[1]; 2409191783Srmacklem *tl = tdstateid.other[2]; 2410191783Srmacklem } 2411191783Srmacklem if (ret > 0) { 2412191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2413191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2414191783Srmacklem np = VTONFS(fdvp); 2415191783Srmacklem (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2416191783Srmacklem np->n_fhp->nfh_len, 0); 2417191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2418191783Srmacklem *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2419191783Srmacklem } 2420191783Srmacklem } else { 2421191783Srmacklem ret = 0; 2422191783Srmacklem } 2423191783Srmacklem if (ret == 0) 2424191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp); 2425191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2426191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2427191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2428191783Srmacklem NFSWCCATTR_ATTRBIT(&attrbits); 2429191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2430191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2431191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2432191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2433191783Srmacklem VTONFS(tdvp)->n_fhp->nfh_len, 0); 2434191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2435191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2436191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2437191783Srmacklem nd->nd_flag |= ND_V4WCCATTR; 2438191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2439191783Srmacklem *tl = txdr_unsigned(NFSV4OP_RENAME); 2440191783Srmacklem } 2441191783Srmacklem (void) nfsm_strtom(nd, fnameptr, fnamelen); 2442191783Srmacklem if (!(nd->nd_flag & ND_NFSV4)) 2443191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2444191783Srmacklem VTONFS(tdvp)->n_fhp->nfh_len, 0); 2445191783Srmacklem (void) nfsm_strtom(nd, tnameptr, tnamelen); 2446191783Srmacklem error = nfscl_request(nd, fdvp, p, cred, fstuff); 2447191783Srmacklem if (error) 2448191783Srmacklem return (error); 2449191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2450191783Srmacklem /* For NFSv4, parse out any Delereturn replies. */ 2451191783Srmacklem if (ret > 0 && nd->nd_repstat != 0 && 2452191783Srmacklem (nd->nd_flag & ND_NOMOREDATA)) { 2453191783Srmacklem /* 2454191783Srmacklem * If the Delegreturn failed, try again without 2455191783Srmacklem * it. The server will Recall, as required. 2456191783Srmacklem */ 2457191783Srmacklem mbuf_freem(nd->nd_mrep); 2458191783Srmacklem goto tryagain; 2459191783Srmacklem } 2460191783Srmacklem for (i = 0; i < (ret * 2); i++) { 2461191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2462191783Srmacklem ND_NFSV4) { 2463191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2464191783Srmacklem if (*(tl + 1)) { 2465191783Srmacklem if (i == 0 && ret > 1) { 2466191783Srmacklem /* 2467191783Srmacklem * If the Delegreturn failed, try again 2468191783Srmacklem * without it. The server will Recall, as 2469191783Srmacklem * required. 2470191783Srmacklem * If ret > 1, the first iteration of this 2471191783Srmacklem * loop is the second DelegReturn result. 2472191783Srmacklem */ 2473191783Srmacklem mbuf_freem(nd->nd_mrep); 2474191783Srmacklem goto tryagain; 2475191783Srmacklem } else { 2476191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2477191783Srmacklem } 2478191783Srmacklem } 2479191783Srmacklem } 2480191783Srmacklem } 2481191783Srmacklem /* Now, the first wcc attribute reply. */ 2482191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2483191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2484191783Srmacklem if (*(tl + 1)) 2485191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2486191783Srmacklem } 2487191783Srmacklem error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, 2488191783Srmacklem fstuff); 2489191783Srmacklem /* and the second wcc attribute reply. */ 2490191783Srmacklem if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2491191783Srmacklem !error) { 2492191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2493191783Srmacklem if (*(tl + 1)) 2494191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2495191783Srmacklem } 2496191783Srmacklem if (!error) 2497191783Srmacklem error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2498191783Srmacklem NULL, tstuff); 2499191783Srmacklem } 2500191783Srmacklem if (nd->nd_repstat && !error) 2501191783Srmacklem error = nd->nd_repstat; 2502191783Srmacklemnfsmout: 2503191783Srmacklem mbuf_freem(nd->nd_mrep); 2504191783Srmacklem return (error); 2505191783Srmacklem} 2506191783Srmacklem 2507191783Srmacklem/* 2508191783Srmacklem * nfs hard link create rpc 2509191783Srmacklem */ 2510361236Sfreqlabsint 2511191783Srmacklemnfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2512191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2513191783Srmacklem struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2514191783Srmacklem{ 2515191783Srmacklem u_int32_t *tl; 2516191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2517191783Srmacklem nfsattrbit_t attrbits; 2518191783Srmacklem int error = 0; 2519191783Srmacklem 2520191783Srmacklem *attrflagp = 0; 2521191783Srmacklem *dattrflagp = 0; 2522191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2523191783Srmacklem return (ENAMETOOLONG); 2524191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2525191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2526191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2527191783Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2528191783Srmacklem } 2529191783Srmacklem (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2530191783Srmacklem VTONFS(dvp)->n_fhp->nfh_len, 0); 2531191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2532191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2533191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2534191783Srmacklem NFSWCCATTR_ATTRBIT(&attrbits); 2535191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2536191783Srmacklem nd->nd_flag |= ND_V4WCCATTR; 2537191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2538191783Srmacklem *tl = txdr_unsigned(NFSV4OP_LINK); 2539191783Srmacklem } 2540191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2541191783Srmacklem error = nfscl_request(nd, vp, p, cred, dstuff); 2542191783Srmacklem if (error) 2543191783Srmacklem return (error); 2544191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 2545191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2546191783Srmacklem if (!error) 2547191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2548191783Srmacklem NULL, dstuff); 2549191783Srmacklem } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2550191783Srmacklem /* 2551191783Srmacklem * First, parse out the PutFH and Getattr result. 2552191783Srmacklem */ 2553191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2554191783Srmacklem if (!(*(tl + 1))) 2555191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2556191783Srmacklem if (*(tl + 1)) 2557191783Srmacklem nd->nd_flag |= ND_NOMOREDATA; 2558191783Srmacklem /* 2559191783Srmacklem * Get the pre-op attributes. 2560191783Srmacklem */ 2561191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2562191783Srmacklem } 2563191783Srmacklem if (nd->nd_repstat && !error) 2564191783Srmacklem error = nd->nd_repstat; 2565191783Srmacklemnfsmout: 2566191783Srmacklem mbuf_freem(nd->nd_mrep); 2567191783Srmacklem return (error); 2568191783Srmacklem} 2569191783Srmacklem 2570191783Srmacklem/* 2571191783Srmacklem * nfs symbolic link create rpc 2572191783Srmacklem */ 2573361236Sfreqlabsint 2574191783Srmacklemnfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target, 2575191783Srmacklem struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2576191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2577191783Srmacklem int *dattrflagp, void *dstuff) 2578191783Srmacklem{ 2579191783Srmacklem u_int32_t *tl; 2580191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2581191783Srmacklem struct nfsmount *nmp; 2582191783Srmacklem int slen, error = 0; 2583191783Srmacklem 2584191783Srmacklem *nfhpp = NULL; 2585191783Srmacklem *attrflagp = 0; 2586191783Srmacklem *dattrflagp = 0; 2587191783Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 2588191783Srmacklem slen = strlen(target); 2589191783Srmacklem if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2590191783Srmacklem return (ENAMETOOLONG); 2591191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2592191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2593191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2594191783Srmacklem *tl = txdr_unsigned(NFLNK); 2595191783Srmacklem (void) nfsm_strtom(nd, target, slen); 2596191783Srmacklem } 2597191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2598191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2599191783Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 2600191783Srmacklem if (!(nd->nd_flag & ND_NFSV4)) 2601191783Srmacklem (void) nfsm_strtom(nd, target, slen); 2602191783Srmacklem if (nd->nd_flag & ND_NFSV2) 2603191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2604191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2605191783Srmacklem if (error) 2606191783Srmacklem return (error); 2607191783Srmacklem if (nd->nd_flag & ND_NFSV4) 2608191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2609191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) { 2610191783Srmacklem if (!nd->nd_repstat) 2611191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2612191783Srmacklem if (!error) 2613191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2614191783Srmacklem NULL, dstuff); 2615191783Srmacklem } 2616191783Srmacklem if (nd->nd_repstat && !error) 2617191783Srmacklem error = nd->nd_repstat; 2618191783Srmacklem mbuf_freem(nd->nd_mrep); 2619191783Srmacklem /* 2620191783Srmacklem * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2621285066Srmacklem * Only do this if vfs.nfs.ignore_eexist is set. 2622285066Srmacklem * Never do this for NFSv4.1 or later minor versions, since sessions 2623285066Srmacklem * should guarantee "exactly once" RPC semantics. 2624191783Srmacklem */ 2625285066Srmacklem if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2626285066Srmacklem nmp->nm_minorvers == 0)) 2627191783Srmacklem error = 0; 2628191783Srmacklem return (error); 2629191783Srmacklem} 2630191783Srmacklem 2631191783Srmacklem/* 2632191783Srmacklem * nfs make dir rpc 2633191783Srmacklem */ 2634361236Sfreqlabsint 2635191783Srmacklemnfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2636191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2637191783Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2638191783Srmacklem int *dattrflagp, void *dstuff) 2639191783Srmacklem{ 2640191783Srmacklem u_int32_t *tl; 2641191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2642191783Srmacklem nfsattrbit_t attrbits; 2643191783Srmacklem int error = 0; 2644264705Srmacklem struct nfsfh *fhp; 2645285066Srmacklem struct nfsmount *nmp; 2646191783Srmacklem 2647191783Srmacklem *nfhpp = NULL; 2648191783Srmacklem *attrflagp = 0; 2649191783Srmacklem *dattrflagp = 0; 2650285066Srmacklem nmp = VFSTONFS(vnode_mount(dvp)); 2651264705Srmacklem fhp = VTONFS(dvp)->n_fhp; 2652191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2653191783Srmacklem return (ENAMETOOLONG); 2654191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 2655191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2656191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2657191783Srmacklem *tl = txdr_unsigned(NFDIR); 2658191783Srmacklem } 2659191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2660191783Srmacklem nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2661191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2662191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 2663191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2664191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2665191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2666191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2667264705Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2668264705Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 2669264705Srmacklem (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0); 2670264705Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2671264705Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2672264705Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2673191783Srmacklem } 2674191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2675191783Srmacklem if (error) 2676191783Srmacklem return (error); 2677191783Srmacklem if (nd->nd_flag & ND_NFSV4) 2678191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2679191783Srmacklem if (!nd->nd_repstat && !error) { 2680191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2681191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2682191783Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2683191783Srmacklem } 2684191783Srmacklem if (!error) 2685191783Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2686264749Srmacklem if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 2687264705Srmacklem /* Get rid of the PutFH and Getattr status values. */ 2688264705Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2689264705Srmacklem /* Load the directory attributes. */ 2690264705Srmacklem error = nfsm_loadattr(nd, dnap); 2691264705Srmacklem if (error == 0) 2692264705Srmacklem *dattrflagp = 1; 2693264705Srmacklem } 2694191783Srmacklem } 2695191783Srmacklem if ((nd->nd_flag & ND_NFSV3) && !error) 2696191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2697191783Srmacklem if (nd->nd_repstat && !error) 2698191783Srmacklem error = nd->nd_repstat; 2699191783Srmacklemnfsmout: 2700191783Srmacklem mbuf_freem(nd->nd_mrep); 2701191783Srmacklem /* 2702285066Srmacklem * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2703285066Srmacklem * Only do this if vfs.nfs.ignore_eexist is set. 2704285066Srmacklem * Never do this for NFSv4.1 or later minor versions, since sessions 2705285066Srmacklem * should guarantee "exactly once" RPC semantics. 2706191783Srmacklem */ 2707285066Srmacklem if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2708285066Srmacklem nmp->nm_minorvers == 0)) 2709191783Srmacklem error = 0; 2710191783Srmacklem return (error); 2711191783Srmacklem} 2712191783Srmacklem 2713191783Srmacklem/* 2714191783Srmacklem * nfs remove directory call 2715191783Srmacklem */ 2716361236Sfreqlabsint 2717191783Srmacklemnfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 2718191783Srmacklem NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 2719191783Srmacklem{ 2720191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2721191783Srmacklem int error = 0; 2722191783Srmacklem 2723191783Srmacklem *dattrflagp = 0; 2724191783Srmacklem if (namelen > NFS_MAXNAMLEN) 2725191783Srmacklem return (ENAMETOOLONG); 2726191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 2727191783Srmacklem (void) nfsm_strtom(nd, name, namelen); 2728191783Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 2729191783Srmacklem if (error) 2730191783Srmacklem return (error); 2731191783Srmacklem if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2732191783Srmacklem error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2733191783Srmacklem if (nd->nd_repstat && !error) 2734191783Srmacklem error = nd->nd_repstat; 2735191783Srmacklem mbuf_freem(nd->nd_mrep); 2736191783Srmacklem /* 2737191783Srmacklem * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2738191783Srmacklem */ 2739191783Srmacklem if (error == ENOENT) 2740191783Srmacklem error = 0; 2741191783Srmacklem return (error); 2742191783Srmacklem} 2743191783Srmacklem 2744191783Srmacklem/* 2745191783Srmacklem * Readdir rpc. 2746191783Srmacklem * Always returns with either uio_resid unchanged, if you are at the 2747191783Srmacklem * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 2748191783Srmacklem * filled in. 2749191783Srmacklem * I felt this would allow caching of directory blocks more easily 2750191783Srmacklem * than returning a pertially filled block. 2751191783Srmacklem * Directory offset cookies: 2752191783Srmacklem * Oh my, what to do with them... 2753191783Srmacklem * I can think of three ways to deal with them: 2754191783Srmacklem * 1 - have the layer above these RPCs maintain a map between logical 2755191783Srmacklem * directory byte offsets and the NFS directory offset cookies 2756191783Srmacklem * 2 - pass the opaque directory offset cookies up into userland 2757191783Srmacklem * and let the libc functions deal with them, via the system call 2758191783Srmacklem * 3 - return them to userland in the "struct dirent", so future versions 2759298788Spfg * of libc can use them and do whatever is necessary to make things work 2760191783Srmacklem * above these rpc calls, in the meantime 2761191783Srmacklem * For now, I do #3 by "hiding" the directory offset cookies after the 2762191783Srmacklem * d_name field in struct dirent. This is space inside d_reclen that 2763191783Srmacklem * will be ignored by anything that doesn't know about them. 2764191783Srmacklem * The directory offset cookies are filled in as the last 8 bytes of 2765191783Srmacklem * each directory entry, after d_name. Someday, the userland libc 2766191783Srmacklem * functions may be able to use these. In the meantime, it satisfies 2767191783Srmacklem * OpenBSD's requirements for cookies being returned. 2768191783Srmacklem * If expects the directory offset cookie for the read to be in uio_offset 2769191783Srmacklem * and returns the one for the next entry after this directory block in 2770191783Srmacklem * there, as well. 2771191783Srmacklem */ 2772361236Sfreqlabsint 2773191783Srmacklemnfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2774191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2775191783Srmacklem int *eofp, void *stuff) 2776191783Srmacklem{ 2777191783Srmacklem int len, left; 2778191783Srmacklem struct dirent *dp = NULL; 2779191783Srmacklem u_int32_t *tl; 2780191783Srmacklem nfsquad_t cookie, ncookie; 2781191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2782191783Srmacklem struct nfsnode *dnp = VTONFS(vp); 2783191783Srmacklem struct nfsvattr nfsva; 2784191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 2785191783Srmacklem int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2786191783Srmacklem int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 2787191783Srmacklem long dotfileid, dotdotfileid = 0; 2788191783Srmacklem u_int32_t fakefileno = 0xffffffff, rderr; 2789191783Srmacklem char *cp; 2790191783Srmacklem nfsattrbit_t attrbits, dattrbits; 2791191783Srmacklem u_int32_t *tl2 = NULL; 2792191783Srmacklem size_t tresid; 2793191783Srmacklem 2794209120Skib KASSERT(uiop->uio_iovcnt == 1 && 2795209120Skib (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2796209120Skib ("nfs readdirrpc bad uio")); 2797191783Srmacklem 2798191783Srmacklem /* 2799191783Srmacklem * There is no point in reading a lot more than uio_resid, however 2800191783Srmacklem * adding one additional DIRBLKSIZ makes sense. Since uio_resid 2801191783Srmacklem * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 2802191783Srmacklem * will never make readsize > nm_readdirsize. 2803191783Srmacklem */ 2804191783Srmacklem readsize = nmp->nm_readdirsize; 2805191783Srmacklem if (readsize > uio_uio_resid(uiop)) 2806191783Srmacklem readsize = uio_uio_resid(uiop) + DIRBLKSIZ; 2807191783Srmacklem 2808191783Srmacklem *attrflagp = 0; 2809191783Srmacklem if (eofp) 2810191783Srmacklem *eofp = 0; 2811191783Srmacklem tresid = uio_uio_resid(uiop); 2812191783Srmacklem cookie.lval[0] = cookiep->nfsuquad[0]; 2813191783Srmacklem cookie.lval[1] = cookiep->nfsuquad[1]; 2814191783Srmacklem nd->nd_mrep = NULL; 2815191783Srmacklem 2816191783Srmacklem /* 2817191783Srmacklem * For NFSv4, first create the "." and ".." entries. 2818191783Srmacklem */ 2819191783Srmacklem if (NFSHASNFSV4(nmp)) { 2820191783Srmacklem reqsize = 6 * NFSX_UNSIGNED; 2821191783Srmacklem NFSGETATTR_ATTRBIT(&dattrbits); 2822191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 2823191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2824191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 2825191783Srmacklem if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2826191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID)) { 2827191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 2828191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 2829191783Srmacklem gotmnton = 1; 2830191783Srmacklem } else { 2831191783Srmacklem /* 2832191783Srmacklem * Must fake it. Use the fileno, except when the 2833191783Srmacklem * fsid is != to that of the directory. For that 2834191783Srmacklem * case, generate a fake fileno that is not the same. 2835191783Srmacklem */ 2836191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2837191783Srmacklem gotmnton = 0; 2838191783Srmacklem } 2839191783Srmacklem 2840191783Srmacklem /* 2841191783Srmacklem * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2842191783Srmacklem */ 2843191783Srmacklem if (uiop->uio_offset == 0) { 2844191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2845191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2846191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2847191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2848191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2849191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 2850191783Srmacklem if (error) 2851191783Srmacklem return (error); 2852264672Srmacklem dotfileid = 0; /* Fake out the compiler. */ 2853264672Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 2854264672Srmacklem error = nfsm_loadattr(nd, &nfsva); 2855264672Srmacklem if (error != 0) 2856264672Srmacklem goto nfsmout; 2857264672Srmacklem dotfileid = nfsva.na_fileid; 2858264672Srmacklem } 2859191783Srmacklem if (nd->nd_repstat == 0) { 2860264672Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2861264672Srmacklem len = fxdr_unsigned(int, *(tl + 4)); 2862191783Srmacklem if (len > 0 && len <= NFSX_V4FHMAX) 2863191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2864191783Srmacklem else 2865191783Srmacklem error = EPERM; 2866191783Srmacklem if (!error) { 2867191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2868191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 2869191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2870191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2871191783Srmacklem NULL, NULL, NULL, p, cred); 2872191783Srmacklem if (error) { 2873191783Srmacklem dotdotfileid = dotfileid; 2874191783Srmacklem } else if (gotmnton) { 2875191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 2876191783Srmacklem dotdotfileid = nfsva.na_mntonfileno; 2877191783Srmacklem else 2878191783Srmacklem dotdotfileid = nfsva.na_fileid; 2879191783Srmacklem } else if (nfsva.na_filesid[0] == 2880191783Srmacklem dnp->n_vattr.na_filesid[0] && 2881191783Srmacklem nfsva.na_filesid[1] == 2882191783Srmacklem dnp->n_vattr.na_filesid[1]) { 2883191783Srmacklem dotdotfileid = nfsva.na_fileid; 2884191783Srmacklem } else { 2885191783Srmacklem do { 2886191783Srmacklem fakefileno--; 2887191783Srmacklem } while (fakefileno == 2888191783Srmacklem nfsva.na_fileid); 2889191783Srmacklem dotdotfileid = fakefileno; 2890191783Srmacklem } 2891191783Srmacklem } 2892191783Srmacklem } else if (nd->nd_repstat == NFSERR_NOENT) { 2893191783Srmacklem /* 2894191783Srmacklem * Lookupp returns NFSERR_NOENT when we are 2895191783Srmacklem * at the root, so just use the current dir. 2896191783Srmacklem */ 2897191783Srmacklem nd->nd_repstat = 0; 2898191783Srmacklem dotdotfileid = dotfileid; 2899191783Srmacklem } else { 2900191783Srmacklem error = nd->nd_repstat; 2901191783Srmacklem } 2902191783Srmacklem mbuf_freem(nd->nd_mrep); 2903191783Srmacklem if (error) 2904191783Srmacklem return (error); 2905191783Srmacklem nd->nd_mrep = NULL; 2906191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2907191783Srmacklem dp->d_type = DT_DIR; 2908191783Srmacklem dp->d_fileno = dotfileid; 2909191783Srmacklem dp->d_namlen = 1; 2910191783Srmacklem dp->d_name[0] = '.'; 2911191783Srmacklem dp->d_name[1] = '\0'; 2912191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2913191783Srmacklem /* 2914191783Srmacklem * Just make these offset cookie 0. 2915191783Srmacklem */ 2916191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2917191783Srmacklem *tl++ = 0; 2918191783Srmacklem *tl = 0; 2919191783Srmacklem blksiz += dp->d_reclen; 2920191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 2921191783Srmacklem uiop->uio_offset += dp->d_reclen; 2922191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 2923191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 2924191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2925191783Srmacklem dp->d_type = DT_DIR; 2926191783Srmacklem dp->d_fileno = dotdotfileid; 2927191783Srmacklem dp->d_namlen = 2; 2928191783Srmacklem dp->d_name[0] = '.'; 2929191783Srmacklem dp->d_name[1] = '.'; 2930191783Srmacklem dp->d_name[2] = '\0'; 2931191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2932191783Srmacklem /* 2933191783Srmacklem * Just make these offset cookie 0. 2934191783Srmacklem */ 2935191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 2936191783Srmacklem *tl++ = 0; 2937191783Srmacklem *tl = 0; 2938191783Srmacklem blksiz += dp->d_reclen; 2939191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 2940191783Srmacklem uiop->uio_offset += dp->d_reclen; 2941191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 2942191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 2943191783Srmacklem } 2944191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 2945191783Srmacklem } else { 2946191783Srmacklem reqsize = 5 * NFSX_UNSIGNED; 2947191783Srmacklem } 2948191783Srmacklem 2949191783Srmacklem 2950191783Srmacklem /* 2951191783Srmacklem * Loop around doing readdir rpc's of size readsize. 2952191783Srmacklem * The stopping criteria is EOF or buffer full. 2953191783Srmacklem */ 2954191783Srmacklem while (more_dirs && bigenough) { 2955191783Srmacklem *attrflagp = 0; 2956191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 2957191783Srmacklem if (nd->nd_flag & ND_NFSV2) { 2958191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2959191783Srmacklem *tl++ = cookie.lval[1]; 2960191783Srmacklem *tl = txdr_unsigned(readsize); 2961191783Srmacklem } else { 2962191783Srmacklem NFSM_BUILD(tl, u_int32_t *, reqsize); 2963191783Srmacklem *tl++ = cookie.lval[0]; 2964191783Srmacklem *tl++ = cookie.lval[1]; 2965191783Srmacklem if (cookie.qval == 0) { 2966191783Srmacklem *tl++ = 0; 2967191783Srmacklem *tl++ = 0; 2968191783Srmacklem } else { 2969191783Srmacklem NFSLOCKNODE(dnp); 2970191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[0]; 2971191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[1]; 2972191783Srmacklem NFSUNLOCKNODE(dnp); 2973191783Srmacklem } 2974191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 2975191783Srmacklem *tl++ = txdr_unsigned(readsize); 2976191783Srmacklem *tl = txdr_unsigned(readsize); 2977191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 2978191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2979191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 2980191783Srmacklem (void) nfsrv_putattrbit(nd, &dattrbits); 2981191783Srmacklem } else { 2982191783Srmacklem *tl = txdr_unsigned(readsize); 2983191783Srmacklem } 2984191783Srmacklem } 2985191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 2986191783Srmacklem if (error) 2987191783Srmacklem return (error); 2988191783Srmacklem if (!(nd->nd_flag & ND_NFSV2)) { 2989191783Srmacklem if (nd->nd_flag & ND_NFSV3) 2990191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 2991191783Srmacklem stuff); 2992191783Srmacklem if (!nd->nd_repstat && !error) { 2993191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 2994191783Srmacklem NFSLOCKNODE(dnp); 2995191783Srmacklem dnp->n_cookieverf.nfsuquad[0] = *tl++; 2996191783Srmacklem dnp->n_cookieverf.nfsuquad[1] = *tl; 2997191783Srmacklem NFSUNLOCKNODE(dnp); 2998191783Srmacklem } 2999191783Srmacklem } 3000191783Srmacklem if (nd->nd_repstat || error) { 3001191783Srmacklem if (!error) 3002191783Srmacklem error = nd->nd_repstat; 3003191783Srmacklem goto nfsmout; 3004191783Srmacklem } 3005191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3006191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3007191783Srmacklem if (!more_dirs) 3008191783Srmacklem tryformoredirs = 0; 3009191783Srmacklem 3010298788Spfg /* loop through the dir entries, doctoring them to 4bsd form */ 3011191783Srmacklem while (more_dirs && bigenough) { 3012191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3013191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3014191783Srmacklem ncookie.lval[0] = *tl++; 3015191783Srmacklem ncookie.lval[1] = *tl++; 3016191783Srmacklem len = fxdr_unsigned(int, *tl); 3017191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 3018191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3019220152Szack nfsva.na_fileid = fxdr_hyper(tl); 3020220152Szack tl += 2; 3021220152Szack len = fxdr_unsigned(int, *tl); 3022191783Srmacklem } else { 3023191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3024191783Srmacklem nfsva.na_fileid = 3025191783Srmacklem fxdr_unsigned(long, *tl++); 3026191783Srmacklem len = fxdr_unsigned(int, *tl); 3027191783Srmacklem } 3028191783Srmacklem if (len <= 0 || len > NFS_MAXNAMLEN) { 3029191783Srmacklem error = EBADRPC; 3030191783Srmacklem goto nfsmout; 3031191783Srmacklem } 3032191783Srmacklem tlen = NFSM_RNDUP(len); 3033191783Srmacklem if (tlen == len) 3034191783Srmacklem tlen += 4; /* To ensure null termination */ 3035191783Srmacklem left = DIRBLKSIZ - blksiz; 3036191783Srmacklem if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) { 3037341074Smarkj NFSBZERO(uio_iov_base(uiop), left); 3038191783Srmacklem dp->d_reclen += left; 3039191783Srmacklem uio_iov_base_add(uiop, left); 3040191783Srmacklem uio_iov_len_add(uiop, -(left)); 3041191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3042191783Srmacklem uiop->uio_offset += left; 3043191783Srmacklem blksiz = 0; 3044191783Srmacklem } 3045191783Srmacklem if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 3046191783Srmacklem bigenough = 0; 3047191783Srmacklem if (bigenough) { 3048191783Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 3049191783Srmacklem dp->d_namlen = len; 3050191783Srmacklem dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 3051191783Srmacklem dp->d_type = DT_UNKNOWN; 3052191783Srmacklem blksiz += dp->d_reclen; 3053191783Srmacklem if (blksiz == DIRBLKSIZ) 3054191783Srmacklem blksiz = 0; 3055191783Srmacklem uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3056191783Srmacklem uiop->uio_offset += DIRHDSIZ; 3057191783Srmacklem uio_iov_base_add(uiop, DIRHDSIZ); 3058191783Srmacklem uio_iov_len_add(uiop, -(DIRHDSIZ)); 3059191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 3060191783Srmacklem if (error) 3061191783Srmacklem goto nfsmout; 3062191783Srmacklem cp = CAST_DOWN(caddr_t, uio_iov_base(uiop)); 3063191783Srmacklem tlen -= len; 3064341074Smarkj NFSBZERO(cp, tlen); 3065191783Srmacklem cp += tlen; /* points to cookie storage */ 3066191783Srmacklem tl2 = (u_int32_t *)cp; 3067191783Srmacklem uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3068191783Srmacklem uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3069191783Srmacklem uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3070191783Srmacklem uiop->uio_offset += (tlen + NFSX_HYPER); 3071191783Srmacklem } else { 3072191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3073191783Srmacklem if (error) 3074191783Srmacklem goto nfsmout; 3075191783Srmacklem } 3076191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3077191783Srmacklem rderr = 0; 3078191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 3079191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3080191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3081191783Srmacklem NULL, NULL, &rderr, p, cred); 3082191783Srmacklem if (error) 3083191783Srmacklem goto nfsmout; 3084191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3085191783Srmacklem } else if (nd->nd_flag & ND_NFSV3) { 3086191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3087191783Srmacklem ncookie.lval[0] = *tl++; 3088191783Srmacklem ncookie.lval[1] = *tl++; 3089191783Srmacklem } else { 3090191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3091191783Srmacklem ncookie.lval[0] = 0; 3092191783Srmacklem ncookie.lval[1] = *tl++; 3093191783Srmacklem } 3094191783Srmacklem if (bigenough) { 3095191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3096191783Srmacklem if (rderr) { 3097191783Srmacklem dp->d_fileno = 0; 3098191783Srmacklem } else { 3099191783Srmacklem if (gotmnton) { 3100191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 3101191783Srmacklem dp->d_fileno = nfsva.na_mntonfileno; 3102191783Srmacklem else 3103191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3104191783Srmacklem } else if (nfsva.na_filesid[0] == 3105191783Srmacklem dnp->n_vattr.na_filesid[0] && 3106191783Srmacklem nfsva.na_filesid[1] == 3107191783Srmacklem dnp->n_vattr.na_filesid[1]) { 3108191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3109191783Srmacklem } else { 3110191783Srmacklem do { 3111191783Srmacklem fakefileno--; 3112191783Srmacklem } while (fakefileno == 3113191783Srmacklem nfsva.na_fileid); 3114191783Srmacklem dp->d_fileno = fakefileno; 3115191783Srmacklem } 3116191783Srmacklem dp->d_type = vtonfs_dtype(nfsva.na_type); 3117191783Srmacklem } 3118191783Srmacklem } else { 3119191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3120191783Srmacklem } 3121191783Srmacklem *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3122191783Srmacklem ncookie.lval[0]; 3123191783Srmacklem *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3124191783Srmacklem ncookie.lval[1]; 3125191783Srmacklem } 3126191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3127191783Srmacklem } 3128191783Srmacklem /* 3129191783Srmacklem * If at end of rpc data, get the eof boolean 3130191783Srmacklem */ 3131191783Srmacklem if (!more_dirs) { 3132191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3133191783Srmacklem eof = fxdr_unsigned(int, *tl); 3134191783Srmacklem if (tryformoredirs) 3135191783Srmacklem more_dirs = !eof; 3136191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3137191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 3138191783Srmacklem stuff); 3139191783Srmacklem if (error) 3140191783Srmacklem goto nfsmout; 3141191783Srmacklem } 3142191783Srmacklem } 3143191783Srmacklem mbuf_freem(nd->nd_mrep); 3144191783Srmacklem nd->nd_mrep = NULL; 3145191783Srmacklem } 3146191783Srmacklem /* 3147191783Srmacklem * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3148191783Srmacklem * by increasing d_reclen for the last record. 3149191783Srmacklem */ 3150191783Srmacklem if (blksiz > 0) { 3151191783Srmacklem left = DIRBLKSIZ - blksiz; 3152341074Smarkj NFSBZERO(uio_iov_base(uiop), left); 3153191783Srmacklem dp->d_reclen += left; 3154191783Srmacklem uio_iov_base_add(uiop, left); 3155191783Srmacklem uio_iov_len_add(uiop, -(left)); 3156191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3157191783Srmacklem uiop->uio_offset += left; 3158191783Srmacklem } 3159191783Srmacklem 3160191783Srmacklem /* 3161191783Srmacklem * If returning no data, assume end of file. 3162191783Srmacklem * If not bigenough, return not end of file, since you aren't 3163191783Srmacklem * returning all the data 3164191783Srmacklem * Otherwise, return the eof flag from the server. 3165191783Srmacklem */ 3166191783Srmacklem if (eofp) { 3167191783Srmacklem if (tresid == ((size_t)(uio_uio_resid(uiop)))) 3168191783Srmacklem *eofp = 1; 3169191783Srmacklem else if (!bigenough) 3170191783Srmacklem *eofp = 0; 3171191783Srmacklem else 3172191783Srmacklem *eofp = eof; 3173191783Srmacklem } 3174191783Srmacklem 3175291117Srmacklem /* 3176291117Srmacklem * Add extra empty records to any remaining DIRBLKSIZ chunks. 3177291117Srmacklem */ 3178291117Srmacklem while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) { 3179291117Srmacklem dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 3180341074Smarkj NFSBZERO(dp, DIRBLKSIZ); 3181291117Srmacklem dp->d_type = DT_UNKNOWN; 3182291117Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3183291117Srmacklem *tl++ = cookie.lval[0]; 3184291117Srmacklem *tl = cookie.lval[1]; 3185291117Srmacklem dp->d_reclen = DIRBLKSIZ; 3186291117Srmacklem uio_iov_base_add(uiop, DIRBLKSIZ); 3187291117Srmacklem uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3188291117Srmacklem uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3189291117Srmacklem uiop->uio_offset += DIRBLKSIZ; 3190291117Srmacklem } 3191291117Srmacklem 3192191783Srmacklemnfsmout: 3193191783Srmacklem if (nd->nd_mrep != NULL) 3194191783Srmacklem mbuf_freem(nd->nd_mrep); 3195191783Srmacklem return (error); 3196191783Srmacklem} 3197191783Srmacklem 3198191783Srmacklem#ifndef APPLE 3199191783Srmacklem/* 3200191783Srmacklem * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 3201191783Srmacklem * (Also used for NFS V4 when mount flag set.) 3202191783Srmacklem * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 3203191783Srmacklem */ 3204361236Sfreqlabsint 3205191783Srmacklemnfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3206191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3207191783Srmacklem int *eofp, void *stuff) 3208191783Srmacklem{ 3209191783Srmacklem int len, left; 3210191783Srmacklem struct dirent *dp = NULL; 3211191783Srmacklem u_int32_t *tl; 3212191783Srmacklem vnode_t newvp = NULLVP; 3213191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3214191783Srmacklem struct nameidata nami, *ndp = &nami; 3215191783Srmacklem struct componentname *cnp = &ndp->ni_cnd; 3216191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3217191783Srmacklem struct nfsnode *dnp = VTONFS(vp), *np; 3218191783Srmacklem struct nfsvattr nfsva; 3219191783Srmacklem struct nfsfh *nfhp; 3220191783Srmacklem nfsquad_t cookie, ncookie; 3221191783Srmacklem int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3222191783Srmacklem int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 3223220735Srmacklem int isdotdot = 0, unlocknewvp = 0; 3224191783Srmacklem long dotfileid, dotdotfileid = 0, fileno = 0; 3225191783Srmacklem char *cp; 3226191783Srmacklem nfsattrbit_t attrbits, dattrbits; 3227191783Srmacklem size_t tresid; 3228191783Srmacklem u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr; 3229232420Srmacklem struct timespec dctime; 3230191783Srmacklem 3231209120Skib KASSERT(uiop->uio_iovcnt == 1 && 3232209120Skib (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 3233209120Skib ("nfs readdirplusrpc bad uio")); 3234232420Srmacklem timespecclear(&dctime); 3235191783Srmacklem *attrflagp = 0; 3236191783Srmacklem if (eofp != NULL) 3237191783Srmacklem *eofp = 0; 3238191783Srmacklem ndp->ni_dvp = vp; 3239191783Srmacklem nd->nd_mrep = NULL; 3240191783Srmacklem cookie.lval[0] = cookiep->nfsuquad[0]; 3241191783Srmacklem cookie.lval[1] = cookiep->nfsuquad[1]; 3242191783Srmacklem tresid = uio_uio_resid(uiop); 3243191783Srmacklem 3244191783Srmacklem /* 3245191783Srmacklem * For NFSv4, first create the "." and ".." entries. 3246191783Srmacklem */ 3247191783Srmacklem if (NFSHASNFSV4(nmp)) { 3248191783Srmacklem NFSGETATTR_ATTRBIT(&dattrbits); 3249191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 3250191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3251191783Srmacklem if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3252191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID)) { 3253191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 3254191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 3255191783Srmacklem gotmnton = 1; 3256191783Srmacklem } else { 3257191783Srmacklem /* 3258191783Srmacklem * Must fake it. Use the fileno, except when the 3259191783Srmacklem * fsid is != to that of the directory. For that 3260191783Srmacklem * case, generate a fake fileno that is not the same. 3261191783Srmacklem */ 3262191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3263191783Srmacklem gotmnton = 0; 3264191783Srmacklem } 3265191783Srmacklem 3266191783Srmacklem /* 3267191783Srmacklem * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3268191783Srmacklem */ 3269191783Srmacklem if (uiop->uio_offset == 0) { 3270191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3271191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3272191783Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3273191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3274191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3275191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3276191783Srmacklem if (error) 3277191783Srmacklem return (error); 3278264672Srmacklem dotfileid = 0; /* Fake out the compiler. */ 3279264672Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3280264672Srmacklem error = nfsm_loadattr(nd, &nfsva); 3281264672Srmacklem if (error != 0) 3282264672Srmacklem goto nfsmout; 3283264672Srmacklem dctime = nfsva.na_ctime; 3284264672Srmacklem dotfileid = nfsva.na_fileid; 3285264672Srmacklem } 3286191783Srmacklem if (nd->nd_repstat == 0) { 3287264672Srmacklem NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3288264672Srmacklem len = fxdr_unsigned(int, *(tl + 4)); 3289191783Srmacklem if (len > 0 && len <= NFSX_V4FHMAX) 3290191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3291191783Srmacklem else 3292191783Srmacklem error = EPERM; 3293191783Srmacklem if (!error) { 3294191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3295191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 3296191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3297191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3298191783Srmacklem NULL, NULL, NULL, p, cred); 3299191783Srmacklem if (error) { 3300191783Srmacklem dotdotfileid = dotfileid; 3301191783Srmacklem } else if (gotmnton) { 3302191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 3303191783Srmacklem dotdotfileid = nfsva.na_mntonfileno; 3304191783Srmacklem else 3305191783Srmacklem dotdotfileid = nfsva.na_fileid; 3306191783Srmacklem } else if (nfsva.na_filesid[0] == 3307191783Srmacklem dnp->n_vattr.na_filesid[0] && 3308191783Srmacklem nfsva.na_filesid[1] == 3309191783Srmacklem dnp->n_vattr.na_filesid[1]) { 3310191783Srmacklem dotdotfileid = nfsva.na_fileid; 3311191783Srmacklem } else { 3312191783Srmacklem do { 3313191783Srmacklem fakefileno--; 3314191783Srmacklem } while (fakefileno == 3315191783Srmacklem nfsva.na_fileid); 3316191783Srmacklem dotdotfileid = fakefileno; 3317191783Srmacklem } 3318191783Srmacklem } 3319191783Srmacklem } else if (nd->nd_repstat == NFSERR_NOENT) { 3320191783Srmacklem /* 3321191783Srmacklem * Lookupp returns NFSERR_NOENT when we are 3322191783Srmacklem * at the root, so just use the current dir. 3323191783Srmacklem */ 3324191783Srmacklem nd->nd_repstat = 0; 3325191783Srmacklem dotdotfileid = dotfileid; 3326191783Srmacklem } else { 3327191783Srmacklem error = nd->nd_repstat; 3328191783Srmacklem } 3329191783Srmacklem mbuf_freem(nd->nd_mrep); 3330191783Srmacklem if (error) 3331191783Srmacklem return (error); 3332191783Srmacklem nd->nd_mrep = NULL; 3333191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3334191783Srmacklem dp->d_type = DT_DIR; 3335191783Srmacklem dp->d_fileno = dotfileid; 3336191783Srmacklem dp->d_namlen = 1; 3337191783Srmacklem dp->d_name[0] = '.'; 3338191783Srmacklem dp->d_name[1] = '\0'; 3339191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3340191783Srmacklem /* 3341191783Srmacklem * Just make these offset cookie 0. 3342191783Srmacklem */ 3343191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3344191783Srmacklem *tl++ = 0; 3345191783Srmacklem *tl = 0; 3346191783Srmacklem blksiz += dp->d_reclen; 3347191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 3348191783Srmacklem uiop->uio_offset += dp->d_reclen; 3349191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 3350191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 3351191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3352191783Srmacklem dp->d_type = DT_DIR; 3353191783Srmacklem dp->d_fileno = dotdotfileid; 3354191783Srmacklem dp->d_namlen = 2; 3355191783Srmacklem dp->d_name[0] = '.'; 3356191783Srmacklem dp->d_name[1] = '.'; 3357191783Srmacklem dp->d_name[2] = '\0'; 3358191783Srmacklem dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3359191783Srmacklem /* 3360191783Srmacklem * Just make these offset cookie 0. 3361191783Srmacklem */ 3362191783Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3363191783Srmacklem *tl++ = 0; 3364191783Srmacklem *tl = 0; 3365191783Srmacklem blksiz += dp->d_reclen; 3366191783Srmacklem uio_uio_resid_add(uiop, -(dp->d_reclen)); 3367191783Srmacklem uiop->uio_offset += dp->d_reclen; 3368191783Srmacklem uio_iov_base_add(uiop, dp->d_reclen); 3369191783Srmacklem uio_iov_len_add(uiop, -(dp->d_reclen)); 3370191783Srmacklem } 3371191783Srmacklem NFSREADDIRPLUS_ATTRBIT(&attrbits); 3372191783Srmacklem if (gotmnton) 3373191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, 3374191783Srmacklem NFSATTRBIT_MOUNTEDONFILEID); 3375191783Srmacklem } 3376191783Srmacklem 3377191783Srmacklem /* 3378191783Srmacklem * Loop around doing readdir rpc's of size nm_readdirsize. 3379191783Srmacklem * The stopping criteria is EOF or buffer full. 3380191783Srmacklem */ 3381191783Srmacklem while (more_dirs && bigenough) { 3382191783Srmacklem *attrflagp = 0; 3383191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3384191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3385191783Srmacklem *tl++ = cookie.lval[0]; 3386191783Srmacklem *tl++ = cookie.lval[1]; 3387191783Srmacklem if (cookie.qval == 0) { 3388191783Srmacklem *tl++ = 0; 3389191783Srmacklem *tl++ = 0; 3390191783Srmacklem } else { 3391191783Srmacklem NFSLOCKNODE(dnp); 3392191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3393191783Srmacklem *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3394191783Srmacklem NFSUNLOCKNODE(dnp); 3395191783Srmacklem } 3396191783Srmacklem *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3397191783Srmacklem *tl = txdr_unsigned(nmp->nm_readdirsize); 3398191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3399191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3400191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3401191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3402191783Srmacklem (void) nfsrv_putattrbit(nd, &dattrbits); 3403191783Srmacklem } 3404191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3405191783Srmacklem if (error) 3406191783Srmacklem return (error); 3407191783Srmacklem if (nd->nd_flag & ND_NFSV3) 3408191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3409191783Srmacklem if (nd->nd_repstat || error) { 3410191783Srmacklem if (!error) 3411191783Srmacklem error = nd->nd_repstat; 3412191783Srmacklem goto nfsmout; 3413191783Srmacklem } 3414232420Srmacklem if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 3415232420Srmacklem dctime = nap->na_ctime; 3416191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3417191783Srmacklem NFSLOCKNODE(dnp); 3418191783Srmacklem dnp->n_cookieverf.nfsuquad[0] = *tl++; 3419191783Srmacklem dnp->n_cookieverf.nfsuquad[1] = *tl++; 3420191783Srmacklem NFSUNLOCKNODE(dnp); 3421191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3422191783Srmacklem if (!more_dirs) 3423191783Srmacklem tryformoredirs = 0; 3424191783Srmacklem 3425298788Spfg /* loop through the dir entries, doctoring them to 4bsd form */ 3426191783Srmacklem while (more_dirs && bigenough) { 3427191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3428191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3429191783Srmacklem ncookie.lval[0] = *tl++; 3430191783Srmacklem ncookie.lval[1] = *tl++; 3431191783Srmacklem } else { 3432191783Srmacklem fileno = fxdr_unsigned(long, *++tl); 3433191783Srmacklem tl++; 3434191783Srmacklem } 3435191783Srmacklem len = fxdr_unsigned(int, *tl); 3436191783Srmacklem if (len <= 0 || len > NFS_MAXNAMLEN) { 3437191783Srmacklem error = EBADRPC; 3438191783Srmacklem goto nfsmout; 3439191783Srmacklem } 3440191783Srmacklem tlen = NFSM_RNDUP(len); 3441191783Srmacklem if (tlen == len) 3442191783Srmacklem tlen += 4; /* To ensure null termination */ 3443191783Srmacklem left = DIRBLKSIZ - blksiz; 3444191783Srmacklem if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) { 3445341074Smarkj NFSBZERO(uio_iov_base(uiop), left); 3446191783Srmacklem dp->d_reclen += left; 3447191783Srmacklem uio_iov_base_add(uiop, left); 3448191783Srmacklem uio_iov_len_add(uiop, -(left)); 3449191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3450191783Srmacklem uiop->uio_offset += left; 3451191783Srmacklem blksiz = 0; 3452191783Srmacklem } 3453191783Srmacklem if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 3454191783Srmacklem bigenough = 0; 3455191783Srmacklem if (bigenough) { 3456191783Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3457191783Srmacklem dp->d_namlen = len; 3458191783Srmacklem dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 3459191783Srmacklem dp->d_type = DT_UNKNOWN; 3460191783Srmacklem blksiz += dp->d_reclen; 3461191783Srmacklem if (blksiz == DIRBLKSIZ) 3462191783Srmacklem blksiz = 0; 3463191783Srmacklem uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3464191783Srmacklem uiop->uio_offset += DIRHDSIZ; 3465191783Srmacklem uio_iov_base_add(uiop, DIRHDSIZ); 3466191783Srmacklem uio_iov_len_add(uiop, -(DIRHDSIZ)); 3467191783Srmacklem cnp->cn_nameptr = uio_iov_base(uiop); 3468191783Srmacklem cnp->cn_namelen = len; 3469191783Srmacklem NFSCNHASHZERO(cnp); 3470191783Srmacklem error = nfsm_mbufuio(nd, uiop, len); 3471191783Srmacklem if (error) 3472191783Srmacklem goto nfsmout; 3473191783Srmacklem cp = uio_iov_base(uiop); 3474191783Srmacklem tlen -= len; 3475341074Smarkj NFSBZERO(cp, tlen); 3476191783Srmacklem cp += tlen; /* points to cookie storage */ 3477191783Srmacklem tl2 = (u_int32_t *)cp; 3478220735Srmacklem if (len == 2 && cnp->cn_nameptr[0] == '.' && 3479220735Srmacklem cnp->cn_nameptr[1] == '.') 3480220735Srmacklem isdotdot = 1; 3481220735Srmacklem else 3482220735Srmacklem isdotdot = 0; 3483191783Srmacklem uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3484191783Srmacklem uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3485191783Srmacklem uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3486191783Srmacklem uiop->uio_offset += (tlen + NFSX_HYPER); 3487191783Srmacklem } else { 3488191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3489191783Srmacklem if (error) 3490191783Srmacklem goto nfsmout; 3491191783Srmacklem } 3492191783Srmacklem nfhp = NULL; 3493191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 3494191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3495191783Srmacklem ncookie.lval[0] = *tl++; 3496191783Srmacklem ncookie.lval[1] = *tl++; 3497191783Srmacklem attrflag = fxdr_unsigned(int, *tl); 3498191783Srmacklem if (attrflag) { 3499191783Srmacklem error = nfsm_loadattr(nd, &nfsva); 3500191783Srmacklem if (error) 3501191783Srmacklem goto nfsmout; 3502191783Srmacklem } 3503191783Srmacklem NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3504191783Srmacklem if (*tl) { 3505191783Srmacklem error = nfsm_getfh(nd, &nfhp); 3506191783Srmacklem if (error) 3507191783Srmacklem goto nfsmout; 3508191783Srmacklem } 3509191783Srmacklem if (!attrflag && nfhp != NULL) { 3510191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3511191783Srmacklem nfhp = NULL; 3512191783Srmacklem } 3513191783Srmacklem } else { 3514191783Srmacklem rderr = 0; 3515191783Srmacklem nfsva.na_mntonfileno = 0xffffffff; 3516191783Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3517191783Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3518191783Srmacklem NULL, NULL, &rderr, p, cred); 3519191783Srmacklem if (error) 3520191783Srmacklem goto nfsmout; 3521191783Srmacklem } 3522191783Srmacklem 3523191783Srmacklem if (bigenough) { 3524191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3525191783Srmacklem if (rderr) { 3526191783Srmacklem dp->d_fileno = 0; 3527191783Srmacklem } else if (gotmnton) { 3528191783Srmacklem if (nfsva.na_mntonfileno != 0xffffffff) 3529191783Srmacklem dp->d_fileno = nfsva.na_mntonfileno; 3530191783Srmacklem else 3531191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3532191783Srmacklem } else if (nfsva.na_filesid[0] == 3533191783Srmacklem dnp->n_vattr.na_filesid[0] && 3534191783Srmacklem nfsva.na_filesid[1] == 3535191783Srmacklem dnp->n_vattr.na_filesid[1]) { 3536191783Srmacklem dp->d_fileno = nfsva.na_fileid; 3537191783Srmacklem } else { 3538191783Srmacklem do { 3539191783Srmacklem fakefileno--; 3540191783Srmacklem } while (fakefileno == 3541191783Srmacklem nfsva.na_fileid); 3542191783Srmacklem dp->d_fileno = fakefileno; 3543191783Srmacklem } 3544191783Srmacklem } else { 3545191783Srmacklem dp->d_fileno = fileno; 3546191783Srmacklem } 3547191783Srmacklem *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3548191783Srmacklem ncookie.lval[0]; 3549191783Srmacklem *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3550191783Srmacklem ncookie.lval[1]; 3551191783Srmacklem 3552191783Srmacklem if (nfhp != NULL) { 3553191783Srmacklem if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3554191783Srmacklem dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3555191783Srmacklem VREF(vp); 3556191783Srmacklem newvp = vp; 3557191783Srmacklem unlocknewvp = 0; 3558191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3559191783Srmacklem np = dnp; 3560220735Srmacklem } else if (isdotdot != 0) { 3561220735Srmacklem /* 3562220735Srmacklem * Skip doing a nfscl_nget() call for "..". 3563220735Srmacklem * There's a race between acquiring the nfs 3564220735Srmacklem * node here and lookups that look for the 3565220735Srmacklem * directory being read (in the parent). 3566220735Srmacklem * It would try to get a lock on ".." here, 3567220735Srmacklem * owning the lock on the directory being 3568220735Srmacklem * read. Lookup will hold the lock on ".." 3569220735Srmacklem * and try to acquire the lock on the 3570220735Srmacklem * directory being read. 3571220735Srmacklem * If the directory is unlocked/relocked, 3572220735Srmacklem * then there is a LOR with the buflock 3573220735Srmacklem * vp is relocked. 3574220735Srmacklem */ 3575220735Srmacklem free(nfhp, M_NFSFH); 3576191783Srmacklem } else { 3577191783Srmacklem error = nfscl_nget(vnode_mount(vp), vp, 3578220732Srmacklem nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 3579191783Srmacklem if (!error) { 3580191783Srmacklem newvp = NFSTOV(np); 3581191783Srmacklem unlocknewvp = 1; 3582191783Srmacklem } 3583191783Srmacklem } 3584191783Srmacklem nfhp = NULL; 3585191783Srmacklem if (newvp != NULLVP) { 3586191783Srmacklem error = nfscl_loadattrcache(&newvp, 3587191783Srmacklem &nfsva, NULL, NULL, 0, 0); 3588191783Srmacklem if (error) { 3589191783Srmacklem if (unlocknewvp) 3590191783Srmacklem vput(newvp); 3591191783Srmacklem else 3592191783Srmacklem vrele(newvp); 3593191783Srmacklem goto nfsmout; 3594191783Srmacklem } 3595191783Srmacklem dp->d_type = 3596191783Srmacklem vtonfs_dtype(np->n_vattr.na_type); 3597191783Srmacklem ndp->ni_vp = newvp; 3598191783Srmacklem NFSCNHASH(cnp, HASHINIT); 3599232420Srmacklem if (cnp->cn_namelen <= NCHNAMLEN && 3600232420Srmacklem (newvp->v_type != VDIR || 3601232420Srmacklem dctime.tv_sec != 0)) { 3602230394Sjhb cache_enter_time(ndp->ni_dvp, 3603230394Sjhb ndp->ni_vp, cnp, 3604232420Srmacklem &nfsva.na_ctime, 3605232420Srmacklem newvp->v_type != VDIR ? NULL : 3606232420Srmacklem &dctime); 3607191783Srmacklem } 3608191783Srmacklem if (unlocknewvp) 3609191783Srmacklem vput(newvp); 3610191783Srmacklem else 3611191783Srmacklem vrele(newvp); 3612191783Srmacklem newvp = NULLVP; 3613191783Srmacklem } 3614191783Srmacklem } 3615191783Srmacklem } else if (nfhp != NULL) { 3616191783Srmacklem FREE((caddr_t)nfhp, M_NFSFH); 3617191783Srmacklem } 3618191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3619191783Srmacklem more_dirs = fxdr_unsigned(int, *tl); 3620191783Srmacklem } 3621191783Srmacklem /* 3622191783Srmacklem * If at end of rpc data, get the eof boolean 3623191783Srmacklem */ 3624191783Srmacklem if (!more_dirs) { 3625191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3626191783Srmacklem eof = fxdr_unsigned(int, *tl); 3627191783Srmacklem if (tryformoredirs) 3628191783Srmacklem more_dirs = !eof; 3629191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3630191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, 3631191783Srmacklem stuff); 3632191783Srmacklem if (error) 3633191783Srmacklem goto nfsmout; 3634191783Srmacklem } 3635191783Srmacklem } 3636191783Srmacklem mbuf_freem(nd->nd_mrep); 3637191783Srmacklem nd->nd_mrep = NULL; 3638191783Srmacklem } 3639191783Srmacklem /* 3640191783Srmacklem * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3641191783Srmacklem * by increasing d_reclen for the last record. 3642191783Srmacklem */ 3643191783Srmacklem if (blksiz > 0) { 3644191783Srmacklem left = DIRBLKSIZ - blksiz; 3645341074Smarkj NFSBZERO(uio_iov_base(uiop), left); 3646191783Srmacklem dp->d_reclen += left; 3647191783Srmacklem uio_iov_base_add(uiop, left); 3648191783Srmacklem uio_iov_len_add(uiop, -(left)); 3649191783Srmacklem uio_uio_resid_add(uiop, -(left)); 3650191783Srmacklem uiop->uio_offset += left; 3651191783Srmacklem } 3652191783Srmacklem 3653191783Srmacklem /* 3654191783Srmacklem * If returning no data, assume end of file. 3655191783Srmacklem * If not bigenough, return not end of file, since you aren't 3656191783Srmacklem * returning all the data 3657191783Srmacklem * Otherwise, return the eof flag from the server. 3658191783Srmacklem */ 3659191783Srmacklem if (eofp != NULL) { 3660191783Srmacklem if (tresid == uio_uio_resid(uiop)) 3661191783Srmacklem *eofp = 1; 3662191783Srmacklem else if (!bigenough) 3663191783Srmacklem *eofp = 0; 3664191783Srmacklem else 3665191783Srmacklem *eofp = eof; 3666191783Srmacklem } 3667191783Srmacklem 3668291117Srmacklem /* 3669291117Srmacklem * Add extra empty records to any remaining DIRBLKSIZ chunks. 3670291117Srmacklem */ 3671291117Srmacklem while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3672291117Srmacklem dp = (struct dirent *)uio_iov_base(uiop); 3673341074Smarkj NFSBZERO(dp, DIRBLKSIZ); 3674291117Srmacklem dp->d_type = DT_UNKNOWN; 3675291117Srmacklem tl = (u_int32_t *)&dp->d_name[4]; 3676291117Srmacklem *tl++ = cookie.lval[0]; 3677291117Srmacklem *tl = cookie.lval[1]; 3678291117Srmacklem dp->d_reclen = DIRBLKSIZ; 3679291117Srmacklem uio_iov_base_add(uiop, DIRBLKSIZ); 3680291117Srmacklem uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3681291117Srmacklem uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3682291117Srmacklem uiop->uio_offset += DIRBLKSIZ; 3683291117Srmacklem } 3684291117Srmacklem 3685191783Srmacklemnfsmout: 3686191783Srmacklem if (nd->nd_mrep != NULL) 3687191783Srmacklem mbuf_freem(nd->nd_mrep); 3688191783Srmacklem return (error); 3689191783Srmacklem} 3690191783Srmacklem#endif /* !APPLE */ 3691191783Srmacklem 3692191783Srmacklem/* 3693191783Srmacklem * Nfs commit rpc 3694191783Srmacklem */ 3695361236Sfreqlabsint 3696191783Srmacklemnfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 3697244042Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 3698191783Srmacklem{ 3699191783Srmacklem u_int32_t *tl; 3700191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3701191783Srmacklem nfsattrbit_t attrbits; 3702191783Srmacklem int error; 3703244042Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3704191783Srmacklem 3705191783Srmacklem *attrflagp = 0; 3706191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 3707191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3708191783Srmacklem txdr_hyper(offset, tl); 3709191783Srmacklem tl += 2; 3710191783Srmacklem *tl = txdr_unsigned(cnt); 3711191783Srmacklem if (nd->nd_flag & ND_NFSV4) { 3712191783Srmacklem /* 3713191783Srmacklem * And do a Getattr op. 3714191783Srmacklem */ 3715191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3716191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 3717191783Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 3718191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 3719191783Srmacklem } 3720191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 3721191783Srmacklem if (error) 3722191783Srmacklem return (error); 3723191783Srmacklem error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 3724191783Srmacklem if (!error && !nd->nd_repstat) { 3725191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3726244042Srmacklem NFSLOCKMNT(nmp); 3727244042Srmacklem if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { 3728244042Srmacklem NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 3729244042Srmacklem nd->nd_repstat = NFSERR_STALEWRITEVERF; 3730244042Srmacklem } 3731244042Srmacklem NFSUNLOCKMNT(nmp); 3732191783Srmacklem if (nd->nd_flag & ND_NFSV4) 3733191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3734191783Srmacklem } 3735191783Srmacklemnfsmout: 3736191783Srmacklem if (!error && nd->nd_repstat) 3737191783Srmacklem error = nd->nd_repstat; 3738191783Srmacklem mbuf_freem(nd->nd_mrep); 3739191783Srmacklem return (error); 3740191783Srmacklem} 3741191783Srmacklem 3742191783Srmacklem/* 3743191783Srmacklem * NFS byte range lock rpc. 3744191783Srmacklem * (Mostly just calls one of the three lower level RPC routines.) 3745191783Srmacklem */ 3746361236Sfreqlabsint 3747191783Srmacklemnfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 3748222719Srmacklem int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3749191783Srmacklem{ 3750191783Srmacklem struct nfscllockowner *lp; 3751191783Srmacklem struct nfsclclient *clp; 3752191783Srmacklem struct nfsfh *nfhp; 3753191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 3754191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3755191783Srmacklem u_int64_t off, len; 3756191783Srmacklem off_t start, end; 3757191783Srmacklem u_int32_t clidrev = 0; 3758191783Srmacklem int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 3759191783Srmacklem int callcnt, dorpc; 3760191783Srmacklem 3761191783Srmacklem /* 3762191783Srmacklem * Convert the flock structure into a start and end and do POSIX 3763191783Srmacklem * bounds checking. 3764191783Srmacklem */ 3765191783Srmacklem switch (fl->l_whence) { 3766191783Srmacklem case SEEK_SET: 3767191783Srmacklem case SEEK_CUR: 3768191783Srmacklem /* 3769191783Srmacklem * Caller is responsible for adding any necessary offset 3770191783Srmacklem * when SEEK_CUR is used. 3771191783Srmacklem */ 3772191783Srmacklem start = fl->l_start; 3773191783Srmacklem off = fl->l_start; 3774191783Srmacklem break; 3775191783Srmacklem case SEEK_END: 3776191783Srmacklem start = size + fl->l_start; 3777191783Srmacklem off = size + fl->l_start; 3778191783Srmacklem break; 3779191783Srmacklem default: 3780191783Srmacklem return (EINVAL); 3781297793Spfg } 3782191783Srmacklem if (start < 0) 3783191783Srmacklem return (EINVAL); 3784191783Srmacklem if (fl->l_len != 0) { 3785191783Srmacklem end = start + fl->l_len - 1; 3786191783Srmacklem if (end < start) 3787191783Srmacklem return (EINVAL); 3788191783Srmacklem } 3789191783Srmacklem 3790191783Srmacklem len = fl->l_len; 3791191783Srmacklem if (len == 0) 3792191783Srmacklem len = NFS64BITSSET; 3793191783Srmacklem retrycnt = 0; 3794191783Srmacklem do { 3795191783Srmacklem nd->nd_repstat = 0; 3796191783Srmacklem if (op == F_GETLK) { 3797244042Srmacklem error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3798191783Srmacklem if (error) 3799191783Srmacklem return (error); 3800222719Srmacklem error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 3801191783Srmacklem if (!error) { 3802191783Srmacklem clidrev = clp->nfsc_clientidrev; 3803191783Srmacklem error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 3804222719Srmacklem p, id, flags); 3805191783Srmacklem } else if (error == -1) { 3806191783Srmacklem error = 0; 3807191783Srmacklem } 3808191783Srmacklem nfscl_clientrelease(clp); 3809191783Srmacklem } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 3810191783Srmacklem /* 3811191783Srmacklem * We must loop around for all lockowner cases. 3812191783Srmacklem */ 3813191783Srmacklem callcnt = 0; 3814244042Srmacklem error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3815191783Srmacklem if (error) 3816191783Srmacklem return (error); 3817191783Srmacklem do { 3818191783Srmacklem error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 3819222719Srmacklem clp, id, flags, &lp, &dorpc); 3820191783Srmacklem /* 3821191783Srmacklem * If it returns a NULL lp, we're done. 3822191783Srmacklem */ 3823191783Srmacklem if (lp == NULL) { 3824191783Srmacklem if (callcnt == 0) 3825191783Srmacklem nfscl_clientrelease(clp); 3826191783Srmacklem else 3827222719Srmacklem nfscl_releasealllocks(clp, vp, p, id, flags); 3828191783Srmacklem return (error); 3829191783Srmacklem } 3830191783Srmacklem if (nmp->nm_clp != NULL) 3831191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 3832191783Srmacklem else 3833191783Srmacklem clidrev = 0; 3834191783Srmacklem /* 3835191783Srmacklem * If the server doesn't support Posix lock semantics, 3836191783Srmacklem * only allow locks on the entire file, since it won't 3837191783Srmacklem * handle overlapping byte ranges. 3838191783Srmacklem * There might still be a problem when a lock 3839191783Srmacklem * upgrade/downgrade (read<->write) occurs, since the 3840191783Srmacklem * server "might" expect an unlock first? 3841191783Srmacklem */ 3842191783Srmacklem if (dorpc && (lp->nfsl_open->nfso_posixlock || 3843191783Srmacklem (off == 0 && len == NFS64BITSSET))) { 3844191783Srmacklem /* 3845191783Srmacklem * Since the lock records will go away, we must 3846191783Srmacklem * wait for grace and delay here. 3847191783Srmacklem */ 3848191783Srmacklem do { 3849191783Srmacklem error = nfsrpc_locku(nd, nmp, lp, off, len, 3850191783Srmacklem NFSV4LOCKT_READ, cred, p, 0); 3851191783Srmacklem if ((nd->nd_repstat == NFSERR_GRACE || 3852191783Srmacklem nd->nd_repstat == NFSERR_DELAY) && 3853191783Srmacklem error == 0) 3854207170Srmacklem (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3855207170Srmacklem "nfs_advlock"); 3856191783Srmacklem } while ((nd->nd_repstat == NFSERR_GRACE || 3857191783Srmacklem nd->nd_repstat == NFSERR_DELAY) && error == 0); 3858191783Srmacklem } 3859191783Srmacklem callcnt++; 3860191783Srmacklem } while (error == 0 && nd->nd_repstat == 0); 3861222719Srmacklem nfscl_releasealllocks(clp, vp, p, id, flags); 3862191783Srmacklem } else if (op == F_SETLK) { 3863191783Srmacklem error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 3864222719Srmacklem NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 3865191783Srmacklem if (error || donelocally) { 3866191783Srmacklem return (error); 3867191783Srmacklem } 3868191783Srmacklem if (nmp->nm_clp != NULL) 3869191783Srmacklem clidrev = nmp->nm_clp->nfsc_clientidrev; 3870191783Srmacklem else 3871191783Srmacklem clidrev = 0; 3872191783Srmacklem nfhp = VTONFS(vp)->n_fhp; 3873191783Srmacklem if (!lp->nfsl_open->nfso_posixlock && 3874191783Srmacklem (off != 0 || len != NFS64BITSSET)) { 3875191783Srmacklem error = EINVAL; 3876191783Srmacklem } else { 3877191783Srmacklem error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 3878191783Srmacklem nfhp->nfh_len, lp, newone, reclaim, off, 3879191783Srmacklem len, fl->l_type, cred, p, 0); 3880191783Srmacklem } 3881191783Srmacklem if (!error) 3882191783Srmacklem error = nd->nd_repstat; 3883191783Srmacklem nfscl_lockrelease(lp, error, newone); 3884191783Srmacklem } else { 3885191783Srmacklem error = EINVAL; 3886191783Srmacklem } 3887191783Srmacklem if (!error) 3888191783Srmacklem error = nd->nd_repstat; 3889191783Srmacklem if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 3890191783Srmacklem error == NFSERR_STALEDONTRECOVER || 3891244042Srmacklem error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3892244042Srmacklem error == NFSERR_BADSESSION) { 3893207170Srmacklem (void) nfs_catnap(PZERO, error, "nfs_advlock"); 3894191783Srmacklem } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 3895191783Srmacklem && clidrev != 0) { 3896191783Srmacklem expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 3897191783Srmacklem retrycnt++; 3898191783Srmacklem } 3899191783Srmacklem } while (error == NFSERR_GRACE || 3900191783Srmacklem error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3901191783Srmacklem error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 3902244042Srmacklem error == NFSERR_BADSESSION || 3903191783Srmacklem ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 3904191783Srmacklem expireret == 0 && clidrev != 0 && retrycnt < 4)); 3905191783Srmacklem if (error && retrycnt >= 4) 3906191783Srmacklem error = EIO; 3907191783Srmacklem return (error); 3908191783Srmacklem} 3909191783Srmacklem 3910191783Srmacklem/* 3911191783Srmacklem * The lower level routine for the LockT case. 3912191783Srmacklem */ 3913361236Sfreqlabsint 3914191783Srmacklemnfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 3915191783Srmacklem struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 3916222719Srmacklem struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3917191783Srmacklem{ 3918191783Srmacklem u_int32_t *tl; 3919191783Srmacklem int error, type, size; 3920223747Srmacklem uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3921223747Srmacklem struct nfsnode *np; 3922244042Srmacklem struct nfsmount *nmp; 3923317393Srmacklem struct nfsclsession *tsep; 3924191783Srmacklem 3925244042Srmacklem nmp = VFSTONFS(vp->v_mount); 3926191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 3927191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3928191783Srmacklem if (fl->l_type == F_RDLCK) 3929191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3930191783Srmacklem else 3931191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3932191783Srmacklem txdr_hyper(off, tl); 3933191783Srmacklem tl += 2; 3934191783Srmacklem txdr_hyper(len, tl); 3935191783Srmacklem tl += 2; 3936317393Srmacklem tsep = nfsmnt_mdssession(nmp); 3937317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 3938317393Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 3939222719Srmacklem nfscl_filllockowner(id, own, flags); 3940223747Srmacklem np = VTONFS(vp); 3941223747Srmacklem NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 3942223747Srmacklem np->n_fhp->nfh_len); 3943223747Srmacklem (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 3944191783Srmacklem error = nfscl_request(nd, vp, p, cred, NULL); 3945191783Srmacklem if (error) 3946191783Srmacklem return (error); 3947191783Srmacklem if (nd->nd_repstat == 0) { 3948191783Srmacklem fl->l_type = F_UNLCK; 3949191783Srmacklem } else if (nd->nd_repstat == NFSERR_DENIED) { 3950191783Srmacklem nd->nd_repstat = 0; 3951191783Srmacklem fl->l_whence = SEEK_SET; 3952191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3953191783Srmacklem fl->l_start = fxdr_hyper(tl); 3954191783Srmacklem tl += 2; 3955191783Srmacklem len = fxdr_hyper(tl); 3956191783Srmacklem tl += 2; 3957191783Srmacklem if (len == NFS64BITSSET) 3958191783Srmacklem fl->l_len = 0; 3959191783Srmacklem else 3960191783Srmacklem fl->l_len = len; 3961191783Srmacklem type = fxdr_unsigned(int, *tl++); 3962191783Srmacklem if (type == NFSV4LOCKT_WRITE) 3963191783Srmacklem fl->l_type = F_WRLCK; 3964191783Srmacklem else 3965191783Srmacklem fl->l_type = F_RDLCK; 3966191783Srmacklem /* 3967191783Srmacklem * XXX For now, I have no idea what to do with the 3968191783Srmacklem * conflicting lock_owner, so I'll just set the pid == 0 3969191783Srmacklem * and skip over the lock_owner. 3970191783Srmacklem */ 3971191783Srmacklem fl->l_pid = (pid_t)0; 3972191783Srmacklem tl += 2; 3973191783Srmacklem size = fxdr_unsigned(int, *tl); 3974191783Srmacklem if (size < 0 || size > NFSV4_OPAQUELIMIT) 3975191783Srmacklem error = EBADRPC; 3976191783Srmacklem if (!error) 3977191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3978317393Srmacklem } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 3979191783Srmacklem nfscl_initiate_recovery(clp); 3980191783Srmacklemnfsmout: 3981191783Srmacklem mbuf_freem(nd->nd_mrep); 3982191783Srmacklem return (error); 3983191783Srmacklem} 3984191783Srmacklem 3985191783Srmacklem/* 3986191783Srmacklem * Lower level function that performs the LockU RPC. 3987191783Srmacklem */ 3988191783Srmacklemstatic int 3989191783Srmacklemnfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 3990191783Srmacklem struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 3991191783Srmacklem u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 3992191783Srmacklem{ 3993191783Srmacklem u_int32_t *tl; 3994191783Srmacklem int error; 3995191783Srmacklem 3996191783Srmacklem nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 3997244042Srmacklem lp->nfsl_open->nfso_fhlen, NULL, NULL); 3998191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3999191783Srmacklem *tl++ = txdr_unsigned(type); 4000191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid); 4001191783Srmacklem if (nfstest_outofseq && 4002191783Srmacklem (arc4random() % nfstest_outofseq) == 0) 4003191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4004191783Srmacklem tl++; 4005244042Srmacklem if (NFSHASNFSV4N(nmp)) 4006244042Srmacklem *tl++ = 0; 4007244042Srmacklem else 4008244042Srmacklem *tl++ = lp->nfsl_stateid.seqid; 4009191783Srmacklem *tl++ = lp->nfsl_stateid.other[0]; 4010191783Srmacklem *tl++ = lp->nfsl_stateid.other[1]; 4011191783Srmacklem *tl++ = lp->nfsl_stateid.other[2]; 4012191783Srmacklem txdr_hyper(off, tl); 4013191783Srmacklem tl += 2; 4014191783Srmacklem txdr_hyper(len, tl); 4015191783Srmacklem if (syscred) 4016191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4017191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4018244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4019191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4020191783Srmacklem if (error) 4021191783Srmacklem return (error); 4022191783Srmacklem if (nd->nd_repstat == 0) { 4023191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4024191783Srmacklem lp->nfsl_stateid.seqid = *tl++; 4025191783Srmacklem lp->nfsl_stateid.other[0] = *tl++; 4026191783Srmacklem lp->nfsl_stateid.other[1] = *tl++; 4027191783Srmacklem lp->nfsl_stateid.other[2] = *tl; 4028317393Srmacklem } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4029191783Srmacklem nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4030191783Srmacklemnfsmout: 4031191783Srmacklem mbuf_freem(nd->nd_mrep); 4032191783Srmacklem return (error); 4033191783Srmacklem} 4034191783Srmacklem 4035191783Srmacklem/* 4036191783Srmacklem * The actual Lock RPC. 4037191783Srmacklem */ 4038361236Sfreqlabsint 4039191783Srmacklemnfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 4040191783Srmacklem u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 4041191783Srmacklem int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 4042191783Srmacklem NFSPROC_T *p, int syscred) 4043191783Srmacklem{ 4044191783Srmacklem u_int32_t *tl; 4045191783Srmacklem int error, size; 4046223747Srmacklem uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4047317393Srmacklem struct nfsclsession *tsep; 4048191783Srmacklem 4049244042Srmacklem nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL); 4050191783Srmacklem NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4051191783Srmacklem if (type == F_RDLCK) 4052191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4053191783Srmacklem else 4054191783Srmacklem *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4055191783Srmacklem *tl++ = txdr_unsigned(reclaim); 4056191783Srmacklem txdr_hyper(off, tl); 4057191783Srmacklem tl += 2; 4058191783Srmacklem txdr_hyper(len, tl); 4059191783Srmacklem tl += 2; 4060191783Srmacklem if (newone) { 4061191783Srmacklem *tl = newnfs_true; 4062191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 4063191783Srmacklem 2 * NFSX_UNSIGNED + NFSX_HYPER); 4064191783Srmacklem *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 4065244042Srmacklem if (NFSHASNFSV4N(nmp)) 4066244042Srmacklem *tl++ = 0; 4067244042Srmacklem else 4068244042Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.seqid; 4069191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 4070191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 4071191783Srmacklem *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 4072191783Srmacklem *tl++ = txdr_unsigned(lp->nfsl_seqid); 4073317393Srmacklem tsep = nfsmnt_mdssession(nmp); 4074317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 4075317393Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 4076223747Srmacklem NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4077223747Srmacklem NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4078223747Srmacklem (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4079191783Srmacklem } else { 4080191783Srmacklem *tl = newnfs_false; 4081191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 4082244042Srmacklem if (NFSHASNFSV4N(nmp)) 4083244042Srmacklem *tl++ = 0; 4084244042Srmacklem else 4085244042Srmacklem *tl++ = lp->nfsl_stateid.seqid; 4086191783Srmacklem *tl++ = lp->nfsl_stateid.other[0]; 4087191783Srmacklem *tl++ = lp->nfsl_stateid.other[1]; 4088191783Srmacklem *tl++ = lp->nfsl_stateid.other[2]; 4089191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid); 4090191783Srmacklem if (nfstest_outofseq && 4091191783Srmacklem (arc4random() % nfstest_outofseq) == 0) 4092191783Srmacklem *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4093191783Srmacklem } 4094191783Srmacklem if (syscred) 4095191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4096191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 4097244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4098191783Srmacklem if (error) 4099191783Srmacklem return (error); 4100191783Srmacklem if (newone) 4101191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 4102191783Srmacklem NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4103191783Srmacklem if (nd->nd_repstat == 0) { 4104191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4105191783Srmacklem lp->nfsl_stateid.seqid = *tl++; 4106191783Srmacklem lp->nfsl_stateid.other[0] = *tl++; 4107191783Srmacklem lp->nfsl_stateid.other[1] = *tl++; 4108191783Srmacklem lp->nfsl_stateid.other[2] = *tl; 4109191783Srmacklem } else if (nd->nd_repstat == NFSERR_DENIED) { 4110191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4111191783Srmacklem size = fxdr_unsigned(int, *(tl + 7)); 4112191783Srmacklem if (size < 0 || size > NFSV4_OPAQUELIMIT) 4113191783Srmacklem error = EBADRPC; 4114191783Srmacklem if (!error) 4115191783Srmacklem error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4116317393Srmacklem } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4117191783Srmacklem nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4118191783Srmacklemnfsmout: 4119191783Srmacklem mbuf_freem(nd->nd_mrep); 4120191783Srmacklem return (error); 4121191783Srmacklem} 4122191783Srmacklem 4123191783Srmacklem/* 4124191783Srmacklem * nfs statfs rpc 4125191783Srmacklem * (always called with the vp for the mount point) 4126191783Srmacklem */ 4127361236Sfreqlabsint 4128191783Srmacklemnfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 4129191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4130191783Srmacklem void *stuff) 4131191783Srmacklem{ 4132191783Srmacklem u_int32_t *tl = NULL; 4133191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4134191783Srmacklem struct nfsmount *nmp; 4135191783Srmacklem nfsattrbit_t attrbits; 4136191783Srmacklem int error; 4137191783Srmacklem 4138191783Srmacklem *attrflagp = 0; 4139191783Srmacklem nmp = VFSTONFS(vnode_mount(vp)); 4140191783Srmacklem if (NFSHASNFSV4(nmp)) { 4141191783Srmacklem /* 4142191783Srmacklem * For V4, you actually do a getattr. 4143191783Srmacklem */ 4144191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4145191783Srmacklem NFSSTATFS_GETATTRBIT(&attrbits); 4146191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 4147191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4148191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4149191783Srmacklem if (error) 4150191783Srmacklem return (error); 4151191783Srmacklem if (nd->nd_repstat == 0) { 4152191783Srmacklem error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4153191783Srmacklem NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 4154191783Srmacklem cred); 4155191783Srmacklem if (!error) { 4156191783Srmacklem nmp->nm_fsid[0] = nap->na_filesid[0]; 4157191783Srmacklem nmp->nm_fsid[1] = nap->na_filesid[1]; 4158191783Srmacklem NFSSETHASSETFSID(nmp); 4159191783Srmacklem *attrflagp = 1; 4160191783Srmacklem } 4161191783Srmacklem } else { 4162191783Srmacklem error = nd->nd_repstat; 4163191783Srmacklem } 4164191783Srmacklem if (error) 4165191783Srmacklem goto nfsmout; 4166191783Srmacklem } else { 4167191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 4168191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4169191783Srmacklem if (error) 4170191783Srmacklem return (error); 4171191783Srmacklem if (nd->nd_flag & ND_NFSV3) { 4172191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4173191783Srmacklem if (error) 4174191783Srmacklem goto nfsmout; 4175191783Srmacklem } 4176191783Srmacklem if (nd->nd_repstat) { 4177191783Srmacklem error = nd->nd_repstat; 4178191783Srmacklem goto nfsmout; 4179191783Srmacklem } 4180191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, 4181191783Srmacklem NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 4182191783Srmacklem } 4183191783Srmacklem if (NFSHASNFSV3(nmp)) { 4184191783Srmacklem sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 4185191783Srmacklem sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 4186191783Srmacklem sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 4187191783Srmacklem sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 4188191783Srmacklem sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 4189191783Srmacklem sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 4190191783Srmacklem sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 4191191783Srmacklem } else if (NFSHASNFSV4(nmp) == 0) { 4192191783Srmacklem sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 4193191783Srmacklem sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 4194191783Srmacklem sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 4195191783Srmacklem sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 4196191783Srmacklem sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 4197191783Srmacklem } 4198191783Srmacklemnfsmout: 4199191783Srmacklem mbuf_freem(nd->nd_mrep); 4200191783Srmacklem return (error); 4201191783Srmacklem} 4202191783Srmacklem 4203191783Srmacklem/* 4204191783Srmacklem * nfs pathconf rpc 4205191783Srmacklem */ 4206361236Sfreqlabsint 4207191783Srmacklemnfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 4208191783Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4209191783Srmacklem void *stuff) 4210191783Srmacklem{ 4211191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4212191783Srmacklem struct nfsmount *nmp; 4213191783Srmacklem u_int32_t *tl; 4214191783Srmacklem nfsattrbit_t attrbits; 4215191783Srmacklem int error; 4216191783Srmacklem 4217191783Srmacklem *attrflagp = 0; 4218191783Srmacklem nmp = VFSTONFS(vnode_mount(vp)); 4219191783Srmacklem if (NFSHASNFSV4(nmp)) { 4220191783Srmacklem /* 4221191783Srmacklem * For V4, you actually do a getattr. 4222191783Srmacklem */ 4223191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4224191783Srmacklem NFSPATHCONF_GETATTRBIT(&attrbits); 4225191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 4226191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4227191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4228191783Srmacklem if (error) 4229191783Srmacklem return (error); 4230191783Srmacklem if (nd->nd_repstat == 0) { 4231191783Srmacklem error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4232191783Srmacklem pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 4233191783Srmacklem cred); 4234191783Srmacklem if (!error) 4235191783Srmacklem *attrflagp = 1; 4236191783Srmacklem } else { 4237191783Srmacklem error = nd->nd_repstat; 4238191783Srmacklem } 4239191783Srmacklem } else { 4240191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 4241191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4242191783Srmacklem if (error) 4243191783Srmacklem return (error); 4244191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4245191783Srmacklem if (nd->nd_repstat && !error) 4246191783Srmacklem error = nd->nd_repstat; 4247191783Srmacklem if (!error) { 4248191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 4249191783Srmacklem pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 4250191783Srmacklem pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 4251191783Srmacklem pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 4252191783Srmacklem pc->pc_chownrestricted = 4253191783Srmacklem fxdr_unsigned(u_int32_t, *tl++); 4254191783Srmacklem pc->pc_caseinsensitive = 4255191783Srmacklem fxdr_unsigned(u_int32_t, *tl++); 4256191783Srmacklem pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 4257191783Srmacklem } 4258191783Srmacklem } 4259191783Srmacklemnfsmout: 4260191783Srmacklem mbuf_freem(nd->nd_mrep); 4261191783Srmacklem return (error); 4262191783Srmacklem} 4263191783Srmacklem 4264191783Srmacklem/* 4265191783Srmacklem * nfs version 3 fsinfo rpc call 4266191783Srmacklem */ 4267361236Sfreqlabsint 4268191783Srmacklemnfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 4269191783Srmacklem NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 4270191783Srmacklem{ 4271191783Srmacklem u_int32_t *tl; 4272191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4273191783Srmacklem int error; 4274191783Srmacklem 4275191783Srmacklem *attrflagp = 0; 4276191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 4277191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4278191783Srmacklem if (error) 4279191783Srmacklem return (error); 4280191783Srmacklem error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4281191783Srmacklem if (nd->nd_repstat && !error) 4282191783Srmacklem error = nd->nd_repstat; 4283191783Srmacklem if (!error) { 4284191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 4285191783Srmacklem fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 4286191783Srmacklem fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 4287191783Srmacklem fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 4288191783Srmacklem fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 4289191783Srmacklem fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 4290191783Srmacklem fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 4291191783Srmacklem fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 4292191783Srmacklem fsp->fs_maxfilesize = fxdr_hyper(tl); 4293191783Srmacklem tl += 2; 4294191783Srmacklem fxdr_nfsv3time(tl, &fsp->fs_timedelta); 4295191783Srmacklem tl += 2; 4296191783Srmacklem fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 4297191783Srmacklem } 4298191783Srmacklemnfsmout: 4299191783Srmacklem mbuf_freem(nd->nd_mrep); 4300191783Srmacklem return (error); 4301191783Srmacklem} 4302191783Srmacklem 4303191783Srmacklem/* 4304191783Srmacklem * This function performs the Renew RPC. 4305191783Srmacklem */ 4306361236Sfreqlabsint 4307244042Srmacklemnfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, 4308244042Srmacklem NFSPROC_T *p) 4309191783Srmacklem{ 4310191783Srmacklem u_int32_t *tl; 4311191783Srmacklem struct nfsrv_descript nfsd; 4312191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4313191783Srmacklem struct nfsmount *nmp; 4314191783Srmacklem int error; 4315244042Srmacklem struct nfssockreq *nrp; 4316317393Srmacklem struct nfsclsession *tsep; 4317191783Srmacklem 4318191783Srmacklem nmp = clp->nfsc_nmp; 4319191783Srmacklem if (nmp == NULL) 4320191783Srmacklem return (0); 4321317393Srmacklem if (dsp == NULL) 4322317393Srmacklem nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL); 4323317393Srmacklem else 4324317393Srmacklem nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, 4325317393Srmacklem &dsp->nfsclds_sess); 4326244042Srmacklem if (!NFSHASNFSV4N(nmp)) { 4327244042Srmacklem /* NFSv4.1 just uses a Sequence Op and not a Renew. */ 4328244042Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4329317393Srmacklem tsep = nfsmnt_mdssession(nmp); 4330317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 4331317393Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 4332244042Srmacklem } 4333317393Srmacklem nrp = NULL; 4334317393Srmacklem if (dsp != NULL) 4335317393Srmacklem nrp = dsp->nfsclds_sockp; 4336244042Srmacklem if (nrp == NULL) 4337244042Srmacklem /* If NULL, use the MDS socket. */ 4338244042Srmacklem nrp = &nmp->nm_sockreq; 4339191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4340317393Srmacklem if (dsp == NULL) 4341317393Srmacklem error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4342317393Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4343317393Srmacklem else 4344317393Srmacklem error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4345317393Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 4346191783Srmacklem if (error) 4347191783Srmacklem return (error); 4348191783Srmacklem error = nd->nd_repstat; 4349191783Srmacklem mbuf_freem(nd->nd_mrep); 4350191783Srmacklem return (error); 4351191783Srmacklem} 4352191783Srmacklem 4353191783Srmacklem/* 4354191783Srmacklem * This function performs the Releaselockowner RPC. 4355191783Srmacklem */ 4356361236Sfreqlabsint 4357191783Srmacklemnfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4358227760Srmacklem uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4359191783Srmacklem{ 4360191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4361191783Srmacklem u_int32_t *tl; 4362191783Srmacklem int error; 4363223747Srmacklem uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4364317393Srmacklem struct nfsclsession *tsep; 4365191783Srmacklem 4366244042Srmacklem if (NFSHASNFSV4N(nmp)) { 4367244042Srmacklem /* For NFSv4.1, do a FreeStateID. */ 4368244042Srmacklem nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, 4369244042Srmacklem NULL); 4370244042Srmacklem nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); 4371244042Srmacklem } else { 4372244042Srmacklem nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, 4373244042Srmacklem NULL); 4374244042Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4375317393Srmacklem tsep = nfsmnt_mdssession(nmp); 4376317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 4377317393Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 4378244042Srmacklem NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4379244042Srmacklem NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4380244042Srmacklem (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4381244042Srmacklem } 4382191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4383191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4384244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4385191783Srmacklem if (error) 4386191783Srmacklem return (error); 4387191783Srmacklem error = nd->nd_repstat; 4388191783Srmacklem mbuf_freem(nd->nd_mrep); 4389191783Srmacklem return (error); 4390191783Srmacklem} 4391191783Srmacklem 4392191783Srmacklem/* 4393191783Srmacklem * This function performs the Compound to get the mount pt FH. 4394191783Srmacklem */ 4395361236Sfreqlabsint 4396191783Srmacklemnfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4397191783Srmacklem NFSPROC_T *p) 4398191783Srmacklem{ 4399191783Srmacklem u_int32_t *tl; 4400191783Srmacklem struct nfsrv_descript nfsd; 4401191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4402191783Srmacklem u_char *cp, *cp2; 4403191783Srmacklem int error, cnt, len, setnil; 4404191783Srmacklem u_int32_t *opcntp; 4405191783Srmacklem 4406244042Srmacklem nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL); 4407191783Srmacklem cp = dirpath; 4408191783Srmacklem cnt = 0; 4409191783Srmacklem do { 4410191783Srmacklem setnil = 0; 4411191783Srmacklem while (*cp == '/') 4412191783Srmacklem cp++; 4413191783Srmacklem cp2 = cp; 4414191783Srmacklem while (*cp2 != '\0' && *cp2 != '/') 4415191783Srmacklem cp2++; 4416191783Srmacklem if (*cp2 == '/') { 4417191783Srmacklem setnil = 1; 4418191783Srmacklem *cp2 = '\0'; 4419191783Srmacklem } 4420191783Srmacklem if (cp2 != cp) { 4421191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4422191783Srmacklem *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4423191783Srmacklem nfsm_strtom(nd, cp, strlen(cp)); 4424191783Srmacklem cnt++; 4425191783Srmacklem } 4426191783Srmacklem if (setnil) 4427191783Srmacklem *cp2++ = '/'; 4428191783Srmacklem cp = cp2; 4429191783Srmacklem } while (*cp != '\0'); 4430244042Srmacklem if (NFSHASNFSV4N(nmp)) 4431244042Srmacklem /* Has a Sequence Op done by nfscl_reqstart(). */ 4432244042Srmacklem *opcntp = txdr_unsigned(3 + cnt); 4433244042Srmacklem else 4434244042Srmacklem *opcntp = txdr_unsigned(2 + cnt); 4435191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4436191783Srmacklem *tl = txdr_unsigned(NFSV4OP_GETFH); 4437191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4438191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4439244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4440191783Srmacklem if (error) 4441191783Srmacklem return (error); 4442191783Srmacklem if (nd->nd_repstat == 0) { 4443191783Srmacklem NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4444191783Srmacklem tl += (2 + 2 * cnt); 4445191783Srmacklem if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4446191783Srmacklem len > NFSX_FHMAX) { 4447191783Srmacklem nd->nd_repstat = NFSERR_BADXDR; 4448191783Srmacklem } else { 4449191783Srmacklem nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4450191783Srmacklem if (nd->nd_repstat == 0) 4451191783Srmacklem nmp->nm_fhsize = len; 4452191783Srmacklem } 4453191783Srmacklem } 4454191783Srmacklem error = nd->nd_repstat; 4455191783Srmacklemnfsmout: 4456191783Srmacklem mbuf_freem(nd->nd_mrep); 4457191783Srmacklem return (error); 4458191783Srmacklem} 4459191783Srmacklem 4460191783Srmacklem/* 4461191783Srmacklem * This function performs the Delegreturn RPC. 4462191783Srmacklem */ 4463361236Sfreqlabsint 4464191783Srmacklemnfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4465191783Srmacklem struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4466191783Srmacklem{ 4467191783Srmacklem u_int32_t *tl; 4468191783Srmacklem struct nfsrv_descript nfsd; 4469191783Srmacklem struct nfsrv_descript *nd = &nfsd; 4470191783Srmacklem int error; 4471191783Srmacklem 4472191783Srmacklem nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4473244042Srmacklem dp->nfsdl_fhlen, NULL, NULL); 4474191783Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4475244042Srmacklem if (NFSHASNFSV4N(nmp)) 4476244042Srmacklem *tl++ = 0; 4477244042Srmacklem else 4478244042Srmacklem *tl++ = dp->nfsdl_stateid.seqid; 4479191783Srmacklem *tl++ = dp->nfsdl_stateid.other[0]; 4480191783Srmacklem *tl++ = dp->nfsdl_stateid.other[1]; 4481191783Srmacklem *tl = dp->nfsdl_stateid.other[2]; 4482191783Srmacklem if (syscred) 4483191783Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4484191783Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4485244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4486191783Srmacklem if (error) 4487191783Srmacklem return (error); 4488191783Srmacklem error = nd->nd_repstat; 4489191783Srmacklem mbuf_freem(nd->nd_mrep); 4490191783Srmacklem return (error); 4491191783Srmacklem} 4492191783Srmacklem 4493191783Srmacklem/* 4494191783Srmacklem * nfs getacl call. 4495191783Srmacklem */ 4496361236Sfreqlabsint 4497191783Srmacklemnfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4498191783Srmacklem struct acl *aclp, void *stuff) 4499191783Srmacklem{ 4500191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4501191783Srmacklem int error; 4502191783Srmacklem nfsattrbit_t attrbits; 4503191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4504191783Srmacklem 4505191783Srmacklem if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4506191783Srmacklem return (EOPNOTSUPP); 4507191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4508191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 4509191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4510191783Srmacklem (void) nfsrv_putattrbit(nd, &attrbits); 4511191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4512191783Srmacklem if (error) 4513191783Srmacklem return (error); 4514191783Srmacklem if (!nd->nd_repstat) 4515191783Srmacklem error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4516191783Srmacklem NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4517191783Srmacklem else 4518191783Srmacklem error = nd->nd_repstat; 4519191783Srmacklem mbuf_freem(nd->nd_mrep); 4520191783Srmacklem return (error); 4521191783Srmacklem} 4522191783Srmacklem 4523191783Srmacklem/* 4524191783Srmacklem * nfs setacl call. 4525191783Srmacklem */ 4526361236Sfreqlabsint 4527191783Srmacklemnfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4528191783Srmacklem struct acl *aclp, void *stuff) 4529191783Srmacklem{ 4530191783Srmacklem int error; 4531191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4532191783Srmacklem 4533191783Srmacklem if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4534191783Srmacklem return (EOPNOTSUPP); 4535191783Srmacklem error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4536191783Srmacklem return (error); 4537191783Srmacklem} 4538191783Srmacklem 4539191783Srmacklem/* 4540191783Srmacklem * nfs setacl call. 4541191783Srmacklem */ 4542191783Srmacklemstatic int 4543191783Srmacklemnfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4544191783Srmacklem struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 4545191783Srmacklem{ 4546191783Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4547191783Srmacklem int error; 4548191783Srmacklem nfsattrbit_t attrbits; 4549191783Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4550191783Srmacklem 4551191783Srmacklem if (!NFSHASNFSV4(nmp)) 4552191783Srmacklem return (EOPNOTSUPP); 4553191783Srmacklem NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 4554191783Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 4555191783Srmacklem NFSZERO_ATTRBIT(&attrbits); 4556191783Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4557220645Srmacklem (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0, 4558220648Srmacklem &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0); 4559191783Srmacklem error = nfscl_request(nd, vp, p, cred, stuff); 4560191783Srmacklem if (error) 4561191783Srmacklem return (error); 4562191783Srmacklem /* Don't care about the pre/postop attributes */ 4563191783Srmacklem mbuf_freem(nd->nd_mrep); 4564191783Srmacklem return (nd->nd_repstat); 4565191783Srmacklem} 4566244042Srmacklem 4567244042Srmacklem/* 4568244042Srmacklem * Do the NFSv4.1 Exchange ID. 4569244042Srmacklem */ 4570244042Srmacklemint 4571244042Srmacklemnfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, 4572244042Srmacklem struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp, 4573244042Srmacklem struct ucred *cred, NFSPROC_T *p) 4574244042Srmacklem{ 4575244042Srmacklem uint32_t *tl, v41flags; 4576244042Srmacklem struct nfsrv_descript nfsd; 4577244042Srmacklem struct nfsrv_descript *nd = &nfsd; 4578244042Srmacklem struct nfsclds *dsp; 4579244042Srmacklem struct timespec verstime; 4580244042Srmacklem int error, len; 4581244042Srmacklem 4582244042Srmacklem *dspp = NULL; 4583244042Srmacklem nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL); 4584244042Srmacklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4585244042Srmacklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ 4586244042Srmacklem *tl = txdr_unsigned(clp->nfsc_rev); 4587244042Srmacklem (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 4588244042Srmacklem 4589244042Srmacklem NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4590244042Srmacklem *tl++ = txdr_unsigned(exchflags); 4591244042Srmacklem *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); 4592244042Srmacklem 4593244042Srmacklem /* Set the implementation id4 */ 4594244042Srmacklem *tl = txdr_unsigned(1); 4595244042Srmacklem (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4596244042Srmacklem (void) nfsm_strtom(nd, version, strlen(version)); 4597244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4598244042Srmacklem verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4599244042Srmacklem verstime.tv_nsec = 0; 4600244042Srmacklem txdr_nfsv4time(&verstime, tl); 4601244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4602244042Srmacklem error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4603244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4604244042Srmacklem NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, 4605244042Srmacklem (int)nd->nd_repstat); 4606244042Srmacklem if (error != 0) 4607244042Srmacklem return (error); 4608244042Srmacklem if (nd->nd_repstat == 0) { 4609244042Srmacklem NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); 4610244042Srmacklem len = fxdr_unsigned(int, *(tl + 7)); 4611244042Srmacklem if (len < 0 || len > NFSV4_OPAQUELIMIT) { 4612244042Srmacklem error = NFSERR_BADXDR; 4613244042Srmacklem goto nfsmout; 4614244042Srmacklem } 4615317393Srmacklem dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, 4616244042Srmacklem M_WAITOK | M_ZERO); 4617244042Srmacklem dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; 4618244042Srmacklem dsp->nfsclds_servownlen = len; 4619244042Srmacklem dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; 4620244042Srmacklem dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; 4621244042Srmacklem dsp->nfsclds_sess.nfsess_sequenceid = 4622244042Srmacklem fxdr_unsigned(uint32_t, *tl++); 4623244042Srmacklem v41flags = fxdr_unsigned(uint32_t, *tl); 4624244042Srmacklem if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && 4625244042Srmacklem NFSHASPNFSOPT(nmp)) { 4626244042Srmacklem NFSCL_DEBUG(1, "set PNFS\n"); 4627244042Srmacklem NFSLOCKMNT(nmp); 4628244042Srmacklem nmp->nm_state |= NFSSTA_PNFS; 4629244042Srmacklem NFSUNLOCKMNT(nmp); 4630244042Srmacklem dsp->nfsclds_flags |= NFSCLDS_MDS; 4631244042Srmacklem } 4632244042Srmacklem if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) 4633244042Srmacklem dsp->nfsclds_flags |= NFSCLDS_DS; 4634244042Srmacklem if (len > 0) 4635244042Srmacklem nd->nd_repstat = nfsrv_mtostr(nd, 4636244042Srmacklem dsp->nfsclds_serverown, len); 4637244042Srmacklem if (nd->nd_repstat == 0) { 4638244042Srmacklem mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 4639244042Srmacklem mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 4640244042Srmacklem NULL, MTX_DEF); 4641244042Srmacklem nfscl_initsessionslots(&dsp->nfsclds_sess); 4642244042Srmacklem *dspp = dsp; 4643244042Srmacklem } else 4644244042Srmacklem free(dsp, M_NFSCLDS); 4645244042Srmacklem } 4646244042Srmacklem error = nd->nd_repstat; 4647244042Srmacklemnfsmout: 4648244042Srmacklem mbuf_freem(nd->nd_mrep); 4649244042Srmacklem return (error); 4650244042Srmacklem} 4651244042Srmacklem 4652244042Srmacklem/* 4653244042Srmacklem * Do the NFSv4.1 Create Session. 4654244042Srmacklem */ 4655244042Srmacklemint 4656244042Srmacklemnfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, 4657244042Srmacklem struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred, 4658244042Srmacklem NFSPROC_T *p) 4659244042Srmacklem{ 4660320615Srmacklem uint32_t crflags, maxval, *tl; 4661244042Srmacklem struct nfsrv_descript nfsd; 4662244042Srmacklem struct nfsrv_descript *nd = &nfsd; 4663244042Srmacklem int error, irdcnt; 4664244042Srmacklem 4665321632Srmacklem /* Make sure nm_rsize, nm_wsize is set. */ 4666321632Srmacklem if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0) 4667321632Srmacklem nmp->nm_rsize = NFS_MAXBSIZE; 4668321632Srmacklem if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0) 4669321632Srmacklem nmp->nm_wsize = NFS_MAXBSIZE; 4670244042Srmacklem nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL); 4671244042Srmacklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4672244042Srmacklem *tl++ = sep->nfsess_clientid.lval[0]; 4673244042Srmacklem *tl++ = sep->nfsess_clientid.lval[1]; 4674244042Srmacklem *tl++ = txdr_unsigned(sequenceid); 4675244042Srmacklem crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); 4676317926Srmacklem if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0) 4677244042Srmacklem crflags |= NFSV4CRSESS_CONNBACKCHAN; 4678244042Srmacklem *tl = txdr_unsigned(crflags); 4679244042Srmacklem 4680244042Srmacklem /* Fill in fore channel attributes. */ 4681244042Srmacklem NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4682244042Srmacklem *tl++ = 0; /* Header pad size */ 4683320615Srmacklem *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);/* Max request size */ 4684320615Srmacklem *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);/* Max reply size */ 4685244042Srmacklem *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4686244042Srmacklem *tl++ = txdr_unsigned(20); /* Max operations */ 4687244042Srmacklem *tl++ = txdr_unsigned(64); /* Max slots */ 4688244042Srmacklem *tl = 0; /* No rdma ird */ 4689244042Srmacklem 4690244042Srmacklem /* Fill in back channel attributes. */ 4691244042Srmacklem NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4692244042Srmacklem *tl++ = 0; /* Header pad size */ 4693244042Srmacklem *tl++ = txdr_unsigned(10000); /* Max request size */ 4694244042Srmacklem *tl++ = txdr_unsigned(10000); /* Max response size */ 4695244042Srmacklem *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4696244042Srmacklem *tl++ = txdr_unsigned(4); /* Max operations */ 4697244042Srmacklem *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ 4698244042Srmacklem *tl = 0; /* No rdma ird */ 4699244042Srmacklem 4700244042Srmacklem NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); 4701244042Srmacklem *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ 4702244042Srmacklem 4703244042Srmacklem /* Allow AUTH_SYS callbacks as uid, gid == 0. */ 4704244042Srmacklem *tl++ = txdr_unsigned(1); /* Auth_sys only */ 4705244042Srmacklem *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ 4706244042Srmacklem *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ 4707244042Srmacklem *tl++ = 0; /* Null machine name */ 4708244042Srmacklem *tl++ = 0; /* Uid == 0 */ 4709244042Srmacklem *tl++ = 0; /* Gid == 0 */ 4710244042Srmacklem *tl = 0; /* No additional gids */ 4711244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4712244042Srmacklem error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, 4713244042Srmacklem NFS_VER4, NULL, 1, NULL, NULL); 4714244042Srmacklem if (error != 0) 4715244042Srmacklem return (error); 4716244042Srmacklem if (nd->nd_repstat == 0) { 4717244042Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 4718244042Srmacklem 2 * NFSX_UNSIGNED); 4719244042Srmacklem bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); 4720244042Srmacklem tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4721244042Srmacklem sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); 4722244042Srmacklem crflags = fxdr_unsigned(uint32_t, *tl); 4723244042Srmacklem if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { 4724244042Srmacklem NFSLOCKMNT(nmp); 4725244042Srmacklem nmp->nm_state |= NFSSTA_SESSPERSIST; 4726244042Srmacklem NFSUNLOCKMNT(nmp); 4727244042Srmacklem } 4728244042Srmacklem 4729244042Srmacklem /* Get the fore channel slot count. */ 4730244042Srmacklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4731320615Srmacklem tl++; /* Skip the header pad size. */ 4732320615Srmacklem 4733320615Srmacklem /* Make sure nm_wsize is small enough. */ 4734320615Srmacklem maxval = fxdr_unsigned(uint32_t, *tl++); 4735320615Srmacklem while (maxval < nmp->nm_wsize + NFS_MAXXDR) { 4736320615Srmacklem if (nmp->nm_wsize > 8096) 4737320615Srmacklem nmp->nm_wsize /= 2; 4738320615Srmacklem else 4739320615Srmacklem break; 4740320615Srmacklem } 4741320615Srmacklem 4742320615Srmacklem /* Make sure nm_rsize is small enough. */ 4743320615Srmacklem maxval = fxdr_unsigned(uint32_t, *tl++); 4744320615Srmacklem while (maxval < nmp->nm_rsize + NFS_MAXXDR) { 4745320615Srmacklem if (nmp->nm_rsize > 8096) 4746320615Srmacklem nmp->nm_rsize /= 2; 4747320615Srmacklem else 4748320615Srmacklem break; 4749320615Srmacklem } 4750320615Srmacklem 4751244042Srmacklem sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); 4752244042Srmacklem tl++; 4753244042Srmacklem sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); 4754244042Srmacklem NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); 4755244042Srmacklem irdcnt = fxdr_unsigned(int, *tl); 4756244042Srmacklem if (irdcnt > 0) 4757244042Srmacklem NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 4758244042Srmacklem 4759244042Srmacklem /* and the back channel slot count. */ 4760244042Srmacklem NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4761244042Srmacklem tl += 5; 4762244042Srmacklem sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 4763244042Srmacklem NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 4764244042Srmacklem } 4765244042Srmacklem error = nd->nd_repstat; 4766244042Srmacklemnfsmout: 4767244042Srmacklem mbuf_freem(nd->nd_mrep); 4768244042Srmacklem return (error); 4769244042Srmacklem} 4770244042Srmacklem 4771244042Srmacklem/* 4772244042Srmacklem * Do the NFSv4.1 Destroy Session. 4773244042Srmacklem */ 4774244042Srmacklemint 4775244042Srmacklemnfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp, 4776244042Srmacklem struct ucred *cred, NFSPROC_T *p) 4777244042Srmacklem{ 4778244042Srmacklem uint32_t *tl; 4779244042Srmacklem struct nfsrv_descript nfsd; 4780244042Srmacklem struct nfsrv_descript *nd = &nfsd; 4781244042Srmacklem int error; 4782317393Srmacklem struct nfsclsession *tsep; 4783244042Srmacklem 4784244042Srmacklem nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL); 4785244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4786317393Srmacklem tsep = nfsmnt_mdssession(nmp); 4787317393Srmacklem bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID); 4788244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4789244042Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4790244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4791244042Srmacklem if (error != 0) 4792244042Srmacklem return (error); 4793244042Srmacklem error = nd->nd_repstat; 4794244042Srmacklem mbuf_freem(nd->nd_mrep); 4795244042Srmacklem return (error); 4796244042Srmacklem} 4797244042Srmacklem 4798244042Srmacklem/* 4799244042Srmacklem * Do the NFSv4.1 Destroy Client. 4800244042Srmacklem */ 4801244042Srmacklemint 4802244042Srmacklemnfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 4803244042Srmacklem struct ucred *cred, NFSPROC_T *p) 4804244042Srmacklem{ 4805244042Srmacklem uint32_t *tl; 4806244042Srmacklem struct nfsrv_descript nfsd; 4807244042Srmacklem struct nfsrv_descript *nd = &nfsd; 4808244042Srmacklem int error; 4809317393Srmacklem struct nfsclsession *tsep; 4810244042Srmacklem 4811244042Srmacklem nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL); 4812244042Srmacklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4813317393Srmacklem tsep = nfsmnt_mdssession(nmp); 4814317393Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 4815317393Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 4816244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4817244042Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4818244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4819244042Srmacklem if (error != 0) 4820244042Srmacklem return (error); 4821244042Srmacklem error = nd->nd_repstat; 4822244042Srmacklem mbuf_freem(nd->nd_mrep); 4823244042Srmacklem return (error); 4824244042Srmacklem} 4825244042Srmacklem 4826244042Srmacklem/* 4827244042Srmacklem * Do the NFSv4.1 LayoutGet. 4828244042Srmacklem */ 4829244042Srmacklemint 4830244042Srmacklemnfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 4831244042Srmacklem uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen, 4832244042Srmacklem nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp, 4833244042Srmacklem struct ucred *cred, NFSPROC_T *p, void *stuff) 4834244042Srmacklem{ 4835244042Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 4836320998Srmacklem int error; 4837244042Srmacklem 4838244042Srmacklem nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL); 4839320998Srmacklem nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, 4840320998Srmacklem layoutlen, 0); 4841244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4842244042Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4843244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4844320998Srmacklem NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); 4845244042Srmacklem if (error != 0) 4846244042Srmacklem return (error); 4847320998Srmacklem if (nd->nd_repstat == 0) 4848320998Srmacklem error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp); 4849320998Srmacklem if (error == 0 && nd->nd_repstat != 0) 4850244042Srmacklem error = nd->nd_repstat; 4851244042Srmacklem mbuf_freem(nd->nd_mrep); 4852244042Srmacklem return (error); 4853244042Srmacklem} 4854244042Srmacklem 4855244042Srmacklem/* 4856244042Srmacklem * Do the NFSv4.1 Get Device Info. 4857244042Srmacklem */ 4858244042Srmacklemint 4859244042Srmacklemnfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 4860244042Srmacklem uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 4861244042Srmacklem NFSPROC_T *p) 4862244042Srmacklem{ 4863244042Srmacklem uint32_t cnt, *tl; 4864244042Srmacklem struct nfsrv_descript nfsd; 4865244042Srmacklem struct nfsrv_descript *nd = &nfsd; 4866244042Srmacklem struct sockaddr_storage ss; 4867244042Srmacklem struct nfsclds *dsp = NULL, **dspp; 4868244042Srmacklem struct nfscldevinfo *ndi; 4869244042Srmacklem int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt; 4870244042Srmacklem uint8_t stripeindex; 4871244042Srmacklem 4872244042Srmacklem *ndip = NULL; 4873244042Srmacklem ndi = NULL; 4874244042Srmacklem nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL); 4875244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 4876244042Srmacklem NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 4877244042Srmacklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4878244042Srmacklem *tl++ = txdr_unsigned(layouttype); 4879244042Srmacklem *tl++ = txdr_unsigned(100000); 4880244042Srmacklem if (notifybitsp != NULL && *notifybitsp != 0) { 4881244042Srmacklem *tl = txdr_unsigned(1); /* One word of bits. */ 4882244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4883244042Srmacklem *tl = txdr_unsigned(*notifybitsp); 4884244042Srmacklem } else 4885244042Srmacklem *tl = txdr_unsigned(0); 4886244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 4887244042Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4888244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4889244042Srmacklem if (error != 0) 4890244042Srmacklem return (error); 4891244042Srmacklem if (nd->nd_repstat == 0) { 4892244042Srmacklem NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4893244042Srmacklem if (layouttype != fxdr_unsigned(int, *tl++)) 4894244042Srmacklem printf("EEK! devinfo layout type not same!\n"); 4895244042Srmacklem stripecnt = fxdr_unsigned(int, *++tl); 4896244042Srmacklem NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 4897244042Srmacklem if (stripecnt < 1 || stripecnt > 4096) { 4898244042Srmacklem printf("NFS devinfo stripecnt %d: out of range\n", 4899244042Srmacklem stripecnt); 4900244042Srmacklem error = NFSERR_BADXDR; 4901244042Srmacklem goto nfsmout; 4902244042Srmacklem } 4903244042Srmacklem NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED); 4904244042Srmacklem addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 4905244042Srmacklem NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 4906244042Srmacklem if (addrcnt < 1 || addrcnt > 128) { 4907244042Srmacklem printf("NFS devinfo addrcnt %d: out of range\n", 4908244042Srmacklem addrcnt); 4909244042Srmacklem error = NFSERR_BADXDR; 4910244042Srmacklem goto nfsmout; 4911244042Srmacklem } 4912244042Srmacklem 4913244042Srmacklem /* 4914244042Srmacklem * Now we know how many stripe indices and addresses, so 4915244042Srmacklem * we can allocate the structure the correct size. 4916244042Srmacklem */ 4917244042Srmacklem i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *) 4918244042Srmacklem + 1; 4919244042Srmacklem NFSCL_DEBUG(4, "stripeindices=%d\n", i); 4920244042Srmacklem ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 4921244042Srmacklem sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO); 4922244042Srmacklem NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID); 4923244042Srmacklem ndi->nfsdi_refcnt = 0; 4924244042Srmacklem ndi->nfsdi_stripecnt = stripecnt; 4925244042Srmacklem ndi->nfsdi_addrcnt = addrcnt; 4926244042Srmacklem /* Fill in the stripe indices. */ 4927244042Srmacklem for (i = 0; i < stripecnt; i++) { 4928244042Srmacklem stripeindex = fxdr_unsigned(uint8_t, *tl++); 4929244042Srmacklem NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 4930244042Srmacklem if (stripeindex >= addrcnt) { 4931244042Srmacklem printf("NFS devinfo stripeindex %d: too big\n", 4932244042Srmacklem (int)stripeindex); 4933244042Srmacklem error = NFSERR_BADXDR; 4934244042Srmacklem goto nfsmout; 4935244042Srmacklem } 4936244042Srmacklem nfsfldi_setstripeindex(ndi, i, stripeindex); 4937244042Srmacklem } 4938244042Srmacklem 4939244042Srmacklem /* Now, dissect the server address(es). */ 4940244042Srmacklem safilled = 0; 4941244042Srmacklem for (i = 0; i < addrcnt; i++) { 4942244042Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4943244042Srmacklem cnt = fxdr_unsigned(uint32_t, *tl); 4944244042Srmacklem if (cnt == 0) { 4945244042Srmacklem printf("NFS devinfo 0 len addrlist\n"); 4946244042Srmacklem error = NFSERR_BADXDR; 4947244042Srmacklem goto nfsmout; 4948244042Srmacklem } 4949244042Srmacklem dspp = nfsfldi_addr(ndi, i); 4950244042Srmacklem pos = arc4random() % cnt; /* Choose one. */ 4951244042Srmacklem safilled = 0; 4952244042Srmacklem for (j = 0; j < cnt; j++) { 4953244042Srmacklem error = nfsv4_getipaddr(nd, &ss, &isudp); 4954244042Srmacklem if (error != 0 && error != EPERM) { 4955244042Srmacklem error = NFSERR_BADXDR; 4956244042Srmacklem goto nfsmout; 4957244042Srmacklem } 4958244042Srmacklem if (error == 0 && isudp == 0) { 4959244042Srmacklem /* 4960244042Srmacklem * The algorithm is: 4961244042Srmacklem * - use "pos" entry if it is of the 4962244042Srmacklem * same af_family or none of them 4963244042Srmacklem * is of the same af_family 4964244042Srmacklem * else 4965244042Srmacklem * - use the first one of the same 4966244042Srmacklem * af_family. 4967244042Srmacklem */ 4968244042Srmacklem if ((safilled == 0 && ss.ss_family == 4969244042Srmacklem nmp->nm_nam->sa_family) || 4970244042Srmacklem (j == pos && 4971244042Srmacklem (safilled == 0 || ss.ss_family == 4972244042Srmacklem nmp->nm_nam->sa_family)) || 4973244042Srmacklem (safilled == 1 && ss.ss_family == 4974244042Srmacklem nmp->nm_nam->sa_family)) { 4975244042Srmacklem error = nfsrpc_fillsa(nmp, &ss, 4976244042Srmacklem &dsp, p); 4977244042Srmacklem if (error == 0) { 4978244042Srmacklem *dspp = dsp; 4979244042Srmacklem if (ss.ss_family == 4980244042Srmacklem nmp->nm_nam->sa_family) 4981244042Srmacklem safilled = 2; 4982244042Srmacklem else 4983244042Srmacklem safilled = 1; 4984244042Srmacklem } 4985244042Srmacklem } 4986244042Srmacklem } 4987244042Srmacklem } 4988244042Srmacklem if (safilled == 0) 4989244042Srmacklem break; 4990244042Srmacklem } 4991244042Srmacklem 4992244042Srmacklem /* And the notify bits. */ 4993244042Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4994244042Srmacklem if (safilled != 0) { 4995244042Srmacklem bitcnt = fxdr_unsigned(int, *tl); 4996244042Srmacklem if (bitcnt > 0) { 4997244042Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4998244042Srmacklem if (notifybitsp != NULL) 4999244042Srmacklem *notifybitsp = 5000244042Srmacklem fxdr_unsigned(uint32_t, *tl); 5001244042Srmacklem } 5002244042Srmacklem *ndip = ndi; 5003244042Srmacklem } else 5004244042Srmacklem error = EPERM; 5005244042Srmacklem } 5006244042Srmacklem if (nd->nd_repstat != 0) 5007244042Srmacklem error = nd->nd_repstat; 5008244042Srmacklemnfsmout: 5009244042Srmacklem if (error != 0 && ndi != NULL) 5010244042Srmacklem nfscl_freedevinfo(ndi); 5011244042Srmacklem mbuf_freem(nd->nd_mrep); 5012244042Srmacklem return (error); 5013244042Srmacklem} 5014244042Srmacklem 5015244042Srmacklem/* 5016244042Srmacklem * Do the NFSv4.1 LayoutCommit. 5017244042Srmacklem */ 5018244042Srmacklemint 5019244042Srmacklemnfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5020244042Srmacklem uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5021244042Srmacklem int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred, 5022244042Srmacklem NFSPROC_T *p, void *stuff) 5023244042Srmacklem{ 5024244042Srmacklem uint32_t *tl; 5025244042Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 5026244042Srmacklem int error, outcnt, i; 5027244042Srmacklem uint8_t *cp; 5028244042Srmacklem 5029244042Srmacklem nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL); 5030244042Srmacklem NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5031244042Srmacklem NFSX_STATEID); 5032244042Srmacklem txdr_hyper(off, tl); 5033244042Srmacklem tl += 2; 5034244042Srmacklem txdr_hyper(len, tl); 5035244042Srmacklem tl += 2; 5036244042Srmacklem if (reclaim != 0) 5037244042Srmacklem *tl++ = newnfs_true; 5038244042Srmacklem else 5039244042Srmacklem *tl++ = newnfs_false; 5040244042Srmacklem *tl++ = txdr_unsigned(stateidp->seqid); 5041244042Srmacklem *tl++ = stateidp->other[0]; 5042244042Srmacklem *tl++ = stateidp->other[1]; 5043244042Srmacklem *tl++ = stateidp->other[2]; 5044244042Srmacklem *tl++ = newnfs_true; 5045244042Srmacklem if (lastbyte < off) 5046244042Srmacklem lastbyte = off; 5047244042Srmacklem else if (lastbyte >= (off + len)) 5048244042Srmacklem lastbyte = off + len - 1; 5049244042Srmacklem txdr_hyper(lastbyte, tl); 5050244042Srmacklem tl += 2; 5051244042Srmacklem *tl++ = newnfs_false; 5052244042Srmacklem *tl++ = txdr_unsigned(layouttype); 5053244042Srmacklem *tl = txdr_unsigned(layoutupdatecnt); 5054244042Srmacklem if (layoutupdatecnt > 0) { 5055244042Srmacklem KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES, 5056244042Srmacklem ("Must be nil for Files Layout")); 5057244042Srmacklem outcnt = NFSM_RNDUP(layoutupdatecnt); 5058244042Srmacklem NFSM_BUILD(cp, uint8_t *, outcnt); 5059244042Srmacklem NFSBCOPY(layp, cp, layoutupdatecnt); 5060244042Srmacklem cp += layoutupdatecnt; 5061244042Srmacklem for (i = 0; i < (outcnt - layoutupdatecnt); i++) 5062244042Srmacklem *cp++ = 0x0; 5063244042Srmacklem } 5064244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 5065244042Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5066244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5067244042Srmacklem if (error != 0) 5068244042Srmacklem return (error); 5069244042Srmacklem error = nd->nd_repstat; 5070244042Srmacklem mbuf_freem(nd->nd_mrep); 5071244042Srmacklem return (error); 5072244042Srmacklem} 5073244042Srmacklem 5074244042Srmacklem/* 5075244042Srmacklem * Do the NFSv4.1 LayoutReturn. 5076244042Srmacklem */ 5077244042Srmacklemint 5078244042Srmacklemnfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5079244042Srmacklem int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5080244042Srmacklem uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp, 5081244042Srmacklem struct ucred *cred, NFSPROC_T *p, void *stuff) 5082244042Srmacklem{ 5083244042Srmacklem uint32_t *tl; 5084244042Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 5085244042Srmacklem int error, outcnt, i; 5086244042Srmacklem uint8_t *cp; 5087244042Srmacklem 5088244042Srmacklem nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL); 5089244042Srmacklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5090244042Srmacklem if (reclaim != 0) 5091244042Srmacklem *tl++ = newnfs_true; 5092244042Srmacklem else 5093244042Srmacklem *tl++ = newnfs_false; 5094244042Srmacklem *tl++ = txdr_unsigned(layouttype); 5095244042Srmacklem *tl++ = txdr_unsigned(iomode); 5096244042Srmacklem *tl = txdr_unsigned(layoutreturn); 5097244042Srmacklem if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5098244042Srmacklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5099244042Srmacklem NFSX_UNSIGNED); 5100244042Srmacklem txdr_hyper(offset, tl); 5101244042Srmacklem tl += 2; 5102244042Srmacklem txdr_hyper(len, tl); 5103244042Srmacklem tl += 2; 5104244042Srmacklem NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5105244042Srmacklem *tl++ = txdr_unsigned(stateidp->seqid); 5106244042Srmacklem *tl++ = stateidp->other[0]; 5107244042Srmacklem *tl++ = stateidp->other[1]; 5108244042Srmacklem *tl++ = stateidp->other[2]; 5109244042Srmacklem *tl = txdr_unsigned(layoutcnt); 5110244042Srmacklem if (layoutcnt > 0) { 5111244042Srmacklem outcnt = NFSM_RNDUP(layoutcnt); 5112244042Srmacklem NFSM_BUILD(cp, uint8_t *, outcnt); 5113244042Srmacklem NFSBCOPY(layp, cp, layoutcnt); 5114244042Srmacklem cp += layoutcnt; 5115244042Srmacklem for (i = 0; i < (outcnt - layoutcnt); i++) 5116244042Srmacklem *cp++ = 0x0; 5117244042Srmacklem } 5118244042Srmacklem } 5119244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 5120244042Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5121244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5122244042Srmacklem if (error != 0) 5123244042Srmacklem return (error); 5124244042Srmacklem if (nd->nd_repstat == 0) { 5125244042Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5126244042Srmacklem if (*tl != 0) { 5127244042Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5128244042Srmacklem stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5129244042Srmacklem stateidp->other[0] = *tl++; 5130244042Srmacklem stateidp->other[1] = *tl++; 5131244042Srmacklem stateidp->other[2] = *tl; 5132244042Srmacklem } 5133244042Srmacklem } else 5134244042Srmacklem error = nd->nd_repstat; 5135244042Srmacklemnfsmout: 5136244042Srmacklem mbuf_freem(nd->nd_mrep); 5137244042Srmacklem return (error); 5138244042Srmacklem} 5139244042Srmacklem 5140244042Srmacklem/* 5141244042Srmacklem * Acquire a layout and devinfo, if possible. The caller must have acquired 5142244042Srmacklem * a reference count on the nfsclclient structure before calling this. 5143244042Srmacklem * Return the layout in lypp with a reference count on it, if successful. 5144244042Srmacklem */ 5145244042Srmacklemstatic int 5146244042Srmacklemnfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 5147244042Srmacklem int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off, 5148244042Srmacklem struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 5149244042Srmacklem{ 5150244042Srmacklem struct nfscllayout *lyp; 5151320998Srmacklem struct nfsclflayout *flp; 5152244042Srmacklem struct nfsclflayouthead flh; 5153244042Srmacklem int error = 0, islocked, layoutlen, recalled, retonclose; 5154244042Srmacklem nfsv4stateid_t stateid; 5155317393Srmacklem struct nfsclsession *tsep; 5156244042Srmacklem 5157244042Srmacklem *lypp = NULL; 5158244042Srmacklem /* 5159244042Srmacklem * If lyp is returned non-NULL, there will be a refcnt (shared lock) 5160244042Srmacklem * on it, iff flp != NULL or a lock (exclusive lock) on it iff 5161244042Srmacklem * flp == NULL. 5162244042Srmacklem */ 5163244042Srmacklem lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 5164244042Srmacklem off, &flp, &recalled); 5165244042Srmacklem islocked = 0; 5166244042Srmacklem if (lyp == NULL || flp == NULL) { 5167244042Srmacklem if (recalled != 0) 5168244042Srmacklem return (EIO); 5169244042Srmacklem LIST_INIT(&flh); 5170317393Srmacklem tsep = nfsmnt_mdssession(nmp); 5171317393Srmacklem layoutlen = tsep->nfsess_maxcache - 5172244042Srmacklem (NFSX_STATEID + 3 * NFSX_UNSIGNED); 5173244042Srmacklem if (lyp == NULL) { 5174244042Srmacklem stateid.seqid = 0; 5175244042Srmacklem stateid.other[0] = stateidp->other[0]; 5176244042Srmacklem stateid.other[1] = stateidp->other[1]; 5177244042Srmacklem stateid.other[2] = stateidp->other[2]; 5178244042Srmacklem error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5179318260Srmacklem nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, 5180244042Srmacklem (uint64_t)0, layoutlen, &stateid, &retonclose, 5181244042Srmacklem &flh, cred, p, NULL); 5182244042Srmacklem } else { 5183244042Srmacklem islocked = 1; 5184244042Srmacklem stateid.seqid = lyp->nfsly_stateid.seqid; 5185244042Srmacklem stateid.other[0] = lyp->nfsly_stateid.other[0]; 5186244042Srmacklem stateid.other[1] = lyp->nfsly_stateid.other[1]; 5187244042Srmacklem stateid.other[2] = lyp->nfsly_stateid.other[2]; 5188244042Srmacklem error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5189318260Srmacklem nfhp->nfh_len, iomode, off, UINT64_MAX, 5190244042Srmacklem (uint64_t)0, layoutlen, &stateid, &retonclose, 5191244042Srmacklem &flh, cred, p, NULL); 5192244042Srmacklem } 5193320998Srmacklem error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, 5194320998Srmacklem nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, 5195320998Srmacklem &flh, error, NULL, cred, p); 5196244042Srmacklem if (error == 0) 5197320998Srmacklem *lypp = lyp; 5198320998Srmacklem else if (islocked != 0) 5199320998Srmacklem nfscl_rellayout(lyp, 1); 5200244042Srmacklem } else 5201244042Srmacklem *lypp = lyp; 5202244042Srmacklem return (error); 5203244042Srmacklem} 5204244042Srmacklem 5205244042Srmacklem/* 5206244042Srmacklem * Do a TCP connection plus exchange id and create session. 5207244042Srmacklem * If successful, a "struct nfsclds" is linked into the list for the 5208244042Srmacklem * mount point and a pointer to it is returned. 5209244042Srmacklem */ 5210244042Srmacklemstatic int 5211244042Srmacklemnfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp, 5212244042Srmacklem struct nfsclds **dspp, NFSPROC_T *p) 5213244042Srmacklem{ 5214244042Srmacklem struct sockaddr_in *msad, *sad, *ssd; 5215244042Srmacklem struct sockaddr_in6 *msad6, *sad6, *ssd6; 5216244042Srmacklem struct nfsclclient *clp; 5217244042Srmacklem struct nfssockreq *nrp; 5218244042Srmacklem struct nfsclds *dsp, *tdsp; 5219244042Srmacklem int error; 5220244042Srmacklem enum nfsclds_state retv; 5221244042Srmacklem uint32_t sequenceid; 5222244042Srmacklem 5223244042Srmacklem KASSERT(nmp->nm_sockreq.nr_cred != NULL, 5224244042Srmacklem ("nfsrpc_fillsa: NULL nr_cred")); 5225244042Srmacklem NFSLOCKCLSTATE(); 5226244042Srmacklem clp = nmp->nm_clp; 5227244042Srmacklem NFSUNLOCKCLSTATE(); 5228244042Srmacklem if (clp == NULL) 5229244042Srmacklem return (EPERM); 5230244042Srmacklem if (ssp->ss_family == AF_INET) { 5231244042Srmacklem ssd = (struct sockaddr_in *)ssp; 5232244042Srmacklem NFSLOCKMNT(nmp); 5233244042Srmacklem 5234244042Srmacklem /* 5235244042Srmacklem * Check to see if we already have a session for this 5236244042Srmacklem * address that is usable for a DS. 5237244042Srmacklem * Note that the MDS's address is in a different place 5238244042Srmacklem * than the sessions already acquired for DS's. 5239244042Srmacklem */ 5240244042Srmacklem msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 5241244042Srmacklem tdsp = TAILQ_FIRST(&nmp->nm_sess); 5242244042Srmacklem while (tdsp != NULL) { 5243244042Srmacklem if (msad != NULL && msad->sin_family == AF_INET && 5244244042Srmacklem ssd->sin_addr.s_addr == msad->sin_addr.s_addr && 5245244042Srmacklem ssd->sin_port == msad->sin_port && 5246317393Srmacklem (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5247317393Srmacklem tdsp->nfsclds_sess.nfsess_defunct == 0) { 5248244042Srmacklem *dspp = tdsp; 5249244042Srmacklem NFSUNLOCKMNT(nmp); 5250244042Srmacklem NFSCL_DEBUG(4, "fnd same addr\n"); 5251244042Srmacklem return (0); 5252244042Srmacklem } 5253244042Srmacklem tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5254244042Srmacklem if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5255244042Srmacklem msad = (struct sockaddr_in *) 5256244042Srmacklem tdsp->nfsclds_sockp->nr_nam; 5257244042Srmacklem else 5258244042Srmacklem msad = NULL; 5259244042Srmacklem } 5260244042Srmacklem NFSUNLOCKMNT(nmp); 5261244042Srmacklem 5262244042Srmacklem /* No IP address match, so look for new/trunked one. */ 5263244042Srmacklem sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 5264244042Srmacklem sad->sin_len = sizeof(*sad); 5265244042Srmacklem sad->sin_family = AF_INET; 5266244042Srmacklem sad->sin_port = ssd->sin_port; 5267244042Srmacklem sad->sin_addr.s_addr = ssd->sin_addr.s_addr; 5268244042Srmacklem nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5269244042Srmacklem nrp->nr_nam = (struct sockaddr *)sad; 5270244042Srmacklem } else if (ssp->ss_family == AF_INET6) { 5271244042Srmacklem ssd6 = (struct sockaddr_in6 *)ssp; 5272244042Srmacklem NFSLOCKMNT(nmp); 5273244042Srmacklem 5274244042Srmacklem /* 5275244042Srmacklem * Check to see if we already have a session for this 5276244042Srmacklem * address that is usable for a DS. 5277244042Srmacklem * Note that the MDS's address is in a different place 5278244042Srmacklem * than the sessions already acquired for DS's. 5279244042Srmacklem */ 5280244042Srmacklem msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 5281244042Srmacklem tdsp = TAILQ_FIRST(&nmp->nm_sess); 5282244042Srmacklem while (tdsp != NULL) { 5283244042Srmacklem if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 5284244042Srmacklem IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr, 5285244042Srmacklem &msad6->sin6_addr) && 5286244042Srmacklem ssd6->sin6_port == msad6->sin6_port && 5287317393Srmacklem (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5288317393Srmacklem tdsp->nfsclds_sess.nfsess_defunct == 0) { 5289244042Srmacklem *dspp = tdsp; 5290244042Srmacklem NFSUNLOCKMNT(nmp); 5291244042Srmacklem return (0); 5292244042Srmacklem } 5293244042Srmacklem tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5294244042Srmacklem if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5295244042Srmacklem msad6 = (struct sockaddr_in6 *) 5296244042Srmacklem tdsp->nfsclds_sockp->nr_nam; 5297244042Srmacklem else 5298244042Srmacklem msad6 = NULL; 5299244042Srmacklem } 5300244042Srmacklem NFSUNLOCKMNT(nmp); 5301244042Srmacklem 5302244042Srmacklem /* No IP address match, so look for new/trunked one. */ 5303244042Srmacklem sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 5304244042Srmacklem sad6->sin6_len = sizeof(*sad6); 5305244042Srmacklem sad6->sin6_family = AF_INET6; 5306244042Srmacklem sad6->sin6_port = ssd6->sin6_port; 5307244042Srmacklem NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr, 5308244042Srmacklem sizeof(struct in6_addr)); 5309244042Srmacklem nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5310244042Srmacklem nrp->nr_nam = (struct sockaddr *)sad6; 5311244042Srmacklem } else 5312244042Srmacklem return (EPERM); 5313244042Srmacklem 5314244042Srmacklem nrp->nr_sotype = SOCK_STREAM; 5315244042Srmacklem mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 5316244042Srmacklem nrp->nr_prog = NFS_PROG; 5317244042Srmacklem nrp->nr_vers = NFS_VER4; 5318244042Srmacklem 5319244042Srmacklem /* 5320244042Srmacklem * Use the credentials that were used for the mount, which are 5321244042Srmacklem * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 5322244042Srmacklem * Ref. counting the credentials with crhold() is probably not 5323244042Srmacklem * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 5324244042Srmacklem * unmount, but I did it anyhow. 5325244042Srmacklem */ 5326244042Srmacklem nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 5327244042Srmacklem error = newnfs_connect(nmp, nrp, NULL, p, 0); 5328244042Srmacklem NFSCL_DEBUG(3, "DS connect=%d\n", error); 5329244042Srmacklem 5330244042Srmacklem /* Now, do the exchangeid and create session. */ 5331317973Srmacklem if (error == 0) { 5332244042Srmacklem error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS, 5333244042Srmacklem &dsp, nrp->nr_cred, p); 5334317973Srmacklem NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 5335317973Srmacklem if (error != 0) 5336317973Srmacklem newnfs_disconnect(nrp); 5337317973Srmacklem } 5338244042Srmacklem if (error == 0) { 5339244042Srmacklem dsp->nfsclds_sockp = nrp; 5340244042Srmacklem NFSLOCKMNT(nmp); 5341244042Srmacklem retv = nfscl_getsameserver(nmp, dsp, &tdsp); 5342244042Srmacklem NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 5343244042Srmacklem if (retv == NFSDSP_USETHISSESSION) { 5344244042Srmacklem NFSUNLOCKMNT(nmp); 5345244042Srmacklem /* 5346244042Srmacklem * If there is already a session for this server, 5347244042Srmacklem * use it. 5348244042Srmacklem */ 5349244042Srmacklem (void)newnfs_disconnect(nrp); 5350244042Srmacklem nfscl_freenfsclds(dsp); 5351244042Srmacklem *dspp = tdsp; 5352244042Srmacklem return (0); 5353244042Srmacklem } 5354244042Srmacklem if (retv == NFSDSP_SEQTHISSESSION) 5355244042Srmacklem sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid; 5356244042Srmacklem else 5357244042Srmacklem sequenceid = dsp->nfsclds_sess.nfsess_sequenceid; 5358244042Srmacklem NFSUNLOCKMNT(nmp); 5359244042Srmacklem error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 5360244042Srmacklem nrp, sequenceid, 0, nrp->nr_cred, p); 5361244042Srmacklem NFSCL_DEBUG(3, "DS createsess=%d\n", error); 5362244042Srmacklem } else { 5363244042Srmacklem NFSFREECRED(nrp->nr_cred); 5364244042Srmacklem NFSFREEMUTEX(&nrp->nr_mtx); 5365244042Srmacklem free(nrp->nr_nam, M_SONAME); 5366244042Srmacklem free(nrp, M_NFSSOCKREQ); 5367244042Srmacklem } 5368244042Srmacklem if (error == 0) { 5369244042Srmacklem NFSCL_DEBUG(3, "add DS session\n"); 5370244042Srmacklem /* 5371244042Srmacklem * Put it at the end of the list. That way the list 5372244042Srmacklem * is ordered by when the entry was added. This matters 5373244042Srmacklem * since the one done first is the one that should be 5374244042Srmacklem * used for sequencid'ing any subsequent create sessions. 5375244042Srmacklem */ 5376244042Srmacklem NFSLOCKMNT(nmp); 5377244042Srmacklem TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 5378244042Srmacklem NFSUNLOCKMNT(nmp); 5379244042Srmacklem *dspp = dsp; 5380317973Srmacklem } else if (dsp != NULL) { 5381317973Srmacklem newnfs_disconnect(nrp); 5382244042Srmacklem nfscl_freenfsclds(dsp); 5383317973Srmacklem } 5384244042Srmacklem return (error); 5385244042Srmacklem} 5386244042Srmacklem 5387244042Srmacklem/* 5388244042Srmacklem * Do the NFSv4.1 Reclaim Complete. 5389244042Srmacklem */ 5390244042Srmacklemint 5391244042Srmacklemnfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 5392244042Srmacklem{ 5393244042Srmacklem uint32_t *tl; 5394244042Srmacklem struct nfsrv_descript nfsd; 5395244042Srmacklem struct nfsrv_descript *nd = &nfsd; 5396244042Srmacklem int error; 5397244042Srmacklem 5398244042Srmacklem nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL); 5399244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5400244042Srmacklem *tl = newnfs_false; 5401244042Srmacklem nd->nd_flag |= ND_USEGSSNAME; 5402244042Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5403244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5404244042Srmacklem if (error != 0) 5405244042Srmacklem return (error); 5406244042Srmacklem error = nd->nd_repstat; 5407244042Srmacklem mbuf_freem(nd->nd_mrep); 5408244042Srmacklem return (error); 5409244042Srmacklem} 5410244042Srmacklem 5411244042Srmacklem/* 5412244042Srmacklem * Initialize the slot tables for a session. 5413244042Srmacklem */ 5414244042Srmacklemstatic void 5415244042Srmacklemnfscl_initsessionslots(struct nfsclsession *sep) 5416244042Srmacklem{ 5417244042Srmacklem int i; 5418244042Srmacklem 5419244042Srmacklem for (i = 0; i < NFSV4_CBSLOTS; i++) { 5420244042Srmacklem if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 5421244042Srmacklem m_freem(sep->nfsess_cbslots[i].nfssl_reply); 5422244042Srmacklem NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 5423244042Srmacklem } 5424244042Srmacklem for (i = 0; i < 64; i++) 5425244042Srmacklem sep->nfsess_slotseq[i] = 0; 5426244042Srmacklem sep->nfsess_slots = 0; 5427244042Srmacklem} 5428244042Srmacklem 5429244042Srmacklem/* 5430244042Srmacklem * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 5431244042Srmacklem */ 5432244042Srmacklemint 5433244042Srmacklemnfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5434321029Srmacklem uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) 5435244042Srmacklem{ 5436244042Srmacklem struct nfsnode *np = VTONFS(vp); 5437244042Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5438244042Srmacklem struct nfscllayout *layp; 5439244042Srmacklem struct nfscldevinfo *dip; 5440244042Srmacklem struct nfsclflayout *rflp; 5441244042Srmacklem nfsv4stateid_t stateid; 5442244042Srmacklem struct ucred *newcred; 5443244042Srmacklem uint64_t lastbyte, len, off, oresid, xfer; 5444244042Srmacklem int eof, error, iolaymode, recalled; 5445244042Srmacklem void *lckp; 5446244042Srmacklem 5447244042Srmacklem if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 5448244042Srmacklem (np->n_flag & NNOLAYOUT) != 0) 5449244042Srmacklem return (EIO); 5450244042Srmacklem /* Now, get a reference cnt on the clientid for this mount. */ 5451244042Srmacklem if (nfscl_getref(nmp) == 0) 5452244042Srmacklem return (EIO); 5453244042Srmacklem 5454244042Srmacklem /* Find an appropriate stateid. */ 5455244042Srmacklem newcred = NFSNEWCRED(cred); 5456244042Srmacklem error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 5457244042Srmacklem rwaccess, 1, newcred, p, &stateid, &lckp); 5458244042Srmacklem if (error != 0) { 5459244042Srmacklem NFSFREECRED(newcred); 5460244042Srmacklem nfscl_relref(nmp); 5461244042Srmacklem return (error); 5462244042Srmacklem } 5463244042Srmacklem /* Search for a layout for this file. */ 5464244042Srmacklem off = uiop->uio_offset; 5465244042Srmacklem layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 5466244042Srmacklem np->n_fhp->nfh_len, off, &rflp, &recalled); 5467244042Srmacklem if (layp == NULL || rflp == NULL) { 5468244042Srmacklem if (recalled != 0) { 5469244042Srmacklem NFSFREECRED(newcred); 5470244042Srmacklem nfscl_relref(nmp); 5471244042Srmacklem return (EIO); 5472244042Srmacklem } 5473244042Srmacklem if (layp != NULL) { 5474244042Srmacklem nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 5475244042Srmacklem layp = NULL; 5476244042Srmacklem } 5477244042Srmacklem /* Try and get a Layout, if it is supported. */ 5478244042Srmacklem if (rwaccess == NFSV4OPEN_ACCESSWRITE || 5479244042Srmacklem (np->n_flag & NWRITEOPENED) != 0) 5480244042Srmacklem iolaymode = NFSLAYOUTIOMODE_RW; 5481244042Srmacklem else 5482244042Srmacklem iolaymode = NFSLAYOUTIOMODE_READ; 5483244042Srmacklem error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 5484244042Srmacklem NULL, &stateid, off, &layp, newcred, p); 5485244042Srmacklem if (error != 0) { 5486244042Srmacklem NFSLOCKNODE(np); 5487244042Srmacklem np->n_flag |= NNOLAYOUT; 5488244042Srmacklem NFSUNLOCKNODE(np); 5489244042Srmacklem if (lckp != NULL) 5490244042Srmacklem nfscl_lockderef(lckp); 5491244042Srmacklem NFSFREECRED(newcred); 5492244042Srmacklem if (layp != NULL) 5493244042Srmacklem nfscl_rellayout(layp, 0); 5494244042Srmacklem nfscl_relref(nmp); 5495244042Srmacklem return (error); 5496244042Srmacklem } 5497244042Srmacklem } 5498244042Srmacklem 5499244042Srmacklem /* 5500244042Srmacklem * Loop around finding a layout that works for the first part of 5501244042Srmacklem * this I/O operation, and then call the function that actually 5502244042Srmacklem * does the RPC. 5503244042Srmacklem */ 5504244042Srmacklem eof = 0; 5505244042Srmacklem len = (uint64_t)uiop->uio_resid; 5506244042Srmacklem while (len > 0 && error == 0 && eof == 0) { 5507244042Srmacklem off = uiop->uio_offset; 5508244042Srmacklem error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 5509244042Srmacklem if (error == 0) { 5510244042Srmacklem oresid = xfer = (uint64_t)uiop->uio_resid; 5511244042Srmacklem if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 5512244042Srmacklem xfer = rflp->nfsfl_end - rflp->nfsfl_off; 5513244042Srmacklem dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev, 5514244042Srmacklem rflp->nfsfl_devp); 5515244042Srmacklem if (dip != NULL) { 5516244042Srmacklem error = nfscl_doflayoutio(vp, uiop, iomode, 5517244042Srmacklem must_commit, &eof, &stateid, rwaccess, dip, 5518321029Srmacklem layp, rflp, off, xfer, docommit, newcred, 5519321029Srmacklem p); 5520244042Srmacklem nfscl_reldevinfo(dip); 5521244042Srmacklem lastbyte = off + xfer - 1; 5522244042Srmacklem if (error == 0) { 5523244042Srmacklem NFSLOCKCLSTATE(); 5524244042Srmacklem if (lastbyte > layp->nfsly_lastbyte) 5525244042Srmacklem layp->nfsly_lastbyte = lastbyte; 5526244042Srmacklem NFSUNLOCKCLSTATE(); 5527317983Srmacklem } else if (error == NFSERR_OPENMODE && 5528317983Srmacklem rwaccess == NFSV4OPEN_ACCESSREAD) { 5529317983Srmacklem NFSLOCKMNT(nmp); 5530317983Srmacklem nmp->nm_state |= NFSSTA_OPENMODE; 5531317983Srmacklem NFSUNLOCKMNT(nmp); 5532244042Srmacklem } 5533244042Srmacklem } else 5534244042Srmacklem error = EIO; 5535244042Srmacklem if (error == 0) 5536244042Srmacklem len -= (oresid - (uint64_t)uiop->uio_resid); 5537244042Srmacklem } 5538244042Srmacklem } 5539244042Srmacklem if (lckp != NULL) 5540244042Srmacklem nfscl_lockderef(lckp); 5541244042Srmacklem NFSFREECRED(newcred); 5542244042Srmacklem nfscl_rellayout(layp, 0); 5543244042Srmacklem nfscl_relref(nmp); 5544244042Srmacklem return (error); 5545244042Srmacklem} 5546244042Srmacklem 5547244042Srmacklem/* 5548244042Srmacklem * Find a file layout that will handle the first bytes of the requested 5549330446Seadler * range and return the information from it needed to the I/O operation. 5550244042Srmacklem */ 5551244042Srmacklemint 5552244042Srmacklemnfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 5553244042Srmacklem struct nfsclflayout **retflpp) 5554244042Srmacklem{ 5555244042Srmacklem struct nfsclflayout *flp, *nflp, *rflp; 5556244042Srmacklem uint32_t rw; 5557244042Srmacklem 5558244042Srmacklem rflp = NULL; 5559244042Srmacklem rw = rwaccess; 5560244042Srmacklem /* For reading, do the Read list first and then the Write list. */ 5561244042Srmacklem do { 5562244042Srmacklem if (rw == NFSV4OPEN_ACCESSREAD) 5563244042Srmacklem flp = LIST_FIRST(&lyp->nfsly_flayread); 5564244042Srmacklem else 5565244042Srmacklem flp = LIST_FIRST(&lyp->nfsly_flayrw); 5566244042Srmacklem while (flp != NULL) { 5567244042Srmacklem nflp = LIST_NEXT(flp, nfsfl_list); 5568244042Srmacklem if (flp->nfsfl_off > off) 5569244042Srmacklem break; 5570244042Srmacklem if (flp->nfsfl_end > off && 5571244042Srmacklem (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 5572244042Srmacklem rflp = flp; 5573244042Srmacklem flp = nflp; 5574244042Srmacklem } 5575244042Srmacklem if (rw == NFSV4OPEN_ACCESSREAD) 5576244042Srmacklem rw = NFSV4OPEN_ACCESSWRITE; 5577244042Srmacklem else 5578244042Srmacklem rw = 0; 5579244042Srmacklem } while (rw != 0); 5580244042Srmacklem if (rflp != NULL) { 5581244042Srmacklem /* This one covers the most bytes starting at off. */ 5582244042Srmacklem *retflpp = rflp; 5583244042Srmacklem return (0); 5584244042Srmacklem } 5585244042Srmacklem return (EIO); 5586244042Srmacklem} 5587244042Srmacklem 5588244042Srmacklem/* 5589244042Srmacklem * Do I/O using an NFSv4.1 file layout. 5590244042Srmacklem */ 5591244042Srmacklemstatic int 5592244042Srmacklemnfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5593244042Srmacklem int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 5594244042Srmacklem struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 5595321029Srmacklem uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) 5596244042Srmacklem{ 5597244042Srmacklem uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 5598321029Srmacklem int commit_thru_mds, error, stripe_index, stripe_pos; 5599244042Srmacklem struct nfsnode *np; 5600244042Srmacklem struct nfsfh *fhp; 5601244042Srmacklem struct nfsclds **dspp; 5602244042Srmacklem 5603244042Srmacklem np = VTONFS(vp); 5604244042Srmacklem rel_off = off - flp->nfsfl_patoff; 5605244042Srmacklem stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff; 5606244042Srmacklem stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 5607244042Srmacklem dp->nfsdi_stripecnt; 5608244042Srmacklem transfer = stripe_unit_size - (rel_off % stripe_unit_size); 5609321029Srmacklem error = 0; 5610244042Srmacklem 5611244042Srmacklem /* Loop around, doing I/O for each stripe unit. */ 5612244042Srmacklem while (len > 0 && error == 0) { 5613244042Srmacklem stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 5614244042Srmacklem dspp = nfsfldi_addr(dp, stripe_index); 5615321029Srmacklem if (len > transfer && docommit == 0) 5616244042Srmacklem xfer = transfer; 5617244042Srmacklem else 5618244042Srmacklem xfer = len; 5619244042Srmacklem if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 5620244042Srmacklem /* Dense layout. */ 5621244042Srmacklem if (stripe_pos >= flp->nfsfl_fhcnt) 5622244042Srmacklem return (EIO); 5623244042Srmacklem fhp = flp->nfsfl_fh[stripe_pos]; 5624244042Srmacklem io_off = (rel_off / (stripe_unit_size * 5625244042Srmacklem dp->nfsdi_stripecnt)) * stripe_unit_size + 5626244042Srmacklem rel_off % stripe_unit_size; 5627244042Srmacklem } else { 5628244042Srmacklem /* Sparse layout. */ 5629244042Srmacklem if (flp->nfsfl_fhcnt > 1) { 5630244042Srmacklem if (stripe_index >= flp->nfsfl_fhcnt) 5631244042Srmacklem return (EIO); 5632244042Srmacklem fhp = flp->nfsfl_fh[stripe_index]; 5633244042Srmacklem } else if (flp->nfsfl_fhcnt == 1) 5634244042Srmacklem fhp = flp->nfsfl_fh[0]; 5635244042Srmacklem else 5636244042Srmacklem fhp = np->n_fhp; 5637244042Srmacklem io_off = off; 5638244042Srmacklem } 5639321029Srmacklem if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { 5640244042Srmacklem commit_thru_mds = 1; 5641321029Srmacklem if (docommit != 0) 5642321029Srmacklem error = EIO; 5643321029Srmacklem } else { 5644244042Srmacklem commit_thru_mds = 0; 5645321029Srmacklem mtx_lock(&np->n_mtx); 5646321029Srmacklem np->n_flag |= NDSCOMMIT; 5647321029Srmacklem mtx_unlock(&np->n_mtx); 5648321029Srmacklem } 5649321029Srmacklem if (docommit != 0) { 5650321029Srmacklem if (error == 0) 5651321029Srmacklem error = nfsrpc_commitds(vp, io_off, xfer, 5652321029Srmacklem *dspp, fhp, cred, p); 5653321029Srmacklem if (error == 0) { 5654321029Srmacklem /* 5655321029Srmacklem * Set both eof and uio_resid = 0 to end any 5656321029Srmacklem * loops. 5657321029Srmacklem */ 5658321029Srmacklem *eofp = 1; 5659321029Srmacklem uiop->uio_resid = 0; 5660321029Srmacklem } else { 5661321029Srmacklem mtx_lock(&np->n_mtx); 5662321029Srmacklem np->n_flag &= ~NDSCOMMIT; 5663321029Srmacklem mtx_unlock(&np->n_mtx); 5664321029Srmacklem } 5665324180Srmacklem } else if (rwflag == NFSV4OPEN_ACCESSREAD) 5666244042Srmacklem error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 5667244042Srmacklem io_off, xfer, fhp, cred, p); 5668244042Srmacklem else { 5669244042Srmacklem error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 5670244042Srmacklem stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 5671244042Srmacklem cred, p); 5672244042Srmacklem if (error == 0) { 5673244042Srmacklem NFSLOCKCLSTATE(); 5674244042Srmacklem lyp->nfsly_flags |= NFSLY_WRITTEN; 5675244042Srmacklem NFSUNLOCKCLSTATE(); 5676244042Srmacklem } 5677244042Srmacklem } 5678244042Srmacklem if (error == 0) { 5679244042Srmacklem transfer = stripe_unit_size; 5680244042Srmacklem stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 5681244042Srmacklem len -= xfer; 5682244042Srmacklem off += xfer; 5683244042Srmacklem } 5684244042Srmacklem } 5685244042Srmacklem return (error); 5686244042Srmacklem} 5687244042Srmacklem 5688244042Srmacklem/* 5689244042Srmacklem * The actual read RPC done to a DS. 5690244042Srmacklem */ 5691244042Srmacklemstatic int 5692244042Srmacklemnfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 5693244042Srmacklem struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, 5694244042Srmacklem struct ucred *cred, NFSPROC_T *p) 5695244042Srmacklem{ 5696244042Srmacklem uint32_t *tl; 5697244042Srmacklem int error, retlen; 5698244042Srmacklem struct nfsrv_descript nfsd; 5699244042Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5700244042Srmacklem struct nfsrv_descript *nd = &nfsd; 5701244042Srmacklem struct nfssockreq *nrp; 5702244042Srmacklem 5703244042Srmacklem nd->nd_mrep = NULL; 5704244042Srmacklem nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len, 5705244042Srmacklem NULL, &dsp->nfsclds_sess); 5706244042Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 5707244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 5708244042Srmacklem txdr_hyper(io_off, tl); 5709244042Srmacklem *(tl + 2) = txdr_unsigned(len); 5710244042Srmacklem nrp = dsp->nfsclds_sockp; 5711244042Srmacklem if (nrp == NULL) 5712244042Srmacklem /* If NULL, use the MDS socket. */ 5713244042Srmacklem nrp = &nmp->nm_sockreq; 5714244042Srmacklem error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 5715244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 5716244042Srmacklem if (error != 0) 5717244042Srmacklem return (error); 5718244042Srmacklem if (nd->nd_repstat != 0) { 5719244042Srmacklem error = nd->nd_repstat; 5720244042Srmacklem goto nfsmout; 5721244042Srmacklem } 5722244042Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5723244042Srmacklem *eofp = fxdr_unsigned(int, *tl); 5724244042Srmacklem NFSM_STRSIZ(retlen, len); 5725244042Srmacklem error = nfsm_mbufuio(nd, uiop, retlen); 5726244042Srmacklemnfsmout: 5727244042Srmacklem if (nd->nd_mrep != NULL) 5728244042Srmacklem mbuf_freem(nd->nd_mrep); 5729244042Srmacklem return (error); 5730244042Srmacklem} 5731244042Srmacklem 5732244042Srmacklem/* 5733244042Srmacklem * The actual write RPC done to a DS. 5734244042Srmacklem */ 5735244042Srmacklemstatic int 5736244042Srmacklemnfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5737244042Srmacklem nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 5738244042Srmacklem struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p) 5739244042Srmacklem{ 5740244042Srmacklem uint32_t *tl; 5741244042Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5742244042Srmacklem int error, rlen, commit, committed = NFSWRITE_FILESYNC; 5743244042Srmacklem int32_t backup; 5744244042Srmacklem struct nfsrv_descript nfsd; 5745244042Srmacklem struct nfsrv_descript *nd = &nfsd; 5746244042Srmacklem struct nfssockreq *nrp; 5747244042Srmacklem 5748244042Srmacklem KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 5749244042Srmacklem nd->nd_mrep = NULL; 5750244042Srmacklem nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len, 5751244042Srmacklem NULL, &dsp->nfsclds_sess); 5752244042Srmacklem nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 5753244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 5754244042Srmacklem txdr_hyper(io_off, tl); 5755244042Srmacklem tl += 2; 5756244042Srmacklem *tl++ = txdr_unsigned(*iomode); 5757244042Srmacklem *tl = txdr_unsigned(len); 5758244042Srmacklem nfsm_uiombuf(nd, uiop, len); 5759244042Srmacklem nrp = dsp->nfsclds_sockp; 5760244042Srmacklem if (nrp == NULL) 5761244042Srmacklem /* If NULL, use the MDS socket. */ 5762244042Srmacklem nrp = &nmp->nm_sockreq; 5763244042Srmacklem error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 5764244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 5765244042Srmacklem if (error != 0) 5766244042Srmacklem return (error); 5767244042Srmacklem if (nd->nd_repstat != 0) { 5768244042Srmacklem /* 5769244042Srmacklem * In case the rpc gets retried, roll 5770244042Srmacklem * the uio fileds changed by nfsm_uiombuf() 5771244042Srmacklem * back. 5772244042Srmacklem */ 5773244042Srmacklem uiop->uio_offset -= len; 5774244042Srmacklem uio_uio_resid_add(uiop, len); 5775244042Srmacklem uio_iov_base_add(uiop, -len); 5776244042Srmacklem uio_iov_len_add(uiop, len); 5777244042Srmacklem error = nd->nd_repstat; 5778244042Srmacklem } else { 5779244042Srmacklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 5780244042Srmacklem rlen = fxdr_unsigned(int, *tl++); 5781244042Srmacklem if (rlen == 0) { 5782244042Srmacklem error = NFSERR_IO; 5783244042Srmacklem goto nfsmout; 5784244042Srmacklem } else if (rlen < len) { 5785244042Srmacklem backup = len - rlen; 5786244042Srmacklem uio_iov_base_add(uiop, -(backup)); 5787244042Srmacklem uio_iov_len_add(uiop, backup); 5788244042Srmacklem uiop->uio_offset -= backup; 5789244042Srmacklem uio_uio_resid_add(uiop, backup); 5790244042Srmacklem len = rlen; 5791244042Srmacklem } 5792244042Srmacklem commit = fxdr_unsigned(int, *tl++); 5793244042Srmacklem 5794244042Srmacklem /* 5795298788Spfg * Return the lowest commitment level 5796244042Srmacklem * obtained by any of the RPCs. 5797244042Srmacklem */ 5798244042Srmacklem if (committed == NFSWRITE_FILESYNC) 5799244042Srmacklem committed = commit; 5800244042Srmacklem else if (committed == NFSWRITE_DATASYNC && 5801244042Srmacklem commit == NFSWRITE_UNSTABLE) 5802244042Srmacklem committed = commit; 5803244042Srmacklem if (commit_thru_mds != 0) { 5804244042Srmacklem NFSLOCKMNT(nmp); 5805244042Srmacklem if (!NFSHASWRITEVERF(nmp)) { 5806244042Srmacklem NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 5807244042Srmacklem NFSSETWRITEVERF(nmp); 5808244042Srmacklem } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 5809244042Srmacklem *must_commit = 1; 5810244042Srmacklem NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 5811244042Srmacklem } 5812244042Srmacklem NFSUNLOCKMNT(nmp); 5813244042Srmacklem } else { 5814244042Srmacklem NFSLOCKDS(dsp); 5815244042Srmacklem if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 5816244042Srmacklem NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 5817244042Srmacklem dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 5818244042Srmacklem } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 5819244042Srmacklem *must_commit = 1; 5820244042Srmacklem NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 5821244042Srmacklem } 5822244042Srmacklem NFSUNLOCKDS(dsp); 5823244042Srmacklem } 5824244042Srmacklem } 5825244042Srmacklemnfsmout: 5826244042Srmacklem if (nd->nd_mrep != NULL) 5827244042Srmacklem mbuf_freem(nd->nd_mrep); 5828244042Srmacklem *iomode = committed; 5829244042Srmacklem if (nd->nd_repstat != 0 && error == 0) 5830244042Srmacklem error = nd->nd_repstat; 5831244042Srmacklem return (error); 5832244042Srmacklem} 5833244042Srmacklem 5834244042Srmacklem/* 5835244042Srmacklem * Free up the nfsclds structure. 5836244042Srmacklem */ 5837244042Srmacklemvoid 5838244042Srmacklemnfscl_freenfsclds(struct nfsclds *dsp) 5839244042Srmacklem{ 5840244042Srmacklem int i; 5841244042Srmacklem 5842244042Srmacklem if (dsp == NULL) 5843244042Srmacklem return; 5844244042Srmacklem if (dsp->nfsclds_sockp != NULL) { 5845244042Srmacklem NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 5846244042Srmacklem NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 5847244042Srmacklem free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 5848244042Srmacklem free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 5849244042Srmacklem } 5850244042Srmacklem NFSFREEMUTEX(&dsp->nfsclds_mtx); 5851244042Srmacklem NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 5852244042Srmacklem for (i = 0; i < NFSV4_CBSLOTS; i++) { 5853244042Srmacklem if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 5854244042Srmacklem m_freem( 5855244042Srmacklem dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 5856244042Srmacklem } 5857244042Srmacklem free(dsp, M_NFSCLDS); 5858244042Srmacklem} 5859244042Srmacklem 5860244042Srmacklemstatic enum nfsclds_state 5861244042Srmacklemnfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 5862244042Srmacklem struct nfsclds **retdspp) 5863244042Srmacklem{ 5864244042Srmacklem struct nfsclds *dsp, *cur_dsp; 5865244042Srmacklem 5866244042Srmacklem /* 5867244042Srmacklem * Search the list of nfsclds structures for one with the same 5868244042Srmacklem * server. 5869244042Srmacklem */ 5870244042Srmacklem cur_dsp = NULL; 5871244042Srmacklem TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 5872244042Srmacklem if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 5873244042Srmacklem dsp->nfsclds_servownlen != 0 && 5874244042Srmacklem !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 5875317393Srmacklem dsp->nfsclds_servownlen) && 5876317393Srmacklem dsp->nfsclds_sess.nfsess_defunct == 0) { 5877244042Srmacklem NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 5878244042Srmacklem TAILQ_FIRST(&nmp->nm_sess), dsp, 5879244042Srmacklem dsp->nfsclds_flags); 5880244042Srmacklem /* Server major id matches. */ 5881244042Srmacklem if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 5882244042Srmacklem *retdspp = dsp; 5883244042Srmacklem return (NFSDSP_USETHISSESSION); 5884244042Srmacklem } 5885244042Srmacklem 5886244042Srmacklem /* 5887244042Srmacklem * Note the first match, so it can be used for 5888244042Srmacklem * sequence'ing new sessions. 5889244042Srmacklem */ 5890244042Srmacklem if (cur_dsp == NULL) 5891244042Srmacklem cur_dsp = dsp; 5892244042Srmacklem } 5893244042Srmacklem } 5894244042Srmacklem if (cur_dsp != NULL) { 5895244042Srmacklem *retdspp = cur_dsp; 5896244042Srmacklem return (NFSDSP_SEQTHISSESSION); 5897244042Srmacklem } 5898244042Srmacklem return (NFSDSP_NOTFOUND); 5899244042Srmacklem} 5900244042Srmacklem 5901244042Srmacklem/* 5902321029Srmacklem * NFS commit rpc to a NFSv4.1 DS. 5903244042Srmacklem */ 5904244042Srmacklemstatic int 5905244042Srmacklemnfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 5906321029Srmacklem struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p) 5907244042Srmacklem{ 5908244042Srmacklem uint32_t *tl; 5909244042Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 5910244042Srmacklem struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5911244042Srmacklem struct nfssockreq *nrp; 5912244042Srmacklem int error; 5913244042Srmacklem 5914321029Srmacklem nd->nd_mrep = NULL; 5915244042Srmacklem nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len, 5916244042Srmacklem NULL, &dsp->nfsclds_sess); 5917244042Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 5918244042Srmacklem txdr_hyper(offset, tl); 5919244042Srmacklem tl += 2; 5920244042Srmacklem *tl = txdr_unsigned(cnt); 5921244042Srmacklem nrp = dsp->nfsclds_sockp; 5922244042Srmacklem if (nrp == NULL) 5923244042Srmacklem /* If NULL, use the MDS socket. */ 5924244042Srmacklem nrp = &nmp->nm_sockreq; 5925244042Srmacklem error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 5926244042Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 5927321029Srmacklem if (error != 0) 5928244042Srmacklem return (error); 5929244042Srmacklem if (nd->nd_repstat == 0) { 5930244042Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 5931244042Srmacklem NFSLOCKDS(dsp); 5932244042Srmacklem if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 5933244042Srmacklem NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 5934244042Srmacklem error = NFSERR_STALEWRITEVERF; 5935244042Srmacklem } 5936244042Srmacklem NFSUNLOCKDS(dsp); 5937244042Srmacklem } 5938244042Srmacklemnfsmout: 5939244042Srmacklem if (error == 0 && nd->nd_repstat != 0) 5940244042Srmacklem error = nd->nd_repstat; 5941244042Srmacklem mbuf_freem(nd->nd_mrep); 5942244042Srmacklem return (error); 5943244042Srmacklem} 5944244042Srmacklem 5945320998Srmacklem/* 5946320998Srmacklem * Set up the XDR arguments for the LayoutGet operation. 5947320998Srmacklem */ 5948320998Srmacklemstatic void 5949320998Srmacklemnfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, 5950320998Srmacklem uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layoutlen, 5951320998Srmacklem int usecurstateid) 5952320998Srmacklem{ 5953320998Srmacklem uint32_t *tl; 5954320998Srmacklem 5955320998Srmacklem NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5956320998Srmacklem NFSX_STATEID); 5957320998Srmacklem *tl++ = newnfs_false; /* Don't signal availability. */ 5958320998Srmacklem *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES); 5959320998Srmacklem *tl++ = txdr_unsigned(iomode); 5960320998Srmacklem txdr_hyper(offset, tl); 5961320998Srmacklem tl += 2; 5962320998Srmacklem txdr_hyper(len, tl); 5963320998Srmacklem tl += 2; 5964320998Srmacklem txdr_hyper(minlen, tl); 5965320998Srmacklem tl += 2; 5966320998Srmacklem if (usecurstateid != 0) { 5967320998Srmacklem /* Special stateid for Current stateid. */ 5968320998Srmacklem *tl++ = txdr_unsigned(1); 5969320998Srmacklem *tl++ = 0; 5970320998Srmacklem *tl++ = 0; 5971320998Srmacklem *tl++ = 0; 5972320998Srmacklem } else { 5973320998Srmacklem *tl++ = txdr_unsigned(stateidp->seqid); 5974320998Srmacklem NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 5975320998Srmacklem *tl++ = stateidp->other[0]; 5976320998Srmacklem *tl++ = stateidp->other[1]; 5977320998Srmacklem *tl++ = stateidp->other[2]; 5978320998Srmacklem } 5979320998Srmacklem *tl = txdr_unsigned(layoutlen); 5980320998Srmacklem} 5981320998Srmacklem 5982320998Srmacklem/* 5983320998Srmacklem * Parse the reply for a successful LayoutGet operation. 5984320998Srmacklem */ 5985320998Srmacklemstatic int 5986320998Srmacklemnfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, 5987320998Srmacklem int *retonclosep, struct nfsclflayouthead *flhp) 5988320998Srmacklem{ 5989320998Srmacklem uint32_t *tl; 5990320998Srmacklem struct nfsclflayout *flp, *prevflp, *tflp; 5991320998Srmacklem int cnt, error, gotiomode, fhcnt, nfhlen, i, j; 5992320998Srmacklem uint64_t retlen; 5993320998Srmacklem struct nfsfh *nfhp; 5994320998Srmacklem uint8_t *cp; 5995320998Srmacklem 5996320998Srmacklem error = 0; 5997320998Srmacklem flp = NULL; 5998320998Srmacklem gotiomode = -1; 5999320998Srmacklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 6000320998Srmacklem if (*tl++ != 0) 6001320998Srmacklem *retonclosep = 1; 6002320998Srmacklem else 6003320998Srmacklem *retonclosep = 0; 6004320998Srmacklem stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 6005320998Srmacklem NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 6006320998Srmacklem (int)stateidp->seqid); 6007320998Srmacklem stateidp->other[0] = *tl++; 6008320998Srmacklem stateidp->other[1] = *tl++; 6009320998Srmacklem stateidp->other[2] = *tl++; 6010320998Srmacklem cnt = fxdr_unsigned(int, *tl); 6011320998Srmacklem NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 6012320998Srmacklem if (cnt <= 0 || cnt > 10000) { 6013320998Srmacklem /* Don't accept more than 10000 layouts in reply. */ 6014320998Srmacklem error = NFSERR_BADXDR; 6015320998Srmacklem goto nfsmout; 6016320998Srmacklem } 6017320998Srmacklem for (i = 0; i < cnt; i++) { 6018320998Srmacklem /* Dissect all the way to the file handle cnt. */ 6019320998Srmacklem NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER + 6020320998Srmacklem 6 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 6021320998Srmacklem fhcnt = fxdr_unsigned(int, *(tl + 11 + 6022320998Srmacklem NFSX_V4DEVICEID / NFSX_UNSIGNED)); 6023320998Srmacklem NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 6024320998Srmacklem if (fhcnt < 0 || fhcnt > 100) { 6025320998Srmacklem /* Don't accept more than 100 file handles. */ 6026320998Srmacklem error = NFSERR_BADXDR; 6027320998Srmacklem goto nfsmout; 6028320998Srmacklem } 6029320998Srmacklem if (fhcnt > 1) 6030320998Srmacklem flp = malloc(sizeof(*flp) + (fhcnt - 1) * 6031320998Srmacklem sizeof(struct nfsfh *), M_NFSFLAYOUT, M_WAITOK); 6032320998Srmacklem else 6033320998Srmacklem flp = malloc(sizeof(*flp), M_NFSFLAYOUT, M_WAITOK); 6034320998Srmacklem flp->nfsfl_flags = 0; 6035320998Srmacklem flp->nfsfl_fhcnt = 0; 6036320998Srmacklem flp->nfsfl_devp = NULL; 6037320998Srmacklem flp->nfsfl_off = fxdr_hyper(tl); tl += 2; 6038320998Srmacklem retlen = fxdr_hyper(tl); tl += 2; 6039320998Srmacklem if (flp->nfsfl_off + retlen < flp->nfsfl_off) 6040320998Srmacklem flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 6041320998Srmacklem else 6042320998Srmacklem flp->nfsfl_end = flp->nfsfl_off + retlen; 6043320998Srmacklem flp->nfsfl_iomode = fxdr_unsigned(int, *tl++); 6044320998Srmacklem if (gotiomode == -1) 6045320998Srmacklem gotiomode = flp->nfsfl_iomode; 6046320998Srmacklem if (fxdr_unsigned(int, *tl++) != NFSLAYOUT_NFSV4_1_FILES) { 6047320998Srmacklem printf("NFSv4.1: got non-files layout\n"); 6048320998Srmacklem error = NFSERR_BADXDR; 6049320998Srmacklem goto nfsmout; 6050320998Srmacklem } 6051320998Srmacklem NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 6052320998Srmacklem tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 6053320998Srmacklem flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 6054320998Srmacklem NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 6055320998Srmacklem flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 6056320998Srmacklem flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 6057320998Srmacklem if (fxdr_unsigned(int, *tl) != fhcnt) { 6058320998Srmacklem printf("EEK! bad fhcnt\n"); 6059320998Srmacklem error = NFSERR_BADXDR; 6060320998Srmacklem goto nfsmout; 6061320998Srmacklem } 6062320998Srmacklem for (j = 0; j < fhcnt; j++) { 6063320998Srmacklem NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6064320998Srmacklem nfhlen = fxdr_unsigned(int, *tl); 6065320998Srmacklem if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 6066320998Srmacklem error = NFSERR_BADXDR; 6067320998Srmacklem goto nfsmout; 6068320998Srmacklem } 6069320998Srmacklem nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, M_NFSFH, 6070320998Srmacklem M_WAITOK); 6071320998Srmacklem flp->nfsfl_fh[j] = nfhp; 6072320998Srmacklem flp->nfsfl_fhcnt++; 6073320998Srmacklem nfhp->nfh_len = nfhlen; 6074320998Srmacklem NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 6075320998Srmacklem NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 6076320998Srmacklem } 6077320998Srmacklem if (flp->nfsfl_iomode == gotiomode) { 6078320998Srmacklem /* Keep the list in increasing offset order. */ 6079320998Srmacklem tflp = LIST_FIRST(flhp); 6080320998Srmacklem prevflp = NULL; 6081320998Srmacklem while (tflp != NULL && 6082320998Srmacklem tflp->nfsfl_off < flp->nfsfl_off) { 6083320998Srmacklem prevflp = tflp; 6084320998Srmacklem tflp = LIST_NEXT(tflp, nfsfl_list); 6085320998Srmacklem } 6086320998Srmacklem if (prevflp == NULL) 6087320998Srmacklem LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 6088320998Srmacklem else 6089320998Srmacklem LIST_INSERT_AFTER(prevflp, flp, 6090320998Srmacklem nfsfl_list); 6091320998Srmacklem } else { 6092320998Srmacklem printf("nfscl_layoutget(): got wrong iomode\n"); 6093320998Srmacklem nfscl_freeflayout(flp); 6094320998Srmacklem } 6095320998Srmacklem flp = NULL; 6096320998Srmacklem } 6097320998Srmacklemnfsmout: 6098320998Srmacklem if (error != 0 && flp != NULL) 6099320998Srmacklem nfscl_freeflayout(flp); 6100320998Srmacklem return (error); 6101320998Srmacklem} 6102320998Srmacklem 6103320998Srmacklem/* 6104320998Srmacklem * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), 6105320998Srmacklem * so that it does both an Open and a Layoutget. 6106320998Srmacklem */ 6107320998Srmacklemstatic int 6108320998Srmacklemnfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 6109320998Srmacklem int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 6110320998Srmacklem struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 6111320998Srmacklem struct ucred *cred, NFSPROC_T *p) 6112320998Srmacklem{ 6113320998Srmacklem struct nfscllayout *lyp; 6114320998Srmacklem struct nfsclflayout *flp; 6115320998Srmacklem struct nfsclflayouthead flh; 6116320998Srmacklem int error, islocked, layoutlen, recalled, retonclose, usecurstateid; 6117320998Srmacklem int laystat; 6118320998Srmacklem nfsv4stateid_t stateid; 6119320998Srmacklem struct nfsclsession *tsep; 6120320998Srmacklem 6121320998Srmacklem error = 0; 6122320998Srmacklem /* 6123320998Srmacklem * If lyp is returned non-NULL, there will be a refcnt (shared lock) 6124320998Srmacklem * on it, iff flp != NULL or a lock (exclusive lock) on it iff 6125320998Srmacklem * flp == NULL. 6126320998Srmacklem */ 6127320998Srmacklem lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp, 6128320998Srmacklem &recalled); 6129320998Srmacklem NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); 6130320998Srmacklem if (lyp == NULL) 6131320998Srmacklem islocked = 0; 6132320998Srmacklem else if (flp != NULL) 6133320998Srmacklem islocked = 1; 6134320998Srmacklem else 6135320998Srmacklem islocked = 2; 6136320998Srmacklem if ((lyp == NULL || flp == NULL) && recalled == 0) { 6137320998Srmacklem LIST_INIT(&flh); 6138320998Srmacklem tsep = nfsmnt_mdssession(nmp); 6139320998Srmacklem layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 6140320998Srmacklem 3 * NFSX_UNSIGNED); 6141320998Srmacklem if (lyp == NULL) 6142320998Srmacklem usecurstateid = 1; 6143320998Srmacklem else { 6144320998Srmacklem usecurstateid = 0; 6145320998Srmacklem stateid.seqid = lyp->nfsly_stateid.seqid; 6146320998Srmacklem stateid.other[0] = lyp->nfsly_stateid.other[0]; 6147320998Srmacklem stateid.other[1] = lyp->nfsly_stateid.other[1]; 6148320998Srmacklem stateid.other[2] = lyp->nfsly_stateid.other[2]; 6149320998Srmacklem } 6150320998Srmacklem error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, 6151320998Srmacklem newfhp, newfhlen, mode, op, name, namelen, 6152320998Srmacklem dpp, &stateid, usecurstateid, layoutlen, 6153320998Srmacklem &retonclose, &flh, &laystat, cred, p); 6154320998Srmacklem NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", 6155320998Srmacklem laystat, error); 6156320998Srmacklem laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, 6157320998Srmacklem &stateid, retonclose, NULL, &lyp, &flh, laystat, &islocked, 6158320998Srmacklem cred, p); 6159320998Srmacklem } else 6160320998Srmacklem error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, 6161320998Srmacklem mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); 6162320998Srmacklem if (islocked == 2) 6163320998Srmacklem nfscl_rellayout(lyp, 1); 6164320998Srmacklem else if (islocked == 1) 6165320998Srmacklem nfscl_rellayout(lyp, 0); 6166320998Srmacklem return (error); 6167320998Srmacklem} 6168320998Srmacklem 6169320998Srmacklem/* 6170320998Srmacklem * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS 6171320998Srmacklem * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are 6172320998Srmacklem * handled by nfsrpc_openrpc(). 6173320998Srmacklem * For the case where op == NULL, dvp is the directory. When op != NULL, it 6174320998Srmacklem * can be NULL. 6175320998Srmacklem */ 6176320998Srmacklemstatic int 6177320998Srmacklemnfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 6178320998Srmacklem int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 6179320998Srmacklem struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 6180320998Srmacklem nfsv4stateid_t *stateidp, int usecurstateid, 6181320998Srmacklem int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, 6182320998Srmacklem int *laystatp, struct ucred *cred, NFSPROC_T *p) 6183320998Srmacklem{ 6184320998Srmacklem uint32_t *tl; 6185320998Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 6186320998Srmacklem struct nfscldeleg *ndp = NULL; 6187320998Srmacklem struct nfsvattr nfsva; 6188320998Srmacklem struct nfsclsession *tsep; 6189320998Srmacklem uint32_t rflags, deleg; 6190320998Srmacklem nfsattrbit_t attrbits; 6191320998Srmacklem int error, ret, acesize, limitby, iomode; 6192320998Srmacklem 6193320998Srmacklem *dpp = NULL; 6194320998Srmacklem *laystatp = ENXIO; 6195320998Srmacklem nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL); 6196320998Srmacklem NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 6197320998Srmacklem *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 6198320998Srmacklem *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 6199320998Srmacklem *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 6200320998Srmacklem tsep = nfsmnt_mdssession(nmp); 6201320998Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 6202320998Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 6203320998Srmacklem nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 6204320998Srmacklem NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6205320998Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 6206320998Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 6207320998Srmacklem nfsm_strtom(nd, name, namelen); 6208320998Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6209320998Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 6210320998Srmacklem NFSZERO_ATTRBIT(&attrbits); 6211320998Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 6212320998Srmacklem NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 6213320998Srmacklem nfsrv_putattrbit(nd, &attrbits); 6214320998Srmacklem NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6215320998Srmacklem *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 6216320998Srmacklem if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) 6217320998Srmacklem iomode = NFSLAYOUTIOMODE_RW; 6218320998Srmacklem else 6219320998Srmacklem iomode = NFSLAYOUTIOMODE_READ; 6220320998Srmacklem nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, 6221320998Srmacklem layoutlen, usecurstateid); 6222320998Srmacklem error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 6223320998Srmacklem NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 6224320998Srmacklem if (error != 0) 6225320998Srmacklem return (error); 6226320998Srmacklem NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 6227320998Srmacklem if (nd->nd_repstat != 0) 6228320998Srmacklem *laystatp = nd->nd_repstat; 6229320998Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 6230320998Srmacklem /* ND_NOMOREDATA will be set if the Open operation failed. */ 6231320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6232320998Srmacklem 6 * NFSX_UNSIGNED); 6233320998Srmacklem op->nfso_stateid.seqid = *tl++; 6234320998Srmacklem op->nfso_stateid.other[0] = *tl++; 6235320998Srmacklem op->nfso_stateid.other[1] = *tl++; 6236320998Srmacklem op->nfso_stateid.other[2] = *tl; 6237320998Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 6238320998Srmacklem error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 6239320998Srmacklem if (error != 0) 6240320998Srmacklem goto nfsmout; 6241320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 6242320998Srmacklem deleg = fxdr_unsigned(u_int32_t, *tl); 6243320998Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 6244320998Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 6245320998Srmacklem if (!(op->nfso_own->nfsow_clp->nfsc_flags & 6246320998Srmacklem NFSCLFLAGS_FIRSTDELEG)) 6247320998Srmacklem op->nfso_own->nfsow_clp->nfsc_flags |= 6248320998Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 6249320998Srmacklem ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, 6250320998Srmacklem M_NFSCLDELEG, M_WAITOK); 6251320998Srmacklem LIST_INIT(&ndp->nfsdl_owner); 6252320998Srmacklem LIST_INIT(&ndp->nfsdl_lock); 6253320998Srmacklem ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 6254320998Srmacklem ndp->nfsdl_fhlen = newfhlen; 6255320998Srmacklem NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 6256320998Srmacklem newnfs_copyincred(cred, &ndp->nfsdl_cred); 6257320998Srmacklem nfscl_lockinit(&ndp->nfsdl_rwlock); 6258320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6259320998Srmacklem NFSX_UNSIGNED); 6260320998Srmacklem ndp->nfsdl_stateid.seqid = *tl++; 6261320998Srmacklem ndp->nfsdl_stateid.other[0] = *tl++; 6262320998Srmacklem ndp->nfsdl_stateid.other[1] = *tl++; 6263320998Srmacklem ndp->nfsdl_stateid.other[2] = *tl++; 6264320998Srmacklem ret = fxdr_unsigned(int, *tl); 6265320998Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 6266320998Srmacklem ndp->nfsdl_flags = NFSCLDL_WRITE; 6267320998Srmacklem /* 6268320998Srmacklem * Indicates how much the file can grow. 6269320998Srmacklem */ 6270320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, 6271320998Srmacklem 3 * NFSX_UNSIGNED); 6272320998Srmacklem limitby = fxdr_unsigned(int, *tl++); 6273320998Srmacklem switch (limitby) { 6274320998Srmacklem case NFSV4OPEN_LIMITSIZE: 6275320998Srmacklem ndp->nfsdl_sizelimit = fxdr_hyper(tl); 6276320998Srmacklem break; 6277320998Srmacklem case NFSV4OPEN_LIMITBLOCKS: 6278320998Srmacklem ndp->nfsdl_sizelimit = 6279320998Srmacklem fxdr_unsigned(u_int64_t, *tl++); 6280320998Srmacklem ndp->nfsdl_sizelimit *= 6281320998Srmacklem fxdr_unsigned(u_int64_t, *tl); 6282320998Srmacklem break; 6283320998Srmacklem default: 6284320998Srmacklem error = NFSERR_BADXDR; 6285320998Srmacklem goto nfsmout; 6286320998Srmacklem }; 6287320998Srmacklem } else 6288320998Srmacklem ndp->nfsdl_flags = NFSCLDL_READ; 6289320998Srmacklem if (ret != 0) 6290320998Srmacklem ndp->nfsdl_flags |= NFSCLDL_RECALL; 6291320998Srmacklem error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 6292320998Srmacklem &acesize, p); 6293320998Srmacklem if (error != 0) 6294320998Srmacklem goto nfsmout; 6295320998Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 6296320998Srmacklem error = NFSERR_BADXDR; 6297320998Srmacklem goto nfsmout; 6298320998Srmacklem } 6299320998Srmacklem if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || 6300320998Srmacklem nfscl_assumeposixlocks) 6301320998Srmacklem op->nfso_posixlock = 1; 6302320998Srmacklem else 6303320998Srmacklem op->nfso_posixlock = 0; 6304320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 6305320998Srmacklem /* If the 2nd element == NFS_OK, the Getattr succeeded. */ 6306320998Srmacklem if (*++tl == 0) { 6307320998Srmacklem error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 6308320998Srmacklem NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 6309320998Srmacklem NULL, NULL, NULL, p, cred); 6310320998Srmacklem if (error != 0) 6311320998Srmacklem goto nfsmout; 6312320998Srmacklem if (ndp != NULL) { 6313320998Srmacklem ndp->nfsdl_change = nfsva.na_filerev; 6314320998Srmacklem ndp->nfsdl_modtime = nfsva.na_mtime; 6315320998Srmacklem ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 6316320998Srmacklem *dpp = ndp; 6317320998Srmacklem ndp = NULL; 6318320998Srmacklem } 6319320998Srmacklem /* 6320320998Srmacklem * At this point, the Open has succeeded, so set 6321320998Srmacklem * nd_repstat = NFS_OK. If the Layoutget failed, 6322320998Srmacklem * this function just won't return a layout. 6323320998Srmacklem */ 6324320998Srmacklem if (nd->nd_repstat == 0) { 6325320998Srmacklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6326320998Srmacklem *laystatp = fxdr_unsigned(int, *++tl); 6327320998Srmacklem if (*laystatp == 0) { 6328320998Srmacklem error = nfsrv_parselayoutget(nd, 6329320998Srmacklem stateidp, retonclosep, flhp); 6330320998Srmacklem if (error != 0) 6331320998Srmacklem *laystatp = error; 6332320998Srmacklem } 6333320998Srmacklem } else 6334320998Srmacklem nd->nd_repstat = 0; /* Return 0 for Open. */ 6335320998Srmacklem } 6336320998Srmacklem } 6337320998Srmacklem if (nd->nd_repstat != 0 && error == 0) 6338320998Srmacklem error = nd->nd_repstat; 6339320998Srmacklemnfsmout: 6340320998Srmacklem free(ndp, M_NFSCLDELEG); 6341320998Srmacklem mbuf_freem(nd->nd_mrep); 6342320998Srmacklem return (error); 6343320998Srmacklem} 6344320998Srmacklem 6345320998Srmacklem/* 6346320998Srmacklem * Similar nfsrpc_createv4(), but also does the LayoutGet operation. 6347320998Srmacklem * Used only for mounts with pNFS enabled. 6348320998Srmacklem */ 6349320998Srmacklemstatic int 6350320998Srmacklemnfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 6351320998Srmacklem nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 6352320998Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 6353320998Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 6354320998Srmacklem int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp, 6355320998Srmacklem int usecurstateid, int layoutlen, int *retonclosep, 6356320998Srmacklem struct nfsclflayouthead *flhp, int *laystatp) 6357320998Srmacklem{ 6358320998Srmacklem uint32_t *tl; 6359320998Srmacklem int error = 0, deleg, newone, ret, acesize, limitby; 6360320998Srmacklem struct nfsrv_descript nfsd, *nd = &nfsd; 6361320998Srmacklem struct nfsclopen *op; 6362320998Srmacklem struct nfscldeleg *dp = NULL; 6363320998Srmacklem struct nfsnode *np; 6364320998Srmacklem struct nfsfh *nfhp; 6365320998Srmacklem struct nfsclsession *tsep; 6366320998Srmacklem nfsattrbit_t attrbits; 6367320998Srmacklem nfsv4stateid_t stateid; 6368320998Srmacklem uint32_t rflags; 6369320998Srmacklem struct nfsmount *nmp; 6370320998Srmacklem 6371320998Srmacklem nmp = VFSTONFS(dvp->v_mount); 6372320998Srmacklem np = VTONFS(dvp); 6373320998Srmacklem *laystatp = ENXIO; 6374320998Srmacklem *unlockedp = 0; 6375320998Srmacklem *nfhpp = NULL; 6376320998Srmacklem *dpp = NULL; 6377320998Srmacklem *attrflagp = 0; 6378320998Srmacklem *dattrflagp = 0; 6379320998Srmacklem if (namelen > NFS_MAXNAMLEN) 6380320998Srmacklem return (ENAMETOOLONG); 6381320998Srmacklem NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp); 6382320998Srmacklem /* 6383320998Srmacklem * For V4, this is actually an Open op. 6384320998Srmacklem */ 6385320998Srmacklem NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 6386320998Srmacklem *tl++ = txdr_unsigned(owp->nfsow_seqid); 6387320998Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 6388320998Srmacklem NFSV4OPEN_ACCESSREAD); 6389320998Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 6390320998Srmacklem tsep = nfsmnt_mdssession(nmp); 6391320998Srmacklem *tl++ = tsep->nfsess_clientid.lval[0]; 6392320998Srmacklem *tl = tsep->nfsess_clientid.lval[1]; 6393320998Srmacklem nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 6394320998Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 6395320998Srmacklem *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 6396320998Srmacklem if ((fmode & O_EXCL) != 0) { 6397320998Srmacklem if (NFSHASSESSPERSIST(nmp)) { 6398320998Srmacklem /* Use GUARDED for persistent sessions. */ 6399320998Srmacklem *tl = txdr_unsigned(NFSCREATE_GUARDED); 6400320998Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 6401320998Srmacklem } else { 6402320998Srmacklem /* Otherwise, use EXCLUSIVE4_1. */ 6403320998Srmacklem *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 6404320998Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 6405320998Srmacklem *tl++ = cverf.lval[0]; 6406320998Srmacklem *tl = cverf.lval[1]; 6407320998Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 6408320998Srmacklem } 6409320998Srmacklem } else { 6410320998Srmacklem *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 6411320998Srmacklem nfscl_fillsattr(nd, vap, dvp, 0, 0); 6412320998Srmacklem } 6413320998Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 6414320998Srmacklem *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 6415320998Srmacklem nfsm_strtom(nd, name, namelen); 6416320998Srmacklem /* Get the new file's handle and attributes, plus save the FH. */ 6417320998Srmacklem NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 6418320998Srmacklem *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); 6419320998Srmacklem *tl++ = txdr_unsigned(NFSV4OP_GETFH); 6420320998Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 6421320998Srmacklem NFSGETATTR_ATTRBIT(&attrbits); 6422320998Srmacklem nfsrv_putattrbit(nd, &attrbits); 6423320998Srmacklem /* Get the directory's post-op attributes. */ 6424320998Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 6425320998Srmacklem *tl = txdr_unsigned(NFSV4OP_PUTFH); 6426320998Srmacklem nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 6427320998Srmacklem NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 6428320998Srmacklem *tl = txdr_unsigned(NFSV4OP_GETATTR); 6429320998Srmacklem nfsrv_putattrbit(nd, &attrbits); 6430320998Srmacklem NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 6431320998Srmacklem *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); 6432320998Srmacklem *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 6433320998Srmacklem nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, 6434320998Srmacklem layoutlen, usecurstateid); 6435320998Srmacklem error = nfscl_request(nd, dvp, p, cred, dstuff); 6436320998Srmacklem if (error != 0) 6437320998Srmacklem return (error); 6438320998Srmacklem NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, 6439320998Srmacklem error); 6440320998Srmacklem if (nd->nd_repstat != 0) 6441320998Srmacklem *laystatp = nd->nd_repstat; 6442320998Srmacklem NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 6443320998Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 6444320998Srmacklem NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); 6445320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6446320998Srmacklem 6 * NFSX_UNSIGNED); 6447320998Srmacklem stateid.seqid = *tl++; 6448320998Srmacklem stateid.other[0] = *tl++; 6449320998Srmacklem stateid.other[1] = *tl++; 6450320998Srmacklem stateid.other[2] = *tl; 6451320998Srmacklem rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 6452320998Srmacklem nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 6453320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 6454320998Srmacklem deleg = fxdr_unsigned(int, *tl); 6455320998Srmacklem if (deleg == NFSV4OPEN_DELEGATEREAD || 6456320998Srmacklem deleg == NFSV4OPEN_DELEGATEWRITE) { 6457320998Srmacklem if (!(owp->nfsow_clp->nfsc_flags & 6458320998Srmacklem NFSCLFLAGS_FIRSTDELEG)) 6459320998Srmacklem owp->nfsow_clp->nfsc_flags |= 6460320998Srmacklem (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 6461320998Srmacklem dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, 6462320998Srmacklem M_NFSCLDELEG, M_WAITOK); 6463320998Srmacklem LIST_INIT(&dp->nfsdl_owner); 6464320998Srmacklem LIST_INIT(&dp->nfsdl_lock); 6465320998Srmacklem dp->nfsdl_clp = owp->nfsow_clp; 6466320998Srmacklem newnfs_copyincred(cred, &dp->nfsdl_cred); 6467320998Srmacklem nfscl_lockinit(&dp->nfsdl_rwlock); 6468320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 6469320998Srmacklem NFSX_UNSIGNED); 6470320998Srmacklem dp->nfsdl_stateid.seqid = *tl++; 6471320998Srmacklem dp->nfsdl_stateid.other[0] = *tl++; 6472320998Srmacklem dp->nfsdl_stateid.other[1] = *tl++; 6473320998Srmacklem dp->nfsdl_stateid.other[2] = *tl++; 6474320998Srmacklem ret = fxdr_unsigned(int, *tl); 6475320998Srmacklem if (deleg == NFSV4OPEN_DELEGATEWRITE) { 6476320998Srmacklem dp->nfsdl_flags = NFSCLDL_WRITE; 6477320998Srmacklem /* 6478320998Srmacklem * Indicates how much the file can grow. 6479320998Srmacklem */ 6480320998Srmacklem NFSM_DISSECT(tl, u_int32_t *, 6481320998Srmacklem 3 * NFSX_UNSIGNED); 6482320998Srmacklem limitby = fxdr_unsigned(int, *tl++); 6483320998Srmacklem switch (limitby) { 6484320998Srmacklem case NFSV4OPEN_LIMITSIZE: 6485320998Srmacklem dp->nfsdl_sizelimit = fxdr_hyper(tl); 6486320998Srmacklem break; 6487320998Srmacklem case NFSV4OPEN_LIMITBLOCKS: 6488320998Srmacklem dp->nfsdl_sizelimit = 6489320998Srmacklem fxdr_unsigned(u_int64_t, *tl++); 6490320998Srmacklem dp->nfsdl_sizelimit *= 6491320998Srmacklem fxdr_unsigned(u_int64_t, *tl); 6492320998Srmacklem break; 6493320998Srmacklem default: 6494320998Srmacklem error = NFSERR_BADXDR; 6495320998Srmacklem goto nfsmout; 6496320998Srmacklem }; 6497320998Srmacklem } else { 6498320998Srmacklem dp->nfsdl_flags = NFSCLDL_READ; 6499320998Srmacklem } 6500320998Srmacklem if (ret != 0) 6501320998Srmacklem dp->nfsdl_flags |= NFSCLDL_RECALL; 6502320998Srmacklem error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 6503320998Srmacklem &acesize, p); 6504320998Srmacklem if (error != 0) 6505320998Srmacklem goto nfsmout; 6506320998Srmacklem } else if (deleg != NFSV4OPEN_DELEGATENONE) { 6507320998Srmacklem error = NFSERR_BADXDR; 6508320998Srmacklem goto nfsmout; 6509320998Srmacklem } 6510320998Srmacklem 6511320998Srmacklem /* Now, we should have the status for the SaveFH. */ 6512320998Srmacklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6513320998Srmacklem if (*++tl == 0) { 6514320998Srmacklem NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); 6515320998Srmacklem /* 6516320998Srmacklem * Now, process the GetFH and Getattr for the newly 6517320998Srmacklem * created file. nfscl_mtofh() will set 6518320998Srmacklem * ND_NOMOREDATA if these weren't successful. 6519320998Srmacklem */ 6520320998Srmacklem error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 6521320998Srmacklem NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); 6522320998Srmacklem if (error != 0) 6523320998Srmacklem goto nfsmout; 6524320998Srmacklem } else 6525320998Srmacklem nd->nd_flag |= ND_NOMOREDATA; 6526320998Srmacklem /* Now we have the PutFH and Getattr for the directory. */ 6527320998Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 6528320998Srmacklem NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6529320998Srmacklem if (*++tl != 0) 6530320998Srmacklem nd->nd_flag |= ND_NOMOREDATA; 6531320998Srmacklem else { 6532320998Srmacklem NFSM_DISSECT(tl, uint32_t *, 2 * 6533320998Srmacklem NFSX_UNSIGNED); 6534320998Srmacklem if (*++tl != 0) 6535320998Srmacklem nd->nd_flag |= ND_NOMOREDATA; 6536320998Srmacklem } 6537320998Srmacklem } 6538320998Srmacklem if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 6539320998Srmacklem /* Load the directory attributes. */ 6540320998Srmacklem error = nfsm_loadattr(nd, dnap); 6541320998Srmacklem NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); 6542320998Srmacklem if (error != 0) 6543320998Srmacklem goto nfsmout; 6544320998Srmacklem *dattrflagp = 1; 6545320998Srmacklem if (dp != NULL && *attrflagp != 0) { 6546320998Srmacklem dp->nfsdl_change = nnap->na_filerev; 6547320998Srmacklem dp->nfsdl_modtime = nnap->na_mtime; 6548320998Srmacklem dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 6549320998Srmacklem } 6550320998Srmacklem /* 6551320998Srmacklem * We can now complete the Open state. 6552320998Srmacklem */ 6553320998Srmacklem nfhp = *nfhpp; 6554320998Srmacklem if (dp != NULL) { 6555320998Srmacklem dp->nfsdl_fhlen = nfhp->nfh_len; 6556320998Srmacklem NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, 6557320998Srmacklem nfhp->nfh_len); 6558320998Srmacklem } 6559320998Srmacklem /* 6560320998Srmacklem * Get an Open structure that will be 6561320998Srmacklem * attached to the OpenOwner, acquired already. 6562320998Srmacklem */ 6563320998Srmacklem error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 6564320998Srmacklem (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 6565320998Srmacklem cred, p, NULL, &op, &newone, NULL, 0); 6566320998Srmacklem if (error != 0) 6567320998Srmacklem goto nfsmout; 6568320998Srmacklem op->nfso_stateid = stateid; 6569320998Srmacklem newnfs_copyincred(cred, &op->nfso_cred); 6570320998Srmacklem 6571320998Srmacklem nfscl_openrelease(nmp, op, error, newone); 6572320998Srmacklem *unlockedp = 1; 6573320998Srmacklem 6574320998Srmacklem /* Now, handle the RestoreFH and LayoutGet. */ 6575320998Srmacklem if (nd->nd_repstat == 0) { 6576320998Srmacklem NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 6577320998Srmacklem *laystatp = fxdr_unsigned(int, *(tl + 3)); 6578320998Srmacklem if (*laystatp == 0) { 6579320998Srmacklem error = nfsrv_parselayoutget(nd, 6580320998Srmacklem stateidp, retonclosep, flhp); 6581320998Srmacklem if (error != 0) 6582320998Srmacklem *laystatp = error; 6583320998Srmacklem } 6584320998Srmacklem NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", 6585320998Srmacklem error); 6586320998Srmacklem } else 6587320998Srmacklem nd->nd_repstat = 0; 6588320998Srmacklem } 6589320998Srmacklem } 6590320998Srmacklem if (nd->nd_repstat != 0 && error == 0) 6591320998Srmacklem error = nd->nd_repstat; 6592320998Srmacklem if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) 6593320998Srmacklem nfscl_initiate_recovery(owp->nfsow_clp); 6594320998Srmacklemnfsmout: 6595320998Srmacklem NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); 6596320998Srmacklem if (error == 0) 6597320998Srmacklem *dpp = dp; 6598320998Srmacklem else 6599320998Srmacklem free(dp, M_NFSCLDELEG); 6600320998Srmacklem mbuf_freem(nd->nd_mrep); 6601320998Srmacklem return (error); 6602320998Srmacklem} 6603320998Srmacklem 6604320998Srmacklem/* 6605320998Srmacklem * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. 6606320998Srmacklem */ 6607320998Srmacklemstatic int 6608320998Srmacklemnfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 6609320998Srmacklem nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 6610320998Srmacklem struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 6611320998Srmacklem struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 6612320998Srmacklem int *dattrflagp, void *dstuff, int *unlockedp) 6613320998Srmacklem{ 6614320998Srmacklem struct nfscllayout *lyp; 6615320998Srmacklem struct nfsclflayouthead flh; 6616320998Srmacklem struct nfsfh *nfhp; 6617320998Srmacklem struct nfsclsession *tsep; 6618320998Srmacklem struct nfsmount *nmp; 6619320998Srmacklem nfsv4stateid_t stateid; 6620320998Srmacklem int error, layoutlen, retonclose, laystat; 6621320998Srmacklem 6622320998Srmacklem error = 0; 6623320998Srmacklem nmp = VFSTONFS(dvp->v_mount); 6624320998Srmacklem LIST_INIT(&flh); 6625320998Srmacklem tsep = nfsmnt_mdssession(nmp); 6626320998Srmacklem layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); 6627320998Srmacklem error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, 6628320998Srmacklem owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 6629320998Srmacklem dstuff, unlockedp, &stateid, 1, layoutlen, &retonclose, &flh, 6630320998Srmacklem &laystat); 6631320998Srmacklem NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", 6632320998Srmacklem laystat, error); 6633320998Srmacklem lyp = NULL; 6634322908Srmacklem if (laystat == 0) { 6635322908Srmacklem nfhp = *nfhpp; 6636322908Srmacklem laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, 6637322908Srmacklem nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, 6638322908Srmacklem laystat, NULL, cred, p); 6639322908Srmacklem } else 6640322908Srmacklem laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, 6641322908Srmacklem retonclose, NULL, &lyp, &flh, laystat, NULL, cred, p); 6642320998Srmacklem if (laystat == 0) 6643320998Srmacklem nfscl_rellayout(lyp, 0); 6644320998Srmacklem return (error); 6645320998Srmacklem} 6646320998Srmacklem 6647320998Srmacklem/* 6648320998Srmacklem * Process the results of a layoutget() operation. 6649320998Srmacklem */ 6650320998Srmacklemstatic int 6651320998Srmacklemnfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, 6652320998Srmacklem int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, 6653320998Srmacklem struct nfscllayout **lypp, struct nfsclflayouthead *flhp, 6654320998Srmacklem int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) 6655320998Srmacklem{ 6656320998Srmacklem struct nfsclflayout *tflp; 6657320998Srmacklem struct nfscldevinfo *dip; 6658320998Srmacklem 6659320998Srmacklem if (laystat == NFSERR_UNKNLAYOUTTYPE) { 6660320998Srmacklem /* Disable PNFS. */ 6661320998Srmacklem NFSCL_DEBUG(1, "disable PNFS\n"); 6662320998Srmacklem NFSLOCKMNT(nmp); 6663320998Srmacklem nmp->nm_state &= ~NFSSTA_PNFS; 6664320998Srmacklem NFSUNLOCKMNT(nmp); 6665320998Srmacklem } 6666320998Srmacklem if (laystat == 0) { 6667320998Srmacklem NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); 6668320998Srmacklem LIST_FOREACH(tflp, flhp, nfsfl_list) { 6669320998Srmacklem laystat = nfscl_adddevinfo(nmp, NULL, tflp); 6670320998Srmacklem NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); 6671320998Srmacklem if (laystat != 0) { 6672320998Srmacklem laystat = nfsrpc_getdeviceinfo(nmp, 6673320998Srmacklem tflp->nfsfl_dev, NFSLAYOUT_NFSV4_1_FILES, 6674320998Srmacklem notifybit, &dip, cred, p); 6675320998Srmacklem NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", 6676320998Srmacklem laystat); 6677320998Srmacklem if (laystat != 0) 6678320998Srmacklem break; 6679320998Srmacklem laystat = nfscl_adddevinfo(nmp, dip, tflp); 6680320998Srmacklem if (laystat != 0) 6681320998Srmacklem printf("getlayout: cannot add\n"); 6682320998Srmacklem } 6683320998Srmacklem } 6684320998Srmacklem } 6685320998Srmacklem if (laystat == 0) { 6686320998Srmacklem /* 6687320998Srmacklem * nfscl_layout() always returns with the nfsly_lock 6688320998Srmacklem * set to a refcnt (shared lock). 6689320998Srmacklem * Passing in dvp is sufficient, since it is only used to 6690320998Srmacklem * get the fsid for the file system. 6691320998Srmacklem */ 6692320998Srmacklem laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, 6693320998Srmacklem retonclose, flhp, lypp, cred, p); 6694320998Srmacklem NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", 6695320998Srmacklem laystat); 6696320998Srmacklem if (laystat == 0 && islockedp != NULL) 6697320998Srmacklem *islockedp = 1; 6698320998Srmacklem } 6699320998Srmacklem return (laystat); 6700320998Srmacklem} 6701320998Srmacklem 6702