1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 /* 40 * Rpc op calls, generally called from the vnode op calls or through the 41 * buffer cache, for NFS v2, 3 and 4. 42 * These do not normally make any changes to vnode arguments or use 43 * structures that might change between the VFS variants. The returned 44 * arguments are all at the end, after the NFSPROC_T *p one. 45 */ 46 47 #ifndef APPLEKEXT 48 #include "opt_inet6.h" 49 50 #include <fs/nfs/nfsport.h> 51 #include <sys/sysctl.h> 52 #include <sys/taskqueue.h> 53 54 SYSCTL_DECL(_vfs_nfs); 55 56 static int nfsignore_eexist = 0; 57 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW, 58 &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink"); 59 60 static int nfscl_dssameconn = 0; 61 SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW, 62 &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs"); 63 64 /* 65 * Global variables 66 */ 67 extern int nfs_numnfscbd; 68 extern struct timeval nfsboottime; 69 extern u_int32_t newnfs_false, newnfs_true; 70 extern nfstype nfsv34_type[9]; 71 extern int nfsrv_useacl; 72 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 73 extern int nfscl_debuglevel; 74 extern int nfs_pnfsiothreads; 75 NFSCLSTATEMUTEX; 76 int nfstest_outofseq = 0; 77 int nfscl_assumeposixlocks = 1; 78 int nfscl_enablecallb = 0; 79 short nfsv4_cbport = NFSV4_CBPORT; 80 int nfstest_openallsetattr = 0; 81 #endif /* !APPLEKEXT */ 82 83 #define DIRHDSIZ offsetof(struct dirent, d_name) 84 85 /* 86 * nfscl_getsameserver() can return one of three values: 87 * NFSDSP_USETHISSESSION - Use this session for the DS. 88 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new 89 * session. 90 * NFSDSP_NOTFOUND - No matching server was found. 91 */ 92 enum nfsclds_state { 93 NFSDSP_USETHISSESSION = 0, 94 NFSDSP_SEQTHISSESSION = 1, 95 NFSDSP_NOTFOUND = 2, 96 }; 97 98 /* 99 * Do a write RPC on a DS data file, using this structure for the arguments, 100 * so that this function can be executed by a separate kernel process. 101 */ 102 struct nfsclwritedsdorpc { 103 int done; 104 int inprog; 105 struct task tsk; 106 struct vnode *vp; 107 int iomode; 108 int must_commit; 109 nfsv4stateid_t *stateidp; 110 struct nfsclds *dsp; 111 uint64_t off; 112 int len; 113 struct nfsfh *fhp; 114 struct mbuf *m; 115 int vers; 116 int minorvers; 117 struct ucred *cred; 118 NFSPROC_T *p; 119 int err; 120 }; 121 122 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, 123 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); 124 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, 125 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *); 126 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, 127 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, 128 void *); 129 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, 130 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, 131 struct nfsvattr *, struct nfsfh **, int *, int *, void *); 132 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, 133 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, 134 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, 135 int *, void *, int *); 136 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, 137 struct nfscllockowner *, u_int64_t, u_int64_t, 138 u_int32_t, struct ucred *, NFSPROC_T *, int); 139 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, 140 struct acl *, nfsv4stateid_t *, void *); 141 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int, 142 uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **, 143 struct ucred *, NFSPROC_T *); 144 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *, 145 struct sockaddr_in6 *, sa_family_t, int, struct nfsclds **, NFSPROC_T *); 146 static void nfscl_initsessionslots(struct nfsclsession *); 147 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *, 148 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, 149 struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *, 150 NFSPROC_T *); 151 static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *, 152 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, 153 struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *, 154 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); 155 static struct mbuf *nfsm_copym(struct mbuf *, int, int); 156 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *, 157 struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int, 158 struct ucred *, NFSPROC_T *); 159 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *, 160 nfsv4stateid_t *, struct nfsclds *, uint64_t, int, 161 struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *); 162 static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *, 163 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int, 164 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); 165 static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *, 166 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int, 167 struct ucred *, NFSPROC_T *); 168 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *, 169 struct nfsclds *, struct nfsclds **, uint32_t *); 170 static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *, 171 struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *, 172 NFSPROC_T *); 173 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, 174 struct nfsfh *, int, int, struct ucred *, NFSPROC_T *); 175 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t, 176 uint64_t, uint64_t, nfsv4stateid_t *, int, int, int); 177 static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *, 178 NFSPROC_T *); 179 static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *, 180 int *, struct nfsclflayouthead *); 181 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *, 182 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, 183 struct nfscldeleg **, struct ucred *, NFSPROC_T *); 184 static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *, 185 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, 186 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, 187 struct nfsfh **, int *, int *, void *, int *); 188 static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *, 189 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, 190 struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *, 191 struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *); 192 static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *, 193 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, 194 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, 195 struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *, 196 int, int, int, int *, struct nfsclflayouthead *, int *); 197 static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t, 198 uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *, 199 struct nfsclflayouthead *, struct ucred *, NFSPROC_T *, void *); 200 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *, 201 int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **, 202 struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *); 203 204 int nfs_pnfsio(task_fn_t *, void *); 205 206 /* 207 * nfs null call from vfs. 208 */ 209 APPLESTATIC int 210 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) 211 { 212 int error; 213 struct nfsrv_descript nfsd, *nd = &nfsd; 214 215 NFSCL_REQSTART(nd, NFSPROC_NULL, vp); 216 error = nfscl_request(nd, vp, p, cred, NULL); 217 if (nd->nd_repstat && !error) 218 error = nd->nd_repstat; 219 mbuf_freem(nd->nd_mrep); 220 return (error); 221 } 222 223 /* 224 * nfs access rpc op. 225 * For nfs version 3 and 4, use the access rpc to check accessibility. If file 226 * modes are changed on the server, accesses might still fail later. 227 */ 228 APPLESTATIC int 229 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, 230 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 231 { 232 int error; 233 u_int32_t mode, rmode; 234 235 if (acmode & VREAD) 236 mode = NFSACCESS_READ; 237 else 238 mode = 0; 239 if (vnode_vtype(vp) == VDIR) { 240 if (acmode & VWRITE) 241 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | 242 NFSACCESS_DELETE); 243 if (acmode & VEXEC) 244 mode |= NFSACCESS_LOOKUP; 245 } else { 246 if (acmode & VWRITE) 247 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 248 if (acmode & VEXEC) 249 mode |= NFSACCESS_EXECUTE; 250 } 251 252 /* 253 * Now, just call nfsrpc_accessrpc() to do the actual RPC. 254 */ 255 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode, 256 NULL); 257 258 /* 259 * The NFS V3 spec does not clarify whether or not 260 * the returned access bits can be a superset of 261 * the ones requested, so... 262 */ 263 if (!error && (rmode & mode) != mode) 264 error = EACCES; 265 return (error); 266 } 267 268 /* 269 * The actual rpc, separated out for Darwin. 270 */ 271 APPLESTATIC int 272 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, 273 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep, 274 void *stuff) 275 { 276 u_int32_t *tl; 277 u_int32_t supported, rmode; 278 int error; 279 struct nfsrv_descript nfsd, *nd = &nfsd; 280 nfsattrbit_t attrbits; 281 282 *attrflagp = 0; 283 supported = mode; 284 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp); 285 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 286 *tl = txdr_unsigned(mode); 287 if (nd->nd_flag & ND_NFSV4) { 288 /* 289 * And do a Getattr op. 290 */ 291 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 292 *tl = txdr_unsigned(NFSV4OP_GETATTR); 293 NFSGETATTR_ATTRBIT(&attrbits); 294 (void) nfsrv_putattrbit(nd, &attrbits); 295 } 296 error = nfscl_request(nd, vp, p, cred, stuff); 297 if (error) 298 return (error); 299 if (nd->nd_flag & ND_NFSV3) { 300 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 301 if (error) 302 goto nfsmout; 303 } 304 if (!nd->nd_repstat) { 305 if (nd->nd_flag & ND_NFSV4) { 306 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 307 supported = fxdr_unsigned(u_int32_t, *tl++); 308 } else { 309 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 310 } 311 rmode = fxdr_unsigned(u_int32_t, *tl); 312 if (nd->nd_flag & ND_NFSV4) 313 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 314 315 /* 316 * It's not obvious what should be done about 317 * unsupported access modes. For now, be paranoid 318 * and clear the unsupported ones. 319 */ 320 rmode &= supported; 321 *rmodep = rmode; 322 } else 323 error = nd->nd_repstat; 324 nfsmout: 325 mbuf_freem(nd->nd_mrep); 326 return (error); 327 } 328 329 /* 330 * nfs open rpc 331 */ 332 APPLESTATIC int 333 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) 334 { 335 struct nfsclopen *op; 336 struct nfscldeleg *dp; 337 struct nfsfh *nfhp; 338 struct nfsnode *np = VTONFS(vp); 339 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 340 u_int32_t mode, clidrev; 341 int ret, newone, error, expireret = 0, retrycnt; 342 343 /* 344 * For NFSv4, Open Ops are only done on Regular Files. 345 */ 346 if (vnode_vtype(vp) != VREG) 347 return (0); 348 mode = 0; 349 if (amode & FREAD) 350 mode |= NFSV4OPEN_ACCESSREAD; 351 if (amode & FWRITE) 352 mode |= NFSV4OPEN_ACCESSWRITE; 353 nfhp = np->n_fhp; 354 355 retrycnt = 0; 356 #ifdef notdef 357 { char name[100]; int namel; 358 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99; 359 bcopy(NFS4NODENAME(np->n_v4), name, namel); 360 name[namel] = '\0'; 361 printf("rpcopen p=0x%x name=%s",p->p_pid,name); 362 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]); 363 else printf(" fhl=0\n"); 364 } 365 #endif 366 do { 367 dp = NULL; 368 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, 369 cred, p, NULL, &op, &newone, &ret, 1); 370 if (error) { 371 return (error); 372 } 373 if (nmp->nm_clp != NULL) 374 clidrev = nmp->nm_clp->nfsc_clientidrev; 375 else 376 clidrev = 0; 377 if (ret == NFSCLOPEN_DOOPEN) { 378 if (np->n_v4 != NULL) { 379 /* 380 * For the first attempt, try and get a layout, if 381 * pNFS is enabled for the mount. 382 */ 383 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || 384 nfs_numnfscbd == 0 || 385 (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0) 386 error = nfsrpc_openrpc(nmp, vp, 387 np->n_v4->n4_data, 388 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 389 np->n_fhp->nfh_len, mode, op, 390 NFS4NODENAME(np->n_v4), 391 np->n_v4->n4_namelen, 392 &dp, 0, 0x0, cred, p, 0, 0); 393 else 394 error = nfsrpc_getopenlayout(nmp, vp, 395 np->n_v4->n4_data, 396 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 397 np->n_fhp->nfh_len, mode, op, 398 NFS4NODENAME(np->n_v4), 399 np->n_v4->n4_namelen, &dp, cred, p); 400 if (dp != NULL) { 401 #ifdef APPLE 402 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); 403 #else 404 NFSLOCKNODE(np); 405 np->n_flag &= ~NDELEGMOD; 406 /* 407 * Invalidate the attribute cache, so that 408 * attributes that pre-date the issue of a 409 * delegation are not cached, since the 410 * cached attributes will remain valid while 411 * the delegation is held. 412 */ 413 NFSINVALATTRCACHE(np); 414 NFSUNLOCKNODE(np); 415 #endif 416 (void) nfscl_deleg(nmp->nm_mountp, 417 op->nfso_own->nfsow_clp, 418 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); 419 } 420 } else { 421 error = EIO; 422 } 423 newnfs_copyincred(cred, &op->nfso_cred); 424 } else if (ret == NFSCLOPEN_SETCRED) 425 /* 426 * This is a new local open on a delegation. It needs 427 * to have credentials so that an open can be done 428 * against the server during recovery. 429 */ 430 newnfs_copyincred(cred, &op->nfso_cred); 431 432 /* 433 * nfso_opencnt is the count of how many VOP_OPEN()s have 434 * been done on this Open successfully and a VOP_CLOSE() 435 * is expected for each of these. 436 * If error is non-zero, don't increment it, since the Open 437 * hasn't succeeded yet. 438 */ 439 if (!error) 440 op->nfso_opencnt++; 441 nfscl_openrelease(nmp, op, error, newone); 442 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 443 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 444 error == NFSERR_BADSESSION) { 445 (void) nfs_catnap(PZERO, error, "nfs_open"); 446 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 447 && clidrev != 0) { 448 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 449 retrycnt++; 450 } 451 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 452 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 453 error == NFSERR_BADSESSION || 454 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 455 expireret == 0 && clidrev != 0 && retrycnt < 4)); 456 if (error && retrycnt >= 4) 457 error = EIO; 458 return (error); 459 } 460 461 /* 462 * the actual open rpc 463 */ 464 APPLESTATIC int 465 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, 466 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 467 u_int8_t *name, int namelen, struct nfscldeleg **dpp, 468 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, 469 int syscred, int recursed) 470 { 471 u_int32_t *tl; 472 struct nfsrv_descript nfsd, *nd = &nfsd; 473 struct nfscldeleg *dp, *ndp = NULL; 474 struct nfsvattr nfsva; 475 u_int32_t rflags, deleg; 476 nfsattrbit_t attrbits; 477 int error, ret, acesize, limitby; 478 struct nfsclsession *tsep; 479 480 dp = *dpp; 481 *dpp = NULL; 482 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0); 483 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 484 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 485 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 486 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 487 tsep = nfsmnt_mdssession(nmp); 488 *tl++ = tsep->nfsess_clientid.lval[0]; 489 *tl = tsep->nfsess_clientid.lval[1]; 490 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 491 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 492 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 493 if (reclaim) { 494 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); 495 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 496 *tl = txdr_unsigned(delegtype); 497 } else { 498 if (dp != NULL) { 499 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); 500 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 501 if (NFSHASNFSV4N(nmp)) 502 *tl++ = 0; 503 else 504 *tl++ = dp->nfsdl_stateid.seqid; 505 *tl++ = dp->nfsdl_stateid.other[0]; 506 *tl++ = dp->nfsdl_stateid.other[1]; 507 *tl = dp->nfsdl_stateid.other[2]; 508 } else { 509 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 510 } 511 (void) nfsm_strtom(nd, name, namelen); 512 } 513 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 514 *tl = txdr_unsigned(NFSV4OP_GETATTR); 515 NFSZERO_ATTRBIT(&attrbits); 516 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 517 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 518 (void) nfsrv_putattrbit(nd, &attrbits); 519 if (syscred) 520 nd->nd_flag |= ND_USEGSSNAME; 521 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 522 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 523 if (error) 524 return (error); 525 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 526 if (!nd->nd_repstat) { 527 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 528 6 * NFSX_UNSIGNED); 529 op->nfso_stateid.seqid = *tl++; 530 op->nfso_stateid.other[0] = *tl++; 531 op->nfso_stateid.other[1] = *tl++; 532 op->nfso_stateid.other[2] = *tl; 533 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 534 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 535 if (error) 536 goto nfsmout; 537 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 538 deleg = fxdr_unsigned(u_int32_t, *tl); 539 if (deleg == NFSV4OPEN_DELEGATEREAD || 540 deleg == NFSV4OPEN_DELEGATEWRITE) { 541 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 542 NFSCLFLAGS_FIRSTDELEG)) 543 op->nfso_own->nfsow_clp->nfsc_flags |= 544 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 545 ndp = malloc( 546 sizeof (struct nfscldeleg) + newfhlen, 547 M_NFSCLDELEG, M_WAITOK); 548 LIST_INIT(&ndp->nfsdl_owner); 549 LIST_INIT(&ndp->nfsdl_lock); 550 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 551 ndp->nfsdl_fhlen = newfhlen; 552 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 553 newnfs_copyincred(cred, &ndp->nfsdl_cred); 554 nfscl_lockinit(&ndp->nfsdl_rwlock); 555 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 556 NFSX_UNSIGNED); 557 ndp->nfsdl_stateid.seqid = *tl++; 558 ndp->nfsdl_stateid.other[0] = *tl++; 559 ndp->nfsdl_stateid.other[1] = *tl++; 560 ndp->nfsdl_stateid.other[2] = *tl++; 561 ret = fxdr_unsigned(int, *tl); 562 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 563 ndp->nfsdl_flags = NFSCLDL_WRITE; 564 /* 565 * Indicates how much the file can grow. 566 */ 567 NFSM_DISSECT(tl, u_int32_t *, 568 3 * NFSX_UNSIGNED); 569 limitby = fxdr_unsigned(int, *tl++); 570 switch (limitby) { 571 case NFSV4OPEN_LIMITSIZE: 572 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 573 break; 574 case NFSV4OPEN_LIMITBLOCKS: 575 ndp->nfsdl_sizelimit = 576 fxdr_unsigned(u_int64_t, *tl++); 577 ndp->nfsdl_sizelimit *= 578 fxdr_unsigned(u_int64_t, *tl); 579 break; 580 default: 581 error = NFSERR_BADXDR; 582 goto nfsmout; 583 } 584 } else { 585 ndp->nfsdl_flags = NFSCLDL_READ; 586 } 587 if (ret) 588 ndp->nfsdl_flags |= NFSCLDL_RECALL; 589 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 590 &acesize, p); 591 if (error) 592 goto nfsmout; 593 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 594 error = NFSERR_BADXDR; 595 goto nfsmout; 596 } 597 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 598 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 599 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 600 NULL, NULL, NULL, p, cred); 601 if (error) 602 goto nfsmout; 603 if (ndp != NULL) { 604 ndp->nfsdl_change = nfsva.na_filerev; 605 ndp->nfsdl_modtime = nfsva.na_mtime; 606 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 607 } 608 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { 609 do { 610 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, 611 cred, p); 612 if (ret == NFSERR_DELAY) 613 (void) nfs_catnap(PZERO, ret, "nfs_open"); 614 } while (ret == NFSERR_DELAY); 615 error = ret; 616 } 617 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || 618 nfscl_assumeposixlocks) 619 op->nfso_posixlock = 1; 620 else 621 op->nfso_posixlock = 0; 622 623 /* 624 * If the server is handing out delegations, but we didn't 625 * get one because an OpenConfirm was required, try the 626 * Open again, to get a delegation. This is a harmless no-op, 627 * from a server's point of view. 628 */ 629 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && 630 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) 631 && !error && dp == NULL && ndp == NULL && !recursed) { 632 do { 633 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, 634 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, 635 cred, p, syscred, 1); 636 if (ret == NFSERR_DELAY) 637 (void) nfs_catnap(PZERO, ret, "nfs_open2"); 638 } while (ret == NFSERR_DELAY); 639 if (ret) { 640 if (ndp != NULL) { 641 free(ndp, M_NFSCLDELEG); 642 ndp = NULL; 643 } 644 if (ret == NFSERR_STALECLIENTID || 645 ret == NFSERR_STALEDONTRECOVER || 646 ret == NFSERR_BADSESSION) 647 error = ret; 648 } 649 } 650 } 651 if (nd->nd_repstat != 0 && error == 0) 652 error = nd->nd_repstat; 653 if (error == NFSERR_STALECLIENTID) 654 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 655 nfsmout: 656 if (!error) 657 *dpp = ndp; 658 else if (ndp != NULL) 659 free(ndp, M_NFSCLDELEG); 660 mbuf_freem(nd->nd_mrep); 661 return (error); 662 } 663 664 /* 665 * open downgrade rpc 666 */ 667 APPLESTATIC int 668 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, 669 struct ucred *cred, NFSPROC_T *p) 670 { 671 u_int32_t *tl; 672 struct nfsrv_descript nfsd, *nd = &nfsd; 673 int error; 674 675 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp); 676 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 677 if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp)))) 678 *tl++ = 0; 679 else 680 *tl++ = op->nfso_stateid.seqid; 681 *tl++ = op->nfso_stateid.other[0]; 682 *tl++ = op->nfso_stateid.other[1]; 683 *tl++ = op->nfso_stateid.other[2]; 684 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 685 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 686 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 687 error = nfscl_request(nd, vp, p, cred, NULL); 688 if (error) 689 return (error); 690 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 691 if (!nd->nd_repstat) { 692 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 693 op->nfso_stateid.seqid = *tl++; 694 op->nfso_stateid.other[0] = *tl++; 695 op->nfso_stateid.other[1] = *tl++; 696 op->nfso_stateid.other[2] = *tl; 697 } 698 if (nd->nd_repstat && error == 0) 699 error = nd->nd_repstat; 700 if (error == NFSERR_STALESTATEID) 701 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 702 nfsmout: 703 mbuf_freem(nd->nd_mrep); 704 return (error); 705 } 706 707 /* 708 * V4 Close operation. 709 */ 710 APPLESTATIC int 711 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) 712 { 713 struct nfsclclient *clp; 714 int error; 715 716 if (vnode_vtype(vp) != VREG) 717 return (0); 718 if (doclose) 719 error = nfscl_doclose(vp, &clp, p); 720 else 721 error = nfscl_getclose(vp, &clp); 722 if (error) 723 return (error); 724 725 nfscl_clientrelease(clp); 726 return (0); 727 } 728 729 /* 730 * Close the open. 731 */ 732 APPLESTATIC void 733 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p) 734 { 735 struct nfsrv_descript nfsd, *nd = &nfsd; 736 struct nfscllockowner *lp, *nlp; 737 struct nfscllock *lop, *nlop; 738 struct ucred *tcred; 739 u_int64_t off = 0, len = 0; 740 u_int32_t type = NFSV4LOCKT_READ; 741 int error, do_unlock, trycnt; 742 743 tcred = newnfs_getcred(); 744 newnfs_copycred(&op->nfso_cred, tcred); 745 /* 746 * (Theoretically this could be done in the same 747 * compound as the close, but having multiple 748 * sequenced Ops in the same compound might be 749 * too scary for some servers.) 750 */ 751 if (op->nfso_posixlock) { 752 off = 0; 753 len = NFS64BITSSET; 754 type = NFSV4LOCKT_READ; 755 } 756 757 /* 758 * Since this function is only called from VOP_INACTIVE(), no 759 * other thread will be manipulating this Open. As such, the 760 * lock lists are not being changed by other threads, so it should 761 * be safe to do this without locking. 762 */ 763 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 764 do_unlock = 1; 765 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 766 if (op->nfso_posixlock == 0) { 767 off = lop->nfslo_first; 768 len = lop->nfslo_end - lop->nfslo_first; 769 if (lop->nfslo_type == F_WRLCK) 770 type = NFSV4LOCKT_WRITE; 771 else 772 type = NFSV4LOCKT_READ; 773 } 774 if (do_unlock) { 775 trycnt = 0; 776 do { 777 error = nfsrpc_locku(nd, nmp, lp, off, 778 len, type, tcred, p, 0); 779 if ((nd->nd_repstat == NFSERR_GRACE || 780 nd->nd_repstat == NFSERR_DELAY) && 781 error == 0) 782 (void) nfs_catnap(PZERO, 783 (int)nd->nd_repstat, 784 "nfs_close"); 785 } while ((nd->nd_repstat == NFSERR_GRACE || 786 nd->nd_repstat == NFSERR_DELAY) && 787 error == 0 && trycnt++ < 5); 788 if (op->nfso_posixlock) 789 do_unlock = 0; 790 } 791 nfscl_freelock(lop, 0); 792 } 793 /* 794 * Do a ReleaseLockOwner. 795 * The lock owner name nfsl_owner may be used by other opens for 796 * other files but the lock_owner4 name that nfsrpc_rellockown() 797 * puts on the wire has the file handle for this file appended 798 * to it, so it can be done now. 799 */ 800 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh, 801 lp->nfsl_open->nfso_fhlen, tcred, p); 802 } 803 804 /* 805 * There could be other Opens for different files on the same 806 * OpenOwner, so locking is required. 807 */ 808 NFSLOCKCLSTATE(); 809 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 810 NFSUNLOCKCLSTATE(); 811 do { 812 error = nfscl_tryclose(op, tcred, nmp, p); 813 if (error == NFSERR_GRACE) 814 (void) nfs_catnap(PZERO, error, "nfs_close"); 815 } while (error == NFSERR_GRACE); 816 NFSLOCKCLSTATE(); 817 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); 818 819 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) 820 nfscl_freelockowner(lp, 0); 821 nfscl_freeopen(op, 0); 822 NFSUNLOCKCLSTATE(); 823 NFSFREECRED(tcred); 824 } 825 826 /* 827 * The actual Close RPC. 828 */ 829 APPLESTATIC int 830 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp, 831 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p, 832 int syscred) 833 { 834 u_int32_t *tl; 835 int error; 836 837 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh, 838 op->nfso_fhlen, NULL, NULL, 0, 0); 839 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 840 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 841 if (NFSHASNFSV4N(nmp)) 842 *tl++ = 0; 843 else 844 *tl++ = op->nfso_stateid.seqid; 845 *tl++ = op->nfso_stateid.other[0]; 846 *tl++ = op->nfso_stateid.other[1]; 847 *tl = op->nfso_stateid.other[2]; 848 if (syscred) 849 nd->nd_flag |= ND_USEGSSNAME; 850 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 851 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 852 if (error) 853 return (error); 854 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 855 if (nd->nd_repstat == 0) 856 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 857 error = nd->nd_repstat; 858 if (error == NFSERR_STALESTATEID) 859 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 860 nfsmout: 861 mbuf_freem(nd->nd_mrep); 862 return (error); 863 } 864 865 /* 866 * V4 Open Confirm RPC. 867 */ 868 APPLESTATIC int 869 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen, 870 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) 871 { 872 u_int32_t *tl; 873 struct nfsrv_descript nfsd, *nd = &nfsd; 874 struct nfsmount *nmp; 875 int error; 876 877 nmp = VFSTONFS(vnode_mount(vp)); 878 if (NFSHASNFSV4N(nmp)) 879 return (0); /* No confirmation for NFSv4.1. */ 880 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL, 881 0, 0); 882 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 883 *tl++ = op->nfso_stateid.seqid; 884 *tl++ = op->nfso_stateid.other[0]; 885 *tl++ = op->nfso_stateid.other[1]; 886 *tl++ = op->nfso_stateid.other[2]; 887 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid); 888 error = nfscl_request(nd, vp, p, cred, NULL); 889 if (error) 890 return (error); 891 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 892 if (!nd->nd_repstat) { 893 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 894 op->nfso_stateid.seqid = *tl++; 895 op->nfso_stateid.other[0] = *tl++; 896 op->nfso_stateid.other[1] = *tl++; 897 op->nfso_stateid.other[2] = *tl; 898 } 899 error = nd->nd_repstat; 900 if (error == NFSERR_STALESTATEID) 901 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 902 nfsmout: 903 mbuf_freem(nd->nd_mrep); 904 return (error); 905 } 906 907 /* 908 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs() 909 * when a mount has just occurred and when the server replies NFSERR_EXPIRED. 910 */ 911 APPLESTATIC int 912 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim, 913 struct ucred *cred, NFSPROC_T *p) 914 { 915 u_int32_t *tl; 916 struct nfsrv_descript nfsd; 917 struct nfsrv_descript *nd = &nfsd; 918 nfsattrbit_t attrbits; 919 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9]; 920 u_short port; 921 int error, isinet6 = 0, callblen; 922 nfsquad_t confirm; 923 u_int32_t lease; 924 static u_int32_t rev = 0; 925 struct nfsclds *dsp; 926 struct in6_addr a6; 927 struct nfsclsession *tsep; 928 929 if (nfsboottime.tv_sec == 0) 930 NFSSETBOOTTIME(nfsboottime); 931 clp->nfsc_rev = rev++; 932 if (NFSHASNFSV4N(nmp)) { 933 /* 934 * Either there was no previous session or the 935 * previous session has failed, so... 936 * do an ExchangeID followed by the CreateSession. 937 */ 938 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 939 NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p); 940 NFSCL_DEBUG(1, "aft exch=%d\n", error); 941 if (error == 0) 942 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 943 &nmp->nm_sockreq, 944 dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p); 945 if (error == 0) { 946 NFSLOCKMNT(nmp); 947 /* 948 * The old sessions cannot be safely free'd 949 * here, since they may still be used by 950 * in-progress RPCs. 951 */ 952 tsep = NULL; 953 if (TAILQ_FIRST(&nmp->nm_sess) != NULL) 954 tsep = NFSMNT_MDSSESSION(nmp); 955 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, 956 nfsclds_list); 957 /* 958 * Wake up RPCs waiting for a slot on the 959 * old session. These will then fail with 960 * NFSERR_BADSESSION and be retried with the 961 * new session by nfsv4_setsequence(). 962 * Also wakeup() processes waiting for the 963 * new session. 964 */ 965 if (tsep != NULL) 966 wakeup(&tsep->nfsess_slots); 967 wakeup(&nmp->nm_sess); 968 NFSUNLOCKMNT(nmp); 969 } else 970 nfscl_freenfsclds(dsp); 971 NFSCL_DEBUG(1, "aft createsess=%d\n", error); 972 if (error == 0 && reclaim == 0) { 973 error = nfsrpc_reclaimcomplete(nmp, cred, p); 974 NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error); 975 if (error == NFSERR_COMPLETEALREADY || 976 error == NFSERR_NOTSUPP) 977 /* Ignore this error. */ 978 error = 0; 979 } 980 return (error); 981 } 982 983 /* 984 * Allocate a single session structure for NFSv4.0, because some of 985 * the fields are used by NFSv4.0 although it doesn't do a session. 986 */ 987 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO); 988 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 989 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); 990 NFSLOCKMNT(nmp); 991 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list); 992 tsep = NFSMNT_MDSSESSION(nmp); 993 NFSUNLOCKMNT(nmp); 994 995 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0); 996 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 997 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 998 *tl = txdr_unsigned(clp->nfsc_rev); 999 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 1000 1001 /* 1002 * set up the callback address 1003 */ 1004 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1005 *tl = txdr_unsigned(NFS_CALLBCKPROG); 1006 callblen = strlen(nfsv4_callbackaddr); 1007 if (callblen == 0) 1008 cp = nfscl_getmyip(nmp, &a6, &isinet6); 1009 if (nfscl_enablecallb && nfs_numnfscbd > 0 && 1010 (callblen > 0 || cp != NULL)) { 1011 port = htons(nfsv4_cbport); 1012 cp2 = (u_int8_t *)&port; 1013 #ifdef INET6 1014 if ((callblen > 0 && 1015 strchr(nfsv4_callbackaddr, ':')) || isinet6) { 1016 char ip6buf[INET6_ADDRSTRLEN], *ip6add; 1017 1018 (void) nfsm_strtom(nd, "tcp6", 4); 1019 if (callblen == 0) { 1020 ip6_sprintf(ip6buf, (struct in6_addr *)cp); 1021 ip6add = ip6buf; 1022 } else { 1023 ip6add = nfsv4_callbackaddr; 1024 } 1025 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", 1026 ip6add, cp2[0], cp2[1]); 1027 } else 1028 #endif 1029 { 1030 (void) nfsm_strtom(nd, "tcp", 3); 1031 if (callblen == 0) 1032 snprintf(addr, INET6_ADDRSTRLEN + 9, 1033 "%d.%d.%d.%d.%d.%d", cp[0], cp[1], 1034 cp[2], cp[3], cp2[0], cp2[1]); 1035 else 1036 snprintf(addr, INET6_ADDRSTRLEN + 9, 1037 "%s.%d.%d", nfsv4_callbackaddr, 1038 cp2[0], cp2[1]); 1039 } 1040 (void) nfsm_strtom(nd, addr, strlen(addr)); 1041 } else { 1042 (void) nfsm_strtom(nd, "tcp", 3); 1043 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11); 1044 } 1045 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1046 *tl = txdr_unsigned(clp->nfsc_cbident); 1047 nd->nd_flag |= ND_USEGSSNAME; 1048 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 1049 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1050 if (error) 1051 return (error); 1052 if (nd->nd_repstat == 0) { 1053 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1054 tsep->nfsess_clientid.lval[0] = *tl++; 1055 tsep->nfsess_clientid.lval[1] = *tl++; 1056 confirm.lval[0] = *tl++; 1057 confirm.lval[1] = *tl; 1058 mbuf_freem(nd->nd_mrep); 1059 nd->nd_mrep = NULL; 1060 1061 /* 1062 * and confirm it. 1063 */ 1064 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL, 1065 NULL, 0, 0); 1066 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1067 *tl++ = tsep->nfsess_clientid.lval[0]; 1068 *tl++ = tsep->nfsess_clientid.lval[1]; 1069 *tl++ = confirm.lval[0]; 1070 *tl = confirm.lval[1]; 1071 nd->nd_flag |= ND_USEGSSNAME; 1072 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 1073 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1074 if (error) 1075 return (error); 1076 mbuf_freem(nd->nd_mrep); 1077 nd->nd_mrep = NULL; 1078 if (nd->nd_repstat == 0) { 1079 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh, 1080 nmp->nm_fhsize, NULL, NULL, 0, 0); 1081 NFSZERO_ATTRBIT(&attrbits); 1082 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 1083 (void) nfsrv_putattrbit(nd, &attrbits); 1084 nd->nd_flag |= ND_USEGSSNAME; 1085 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 1086 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1087 if (error) 1088 return (error); 1089 if (nd->nd_repstat == 0) { 1090 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL, 1091 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred); 1092 if (error) 1093 goto nfsmout; 1094 clp->nfsc_renew = NFSCL_RENEW(lease); 1095 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 1096 clp->nfsc_clientidrev++; 1097 if (clp->nfsc_clientidrev == 0) 1098 clp->nfsc_clientidrev++; 1099 } 1100 } 1101 } 1102 error = nd->nd_repstat; 1103 nfsmout: 1104 mbuf_freem(nd->nd_mrep); 1105 return (error); 1106 } 1107 1108 /* 1109 * nfs getattr call. 1110 */ 1111 APPLESTATIC int 1112 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 1113 struct nfsvattr *nap, void *stuff) 1114 { 1115 struct nfsrv_descript nfsd, *nd = &nfsd; 1116 int error; 1117 nfsattrbit_t attrbits; 1118 1119 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 1120 if (nd->nd_flag & ND_NFSV4) { 1121 NFSGETATTR_ATTRBIT(&attrbits); 1122 (void) nfsrv_putattrbit(nd, &attrbits); 1123 } 1124 error = nfscl_request(nd, vp, p, cred, stuff); 1125 if (error) 1126 return (error); 1127 if (!nd->nd_repstat) 1128 error = nfsm_loadattr(nd, nap); 1129 else 1130 error = nd->nd_repstat; 1131 mbuf_freem(nd->nd_mrep); 1132 return (error); 1133 } 1134 1135 /* 1136 * nfs getattr call with non-vnode arguemnts. 1137 */ 1138 APPLESTATIC int 1139 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, 1140 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp, 1141 uint32_t *leasep) 1142 { 1143 struct nfsrv_descript nfsd, *nd = &nfsd; 1144 int error, vers = NFS_VER2; 1145 nfsattrbit_t attrbits; 1146 1147 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0); 1148 if (nd->nd_flag & ND_NFSV4) { 1149 vers = NFS_VER4; 1150 NFSGETATTR_ATTRBIT(&attrbits); 1151 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 1152 (void) nfsrv_putattrbit(nd, &attrbits); 1153 } else if (nd->nd_flag & ND_NFSV3) { 1154 vers = NFS_VER3; 1155 } 1156 if (syscred) 1157 nd->nd_flag |= ND_USEGSSNAME; 1158 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 1159 NFS_PROG, vers, NULL, 1, xidp, NULL); 1160 if (error) 1161 return (error); 1162 if (nd->nd_repstat == 0) { 1163 if ((nd->nd_flag & ND_NFSV4) != 0) 1164 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 1165 NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL, 1166 NULL, NULL); 1167 else 1168 error = nfsm_loadattr(nd, nap); 1169 } else 1170 error = nd->nd_repstat; 1171 mbuf_freem(nd->nd_mrep); 1172 return (error); 1173 } 1174 1175 /* 1176 * Do an nfs setattr operation. 1177 */ 1178 APPLESTATIC int 1179 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, 1180 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp, 1181 void *stuff) 1182 { 1183 int error, expireret = 0, openerr, retrycnt; 1184 u_int32_t clidrev = 0, mode; 1185 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1186 struct nfsfh *nfhp; 1187 nfsv4stateid_t stateid; 1188 void *lckp; 1189 1190 if (nmp->nm_clp != NULL) 1191 clidrev = nmp->nm_clp->nfsc_clientidrev; 1192 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size)) 1193 mode = NFSV4OPEN_ACCESSWRITE; 1194 else 1195 mode = NFSV4OPEN_ACCESSREAD; 1196 retrycnt = 0; 1197 do { 1198 lckp = NULL; 1199 openerr = 1; 1200 if (NFSHASNFSV4(nmp)) { 1201 nfhp = VTONFS(vp)->n_fhp; 1202 error = nfscl_getstateid(vp, nfhp->nfh_fh, 1203 nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp); 1204 if (error && vnode_vtype(vp) == VREG && 1205 (mode == NFSV4OPEN_ACCESSWRITE || 1206 nfstest_openallsetattr)) { 1207 /* 1208 * No Open stateid, so try and open the file 1209 * now. 1210 */ 1211 if (mode == NFSV4OPEN_ACCESSWRITE) 1212 openerr = nfsrpc_open(vp, FWRITE, cred, 1213 p); 1214 else 1215 openerr = nfsrpc_open(vp, FREAD, cred, 1216 p); 1217 if (!openerr) 1218 (void) nfscl_getstateid(vp, 1219 nfhp->nfh_fh, nfhp->nfh_len, 1220 mode, 0, cred, p, &stateid, &lckp); 1221 } 1222 } 1223 if (vap != NULL) 1224 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p, 1225 rnap, attrflagp, stuff); 1226 else 1227 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid, 1228 stuff); 1229 if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) { 1230 NFSLOCKMNT(nmp); 1231 nmp->nm_state |= NFSSTA_OPENMODE; 1232 NFSUNLOCKMNT(nmp); 1233 } 1234 if (error == NFSERR_STALESTATEID) 1235 nfscl_initiate_recovery(nmp->nm_clp); 1236 if (lckp != NULL) 1237 nfscl_lockderef(lckp); 1238 if (!openerr) 1239 (void) nfsrpc_close(vp, 0, p); 1240 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1241 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1242 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1243 (void) nfs_catnap(PZERO, error, "nfs_setattr"); 1244 } else if ((error == NFSERR_EXPIRED || 1245 error == NFSERR_BADSTATEID) && clidrev != 0) { 1246 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1247 } 1248 retrycnt++; 1249 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1250 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1251 error == NFSERR_BADSESSION || 1252 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1253 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1254 expireret == 0 && clidrev != 0 && retrycnt < 4) || 1255 (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD && 1256 retrycnt < 4)); 1257 if (error && retrycnt >= 4) 1258 error = EIO; 1259 return (error); 1260 } 1261 1262 static int 1263 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, 1264 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 1265 struct nfsvattr *rnap, int *attrflagp, void *stuff) 1266 { 1267 u_int32_t *tl; 1268 struct nfsrv_descript nfsd, *nd = &nfsd; 1269 int error; 1270 nfsattrbit_t attrbits; 1271 1272 *attrflagp = 0; 1273 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp); 1274 if (nd->nd_flag & ND_NFSV4) 1275 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1276 vap->va_type = vnode_vtype(vp); 1277 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0); 1278 if (nd->nd_flag & ND_NFSV3) { 1279 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1280 *tl = newnfs_false; 1281 } else if (nd->nd_flag & ND_NFSV4) { 1282 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1283 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1284 NFSGETATTR_ATTRBIT(&attrbits); 1285 (void) nfsrv_putattrbit(nd, &attrbits); 1286 } 1287 error = nfscl_request(nd, vp, p, cred, stuff); 1288 if (error) 1289 return (error); 1290 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1291 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff); 1292 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error) 1293 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1294 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error) 1295 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff); 1296 mbuf_freem(nd->nd_mrep); 1297 if (nd->nd_repstat && !error) 1298 error = nd->nd_repstat; 1299 return (error); 1300 } 1301 1302 /* 1303 * nfs lookup rpc 1304 */ 1305 APPLESTATIC int 1306 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, 1307 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, 1308 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff) 1309 { 1310 u_int32_t *tl; 1311 struct nfsrv_descript nfsd, *nd = &nfsd; 1312 struct nfsmount *nmp; 1313 struct nfsnode *np; 1314 struct nfsfh *nfhp; 1315 nfsattrbit_t attrbits; 1316 int error = 0, lookupp = 0; 1317 1318 *attrflagp = 0; 1319 *dattrflagp = 0; 1320 if (vnode_vtype(dvp) != VDIR) 1321 return (ENOTDIR); 1322 nmp = VFSTONFS(vnode_mount(dvp)); 1323 if (len > NFS_MAXNAMLEN) 1324 return (ENAMETOOLONG); 1325 if (NFSHASNFSV4(nmp) && len == 1 && 1326 name[0] == '.') { 1327 /* 1328 * Just return the current dir's fh. 1329 */ 1330 np = VTONFS(dvp); 1331 nfhp = malloc(sizeof (struct nfsfh) + 1332 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1333 nfhp->nfh_len = np->n_fhp->nfh_len; 1334 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1335 *nfhpp = nfhp; 1336 return (0); 1337 } 1338 if (NFSHASNFSV4(nmp) && len == 2 && 1339 name[0] == '.' && name[1] == '.') { 1340 lookupp = 1; 1341 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp); 1342 } else { 1343 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp); 1344 (void) nfsm_strtom(nd, name, len); 1345 } 1346 if (nd->nd_flag & ND_NFSV4) { 1347 NFSGETATTR_ATTRBIT(&attrbits); 1348 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1349 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1350 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1351 (void) nfsrv_putattrbit(nd, &attrbits); 1352 } 1353 error = nfscl_request(nd, dvp, p, cred, stuff); 1354 if (error) 1355 return (error); 1356 if (nd->nd_repstat) { 1357 /* 1358 * When an NFSv4 Lookupp returns ENOENT, it means that 1359 * the lookup is at the root of an fs, so return this dir. 1360 */ 1361 if (nd->nd_repstat == NFSERR_NOENT && lookupp) { 1362 np = VTONFS(dvp); 1363 nfhp = malloc(sizeof (struct nfsfh) + 1364 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1365 nfhp->nfh_len = np->n_fhp->nfh_len; 1366 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1367 *nfhpp = nfhp; 1368 mbuf_freem(nd->nd_mrep); 1369 return (0); 1370 } 1371 if (nd->nd_flag & ND_NFSV3) 1372 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1373 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 1374 ND_NFSV4) { 1375 /* Load the directory attributes. */ 1376 error = nfsm_loadattr(nd, dnap); 1377 if (error == 0) 1378 *dattrflagp = 1; 1379 } 1380 goto nfsmout; 1381 } 1382 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 1383 /* Load the directory attributes. */ 1384 error = nfsm_loadattr(nd, dnap); 1385 if (error != 0) 1386 goto nfsmout; 1387 *dattrflagp = 1; 1388 /* Skip over the Lookup and GetFH operation status values. */ 1389 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1390 } 1391 error = nfsm_getfh(nd, nfhpp); 1392 if (error) 1393 goto nfsmout; 1394 1395 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1396 if ((nd->nd_flag & ND_NFSV3) && !error) 1397 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1398 nfsmout: 1399 mbuf_freem(nd->nd_mrep); 1400 if (!error && nd->nd_repstat) 1401 error = nd->nd_repstat; 1402 return (error); 1403 } 1404 1405 /* 1406 * Do a readlink rpc. 1407 */ 1408 APPLESTATIC int 1409 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, 1410 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1411 { 1412 u_int32_t *tl; 1413 struct nfsrv_descript nfsd, *nd = &nfsd; 1414 struct nfsnode *np = VTONFS(vp); 1415 nfsattrbit_t attrbits; 1416 int error, len, cangetattr = 1; 1417 1418 *attrflagp = 0; 1419 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp); 1420 if (nd->nd_flag & ND_NFSV4) { 1421 /* 1422 * And do a Getattr op. 1423 */ 1424 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1425 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1426 NFSGETATTR_ATTRBIT(&attrbits); 1427 (void) nfsrv_putattrbit(nd, &attrbits); 1428 } 1429 error = nfscl_request(nd, vp, p, cred, stuff); 1430 if (error) 1431 return (error); 1432 if (nd->nd_flag & ND_NFSV3) 1433 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1434 if (!nd->nd_repstat && !error) { 1435 NFSM_STRSIZ(len, NFS_MAXPATHLEN); 1436 /* 1437 * This seems weird to me, but must have been added to 1438 * FreeBSD for some reason. The only thing I can think of 1439 * is that there was/is some server that replies with 1440 * more link data than it should? 1441 */ 1442 if (len == NFS_MAXPATHLEN) { 1443 NFSLOCKNODE(np); 1444 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { 1445 len = np->n_size; 1446 cangetattr = 0; 1447 } 1448 NFSUNLOCKNODE(np); 1449 } 1450 error = nfsm_mbufuio(nd, uiop, len); 1451 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) 1452 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1453 } 1454 if (nd->nd_repstat && !error) 1455 error = nd->nd_repstat; 1456 nfsmout: 1457 mbuf_freem(nd->nd_mrep); 1458 return (error); 1459 } 1460 1461 /* 1462 * Read operation. 1463 */ 1464 APPLESTATIC int 1465 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, 1466 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1467 { 1468 int error, expireret = 0, retrycnt; 1469 u_int32_t clidrev = 0; 1470 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1471 struct nfsnode *np = VTONFS(vp); 1472 struct ucred *newcred; 1473 struct nfsfh *nfhp = NULL; 1474 nfsv4stateid_t stateid; 1475 void *lckp; 1476 1477 if (nmp->nm_clp != NULL) 1478 clidrev = nmp->nm_clp->nfsc_clientidrev; 1479 newcred = cred; 1480 if (NFSHASNFSV4(nmp)) { 1481 nfhp = np->n_fhp; 1482 newcred = NFSNEWCRED(cred); 1483 } 1484 retrycnt = 0; 1485 do { 1486 lckp = NULL; 1487 if (NFSHASNFSV4(nmp)) 1488 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1489 NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid, 1490 &lckp); 1491 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, 1492 attrflagp, stuff); 1493 if (error == NFSERR_OPENMODE) { 1494 NFSLOCKMNT(nmp); 1495 nmp->nm_state |= NFSSTA_OPENMODE; 1496 NFSUNLOCKMNT(nmp); 1497 } 1498 if (error == NFSERR_STALESTATEID) 1499 nfscl_initiate_recovery(nmp->nm_clp); 1500 if (lckp != NULL) 1501 nfscl_lockderef(lckp); 1502 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1503 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1504 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1505 (void) nfs_catnap(PZERO, error, "nfs_read"); 1506 } else if ((error == NFSERR_EXPIRED || 1507 error == NFSERR_BADSTATEID) && clidrev != 0) { 1508 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1509 } 1510 retrycnt++; 1511 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1512 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1513 error == NFSERR_BADSESSION || 1514 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1515 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1516 expireret == 0 && clidrev != 0 && retrycnt < 4) || 1517 (error == NFSERR_OPENMODE && retrycnt < 4)); 1518 if (error && retrycnt >= 4) 1519 error = EIO; 1520 if (NFSHASNFSV4(nmp)) 1521 NFSFREECRED(newcred); 1522 return (error); 1523 } 1524 1525 /* 1526 * The actual read RPC. 1527 */ 1528 static int 1529 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, 1530 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, 1531 int *attrflagp, void *stuff) 1532 { 1533 u_int32_t *tl; 1534 int error = 0, len, retlen, tsiz, eof = 0; 1535 struct nfsrv_descript nfsd; 1536 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1537 struct nfsrv_descript *nd = &nfsd; 1538 int rsize; 1539 off_t tmp_off; 1540 1541 *attrflagp = 0; 1542 tsiz = uio_uio_resid(uiop); 1543 tmp_off = uiop->uio_offset + tsiz; 1544 NFSLOCKMNT(nmp); 1545 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1546 NFSUNLOCKMNT(nmp); 1547 return (EFBIG); 1548 } 1549 rsize = nmp->nm_rsize; 1550 NFSUNLOCKMNT(nmp); 1551 nd->nd_mrep = NULL; 1552 while (tsiz > 0) { 1553 *attrflagp = 0; 1554 len = (tsiz > rsize) ? rsize : tsiz; 1555 NFSCL_REQSTART(nd, NFSPROC_READ, vp); 1556 if (nd->nd_flag & ND_NFSV4) 1557 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1558 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1559 if (nd->nd_flag & ND_NFSV2) { 1560 *tl++ = txdr_unsigned(uiop->uio_offset); 1561 *tl++ = txdr_unsigned(len); 1562 *tl = 0; 1563 } else { 1564 txdr_hyper(uiop->uio_offset, tl); 1565 *(tl + 2) = txdr_unsigned(len); 1566 } 1567 /* 1568 * Since I can't do a Getattr for NFSv4 for Write, there 1569 * doesn't seem any point in doing one here, either. 1570 * (See the comment in nfsrpc_writerpc() for more info.) 1571 */ 1572 error = nfscl_request(nd, vp, p, cred, stuff); 1573 if (error) 1574 return (error); 1575 if (nd->nd_flag & ND_NFSV3) { 1576 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1577 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { 1578 error = nfsm_loadattr(nd, nap); 1579 if (!error) 1580 *attrflagp = 1; 1581 } 1582 if (nd->nd_repstat || error) { 1583 if (!error) 1584 error = nd->nd_repstat; 1585 goto nfsmout; 1586 } 1587 if (nd->nd_flag & ND_NFSV3) { 1588 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1589 eof = fxdr_unsigned(int, *(tl + 1)); 1590 } else if (nd->nd_flag & ND_NFSV4) { 1591 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1592 eof = fxdr_unsigned(int, *tl); 1593 } 1594 NFSM_STRSIZ(retlen, len); 1595 error = nfsm_mbufuio(nd, uiop, retlen); 1596 if (error) 1597 goto nfsmout; 1598 mbuf_freem(nd->nd_mrep); 1599 nd->nd_mrep = NULL; 1600 tsiz -= retlen; 1601 if (!(nd->nd_flag & ND_NFSV2)) { 1602 if (eof || retlen == 0) 1603 tsiz = 0; 1604 } else if (retlen < len) 1605 tsiz = 0; 1606 } 1607 return (0); 1608 nfsmout: 1609 if (nd->nd_mrep != NULL) 1610 mbuf_freem(nd->nd_mrep); 1611 return (error); 1612 } 1613 1614 /* 1615 * nfs write operation 1616 * When called_from_strategy != 0, it should return EIO for an error that 1617 * indicates recovery is in progress, so that the buffer will be left 1618 * dirty and be written back to the server later. If it loops around, 1619 * the recovery thread could get stuck waiting for the buffer and recovery 1620 * will then deadlock. 1621 */ 1622 APPLESTATIC int 1623 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 1624 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 1625 void *stuff, int called_from_strategy) 1626 { 1627 int error, expireret = 0, retrycnt, nostateid; 1628 u_int32_t clidrev = 0; 1629 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1630 struct nfsnode *np = VTONFS(vp); 1631 struct ucred *newcred; 1632 struct nfsfh *nfhp = NULL; 1633 nfsv4stateid_t stateid; 1634 void *lckp; 1635 1636 *must_commit = 0; 1637 if (nmp->nm_clp != NULL) 1638 clidrev = nmp->nm_clp->nfsc_clientidrev; 1639 newcred = cred; 1640 if (NFSHASNFSV4(nmp)) { 1641 newcred = NFSNEWCRED(cred); 1642 nfhp = np->n_fhp; 1643 } 1644 retrycnt = 0; 1645 do { 1646 lckp = NULL; 1647 nostateid = 0; 1648 if (NFSHASNFSV4(nmp)) { 1649 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1650 NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid, 1651 &lckp); 1652 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 1653 stateid.other[2] == 0) { 1654 nostateid = 1; 1655 NFSCL_DEBUG(1, "stateid0 in write\n"); 1656 } 1657 } 1658 1659 /* 1660 * If there is no stateid for NFSv4, it means this is an 1661 * extraneous write after close. Basically a poorly 1662 * implemented buffer cache. Just don't do the write. 1663 */ 1664 if (nostateid) 1665 error = 0; 1666 else 1667 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, 1668 newcred, &stateid, p, nap, attrflagp, stuff); 1669 if (error == NFSERR_STALESTATEID) 1670 nfscl_initiate_recovery(nmp->nm_clp); 1671 if (lckp != NULL) 1672 nfscl_lockderef(lckp); 1673 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1674 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1675 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1676 (void) nfs_catnap(PZERO, error, "nfs_write"); 1677 } else if ((error == NFSERR_EXPIRED || 1678 error == NFSERR_BADSTATEID) && clidrev != 0) { 1679 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1680 } 1681 retrycnt++; 1682 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 1683 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1684 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || 1685 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1686 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1687 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1688 if (error != 0 && (retrycnt >= 4 || 1689 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1690 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0))) 1691 error = EIO; 1692 if (NFSHASNFSV4(nmp)) 1693 NFSFREECRED(newcred); 1694 return (error); 1695 } 1696 1697 /* 1698 * The actual write RPC. 1699 */ 1700 static int 1701 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, 1702 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, 1703 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1704 { 1705 u_int32_t *tl; 1706 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1707 struct nfsnode *np = VTONFS(vp); 1708 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; 1709 int wccflag = 0, wsize; 1710 int32_t backup; 1711 struct nfsrv_descript nfsd; 1712 struct nfsrv_descript *nd = &nfsd; 1713 nfsattrbit_t attrbits; 1714 off_t tmp_off; 1715 1716 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 1717 *attrflagp = 0; 1718 tsiz = uio_uio_resid(uiop); 1719 tmp_off = uiop->uio_offset + tsiz; 1720 NFSLOCKMNT(nmp); 1721 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1722 NFSUNLOCKMNT(nmp); 1723 return (EFBIG); 1724 } 1725 wsize = nmp->nm_wsize; 1726 NFSUNLOCKMNT(nmp); 1727 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ 1728 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ 1729 while (tsiz > 0) { 1730 *attrflagp = 0; 1731 len = (tsiz > wsize) ? wsize : tsiz; 1732 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); 1733 if (nd->nd_flag & ND_NFSV4) { 1734 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1735 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); 1736 txdr_hyper(uiop->uio_offset, tl); 1737 tl += 2; 1738 *tl++ = txdr_unsigned(*iomode); 1739 *tl = txdr_unsigned(len); 1740 } else if (nd->nd_flag & ND_NFSV3) { 1741 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); 1742 txdr_hyper(uiop->uio_offset, tl); 1743 tl += 2; 1744 *tl++ = txdr_unsigned(len); 1745 *tl++ = txdr_unsigned(*iomode); 1746 *tl = txdr_unsigned(len); 1747 } else { 1748 u_int32_t x; 1749 1750 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1751 /* 1752 * Not sure why someone changed this, since the 1753 * RFC clearly states that "beginoffset" and 1754 * "totalcount" are ignored, but it wouldn't 1755 * surprise me if there's a busted server out there. 1756 */ 1757 /* Set both "begin" and "current" to non-garbage. */ 1758 x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1759 *tl++ = x; /* "begin offset" */ 1760 *tl++ = x; /* "current offset" */ 1761 x = txdr_unsigned(len); 1762 *tl++ = x; /* total to this offset */ 1763 *tl = x; /* size of this write */ 1764 1765 } 1766 nfsm_uiombuf(nd, uiop, len); 1767 /* 1768 * Although it is tempting to do a normal Getattr Op in the 1769 * NFSv4 compound, the result can be a nearly hung client 1770 * system if the Getattr asks for Owner and/or OwnerGroup. 1771 * It occurs when the client can't map either the Owner or 1772 * Owner_group name in the Getattr reply to a uid/gid. When 1773 * there is a cache miss, the kernel does an upcall to the 1774 * nfsuserd. Then, it can try and read the local /etc/passwd 1775 * or /etc/group file. It can then block in getnewbuf(), 1776 * waiting for dirty writes to be pushed to the NFS server. 1777 * The only reason this doesn't result in a complete 1778 * deadlock, is that the upcall times out and allows 1779 * the write to complete. However, progress is so slow 1780 * that it might just as well be deadlocked. 1781 * As such, we get the rest of the attributes, but not 1782 * Owner or Owner_group. 1783 * nb: nfscl_loadattrcache() needs to be told that these 1784 * partial attributes from a write rpc are being 1785 * passed in, via a argument flag. 1786 */ 1787 if (nd->nd_flag & ND_NFSV4) { 1788 NFSWRITEGETATTR_ATTRBIT(&attrbits); 1789 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1790 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1791 (void) nfsrv_putattrbit(nd, &attrbits); 1792 } 1793 error = nfscl_request(nd, vp, p, cred, stuff); 1794 if (error) 1795 return (error); 1796 if (nd->nd_repstat) { 1797 /* 1798 * In case the rpc gets retried, roll 1799 * the uio fileds changed by nfsm_uiombuf() 1800 * back. 1801 */ 1802 uiop->uio_offset -= len; 1803 uio_uio_resid_add(uiop, len); 1804 uio_iov_base_add(uiop, -len); 1805 uio_iov_len_add(uiop, len); 1806 } 1807 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1808 error = nfscl_wcc_data(nd, vp, nap, attrflagp, 1809 &wccflag, stuff); 1810 if (error) 1811 goto nfsmout; 1812 } 1813 if (!nd->nd_repstat) { 1814 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1815 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1816 + NFSX_VERF); 1817 rlen = fxdr_unsigned(int, *tl++); 1818 if (rlen == 0) { 1819 error = NFSERR_IO; 1820 goto nfsmout; 1821 } else if (rlen < len) { 1822 backup = len - rlen; 1823 uio_iov_base_add(uiop, -(backup)); 1824 uio_iov_len_add(uiop, backup); 1825 uiop->uio_offset -= backup; 1826 uio_uio_resid_add(uiop, backup); 1827 len = rlen; 1828 } 1829 commit = fxdr_unsigned(int, *tl++); 1830 1831 /* 1832 * Return the lowest commitment level 1833 * obtained by any of the RPCs. 1834 */ 1835 if (committed == NFSWRITE_FILESYNC) 1836 committed = commit; 1837 else if (committed == NFSWRITE_DATASYNC && 1838 commit == NFSWRITE_UNSTABLE) 1839 committed = commit; 1840 NFSLOCKMNT(nmp); 1841 if (!NFSHASWRITEVERF(nmp)) { 1842 NFSBCOPY((caddr_t)tl, 1843 (caddr_t)&nmp->nm_verf[0], 1844 NFSX_VERF); 1845 NFSSETWRITEVERF(nmp); 1846 } else if (NFSBCMP(tl, nmp->nm_verf, 1847 NFSX_VERF)) { 1848 *must_commit = 1; 1849 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 1850 } 1851 NFSUNLOCKMNT(nmp); 1852 } 1853 if (nd->nd_flag & ND_NFSV4) 1854 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1855 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 1856 error = nfsm_loadattr(nd, nap); 1857 if (!error) 1858 *attrflagp = NFS_LATTR_NOSHRINK; 1859 } 1860 } else { 1861 error = nd->nd_repstat; 1862 } 1863 if (error) 1864 goto nfsmout; 1865 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4)); 1866 mbuf_freem(nd->nd_mrep); 1867 nd->nd_mrep = NULL; 1868 tsiz -= len; 1869 } 1870 nfsmout: 1871 if (nd->nd_mrep != NULL) 1872 mbuf_freem(nd->nd_mrep); 1873 *iomode = committed; 1874 if (nd->nd_repstat && !error) 1875 error = nd->nd_repstat; 1876 return (error); 1877 } 1878 1879 /* 1880 * nfs mknod rpc 1881 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1882 * mode set to specify the file type and the size field for rdev. 1883 */ 1884 APPLESTATIC int 1885 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1886 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p, 1887 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1888 int *attrflagp, int *dattrflagp, void *dstuff) 1889 { 1890 u_int32_t *tl; 1891 int error = 0; 1892 struct nfsrv_descript nfsd, *nd = &nfsd; 1893 nfsattrbit_t attrbits; 1894 1895 *nfhpp = NULL; 1896 *attrflagp = 0; 1897 *dattrflagp = 0; 1898 if (namelen > NFS_MAXNAMLEN) 1899 return (ENAMETOOLONG); 1900 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp); 1901 if (nd->nd_flag & ND_NFSV4) { 1902 if (vtyp == VBLK || vtyp == VCHR) { 1903 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1904 *tl++ = vtonfsv34_type(vtyp); 1905 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1906 *tl = txdr_unsigned(NFSMINOR(rdev)); 1907 } else { 1908 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1909 *tl = vtonfsv34_type(vtyp); 1910 } 1911 } 1912 (void) nfsm_strtom(nd, name, namelen); 1913 if (nd->nd_flag & ND_NFSV3) { 1914 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1915 *tl = vtonfsv34_type(vtyp); 1916 } 1917 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1918 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1919 if ((nd->nd_flag & ND_NFSV3) && 1920 (vtyp == VCHR || vtyp == VBLK)) { 1921 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1922 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1923 *tl = txdr_unsigned(NFSMINOR(rdev)); 1924 } 1925 if (nd->nd_flag & ND_NFSV4) { 1926 NFSGETATTR_ATTRBIT(&attrbits); 1927 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1928 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1929 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1930 (void) nfsrv_putattrbit(nd, &attrbits); 1931 } 1932 if (nd->nd_flag & ND_NFSV2) 1933 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 1934 error = nfscl_request(nd, dvp, p, cred, dstuff); 1935 if (error) 1936 return (error); 1937 if (nd->nd_flag & ND_NFSV4) 1938 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1939 if (!nd->nd_repstat) { 1940 if (nd->nd_flag & ND_NFSV4) { 1941 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1942 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1943 if (error) 1944 goto nfsmout; 1945 } 1946 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1947 if (error) 1948 goto nfsmout; 1949 } 1950 if (nd->nd_flag & ND_NFSV3) 1951 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1952 if (!error && nd->nd_repstat) 1953 error = nd->nd_repstat; 1954 nfsmout: 1955 mbuf_freem(nd->nd_mrep); 1956 return (error); 1957 } 1958 1959 /* 1960 * nfs file create call 1961 * Mostly just call the approriate routine. (I separated out v4, so that 1962 * error recovery wouldn't be as difficult.) 1963 */ 1964 APPLESTATIC int 1965 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1966 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1967 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1968 int *attrflagp, int *dattrflagp, void *dstuff) 1969 { 1970 int error = 0, newone, expireret = 0, retrycnt, unlocked; 1971 struct nfsclowner *owp; 1972 struct nfscldeleg *dp; 1973 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp)); 1974 u_int32_t clidrev; 1975 1976 if (NFSHASNFSV4(nmp)) { 1977 retrycnt = 0; 1978 do { 1979 dp = NULL; 1980 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 1981 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 1982 NULL, 1); 1983 if (error) 1984 return (error); 1985 if (nmp->nm_clp != NULL) 1986 clidrev = nmp->nm_clp->nfsc_clientidrev; 1987 else 1988 clidrev = 0; 1989 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || 1990 nfs_numnfscbd == 0 || retrycnt > 0) 1991 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, 1992 fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 1993 attrflagp, dattrflagp, dstuff, &unlocked); 1994 else 1995 error = nfsrpc_getcreatelayout(dvp, name, namelen, vap, 1996 cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 1997 attrflagp, dattrflagp, dstuff, &unlocked); 1998 /* 1999 * There is no need to invalidate cached attributes here, 2000 * since new post-delegation issue attributes are always 2001 * returned by nfsrpc_createv4() and these will update the 2002 * attribute cache. 2003 */ 2004 if (dp != NULL) 2005 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 2006 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 2007 nfscl_ownerrelease(nmp, owp, error, newone, unlocked); 2008 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 2009 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2010 error == NFSERR_BADSESSION) { 2011 (void) nfs_catnap(PZERO, error, "nfs_open"); 2012 } else if ((error == NFSERR_EXPIRED || 2013 error == NFSERR_BADSTATEID) && clidrev != 0) { 2014 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 2015 retrycnt++; 2016 } 2017 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 2018 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2019 error == NFSERR_BADSESSION || 2020 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 2021 expireret == 0 && clidrev != 0 && retrycnt < 4)); 2022 if (error && retrycnt >= 4) 2023 error = EIO; 2024 } else { 2025 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 2026 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 2027 dstuff); 2028 } 2029 return (error); 2030 } 2031 2032 /* 2033 * The create rpc for v2 and 3. 2034 */ 2035 static int 2036 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2037 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 2038 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 2039 int *attrflagp, int *dattrflagp, void *dstuff) 2040 { 2041 u_int32_t *tl; 2042 int error = 0; 2043 struct nfsrv_descript nfsd, *nd = &nfsd; 2044 2045 *nfhpp = NULL; 2046 *attrflagp = 0; 2047 *dattrflagp = 0; 2048 if (namelen > NFS_MAXNAMLEN) 2049 return (ENAMETOOLONG); 2050 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 2051 (void) nfsm_strtom(nd, name, namelen); 2052 if (nd->nd_flag & ND_NFSV3) { 2053 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2054 if (fmode & O_EXCL) { 2055 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2056 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2057 *tl++ = cverf.lval[0]; 2058 *tl = cverf.lval[1]; 2059 } else { 2060 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2061 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2062 } 2063 } else { 2064 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 2065 } 2066 error = nfscl_request(nd, dvp, p, cred, dstuff); 2067 if (error) 2068 return (error); 2069 if (nd->nd_repstat == 0) { 2070 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2071 if (error) 2072 goto nfsmout; 2073 } 2074 if (nd->nd_flag & ND_NFSV3) 2075 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2076 if (nd->nd_repstat != 0 && error == 0) 2077 error = nd->nd_repstat; 2078 nfsmout: 2079 mbuf_freem(nd->nd_mrep); 2080 return (error); 2081 } 2082 2083 static int 2084 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2085 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 2086 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2087 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2088 int *dattrflagp, void *dstuff, int *unlockedp) 2089 { 2090 u_int32_t *tl; 2091 int error = 0, deleg, newone, ret, acesize, limitby; 2092 struct nfsrv_descript nfsd, *nd = &nfsd; 2093 struct nfsclopen *op; 2094 struct nfscldeleg *dp = NULL; 2095 struct nfsnode *np; 2096 struct nfsfh *nfhp; 2097 nfsattrbit_t attrbits; 2098 nfsv4stateid_t stateid; 2099 u_int32_t rflags; 2100 struct nfsmount *nmp; 2101 struct nfsclsession *tsep; 2102 2103 nmp = VFSTONFS(dvp->v_mount); 2104 np = VTONFS(dvp); 2105 *unlockedp = 0; 2106 *nfhpp = NULL; 2107 *dpp = NULL; 2108 *attrflagp = 0; 2109 *dattrflagp = 0; 2110 if (namelen > NFS_MAXNAMLEN) 2111 return (ENAMETOOLONG); 2112 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 2113 /* 2114 * For V4, this is actually an Open op. 2115 */ 2116 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2117 *tl++ = txdr_unsigned(owp->nfsow_seqid); 2118 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 2119 NFSV4OPEN_ACCESSREAD); 2120 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 2121 tsep = nfsmnt_mdssession(nmp); 2122 *tl++ = tsep->nfsess_clientid.lval[0]; 2123 *tl = tsep->nfsess_clientid.lval[1]; 2124 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 2125 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2126 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 2127 if (fmode & O_EXCL) { 2128 if (NFSHASNFSV4N(nmp)) { 2129 if (NFSHASSESSPERSIST(nmp)) { 2130 /* Use GUARDED for persistent sessions. */ 2131 *tl = txdr_unsigned(NFSCREATE_GUARDED); 2132 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2133 } else { 2134 /* Otherwise, use EXCLUSIVE4_1. */ 2135 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 2136 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2137 *tl++ = cverf.lval[0]; 2138 *tl = cverf.lval[1]; 2139 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2140 } 2141 } else { 2142 /* NFSv4.0 */ 2143 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2144 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2145 *tl++ = cverf.lval[0]; 2146 *tl = cverf.lval[1]; 2147 } 2148 } else { 2149 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2150 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2151 } 2152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2153 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 2154 (void) nfsm_strtom(nd, name, namelen); 2155 /* Get the new file's handle and attributes. */ 2156 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2157 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2158 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2159 NFSGETATTR_ATTRBIT(&attrbits); 2160 (void) nfsrv_putattrbit(nd, &attrbits); 2161 /* Get the directory's post-op attributes. */ 2162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2163 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2164 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 2165 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2166 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2167 (void) nfsrv_putattrbit(nd, &attrbits); 2168 error = nfscl_request(nd, dvp, p, cred, dstuff); 2169 if (error) 2170 return (error); 2171 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 2172 if (nd->nd_repstat == 0) { 2173 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2174 6 * NFSX_UNSIGNED); 2175 stateid.seqid = *tl++; 2176 stateid.other[0] = *tl++; 2177 stateid.other[1] = *tl++; 2178 stateid.other[2] = *tl; 2179 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 2180 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2181 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2182 deleg = fxdr_unsigned(int, *tl); 2183 if (deleg == NFSV4OPEN_DELEGATEREAD || 2184 deleg == NFSV4OPEN_DELEGATEWRITE) { 2185 if (!(owp->nfsow_clp->nfsc_flags & 2186 NFSCLFLAGS_FIRSTDELEG)) 2187 owp->nfsow_clp->nfsc_flags |= 2188 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 2189 dp = malloc( 2190 sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 2191 M_NFSCLDELEG, M_WAITOK); 2192 LIST_INIT(&dp->nfsdl_owner); 2193 LIST_INIT(&dp->nfsdl_lock); 2194 dp->nfsdl_clp = owp->nfsow_clp; 2195 newnfs_copyincred(cred, &dp->nfsdl_cred); 2196 nfscl_lockinit(&dp->nfsdl_rwlock); 2197 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2198 NFSX_UNSIGNED); 2199 dp->nfsdl_stateid.seqid = *tl++; 2200 dp->nfsdl_stateid.other[0] = *tl++; 2201 dp->nfsdl_stateid.other[1] = *tl++; 2202 dp->nfsdl_stateid.other[2] = *tl++; 2203 ret = fxdr_unsigned(int, *tl); 2204 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 2205 dp->nfsdl_flags = NFSCLDL_WRITE; 2206 /* 2207 * Indicates how much the file can grow. 2208 */ 2209 NFSM_DISSECT(tl, u_int32_t *, 2210 3 * NFSX_UNSIGNED); 2211 limitby = fxdr_unsigned(int, *tl++); 2212 switch (limitby) { 2213 case NFSV4OPEN_LIMITSIZE: 2214 dp->nfsdl_sizelimit = fxdr_hyper(tl); 2215 break; 2216 case NFSV4OPEN_LIMITBLOCKS: 2217 dp->nfsdl_sizelimit = 2218 fxdr_unsigned(u_int64_t, *tl++); 2219 dp->nfsdl_sizelimit *= 2220 fxdr_unsigned(u_int64_t, *tl); 2221 break; 2222 default: 2223 error = NFSERR_BADXDR; 2224 goto nfsmout; 2225 } 2226 } else { 2227 dp->nfsdl_flags = NFSCLDL_READ; 2228 } 2229 if (ret) 2230 dp->nfsdl_flags |= NFSCLDL_RECALL; 2231 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 2232 &acesize, p); 2233 if (error) 2234 goto nfsmout; 2235 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 2236 error = NFSERR_BADXDR; 2237 goto nfsmout; 2238 } 2239 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2240 if (error) 2241 goto nfsmout; 2242 /* Get rid of the PutFH and Getattr status values. */ 2243 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2244 /* Load the directory attributes. */ 2245 error = nfsm_loadattr(nd, dnap); 2246 if (error) 2247 goto nfsmout; 2248 *dattrflagp = 1; 2249 if (dp != NULL && *attrflagp) { 2250 dp->nfsdl_change = nnap->na_filerev; 2251 dp->nfsdl_modtime = nnap->na_mtime; 2252 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 2253 } 2254 /* 2255 * We can now complete the Open state. 2256 */ 2257 nfhp = *nfhpp; 2258 if (dp != NULL) { 2259 dp->nfsdl_fhlen = nfhp->nfh_len; 2260 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 2261 } 2262 /* 2263 * Get an Open structure that will be 2264 * attached to the OpenOwner, acquired already. 2265 */ 2266 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 2267 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 2268 cred, p, NULL, &op, &newone, NULL, 0); 2269 if (error) 2270 goto nfsmout; 2271 op->nfso_stateid = stateid; 2272 newnfs_copyincred(cred, &op->nfso_cred); 2273 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 2274 do { 2275 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 2276 nfhp->nfh_len, op, cred, p); 2277 if (ret == NFSERR_DELAY) 2278 (void) nfs_catnap(PZERO, ret, "nfs_create"); 2279 } while (ret == NFSERR_DELAY); 2280 error = ret; 2281 } 2282 2283 /* 2284 * If the server is handing out delegations, but we didn't 2285 * get one because an OpenConfirm was required, try the 2286 * Open again, to get a delegation. This is a harmless no-op, 2287 * from a server's point of view. 2288 */ 2289 if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 2290 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 2291 !error && dp == NULL) { 2292 do { 2293 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp, 2294 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 2295 nfhp->nfh_fh, nfhp->nfh_len, 2296 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2297 name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2298 if (ret == NFSERR_DELAY) 2299 (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2300 } while (ret == NFSERR_DELAY); 2301 if (ret) { 2302 if (dp != NULL) { 2303 free(dp, M_NFSCLDELEG); 2304 dp = NULL; 2305 } 2306 if (ret == NFSERR_STALECLIENTID || 2307 ret == NFSERR_STALEDONTRECOVER || 2308 ret == NFSERR_BADSESSION) 2309 error = ret; 2310 } 2311 } 2312 nfscl_openrelease(nmp, op, error, newone); 2313 *unlockedp = 1; 2314 } 2315 if (nd->nd_repstat != 0 && error == 0) 2316 error = nd->nd_repstat; 2317 if (error == NFSERR_STALECLIENTID) 2318 nfscl_initiate_recovery(owp->nfsow_clp); 2319 nfsmout: 2320 if (!error) 2321 *dpp = dp; 2322 else if (dp != NULL) 2323 free(dp, M_NFSCLDELEG); 2324 mbuf_freem(nd->nd_mrep); 2325 return (error); 2326 } 2327 2328 /* 2329 * Nfs remove rpc 2330 */ 2331 APPLESTATIC int 2332 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2333 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, 2334 void *dstuff) 2335 { 2336 u_int32_t *tl; 2337 struct nfsrv_descript nfsd, *nd = &nfsd; 2338 struct nfsnode *np; 2339 struct nfsmount *nmp; 2340 nfsv4stateid_t dstateid; 2341 int error, ret = 0, i; 2342 2343 *dattrflagp = 0; 2344 if (namelen > NFS_MAXNAMLEN) 2345 return (ENAMETOOLONG); 2346 nmp = VFSTONFS(vnode_mount(dvp)); 2347 tryagain: 2348 if (NFSHASNFSV4(nmp) && ret == 0) { 2349 ret = nfscl_removedeleg(vp, p, &dstateid); 2350 if (ret == 1) { 2351 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp); 2352 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2353 NFSX_UNSIGNED); 2354 if (NFSHASNFSV4N(nmp)) 2355 *tl++ = 0; 2356 else 2357 *tl++ = dstateid.seqid; 2358 *tl++ = dstateid.other[0]; 2359 *tl++ = dstateid.other[1]; 2360 *tl++ = dstateid.other[2]; 2361 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2362 np = VTONFS(dvp); 2363 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2364 np->n_fhp->nfh_len, 0); 2365 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2366 *tl = txdr_unsigned(NFSV4OP_REMOVE); 2367 } 2368 } else { 2369 ret = 0; 2370 } 2371 if (ret == 0) 2372 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp); 2373 (void) nfsm_strtom(nd, name, namelen); 2374 error = nfscl_request(nd, dvp, p, cred, dstuff); 2375 if (error) 2376 return (error); 2377 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2378 /* For NFSv4, parse out any Delereturn replies. */ 2379 if (ret > 0 && nd->nd_repstat != 0 && 2380 (nd->nd_flag & ND_NOMOREDATA)) { 2381 /* 2382 * If the Delegreturn failed, try again without 2383 * it. The server will Recall, as required. 2384 */ 2385 mbuf_freem(nd->nd_mrep); 2386 goto tryagain; 2387 } 2388 for (i = 0; i < (ret * 2); i++) { 2389 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2390 ND_NFSV4) { 2391 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2392 if (*(tl + 1)) 2393 nd->nd_flag |= ND_NOMOREDATA; 2394 } 2395 } 2396 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2397 } 2398 if (nd->nd_repstat && !error) 2399 error = nd->nd_repstat; 2400 nfsmout: 2401 mbuf_freem(nd->nd_mrep); 2402 return (error); 2403 } 2404 2405 /* 2406 * Do an nfs rename rpc. 2407 */ 2408 APPLESTATIC int 2409 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2410 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2411 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2412 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff) 2413 { 2414 u_int32_t *tl; 2415 struct nfsrv_descript nfsd, *nd = &nfsd; 2416 struct nfsmount *nmp; 2417 struct nfsnode *np; 2418 nfsattrbit_t attrbits; 2419 nfsv4stateid_t fdstateid, tdstateid; 2420 int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2421 2422 *fattrflagp = 0; 2423 *tattrflagp = 0; 2424 nmp = VFSTONFS(vnode_mount(fdvp)); 2425 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2426 return (ENAMETOOLONG); 2427 tryagain: 2428 if (NFSHASNFSV4(nmp) && ret == 0) { 2429 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2430 &tdstateid, &gottd, p); 2431 if (gotfd && gottd) { 2432 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp); 2433 } else if (gotfd) { 2434 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp); 2435 } else if (gottd) { 2436 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp); 2437 } 2438 if (gotfd) { 2439 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2440 if (NFSHASNFSV4N(nmp)) 2441 *tl++ = 0; 2442 else 2443 *tl++ = fdstateid.seqid; 2444 *tl++ = fdstateid.other[0]; 2445 *tl++ = fdstateid.other[1]; 2446 *tl = fdstateid.other[2]; 2447 if (gottd) { 2448 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2449 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2450 np = VTONFS(tvp); 2451 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2452 np->n_fhp->nfh_len, 0); 2453 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2454 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2455 } 2456 } 2457 if (gottd) { 2458 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2459 if (NFSHASNFSV4N(nmp)) 2460 *tl++ = 0; 2461 else 2462 *tl++ = tdstateid.seqid; 2463 *tl++ = tdstateid.other[0]; 2464 *tl++ = tdstateid.other[1]; 2465 *tl = tdstateid.other[2]; 2466 } 2467 if (ret > 0) { 2468 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2469 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2470 np = VTONFS(fdvp); 2471 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2472 np->n_fhp->nfh_len, 0); 2473 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2474 *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2475 } 2476 } else { 2477 ret = 0; 2478 } 2479 if (ret == 0) 2480 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp); 2481 if (nd->nd_flag & ND_NFSV4) { 2482 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2483 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2484 NFSWCCATTR_ATTRBIT(&attrbits); 2485 (void) nfsrv_putattrbit(nd, &attrbits); 2486 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2487 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2488 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2489 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2490 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2491 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2492 (void) nfsrv_putattrbit(nd, &attrbits); 2493 nd->nd_flag |= ND_V4WCCATTR; 2494 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2495 *tl = txdr_unsigned(NFSV4OP_RENAME); 2496 } 2497 (void) nfsm_strtom(nd, fnameptr, fnamelen); 2498 if (!(nd->nd_flag & ND_NFSV4)) 2499 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2500 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2501 (void) nfsm_strtom(nd, tnameptr, tnamelen); 2502 error = nfscl_request(nd, fdvp, p, cred, fstuff); 2503 if (error) 2504 return (error); 2505 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2506 /* For NFSv4, parse out any Delereturn replies. */ 2507 if (ret > 0 && nd->nd_repstat != 0 && 2508 (nd->nd_flag & ND_NOMOREDATA)) { 2509 /* 2510 * If the Delegreturn failed, try again without 2511 * it. The server will Recall, as required. 2512 */ 2513 mbuf_freem(nd->nd_mrep); 2514 goto tryagain; 2515 } 2516 for (i = 0; i < (ret * 2); i++) { 2517 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2518 ND_NFSV4) { 2519 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2520 if (*(tl + 1)) { 2521 if (i == 0 && ret > 1) { 2522 /* 2523 * If the Delegreturn failed, try again 2524 * without it. The server will Recall, as 2525 * required. 2526 * If ret > 1, the first iteration of this 2527 * loop is the second DelegReturn result. 2528 */ 2529 mbuf_freem(nd->nd_mrep); 2530 goto tryagain; 2531 } else { 2532 nd->nd_flag |= ND_NOMOREDATA; 2533 } 2534 } 2535 } 2536 } 2537 /* Now, the first wcc attribute reply. */ 2538 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2539 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2540 if (*(tl + 1)) 2541 nd->nd_flag |= ND_NOMOREDATA; 2542 } 2543 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, 2544 fstuff); 2545 /* and the second wcc attribute reply. */ 2546 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2547 !error) { 2548 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2549 if (*(tl + 1)) 2550 nd->nd_flag |= ND_NOMOREDATA; 2551 } 2552 if (!error) 2553 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2554 NULL, tstuff); 2555 } 2556 if (nd->nd_repstat && !error) 2557 error = nd->nd_repstat; 2558 nfsmout: 2559 mbuf_freem(nd->nd_mrep); 2560 return (error); 2561 } 2562 2563 /* 2564 * nfs hard link create rpc 2565 */ 2566 APPLESTATIC int 2567 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2568 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2569 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2570 { 2571 u_int32_t *tl; 2572 struct nfsrv_descript nfsd, *nd = &nfsd; 2573 nfsattrbit_t attrbits; 2574 int error = 0; 2575 2576 *attrflagp = 0; 2577 *dattrflagp = 0; 2578 if (namelen > NFS_MAXNAMLEN) 2579 return (ENAMETOOLONG); 2580 NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2581 if (nd->nd_flag & ND_NFSV4) { 2582 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2583 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2584 } 2585 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2586 VTONFS(dvp)->n_fhp->nfh_len, 0); 2587 if (nd->nd_flag & ND_NFSV4) { 2588 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2589 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2590 NFSWCCATTR_ATTRBIT(&attrbits); 2591 (void) nfsrv_putattrbit(nd, &attrbits); 2592 nd->nd_flag |= ND_V4WCCATTR; 2593 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2594 *tl = txdr_unsigned(NFSV4OP_LINK); 2595 } 2596 (void) nfsm_strtom(nd, name, namelen); 2597 error = nfscl_request(nd, vp, p, cred, dstuff); 2598 if (error) 2599 return (error); 2600 if (nd->nd_flag & ND_NFSV3) { 2601 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2602 if (!error) 2603 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2604 NULL, dstuff); 2605 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2606 /* 2607 * First, parse out the PutFH and Getattr result. 2608 */ 2609 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2610 if (!(*(tl + 1))) 2611 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2612 if (*(tl + 1)) 2613 nd->nd_flag |= ND_NOMOREDATA; 2614 /* 2615 * Get the pre-op attributes. 2616 */ 2617 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2618 } 2619 if (nd->nd_repstat && !error) 2620 error = nd->nd_repstat; 2621 nfsmout: 2622 mbuf_freem(nd->nd_mrep); 2623 return (error); 2624 } 2625 2626 /* 2627 * nfs symbolic link create rpc 2628 */ 2629 APPLESTATIC int 2630 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target, 2631 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2632 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2633 int *dattrflagp, void *dstuff) 2634 { 2635 u_int32_t *tl; 2636 struct nfsrv_descript nfsd, *nd = &nfsd; 2637 struct nfsmount *nmp; 2638 int slen, error = 0; 2639 2640 *nfhpp = NULL; 2641 *attrflagp = 0; 2642 *dattrflagp = 0; 2643 nmp = VFSTONFS(vnode_mount(dvp)); 2644 slen = strlen(target); 2645 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2646 return (ENAMETOOLONG); 2647 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2648 if (nd->nd_flag & ND_NFSV4) { 2649 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2650 *tl = txdr_unsigned(NFLNK); 2651 (void) nfsm_strtom(nd, target, slen); 2652 } 2653 (void) nfsm_strtom(nd, name, namelen); 2654 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2655 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2656 if (!(nd->nd_flag & ND_NFSV4)) 2657 (void) nfsm_strtom(nd, target, slen); 2658 if (nd->nd_flag & ND_NFSV2) 2659 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2660 error = nfscl_request(nd, dvp, p, cred, dstuff); 2661 if (error) 2662 return (error); 2663 if (nd->nd_flag & ND_NFSV4) 2664 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2665 if ((nd->nd_flag & ND_NFSV3) && !error) { 2666 if (!nd->nd_repstat) 2667 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2668 if (!error) 2669 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2670 NULL, dstuff); 2671 } 2672 if (nd->nd_repstat && !error) 2673 error = nd->nd_repstat; 2674 mbuf_freem(nd->nd_mrep); 2675 /* 2676 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2677 * Only do this if vfs.nfs.ignore_eexist is set. 2678 * Never do this for NFSv4.1 or later minor versions, since sessions 2679 * should guarantee "exactly once" RPC semantics. 2680 */ 2681 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2682 nmp->nm_minorvers == 0)) 2683 error = 0; 2684 return (error); 2685 } 2686 2687 /* 2688 * nfs make dir rpc 2689 */ 2690 APPLESTATIC int 2691 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2692 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2693 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2694 int *dattrflagp, void *dstuff) 2695 { 2696 u_int32_t *tl; 2697 struct nfsrv_descript nfsd, *nd = &nfsd; 2698 nfsattrbit_t attrbits; 2699 int error = 0; 2700 struct nfsfh *fhp; 2701 struct nfsmount *nmp; 2702 2703 *nfhpp = NULL; 2704 *attrflagp = 0; 2705 *dattrflagp = 0; 2706 nmp = VFSTONFS(vnode_mount(dvp)); 2707 fhp = VTONFS(dvp)->n_fhp; 2708 if (namelen > NFS_MAXNAMLEN) 2709 return (ENAMETOOLONG); 2710 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 2711 if (nd->nd_flag & ND_NFSV4) { 2712 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2713 *tl = txdr_unsigned(NFDIR); 2714 } 2715 (void) nfsm_strtom(nd, name, namelen); 2716 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2717 if (nd->nd_flag & ND_NFSV4) { 2718 NFSGETATTR_ATTRBIT(&attrbits); 2719 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2720 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2721 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2722 (void) nfsrv_putattrbit(nd, &attrbits); 2723 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2724 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2725 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0); 2726 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2727 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2728 (void) nfsrv_putattrbit(nd, &attrbits); 2729 } 2730 error = nfscl_request(nd, dvp, p, cred, dstuff); 2731 if (error) 2732 return (error); 2733 if (nd->nd_flag & ND_NFSV4) 2734 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2735 if (!nd->nd_repstat && !error) { 2736 if (nd->nd_flag & ND_NFSV4) { 2737 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2738 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2739 } 2740 if (!error) 2741 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2742 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 2743 /* Get rid of the PutFH and Getattr status values. */ 2744 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2745 /* Load the directory attributes. */ 2746 error = nfsm_loadattr(nd, dnap); 2747 if (error == 0) 2748 *dattrflagp = 1; 2749 } 2750 } 2751 if ((nd->nd_flag & ND_NFSV3) && !error) 2752 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2753 if (nd->nd_repstat && !error) 2754 error = nd->nd_repstat; 2755 nfsmout: 2756 mbuf_freem(nd->nd_mrep); 2757 /* 2758 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2759 * Only do this if vfs.nfs.ignore_eexist is set. 2760 * Never do this for NFSv4.1 or later minor versions, since sessions 2761 * should guarantee "exactly once" RPC semantics. 2762 */ 2763 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2764 nmp->nm_minorvers == 0)) 2765 error = 0; 2766 return (error); 2767 } 2768 2769 /* 2770 * nfs remove directory call 2771 */ 2772 APPLESTATIC int 2773 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 2774 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 2775 { 2776 struct nfsrv_descript nfsd, *nd = &nfsd; 2777 int error = 0; 2778 2779 *dattrflagp = 0; 2780 if (namelen > NFS_MAXNAMLEN) 2781 return (ENAMETOOLONG); 2782 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 2783 (void) nfsm_strtom(nd, name, namelen); 2784 error = nfscl_request(nd, dvp, p, cred, dstuff); 2785 if (error) 2786 return (error); 2787 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2788 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2789 if (nd->nd_repstat && !error) 2790 error = nd->nd_repstat; 2791 mbuf_freem(nd->nd_mrep); 2792 /* 2793 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2794 */ 2795 if (error == ENOENT) 2796 error = 0; 2797 return (error); 2798 } 2799 2800 /* 2801 * Readdir rpc. 2802 * Always returns with either uio_resid unchanged, if you are at the 2803 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 2804 * filled in. 2805 * I felt this would allow caching of directory blocks more easily 2806 * than returning a pertially filled block. 2807 * Directory offset cookies: 2808 * Oh my, what to do with them... 2809 * I can think of three ways to deal with them: 2810 * 1 - have the layer above these RPCs maintain a map between logical 2811 * directory byte offsets and the NFS directory offset cookies 2812 * 2 - pass the opaque directory offset cookies up into userland 2813 * and let the libc functions deal with them, via the system call 2814 * 3 - return them to userland in the "struct dirent", so future versions 2815 * of libc can use them and do whatever is necessary to make things work 2816 * above these rpc calls, in the meantime 2817 * For now, I do #3 by "hiding" the directory offset cookies after the 2818 * d_name field in struct dirent. This is space inside d_reclen that 2819 * will be ignored by anything that doesn't know about them. 2820 * The directory offset cookies are filled in as the last 8 bytes of 2821 * each directory entry, after d_name. Someday, the userland libc 2822 * functions may be able to use these. In the meantime, it satisfies 2823 * OpenBSD's requirements for cookies being returned. 2824 * If expects the directory offset cookie for the read to be in uio_offset 2825 * and returns the one for the next entry after this directory block in 2826 * there, as well. 2827 */ 2828 APPLESTATIC int 2829 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2830 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2831 int *eofp, void *stuff) 2832 { 2833 int len, left; 2834 struct dirent *dp = NULL; 2835 u_int32_t *tl; 2836 nfsquad_t cookie, ncookie; 2837 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2838 struct nfsnode *dnp = VTONFS(vp); 2839 struct nfsvattr nfsva; 2840 struct nfsrv_descript nfsd, *nd = &nfsd; 2841 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2842 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 2843 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 2844 char *cp; 2845 nfsattrbit_t attrbits, dattrbits; 2846 u_int32_t rderr, *tl2 = NULL; 2847 size_t tresid; 2848 2849 KASSERT(uiop->uio_iovcnt == 1 && 2850 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2851 ("nfs readdirrpc bad uio")); 2852 ncookie.lval[0] = ncookie.lval[1] = 0; 2853 /* 2854 * There is no point in reading a lot more than uio_resid, however 2855 * adding one additional DIRBLKSIZ makes sense. Since uio_resid 2856 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 2857 * will never make readsize > nm_readdirsize. 2858 */ 2859 readsize = nmp->nm_readdirsize; 2860 if (readsize > uio_uio_resid(uiop)) 2861 readsize = uio_uio_resid(uiop) + DIRBLKSIZ; 2862 2863 *attrflagp = 0; 2864 if (eofp) 2865 *eofp = 0; 2866 tresid = uio_uio_resid(uiop); 2867 cookie.lval[0] = cookiep->nfsuquad[0]; 2868 cookie.lval[1] = cookiep->nfsuquad[1]; 2869 nd->nd_mrep = NULL; 2870 2871 /* 2872 * For NFSv4, first create the "." and ".." entries. 2873 */ 2874 if (NFSHASNFSV4(nmp)) { 2875 reqsize = 6 * NFSX_UNSIGNED; 2876 NFSGETATTR_ATTRBIT(&dattrbits); 2877 NFSZERO_ATTRBIT(&attrbits); 2878 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2879 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 2880 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2881 NFSATTRBIT_MOUNTEDONFILEID)) { 2882 NFSSETBIT_ATTRBIT(&attrbits, 2883 NFSATTRBIT_MOUNTEDONFILEID); 2884 gotmnton = 1; 2885 } else { 2886 /* 2887 * Must fake it. Use the fileno, except when the 2888 * fsid is != to that of the directory. For that 2889 * case, generate a fake fileno that is not the same. 2890 */ 2891 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2892 gotmnton = 0; 2893 } 2894 2895 /* 2896 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2897 */ 2898 if (uiop->uio_offset == 0) { 2899 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2900 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2901 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2902 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2903 (void) nfsrv_putattrbit(nd, &attrbits); 2904 error = nfscl_request(nd, vp, p, cred, stuff); 2905 if (error) 2906 return (error); 2907 dotfileid = 0; /* Fake out the compiler. */ 2908 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 2909 error = nfsm_loadattr(nd, &nfsva); 2910 if (error != 0) 2911 goto nfsmout; 2912 dotfileid = nfsva.na_fileid; 2913 } 2914 if (nd->nd_repstat == 0) { 2915 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2916 len = fxdr_unsigned(int, *(tl + 4)); 2917 if (len > 0 && len <= NFSX_V4FHMAX) 2918 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2919 else 2920 error = EPERM; 2921 if (!error) { 2922 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2923 nfsva.na_mntonfileno = UINT64_MAX; 2924 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2925 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2926 NULL, NULL, NULL, p, cred); 2927 if (error) { 2928 dotdotfileid = dotfileid; 2929 } else if (gotmnton) { 2930 if (nfsva.na_mntonfileno != UINT64_MAX) 2931 dotdotfileid = nfsva.na_mntonfileno; 2932 else 2933 dotdotfileid = nfsva.na_fileid; 2934 } else if (nfsva.na_filesid[0] == 2935 dnp->n_vattr.na_filesid[0] && 2936 nfsva.na_filesid[1] == 2937 dnp->n_vattr.na_filesid[1]) { 2938 dotdotfileid = nfsva.na_fileid; 2939 } else { 2940 do { 2941 fakefileno--; 2942 } while (fakefileno == 2943 nfsva.na_fileid); 2944 dotdotfileid = fakefileno; 2945 } 2946 } 2947 } else if (nd->nd_repstat == NFSERR_NOENT) { 2948 /* 2949 * Lookupp returns NFSERR_NOENT when we are 2950 * at the root, so just use the current dir. 2951 */ 2952 nd->nd_repstat = 0; 2953 dotdotfileid = dotfileid; 2954 } else { 2955 error = nd->nd_repstat; 2956 } 2957 mbuf_freem(nd->nd_mrep); 2958 if (error) 2959 return (error); 2960 nd->nd_mrep = NULL; 2961 dp = (struct dirent *)uio_iov_base(uiop); 2962 dp->d_pad0 = dp->d_pad1 = 0; 2963 dp->d_off = 0; 2964 dp->d_type = DT_DIR; 2965 dp->d_fileno = dotfileid; 2966 dp->d_namlen = 1; 2967 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 2968 dp->d_name[0] = '.'; 2969 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 2970 /* 2971 * Just make these offset cookie 0. 2972 */ 2973 tl = (u_int32_t *)&dp->d_name[8]; 2974 *tl++ = 0; 2975 *tl = 0; 2976 blksiz += dp->d_reclen; 2977 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2978 uiop->uio_offset += dp->d_reclen; 2979 uio_iov_base_add(uiop, dp->d_reclen); 2980 uio_iov_len_add(uiop, -(dp->d_reclen)); 2981 dp = (struct dirent *)uio_iov_base(uiop); 2982 dp->d_pad0 = dp->d_pad1 = 0; 2983 dp->d_off = 0; 2984 dp->d_type = DT_DIR; 2985 dp->d_fileno = dotdotfileid; 2986 dp->d_namlen = 2; 2987 *((uint64_t *)dp->d_name) = 0; 2988 dp->d_name[0] = '.'; 2989 dp->d_name[1] = '.'; 2990 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 2991 /* 2992 * Just make these offset cookie 0. 2993 */ 2994 tl = (u_int32_t *)&dp->d_name[8]; 2995 *tl++ = 0; 2996 *tl = 0; 2997 blksiz += dp->d_reclen; 2998 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2999 uiop->uio_offset += dp->d_reclen; 3000 uio_iov_base_add(uiop, dp->d_reclen); 3001 uio_iov_len_add(uiop, -(dp->d_reclen)); 3002 } 3003 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 3004 } else { 3005 reqsize = 5 * NFSX_UNSIGNED; 3006 } 3007 3008 3009 /* 3010 * Loop around doing readdir rpc's of size readsize. 3011 * The stopping criteria is EOF or buffer full. 3012 */ 3013 while (more_dirs && bigenough) { 3014 *attrflagp = 0; 3015 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 3016 if (nd->nd_flag & ND_NFSV2) { 3017 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3018 *tl++ = cookie.lval[1]; 3019 *tl = txdr_unsigned(readsize); 3020 } else { 3021 NFSM_BUILD(tl, u_int32_t *, reqsize); 3022 *tl++ = cookie.lval[0]; 3023 *tl++ = cookie.lval[1]; 3024 if (cookie.qval == 0) { 3025 *tl++ = 0; 3026 *tl++ = 0; 3027 } else { 3028 NFSLOCKNODE(dnp); 3029 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3030 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3031 NFSUNLOCKNODE(dnp); 3032 } 3033 if (nd->nd_flag & ND_NFSV4) { 3034 *tl++ = txdr_unsigned(readsize); 3035 *tl = txdr_unsigned(readsize); 3036 (void) nfsrv_putattrbit(nd, &attrbits); 3037 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3038 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3039 (void) nfsrv_putattrbit(nd, &dattrbits); 3040 } else { 3041 *tl = txdr_unsigned(readsize); 3042 } 3043 } 3044 error = nfscl_request(nd, vp, p, cred, stuff); 3045 if (error) 3046 return (error); 3047 if (!(nd->nd_flag & ND_NFSV2)) { 3048 if (nd->nd_flag & ND_NFSV3) 3049 error = nfscl_postop_attr(nd, nap, attrflagp, 3050 stuff); 3051 if (!nd->nd_repstat && !error) { 3052 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3053 NFSLOCKNODE(dnp); 3054 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3055 dnp->n_cookieverf.nfsuquad[1] = *tl; 3056 NFSUNLOCKNODE(dnp); 3057 } 3058 } 3059 if (nd->nd_repstat || error) { 3060 if (!error) 3061 error = nd->nd_repstat; 3062 goto nfsmout; 3063 } 3064 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3065 more_dirs = fxdr_unsigned(int, *tl); 3066 if (!more_dirs) 3067 tryformoredirs = 0; 3068 3069 /* loop through the dir entries, doctoring them to 4bsd form */ 3070 while (more_dirs && bigenough) { 3071 if (nd->nd_flag & ND_NFSV4) { 3072 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3073 ncookie.lval[0] = *tl++; 3074 ncookie.lval[1] = *tl++; 3075 len = fxdr_unsigned(int, *tl); 3076 } else if (nd->nd_flag & ND_NFSV3) { 3077 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3078 nfsva.na_fileid = fxdr_hyper(tl); 3079 tl += 2; 3080 len = fxdr_unsigned(int, *tl); 3081 } else { 3082 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3083 nfsva.na_fileid = fxdr_unsigned(uint64_t, 3084 *tl++); 3085 len = fxdr_unsigned(int, *tl); 3086 } 3087 if (len <= 0 || len > NFS_MAXNAMLEN) { 3088 error = EBADRPC; 3089 goto nfsmout; 3090 } 3091 tlen = roundup2(len, 8); 3092 if (tlen == len) 3093 tlen += 8; /* To ensure null termination. */ 3094 left = DIRBLKSIZ - blksiz; 3095 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3096 NFSBZERO(uio_iov_base(uiop), left); 3097 dp->d_reclen += left; 3098 uio_iov_base_add(uiop, left); 3099 uio_iov_len_add(uiop, -(left)); 3100 uio_uio_resid_add(uiop, -(left)); 3101 uiop->uio_offset += left; 3102 blksiz = 0; 3103 } 3104 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3105 uio_uio_resid(uiop)) 3106 bigenough = 0; 3107 if (bigenough) { 3108 dp = (struct dirent *)uio_iov_base(uiop); 3109 dp->d_pad0 = dp->d_pad1 = 0; 3110 dp->d_off = 0; 3111 dp->d_namlen = len; 3112 dp->d_reclen = _GENERIC_DIRLEN(len) + 3113 NFSX_HYPER; 3114 dp->d_type = DT_UNKNOWN; 3115 blksiz += dp->d_reclen; 3116 if (blksiz == DIRBLKSIZ) 3117 blksiz = 0; 3118 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3119 uiop->uio_offset += DIRHDSIZ; 3120 uio_iov_base_add(uiop, DIRHDSIZ); 3121 uio_iov_len_add(uiop, -(DIRHDSIZ)); 3122 error = nfsm_mbufuio(nd, uiop, len); 3123 if (error) 3124 goto nfsmout; 3125 cp = uio_iov_base(uiop); 3126 tlen -= len; 3127 NFSBZERO(cp, tlen); 3128 cp += tlen; /* points to cookie storage */ 3129 tl2 = (u_int32_t *)cp; 3130 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3131 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3132 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3133 uiop->uio_offset += (tlen + NFSX_HYPER); 3134 } else { 3135 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3136 if (error) 3137 goto nfsmout; 3138 } 3139 if (nd->nd_flag & ND_NFSV4) { 3140 rderr = 0; 3141 nfsva.na_mntonfileno = UINT64_MAX; 3142 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3143 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3144 NULL, NULL, &rderr, p, cred); 3145 if (error) 3146 goto nfsmout; 3147 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3148 } else if (nd->nd_flag & ND_NFSV3) { 3149 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3150 ncookie.lval[0] = *tl++; 3151 ncookie.lval[1] = *tl++; 3152 } else { 3153 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3154 ncookie.lval[0] = 0; 3155 ncookie.lval[1] = *tl++; 3156 } 3157 if (bigenough) { 3158 if (nd->nd_flag & ND_NFSV4) { 3159 if (rderr) { 3160 dp->d_fileno = 0; 3161 } else { 3162 if (gotmnton) { 3163 if (nfsva.na_mntonfileno != UINT64_MAX) 3164 dp->d_fileno = nfsva.na_mntonfileno; 3165 else 3166 dp->d_fileno = nfsva.na_fileid; 3167 } else if (nfsva.na_filesid[0] == 3168 dnp->n_vattr.na_filesid[0] && 3169 nfsva.na_filesid[1] == 3170 dnp->n_vattr.na_filesid[1]) { 3171 dp->d_fileno = nfsva.na_fileid; 3172 } else { 3173 do { 3174 fakefileno--; 3175 } while (fakefileno == 3176 nfsva.na_fileid); 3177 dp->d_fileno = fakefileno; 3178 } 3179 dp->d_type = vtonfs_dtype(nfsva.na_type); 3180 } 3181 } else { 3182 dp->d_fileno = nfsva.na_fileid; 3183 } 3184 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3185 ncookie.lval[0]; 3186 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3187 ncookie.lval[1]; 3188 } 3189 more_dirs = fxdr_unsigned(int, *tl); 3190 } 3191 /* 3192 * If at end of rpc data, get the eof boolean 3193 */ 3194 if (!more_dirs) { 3195 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3196 eof = fxdr_unsigned(int, *tl); 3197 if (tryformoredirs) 3198 more_dirs = !eof; 3199 if (nd->nd_flag & ND_NFSV4) { 3200 error = nfscl_postop_attr(nd, nap, attrflagp, 3201 stuff); 3202 if (error) 3203 goto nfsmout; 3204 } 3205 } 3206 mbuf_freem(nd->nd_mrep); 3207 nd->nd_mrep = NULL; 3208 } 3209 /* 3210 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3211 * by increasing d_reclen for the last record. 3212 */ 3213 if (blksiz > 0) { 3214 left = DIRBLKSIZ - blksiz; 3215 NFSBZERO(uio_iov_base(uiop), left); 3216 dp->d_reclen += left; 3217 uio_iov_base_add(uiop, left); 3218 uio_iov_len_add(uiop, -(left)); 3219 uio_uio_resid_add(uiop, -(left)); 3220 uiop->uio_offset += left; 3221 } 3222 3223 /* 3224 * If returning no data, assume end of file. 3225 * If not bigenough, return not end of file, since you aren't 3226 * returning all the data 3227 * Otherwise, return the eof flag from the server. 3228 */ 3229 if (eofp) { 3230 if (tresid == ((size_t)(uio_uio_resid(uiop)))) 3231 *eofp = 1; 3232 else if (!bigenough) 3233 *eofp = 0; 3234 else 3235 *eofp = eof; 3236 } 3237 3238 /* 3239 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3240 */ 3241 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3242 dp = (struct dirent *)uio_iov_base(uiop); 3243 NFSBZERO(dp, DIRBLKSIZ); 3244 dp->d_type = DT_UNKNOWN; 3245 tl = (u_int32_t *)&dp->d_name[4]; 3246 *tl++ = cookie.lval[0]; 3247 *tl = cookie.lval[1]; 3248 dp->d_reclen = DIRBLKSIZ; 3249 uio_iov_base_add(uiop, DIRBLKSIZ); 3250 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3251 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3252 uiop->uio_offset += DIRBLKSIZ; 3253 } 3254 3255 nfsmout: 3256 if (nd->nd_mrep != NULL) 3257 mbuf_freem(nd->nd_mrep); 3258 return (error); 3259 } 3260 3261 #ifndef APPLE 3262 /* 3263 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 3264 * (Also used for NFS V4 when mount flag set.) 3265 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 3266 */ 3267 APPLESTATIC int 3268 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3269 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3270 int *eofp, void *stuff) 3271 { 3272 int len, left; 3273 struct dirent *dp = NULL; 3274 u_int32_t *tl; 3275 vnode_t newvp = NULLVP; 3276 struct nfsrv_descript nfsd, *nd = &nfsd; 3277 struct nameidata nami, *ndp = &nami; 3278 struct componentname *cnp = &ndp->ni_cnd; 3279 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3280 struct nfsnode *dnp = VTONFS(vp), *np; 3281 struct nfsvattr nfsva; 3282 struct nfsfh *nfhp; 3283 nfsquad_t cookie, ncookie; 3284 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3285 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 3286 int isdotdot = 0, unlocknewvp = 0; 3287 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3288 u_int64_t fileno = 0; 3289 char *cp; 3290 nfsattrbit_t attrbits, dattrbits; 3291 size_t tresid; 3292 u_int32_t *tl2 = NULL, rderr; 3293 struct timespec dctime; 3294 3295 KASSERT(uiop->uio_iovcnt == 1 && 3296 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 3297 ("nfs readdirplusrpc bad uio")); 3298 ncookie.lval[0] = ncookie.lval[1] = 0; 3299 timespecclear(&dctime); 3300 *attrflagp = 0; 3301 if (eofp != NULL) 3302 *eofp = 0; 3303 ndp->ni_dvp = vp; 3304 nd->nd_mrep = NULL; 3305 cookie.lval[0] = cookiep->nfsuquad[0]; 3306 cookie.lval[1] = cookiep->nfsuquad[1]; 3307 tresid = uio_uio_resid(uiop); 3308 3309 /* 3310 * For NFSv4, first create the "." and ".." entries. 3311 */ 3312 if (NFSHASNFSV4(nmp)) { 3313 NFSGETATTR_ATTRBIT(&dattrbits); 3314 NFSZERO_ATTRBIT(&attrbits); 3315 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3316 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3317 NFSATTRBIT_MOUNTEDONFILEID)) { 3318 NFSSETBIT_ATTRBIT(&attrbits, 3319 NFSATTRBIT_MOUNTEDONFILEID); 3320 gotmnton = 1; 3321 } else { 3322 /* 3323 * Must fake it. Use the fileno, except when the 3324 * fsid is != to that of the directory. For that 3325 * case, generate a fake fileno that is not the same. 3326 */ 3327 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3328 gotmnton = 0; 3329 } 3330 3331 /* 3332 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3333 */ 3334 if (uiop->uio_offset == 0) { 3335 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3336 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3337 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3338 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3339 (void) nfsrv_putattrbit(nd, &attrbits); 3340 error = nfscl_request(nd, vp, p, cred, stuff); 3341 if (error) 3342 return (error); 3343 dotfileid = 0; /* Fake out the compiler. */ 3344 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3345 error = nfsm_loadattr(nd, &nfsva); 3346 if (error != 0) 3347 goto nfsmout; 3348 dctime = nfsva.na_ctime; 3349 dotfileid = nfsva.na_fileid; 3350 } 3351 if (nd->nd_repstat == 0) { 3352 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3353 len = fxdr_unsigned(int, *(tl + 4)); 3354 if (len > 0 && len <= NFSX_V4FHMAX) 3355 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3356 else 3357 error = EPERM; 3358 if (!error) { 3359 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3360 nfsva.na_mntonfileno = UINT64_MAX; 3361 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3362 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3363 NULL, NULL, NULL, p, cred); 3364 if (error) { 3365 dotdotfileid = dotfileid; 3366 } else if (gotmnton) { 3367 if (nfsva.na_mntonfileno != UINT64_MAX) 3368 dotdotfileid = nfsva.na_mntonfileno; 3369 else 3370 dotdotfileid = nfsva.na_fileid; 3371 } else if (nfsva.na_filesid[0] == 3372 dnp->n_vattr.na_filesid[0] && 3373 nfsva.na_filesid[1] == 3374 dnp->n_vattr.na_filesid[1]) { 3375 dotdotfileid = nfsva.na_fileid; 3376 } else { 3377 do { 3378 fakefileno--; 3379 } while (fakefileno == 3380 nfsva.na_fileid); 3381 dotdotfileid = fakefileno; 3382 } 3383 } 3384 } else if (nd->nd_repstat == NFSERR_NOENT) { 3385 /* 3386 * Lookupp returns NFSERR_NOENT when we are 3387 * at the root, so just use the current dir. 3388 */ 3389 nd->nd_repstat = 0; 3390 dotdotfileid = dotfileid; 3391 } else { 3392 error = nd->nd_repstat; 3393 } 3394 mbuf_freem(nd->nd_mrep); 3395 if (error) 3396 return (error); 3397 nd->nd_mrep = NULL; 3398 dp = (struct dirent *)uio_iov_base(uiop); 3399 dp->d_pad0 = dp->d_pad1 = 0; 3400 dp->d_off = 0; 3401 dp->d_type = DT_DIR; 3402 dp->d_fileno = dotfileid; 3403 dp->d_namlen = 1; 3404 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3405 dp->d_name[0] = '.'; 3406 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3407 /* 3408 * Just make these offset cookie 0. 3409 */ 3410 tl = (u_int32_t *)&dp->d_name[8]; 3411 *tl++ = 0; 3412 *tl = 0; 3413 blksiz += dp->d_reclen; 3414 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3415 uiop->uio_offset += dp->d_reclen; 3416 uio_iov_base_add(uiop, dp->d_reclen); 3417 uio_iov_len_add(uiop, -(dp->d_reclen)); 3418 dp = (struct dirent *)uio_iov_base(uiop); 3419 dp->d_pad0 = dp->d_pad1 = 0; 3420 dp->d_off = 0; 3421 dp->d_type = DT_DIR; 3422 dp->d_fileno = dotdotfileid; 3423 dp->d_namlen = 2; 3424 *((uint64_t *)dp->d_name) = 0; 3425 dp->d_name[0] = '.'; 3426 dp->d_name[1] = '.'; 3427 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3428 /* 3429 * Just make these offset cookie 0. 3430 */ 3431 tl = (u_int32_t *)&dp->d_name[8]; 3432 *tl++ = 0; 3433 *tl = 0; 3434 blksiz += dp->d_reclen; 3435 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3436 uiop->uio_offset += dp->d_reclen; 3437 uio_iov_base_add(uiop, dp->d_reclen); 3438 uio_iov_len_add(uiop, -(dp->d_reclen)); 3439 } 3440 NFSREADDIRPLUS_ATTRBIT(&attrbits); 3441 if (gotmnton) 3442 NFSSETBIT_ATTRBIT(&attrbits, 3443 NFSATTRBIT_MOUNTEDONFILEID); 3444 } 3445 3446 /* 3447 * Loop around doing readdir rpc's of size nm_readdirsize. 3448 * The stopping criteria is EOF or buffer full. 3449 */ 3450 while (more_dirs && bigenough) { 3451 *attrflagp = 0; 3452 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3453 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3454 *tl++ = cookie.lval[0]; 3455 *tl++ = cookie.lval[1]; 3456 if (cookie.qval == 0) { 3457 *tl++ = 0; 3458 *tl++ = 0; 3459 } else { 3460 NFSLOCKNODE(dnp); 3461 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3462 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3463 NFSUNLOCKNODE(dnp); 3464 } 3465 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3466 *tl = txdr_unsigned(nmp->nm_readdirsize); 3467 if (nd->nd_flag & ND_NFSV4) { 3468 (void) nfsrv_putattrbit(nd, &attrbits); 3469 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3470 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3471 (void) nfsrv_putattrbit(nd, &dattrbits); 3472 } 3473 error = nfscl_request(nd, vp, p, cred, stuff); 3474 if (error) 3475 return (error); 3476 if (nd->nd_flag & ND_NFSV3) 3477 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3478 if (nd->nd_repstat || error) { 3479 if (!error) 3480 error = nd->nd_repstat; 3481 goto nfsmout; 3482 } 3483 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 3484 dctime = nap->na_ctime; 3485 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3486 NFSLOCKNODE(dnp); 3487 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3488 dnp->n_cookieverf.nfsuquad[1] = *tl++; 3489 NFSUNLOCKNODE(dnp); 3490 more_dirs = fxdr_unsigned(int, *tl); 3491 if (!more_dirs) 3492 tryformoredirs = 0; 3493 3494 /* loop through the dir entries, doctoring them to 4bsd form */ 3495 while (more_dirs && bigenough) { 3496 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3497 if (nd->nd_flag & ND_NFSV4) { 3498 ncookie.lval[0] = *tl++; 3499 ncookie.lval[1] = *tl++; 3500 } else { 3501 fileno = fxdr_hyper(tl); 3502 tl += 2; 3503 } 3504 len = fxdr_unsigned(int, *tl); 3505 if (len <= 0 || len > NFS_MAXNAMLEN) { 3506 error = EBADRPC; 3507 goto nfsmout; 3508 } 3509 tlen = roundup2(len, 8); 3510 if (tlen == len) 3511 tlen += 8; /* To ensure null termination. */ 3512 left = DIRBLKSIZ - blksiz; 3513 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3514 NFSBZERO(uio_iov_base(uiop), left); 3515 dp->d_reclen += left; 3516 uio_iov_base_add(uiop, left); 3517 uio_iov_len_add(uiop, -(left)); 3518 uio_uio_resid_add(uiop, -(left)); 3519 uiop->uio_offset += left; 3520 blksiz = 0; 3521 } 3522 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3523 uio_uio_resid(uiop)) 3524 bigenough = 0; 3525 if (bigenough) { 3526 dp = (struct dirent *)uio_iov_base(uiop); 3527 dp->d_pad0 = dp->d_pad1 = 0; 3528 dp->d_off = 0; 3529 dp->d_namlen = len; 3530 dp->d_reclen = _GENERIC_DIRLEN(len) + 3531 NFSX_HYPER; 3532 dp->d_type = DT_UNKNOWN; 3533 blksiz += dp->d_reclen; 3534 if (blksiz == DIRBLKSIZ) 3535 blksiz = 0; 3536 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3537 uiop->uio_offset += DIRHDSIZ; 3538 uio_iov_base_add(uiop, DIRHDSIZ); 3539 uio_iov_len_add(uiop, -(DIRHDSIZ)); 3540 cnp->cn_nameptr = uio_iov_base(uiop); 3541 cnp->cn_namelen = len; 3542 NFSCNHASHZERO(cnp); 3543 error = nfsm_mbufuio(nd, uiop, len); 3544 if (error) 3545 goto nfsmout; 3546 cp = uio_iov_base(uiop); 3547 tlen -= len; 3548 NFSBZERO(cp, tlen); 3549 cp += tlen; /* points to cookie storage */ 3550 tl2 = (u_int32_t *)cp; 3551 if (len == 2 && cnp->cn_nameptr[0] == '.' && 3552 cnp->cn_nameptr[1] == '.') 3553 isdotdot = 1; 3554 else 3555 isdotdot = 0; 3556 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3557 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3558 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3559 uiop->uio_offset += (tlen + NFSX_HYPER); 3560 } else { 3561 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3562 if (error) 3563 goto nfsmout; 3564 } 3565 nfhp = NULL; 3566 if (nd->nd_flag & ND_NFSV3) { 3567 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3568 ncookie.lval[0] = *tl++; 3569 ncookie.lval[1] = *tl++; 3570 attrflag = fxdr_unsigned(int, *tl); 3571 if (attrflag) { 3572 error = nfsm_loadattr(nd, &nfsva); 3573 if (error) 3574 goto nfsmout; 3575 } 3576 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3577 if (*tl) { 3578 error = nfsm_getfh(nd, &nfhp); 3579 if (error) 3580 goto nfsmout; 3581 } 3582 if (!attrflag && nfhp != NULL) { 3583 free(nfhp, M_NFSFH); 3584 nfhp = NULL; 3585 } 3586 } else { 3587 rderr = 0; 3588 nfsva.na_mntonfileno = 0xffffffff; 3589 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3590 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3591 NULL, NULL, &rderr, p, cred); 3592 if (error) 3593 goto nfsmout; 3594 } 3595 3596 if (bigenough) { 3597 if (nd->nd_flag & ND_NFSV4) { 3598 if (rderr) { 3599 dp->d_fileno = 0; 3600 } else if (gotmnton) { 3601 if (nfsva.na_mntonfileno != 0xffffffff) 3602 dp->d_fileno = nfsva.na_mntonfileno; 3603 else 3604 dp->d_fileno = nfsva.na_fileid; 3605 } else if (nfsva.na_filesid[0] == 3606 dnp->n_vattr.na_filesid[0] && 3607 nfsva.na_filesid[1] == 3608 dnp->n_vattr.na_filesid[1]) { 3609 dp->d_fileno = nfsva.na_fileid; 3610 } else { 3611 do { 3612 fakefileno--; 3613 } while (fakefileno == 3614 nfsva.na_fileid); 3615 dp->d_fileno = fakefileno; 3616 } 3617 } else { 3618 dp->d_fileno = fileno; 3619 } 3620 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3621 ncookie.lval[0]; 3622 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3623 ncookie.lval[1]; 3624 3625 if (nfhp != NULL) { 3626 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3627 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3628 VREF(vp); 3629 newvp = vp; 3630 unlocknewvp = 0; 3631 free(nfhp, M_NFSFH); 3632 np = dnp; 3633 } else if (isdotdot != 0) { 3634 /* 3635 * Skip doing a nfscl_nget() call for "..". 3636 * There's a race between acquiring the nfs 3637 * node here and lookups that look for the 3638 * directory being read (in the parent). 3639 * It would try to get a lock on ".." here, 3640 * owning the lock on the directory being 3641 * read. Lookup will hold the lock on ".." 3642 * and try to acquire the lock on the 3643 * directory being read. 3644 * If the directory is unlocked/relocked, 3645 * then there is a LOR with the buflock 3646 * vp is relocked. 3647 */ 3648 free(nfhp, M_NFSFH); 3649 } else { 3650 error = nfscl_nget(vnode_mount(vp), vp, 3651 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 3652 if (!error) { 3653 newvp = NFSTOV(np); 3654 unlocknewvp = 1; 3655 } 3656 } 3657 nfhp = NULL; 3658 if (newvp != NULLVP) { 3659 error = nfscl_loadattrcache(&newvp, 3660 &nfsva, NULL, NULL, 0, 0); 3661 if (error) { 3662 if (unlocknewvp) 3663 vput(newvp); 3664 else 3665 vrele(newvp); 3666 goto nfsmout; 3667 } 3668 dp->d_type = 3669 vtonfs_dtype(np->n_vattr.na_type); 3670 ndp->ni_vp = newvp; 3671 NFSCNHASH(cnp, HASHINIT); 3672 if (cnp->cn_namelen <= NCHNAMLEN && 3673 (newvp->v_type != VDIR || 3674 dctime.tv_sec != 0)) { 3675 cache_enter_time(ndp->ni_dvp, 3676 ndp->ni_vp, cnp, 3677 &nfsva.na_ctime, 3678 newvp->v_type != VDIR ? NULL : 3679 &dctime); 3680 } 3681 if (unlocknewvp) 3682 vput(newvp); 3683 else 3684 vrele(newvp); 3685 newvp = NULLVP; 3686 } 3687 } 3688 } else if (nfhp != NULL) { 3689 free(nfhp, M_NFSFH); 3690 } 3691 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3692 more_dirs = fxdr_unsigned(int, *tl); 3693 } 3694 /* 3695 * If at end of rpc data, get the eof boolean 3696 */ 3697 if (!more_dirs) { 3698 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3699 eof = fxdr_unsigned(int, *tl); 3700 if (tryformoredirs) 3701 more_dirs = !eof; 3702 if (nd->nd_flag & ND_NFSV4) { 3703 error = nfscl_postop_attr(nd, nap, attrflagp, 3704 stuff); 3705 if (error) 3706 goto nfsmout; 3707 } 3708 } 3709 mbuf_freem(nd->nd_mrep); 3710 nd->nd_mrep = NULL; 3711 } 3712 /* 3713 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3714 * by increasing d_reclen for the last record. 3715 */ 3716 if (blksiz > 0) { 3717 left = DIRBLKSIZ - blksiz; 3718 NFSBZERO(uio_iov_base(uiop), left); 3719 dp->d_reclen += left; 3720 uio_iov_base_add(uiop, left); 3721 uio_iov_len_add(uiop, -(left)); 3722 uio_uio_resid_add(uiop, -(left)); 3723 uiop->uio_offset += left; 3724 } 3725 3726 /* 3727 * If returning no data, assume end of file. 3728 * If not bigenough, return not end of file, since you aren't 3729 * returning all the data 3730 * Otherwise, return the eof flag from the server. 3731 */ 3732 if (eofp != NULL) { 3733 if (tresid == uio_uio_resid(uiop)) 3734 *eofp = 1; 3735 else if (!bigenough) 3736 *eofp = 0; 3737 else 3738 *eofp = eof; 3739 } 3740 3741 /* 3742 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3743 */ 3744 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3745 dp = (struct dirent *)uio_iov_base(uiop); 3746 NFSBZERO(dp, DIRBLKSIZ); 3747 dp->d_type = DT_UNKNOWN; 3748 tl = (u_int32_t *)&dp->d_name[4]; 3749 *tl++ = cookie.lval[0]; 3750 *tl = cookie.lval[1]; 3751 dp->d_reclen = DIRBLKSIZ; 3752 uio_iov_base_add(uiop, DIRBLKSIZ); 3753 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3754 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3755 uiop->uio_offset += DIRBLKSIZ; 3756 } 3757 3758 nfsmout: 3759 if (nd->nd_mrep != NULL) 3760 mbuf_freem(nd->nd_mrep); 3761 return (error); 3762 } 3763 #endif /* !APPLE */ 3764 3765 /* 3766 * Nfs commit rpc 3767 */ 3768 APPLESTATIC int 3769 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 3770 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 3771 { 3772 u_int32_t *tl; 3773 struct nfsrv_descript nfsd, *nd = &nfsd; 3774 nfsattrbit_t attrbits; 3775 int error; 3776 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3777 3778 *attrflagp = 0; 3779 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 3780 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3781 txdr_hyper(offset, tl); 3782 tl += 2; 3783 *tl = txdr_unsigned(cnt); 3784 if (nd->nd_flag & ND_NFSV4) { 3785 /* 3786 * And do a Getattr op. 3787 */ 3788 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3789 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3790 NFSGETATTR_ATTRBIT(&attrbits); 3791 (void) nfsrv_putattrbit(nd, &attrbits); 3792 } 3793 error = nfscl_request(nd, vp, p, cred, stuff); 3794 if (error) 3795 return (error); 3796 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 3797 if (!error && !nd->nd_repstat) { 3798 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3799 NFSLOCKMNT(nmp); 3800 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { 3801 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 3802 nd->nd_repstat = NFSERR_STALEWRITEVERF; 3803 } 3804 NFSUNLOCKMNT(nmp); 3805 if (nd->nd_flag & ND_NFSV4) 3806 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3807 } 3808 nfsmout: 3809 if (!error && nd->nd_repstat) 3810 error = nd->nd_repstat; 3811 mbuf_freem(nd->nd_mrep); 3812 return (error); 3813 } 3814 3815 /* 3816 * NFS byte range lock rpc. 3817 * (Mostly just calls one of the three lower level RPC routines.) 3818 */ 3819 APPLESTATIC int 3820 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 3821 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3822 { 3823 struct nfscllockowner *lp; 3824 struct nfsclclient *clp; 3825 struct nfsfh *nfhp; 3826 struct nfsrv_descript nfsd, *nd = &nfsd; 3827 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3828 u_int64_t off, len; 3829 off_t start, end; 3830 u_int32_t clidrev = 0; 3831 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 3832 int callcnt, dorpc; 3833 3834 /* 3835 * Convert the flock structure into a start and end and do POSIX 3836 * bounds checking. 3837 */ 3838 switch (fl->l_whence) { 3839 case SEEK_SET: 3840 case SEEK_CUR: 3841 /* 3842 * Caller is responsible for adding any necessary offset 3843 * when SEEK_CUR is used. 3844 */ 3845 start = fl->l_start; 3846 off = fl->l_start; 3847 break; 3848 case SEEK_END: 3849 start = size + fl->l_start; 3850 off = size + fl->l_start; 3851 break; 3852 default: 3853 return (EINVAL); 3854 } 3855 if (start < 0) 3856 return (EINVAL); 3857 if (fl->l_len != 0) { 3858 end = start + fl->l_len - 1; 3859 if (end < start) 3860 return (EINVAL); 3861 } 3862 3863 len = fl->l_len; 3864 if (len == 0) 3865 len = NFS64BITSSET; 3866 retrycnt = 0; 3867 do { 3868 nd->nd_repstat = 0; 3869 if (op == F_GETLK) { 3870 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3871 if (error) 3872 return (error); 3873 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 3874 if (!error) { 3875 clidrev = clp->nfsc_clientidrev; 3876 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 3877 p, id, flags); 3878 } else if (error == -1) { 3879 error = 0; 3880 } 3881 nfscl_clientrelease(clp); 3882 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 3883 /* 3884 * We must loop around for all lockowner cases. 3885 */ 3886 callcnt = 0; 3887 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3888 if (error) 3889 return (error); 3890 do { 3891 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 3892 clp, id, flags, &lp, &dorpc); 3893 /* 3894 * If it returns a NULL lp, we're done. 3895 */ 3896 if (lp == NULL) { 3897 if (callcnt == 0) 3898 nfscl_clientrelease(clp); 3899 else 3900 nfscl_releasealllocks(clp, vp, p, id, flags); 3901 return (error); 3902 } 3903 if (nmp->nm_clp != NULL) 3904 clidrev = nmp->nm_clp->nfsc_clientidrev; 3905 else 3906 clidrev = 0; 3907 /* 3908 * If the server doesn't support Posix lock semantics, 3909 * only allow locks on the entire file, since it won't 3910 * handle overlapping byte ranges. 3911 * There might still be a problem when a lock 3912 * upgrade/downgrade (read<->write) occurs, since the 3913 * server "might" expect an unlock first? 3914 */ 3915 if (dorpc && (lp->nfsl_open->nfso_posixlock || 3916 (off == 0 && len == NFS64BITSSET))) { 3917 /* 3918 * Since the lock records will go away, we must 3919 * wait for grace and delay here. 3920 */ 3921 do { 3922 error = nfsrpc_locku(nd, nmp, lp, off, len, 3923 NFSV4LOCKT_READ, cred, p, 0); 3924 if ((nd->nd_repstat == NFSERR_GRACE || 3925 nd->nd_repstat == NFSERR_DELAY) && 3926 error == 0) 3927 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3928 "nfs_advlock"); 3929 } while ((nd->nd_repstat == NFSERR_GRACE || 3930 nd->nd_repstat == NFSERR_DELAY) && error == 0); 3931 } 3932 callcnt++; 3933 } while (error == 0 && nd->nd_repstat == 0); 3934 nfscl_releasealllocks(clp, vp, p, id, flags); 3935 } else if (op == F_SETLK) { 3936 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 3937 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 3938 if (error || donelocally) { 3939 return (error); 3940 } 3941 if (nmp->nm_clp != NULL) 3942 clidrev = nmp->nm_clp->nfsc_clientidrev; 3943 else 3944 clidrev = 0; 3945 nfhp = VTONFS(vp)->n_fhp; 3946 if (!lp->nfsl_open->nfso_posixlock && 3947 (off != 0 || len != NFS64BITSSET)) { 3948 error = EINVAL; 3949 } else { 3950 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 3951 nfhp->nfh_len, lp, newone, reclaim, off, 3952 len, fl->l_type, cred, p, 0); 3953 } 3954 if (!error) 3955 error = nd->nd_repstat; 3956 nfscl_lockrelease(lp, error, newone); 3957 } else { 3958 error = EINVAL; 3959 } 3960 if (!error) 3961 error = nd->nd_repstat; 3962 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 3963 error == NFSERR_STALEDONTRECOVER || 3964 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3965 error == NFSERR_BADSESSION) { 3966 (void) nfs_catnap(PZERO, error, "nfs_advlock"); 3967 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 3968 && clidrev != 0) { 3969 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 3970 retrycnt++; 3971 } 3972 } while (error == NFSERR_GRACE || 3973 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3974 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 3975 error == NFSERR_BADSESSION || 3976 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 3977 expireret == 0 && clidrev != 0 && retrycnt < 4)); 3978 if (error && retrycnt >= 4) 3979 error = EIO; 3980 return (error); 3981 } 3982 3983 /* 3984 * The lower level routine for the LockT case. 3985 */ 3986 APPLESTATIC int 3987 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 3988 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 3989 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3990 { 3991 u_int32_t *tl; 3992 int error, type, size; 3993 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3994 struct nfsnode *np; 3995 struct nfsmount *nmp; 3996 struct nfsclsession *tsep; 3997 3998 nmp = VFSTONFS(vp->v_mount); 3999 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 4000 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4001 if (fl->l_type == F_RDLCK) 4002 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4003 else 4004 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4005 txdr_hyper(off, tl); 4006 tl += 2; 4007 txdr_hyper(len, tl); 4008 tl += 2; 4009 tsep = nfsmnt_mdssession(nmp); 4010 *tl++ = tsep->nfsess_clientid.lval[0]; 4011 *tl = tsep->nfsess_clientid.lval[1]; 4012 nfscl_filllockowner(id, own, flags); 4013 np = VTONFS(vp); 4014 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 4015 np->n_fhp->nfh_len); 4016 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 4017 error = nfscl_request(nd, vp, p, cred, NULL); 4018 if (error) 4019 return (error); 4020 if (nd->nd_repstat == 0) { 4021 fl->l_type = F_UNLCK; 4022 } else if (nd->nd_repstat == NFSERR_DENIED) { 4023 nd->nd_repstat = 0; 4024 fl->l_whence = SEEK_SET; 4025 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4026 fl->l_start = fxdr_hyper(tl); 4027 tl += 2; 4028 len = fxdr_hyper(tl); 4029 tl += 2; 4030 if (len == NFS64BITSSET) 4031 fl->l_len = 0; 4032 else 4033 fl->l_len = len; 4034 type = fxdr_unsigned(int, *tl++); 4035 if (type == NFSV4LOCKT_WRITE) 4036 fl->l_type = F_WRLCK; 4037 else 4038 fl->l_type = F_RDLCK; 4039 /* 4040 * XXX For now, I have no idea what to do with the 4041 * conflicting lock_owner, so I'll just set the pid == 0 4042 * and skip over the lock_owner. 4043 */ 4044 fl->l_pid = (pid_t)0; 4045 tl += 2; 4046 size = fxdr_unsigned(int, *tl); 4047 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4048 error = EBADRPC; 4049 if (!error) 4050 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4051 } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 4052 nfscl_initiate_recovery(clp); 4053 nfsmout: 4054 mbuf_freem(nd->nd_mrep); 4055 return (error); 4056 } 4057 4058 /* 4059 * Lower level function that performs the LockU RPC. 4060 */ 4061 static int 4062 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 4063 struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 4064 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 4065 { 4066 u_int32_t *tl; 4067 int error; 4068 4069 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 4070 lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0); 4071 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 4072 *tl++ = txdr_unsigned(type); 4073 *tl = txdr_unsigned(lp->nfsl_seqid); 4074 if (nfstest_outofseq && 4075 (arc4random() % nfstest_outofseq) == 0) 4076 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4077 tl++; 4078 if (NFSHASNFSV4N(nmp)) 4079 *tl++ = 0; 4080 else 4081 *tl++ = lp->nfsl_stateid.seqid; 4082 *tl++ = lp->nfsl_stateid.other[0]; 4083 *tl++ = lp->nfsl_stateid.other[1]; 4084 *tl++ = lp->nfsl_stateid.other[2]; 4085 txdr_hyper(off, tl); 4086 tl += 2; 4087 txdr_hyper(len, tl); 4088 if (syscred) 4089 nd->nd_flag |= ND_USEGSSNAME; 4090 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4091 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4092 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4093 if (error) 4094 return (error); 4095 if (nd->nd_repstat == 0) { 4096 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4097 lp->nfsl_stateid.seqid = *tl++; 4098 lp->nfsl_stateid.other[0] = *tl++; 4099 lp->nfsl_stateid.other[1] = *tl++; 4100 lp->nfsl_stateid.other[2] = *tl; 4101 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4102 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4103 nfsmout: 4104 mbuf_freem(nd->nd_mrep); 4105 return (error); 4106 } 4107 4108 /* 4109 * The actual Lock RPC. 4110 */ 4111 APPLESTATIC int 4112 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 4113 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 4114 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 4115 NFSPROC_T *p, int syscred) 4116 { 4117 u_int32_t *tl; 4118 int error, size; 4119 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4120 struct nfsclsession *tsep; 4121 4122 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0); 4123 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4124 if (type == F_RDLCK) 4125 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4126 else 4127 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4128 *tl++ = txdr_unsigned(reclaim); 4129 txdr_hyper(off, tl); 4130 tl += 2; 4131 txdr_hyper(len, tl); 4132 tl += 2; 4133 if (newone) { 4134 *tl = newnfs_true; 4135 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 4136 2 * NFSX_UNSIGNED + NFSX_HYPER); 4137 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 4138 if (NFSHASNFSV4N(nmp)) 4139 *tl++ = 0; 4140 else 4141 *tl++ = lp->nfsl_open->nfso_stateid.seqid; 4142 *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 4143 *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 4144 *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 4145 *tl++ = txdr_unsigned(lp->nfsl_seqid); 4146 tsep = nfsmnt_mdssession(nmp); 4147 *tl++ = tsep->nfsess_clientid.lval[0]; 4148 *tl = tsep->nfsess_clientid.lval[1]; 4149 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4150 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4151 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4152 } else { 4153 *tl = newnfs_false; 4154 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 4155 if (NFSHASNFSV4N(nmp)) 4156 *tl++ = 0; 4157 else 4158 *tl++ = lp->nfsl_stateid.seqid; 4159 *tl++ = lp->nfsl_stateid.other[0]; 4160 *tl++ = lp->nfsl_stateid.other[1]; 4161 *tl++ = lp->nfsl_stateid.other[2]; 4162 *tl = txdr_unsigned(lp->nfsl_seqid); 4163 if (nfstest_outofseq && 4164 (arc4random() % nfstest_outofseq) == 0) 4165 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4166 } 4167 if (syscred) 4168 nd->nd_flag |= ND_USEGSSNAME; 4169 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 4170 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4171 if (error) 4172 return (error); 4173 if (newone) 4174 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 4175 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4176 if (nd->nd_repstat == 0) { 4177 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4178 lp->nfsl_stateid.seqid = *tl++; 4179 lp->nfsl_stateid.other[0] = *tl++; 4180 lp->nfsl_stateid.other[1] = *tl++; 4181 lp->nfsl_stateid.other[2] = *tl; 4182 } else if (nd->nd_repstat == NFSERR_DENIED) { 4183 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4184 size = fxdr_unsigned(int, *(tl + 7)); 4185 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4186 error = EBADRPC; 4187 if (!error) 4188 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4189 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4190 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4191 nfsmout: 4192 mbuf_freem(nd->nd_mrep); 4193 return (error); 4194 } 4195 4196 /* 4197 * nfs statfs rpc 4198 * (always called with the vp for the mount point) 4199 */ 4200 APPLESTATIC int 4201 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 4202 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4203 void *stuff) 4204 { 4205 u_int32_t *tl = NULL; 4206 struct nfsrv_descript nfsd, *nd = &nfsd; 4207 struct nfsmount *nmp; 4208 nfsattrbit_t attrbits; 4209 int error; 4210 4211 *attrflagp = 0; 4212 nmp = VFSTONFS(vnode_mount(vp)); 4213 if (NFSHASNFSV4(nmp)) { 4214 /* 4215 * For V4, you actually do a getattr. 4216 */ 4217 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4218 NFSSTATFS_GETATTRBIT(&attrbits); 4219 (void) nfsrv_putattrbit(nd, &attrbits); 4220 nd->nd_flag |= ND_USEGSSNAME; 4221 error = nfscl_request(nd, vp, p, cred, stuff); 4222 if (error) 4223 return (error); 4224 if (nd->nd_repstat == 0) { 4225 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4226 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 4227 cred); 4228 if (!error) { 4229 nmp->nm_fsid[0] = nap->na_filesid[0]; 4230 nmp->nm_fsid[1] = nap->na_filesid[1]; 4231 NFSSETHASSETFSID(nmp); 4232 *attrflagp = 1; 4233 } 4234 } else { 4235 error = nd->nd_repstat; 4236 } 4237 if (error) 4238 goto nfsmout; 4239 } else { 4240 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 4241 error = nfscl_request(nd, vp, p, cred, stuff); 4242 if (error) 4243 return (error); 4244 if (nd->nd_flag & ND_NFSV3) { 4245 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4246 if (error) 4247 goto nfsmout; 4248 } 4249 if (nd->nd_repstat) { 4250 error = nd->nd_repstat; 4251 goto nfsmout; 4252 } 4253 NFSM_DISSECT(tl, u_int32_t *, 4254 NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 4255 } 4256 if (NFSHASNFSV3(nmp)) { 4257 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 4258 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 4259 sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 4260 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 4261 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 4262 sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 4263 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 4264 } else if (NFSHASNFSV4(nmp) == 0) { 4265 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 4266 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 4267 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 4268 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 4269 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 4270 } 4271 nfsmout: 4272 mbuf_freem(nd->nd_mrep); 4273 return (error); 4274 } 4275 4276 /* 4277 * nfs pathconf rpc 4278 */ 4279 APPLESTATIC int 4280 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 4281 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4282 void *stuff) 4283 { 4284 struct nfsrv_descript nfsd, *nd = &nfsd; 4285 struct nfsmount *nmp; 4286 u_int32_t *tl; 4287 nfsattrbit_t attrbits; 4288 int error; 4289 4290 *attrflagp = 0; 4291 nmp = VFSTONFS(vnode_mount(vp)); 4292 if (NFSHASNFSV4(nmp)) { 4293 /* 4294 * For V4, you actually do a getattr. 4295 */ 4296 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4297 NFSPATHCONF_GETATTRBIT(&attrbits); 4298 (void) nfsrv_putattrbit(nd, &attrbits); 4299 nd->nd_flag |= ND_USEGSSNAME; 4300 error = nfscl_request(nd, vp, p, cred, stuff); 4301 if (error) 4302 return (error); 4303 if (nd->nd_repstat == 0) { 4304 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4305 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 4306 cred); 4307 if (!error) 4308 *attrflagp = 1; 4309 } else { 4310 error = nd->nd_repstat; 4311 } 4312 } else { 4313 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 4314 error = nfscl_request(nd, vp, p, cred, stuff); 4315 if (error) 4316 return (error); 4317 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4318 if (nd->nd_repstat && !error) 4319 error = nd->nd_repstat; 4320 if (!error) { 4321 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 4322 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 4323 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 4324 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 4325 pc->pc_chownrestricted = 4326 fxdr_unsigned(u_int32_t, *tl++); 4327 pc->pc_caseinsensitive = 4328 fxdr_unsigned(u_int32_t, *tl++); 4329 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 4330 } 4331 } 4332 nfsmout: 4333 mbuf_freem(nd->nd_mrep); 4334 return (error); 4335 } 4336 4337 /* 4338 * nfs version 3 fsinfo rpc call 4339 */ 4340 APPLESTATIC int 4341 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 4342 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 4343 { 4344 u_int32_t *tl; 4345 struct nfsrv_descript nfsd, *nd = &nfsd; 4346 int error; 4347 4348 *attrflagp = 0; 4349 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 4350 error = nfscl_request(nd, vp, p, cred, stuff); 4351 if (error) 4352 return (error); 4353 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4354 if (nd->nd_repstat && !error) 4355 error = nd->nd_repstat; 4356 if (!error) { 4357 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 4358 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 4359 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 4360 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 4361 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 4362 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 4363 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 4364 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 4365 fsp->fs_maxfilesize = fxdr_hyper(tl); 4366 tl += 2; 4367 fxdr_nfsv3time(tl, &fsp->fs_timedelta); 4368 tl += 2; 4369 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 4370 } 4371 nfsmout: 4372 mbuf_freem(nd->nd_mrep); 4373 return (error); 4374 } 4375 4376 /* 4377 * This function performs the Renew RPC. 4378 */ 4379 APPLESTATIC int 4380 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, 4381 NFSPROC_T *p) 4382 { 4383 u_int32_t *tl; 4384 struct nfsrv_descript nfsd; 4385 struct nfsrv_descript *nd = &nfsd; 4386 struct nfsmount *nmp; 4387 int error; 4388 struct nfssockreq *nrp; 4389 struct nfsclsession *tsep; 4390 4391 nmp = clp->nfsc_nmp; 4392 if (nmp == NULL) 4393 return (0); 4394 if (dsp == NULL) 4395 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0, 4396 0); 4397 else 4398 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, 4399 &dsp->nfsclds_sess, 0, 0); 4400 if (!NFSHASNFSV4N(nmp)) { 4401 /* NFSv4.1 just uses a Sequence Op and not a Renew. */ 4402 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4403 tsep = nfsmnt_mdssession(nmp); 4404 *tl++ = tsep->nfsess_clientid.lval[0]; 4405 *tl = tsep->nfsess_clientid.lval[1]; 4406 } 4407 nrp = NULL; 4408 if (dsp != NULL) 4409 nrp = dsp->nfsclds_sockp; 4410 if (nrp == NULL) 4411 /* If NULL, use the MDS socket. */ 4412 nrp = &nmp->nm_sockreq; 4413 nd->nd_flag |= ND_USEGSSNAME; 4414 if (dsp == NULL) 4415 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4416 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4417 else { 4418 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4419 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 4420 if (error == ENXIO) 4421 nfscl_cancelreqs(dsp); 4422 } 4423 if (error) 4424 return (error); 4425 error = nd->nd_repstat; 4426 mbuf_freem(nd->nd_mrep); 4427 return (error); 4428 } 4429 4430 /* 4431 * This function performs the Releaselockowner RPC. 4432 */ 4433 APPLESTATIC int 4434 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4435 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4436 { 4437 struct nfsrv_descript nfsd, *nd = &nfsd; 4438 u_int32_t *tl; 4439 int error; 4440 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4441 struct nfsclsession *tsep; 4442 4443 if (NFSHASNFSV4N(nmp)) { 4444 /* For NFSv4.1, do a FreeStateID. */ 4445 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, 4446 NULL, 0, 0); 4447 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); 4448 } else { 4449 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, 4450 NULL, 0, 0); 4451 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4452 tsep = nfsmnt_mdssession(nmp); 4453 *tl++ = tsep->nfsess_clientid.lval[0]; 4454 *tl = tsep->nfsess_clientid.lval[1]; 4455 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4456 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4457 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4458 } 4459 nd->nd_flag |= ND_USEGSSNAME; 4460 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4461 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4462 if (error) 4463 return (error); 4464 error = nd->nd_repstat; 4465 mbuf_freem(nd->nd_mrep); 4466 return (error); 4467 } 4468 4469 /* 4470 * This function performs the Compound to get the mount pt FH. 4471 */ 4472 APPLESTATIC int 4473 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4474 NFSPROC_T *p) 4475 { 4476 u_int32_t *tl; 4477 struct nfsrv_descript nfsd; 4478 struct nfsrv_descript *nd = &nfsd; 4479 u_char *cp, *cp2; 4480 int error, cnt, len, setnil; 4481 u_int32_t *opcntp; 4482 4483 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0, 4484 0); 4485 cp = dirpath; 4486 cnt = 0; 4487 do { 4488 setnil = 0; 4489 while (*cp == '/') 4490 cp++; 4491 cp2 = cp; 4492 while (*cp2 != '\0' && *cp2 != '/') 4493 cp2++; 4494 if (*cp2 == '/') { 4495 setnil = 1; 4496 *cp2 = '\0'; 4497 } 4498 if (cp2 != cp) { 4499 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4500 *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4501 nfsm_strtom(nd, cp, strlen(cp)); 4502 cnt++; 4503 } 4504 if (setnil) 4505 *cp2++ = '/'; 4506 cp = cp2; 4507 } while (*cp != '\0'); 4508 if (NFSHASNFSV4N(nmp)) 4509 /* Has a Sequence Op done by nfscl_reqstart(). */ 4510 *opcntp = txdr_unsigned(3 + cnt); 4511 else 4512 *opcntp = txdr_unsigned(2 + cnt); 4513 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4514 *tl = txdr_unsigned(NFSV4OP_GETFH); 4515 nd->nd_flag |= ND_USEGSSNAME; 4516 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4517 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4518 if (error) 4519 return (error); 4520 if (nd->nd_repstat == 0) { 4521 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4522 tl += (2 + 2 * cnt); 4523 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4524 len > NFSX_FHMAX) { 4525 nd->nd_repstat = NFSERR_BADXDR; 4526 } else { 4527 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4528 if (nd->nd_repstat == 0) 4529 nmp->nm_fhsize = len; 4530 } 4531 } 4532 error = nd->nd_repstat; 4533 nfsmout: 4534 mbuf_freem(nd->nd_mrep); 4535 return (error); 4536 } 4537 4538 /* 4539 * This function performs the Delegreturn RPC. 4540 */ 4541 APPLESTATIC int 4542 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4543 struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4544 { 4545 u_int32_t *tl; 4546 struct nfsrv_descript nfsd; 4547 struct nfsrv_descript *nd = &nfsd; 4548 int error; 4549 4550 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4551 dp->nfsdl_fhlen, NULL, NULL, 0, 0); 4552 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4553 if (NFSHASNFSV4N(nmp)) 4554 *tl++ = 0; 4555 else 4556 *tl++ = dp->nfsdl_stateid.seqid; 4557 *tl++ = dp->nfsdl_stateid.other[0]; 4558 *tl++ = dp->nfsdl_stateid.other[1]; 4559 *tl = dp->nfsdl_stateid.other[2]; 4560 if (syscred) 4561 nd->nd_flag |= ND_USEGSSNAME; 4562 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4563 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4564 if (error) 4565 return (error); 4566 error = nd->nd_repstat; 4567 mbuf_freem(nd->nd_mrep); 4568 return (error); 4569 } 4570 4571 /* 4572 * nfs getacl call. 4573 */ 4574 APPLESTATIC int 4575 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4576 struct acl *aclp, void *stuff) 4577 { 4578 struct nfsrv_descript nfsd, *nd = &nfsd; 4579 int error; 4580 nfsattrbit_t attrbits; 4581 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4582 4583 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4584 return (EOPNOTSUPP); 4585 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4586 NFSZERO_ATTRBIT(&attrbits); 4587 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4588 (void) nfsrv_putattrbit(nd, &attrbits); 4589 error = nfscl_request(nd, vp, p, cred, stuff); 4590 if (error) 4591 return (error); 4592 if (!nd->nd_repstat) 4593 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4594 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4595 else 4596 error = nd->nd_repstat; 4597 mbuf_freem(nd->nd_mrep); 4598 return (error); 4599 } 4600 4601 /* 4602 * nfs setacl call. 4603 */ 4604 APPLESTATIC int 4605 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4606 struct acl *aclp, void *stuff) 4607 { 4608 int error; 4609 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4610 4611 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4612 return (EOPNOTSUPP); 4613 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4614 return (error); 4615 } 4616 4617 /* 4618 * nfs setacl call. 4619 */ 4620 static int 4621 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4622 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 4623 { 4624 struct nfsrv_descript nfsd, *nd = &nfsd; 4625 int error; 4626 nfsattrbit_t attrbits; 4627 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4628 4629 if (!NFSHASNFSV4(nmp)) 4630 return (EOPNOTSUPP); 4631 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 4632 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 4633 NFSZERO_ATTRBIT(&attrbits); 4634 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4635 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0, 4636 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); 4637 error = nfscl_request(nd, vp, p, cred, stuff); 4638 if (error) 4639 return (error); 4640 /* Don't care about the pre/postop attributes */ 4641 mbuf_freem(nd->nd_mrep); 4642 return (nd->nd_repstat); 4643 } 4644 4645 /* 4646 * Do the NFSv4.1 Exchange ID. 4647 */ 4648 int 4649 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, 4650 struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp, 4651 struct ucred *cred, NFSPROC_T *p) 4652 { 4653 uint32_t *tl, v41flags; 4654 struct nfsrv_descript nfsd; 4655 struct nfsrv_descript *nd = &nfsd; 4656 struct nfsclds *dsp; 4657 struct timespec verstime; 4658 int error, len; 4659 4660 *dspp = NULL; 4661 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, 0, 0); 4662 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4663 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ 4664 *tl = txdr_unsigned(clp->nfsc_rev); 4665 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 4666 4667 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4668 *tl++ = txdr_unsigned(exchflags); 4669 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); 4670 4671 /* Set the implementation id4 */ 4672 *tl = txdr_unsigned(1); 4673 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4674 (void) nfsm_strtom(nd, version, strlen(version)); 4675 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4676 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4677 verstime.tv_nsec = 0; 4678 txdr_nfsv4time(&verstime, tl); 4679 nd->nd_flag |= ND_USEGSSNAME; 4680 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4681 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4682 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, 4683 (int)nd->nd_repstat); 4684 if (error != 0) 4685 return (error); 4686 if (nd->nd_repstat == 0) { 4687 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); 4688 len = fxdr_unsigned(int, *(tl + 7)); 4689 if (len < 0 || len > NFSV4_OPAQUELIMIT) { 4690 error = NFSERR_BADXDR; 4691 goto nfsmout; 4692 } 4693 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, 4694 M_WAITOK | M_ZERO); 4695 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; 4696 dsp->nfsclds_servownlen = len; 4697 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; 4698 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; 4699 dsp->nfsclds_sess.nfsess_sequenceid = 4700 fxdr_unsigned(uint32_t, *tl++); 4701 v41flags = fxdr_unsigned(uint32_t, *tl); 4702 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && 4703 NFSHASPNFSOPT(nmp)) { 4704 NFSCL_DEBUG(1, "set PNFS\n"); 4705 NFSLOCKMNT(nmp); 4706 nmp->nm_state |= NFSSTA_PNFS; 4707 NFSUNLOCKMNT(nmp); 4708 dsp->nfsclds_flags |= NFSCLDS_MDS; 4709 } 4710 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) 4711 dsp->nfsclds_flags |= NFSCLDS_DS; 4712 if (len > 0) 4713 nd->nd_repstat = nfsrv_mtostr(nd, 4714 dsp->nfsclds_serverown, len); 4715 if (nd->nd_repstat == 0) { 4716 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 4717 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 4718 NULL, MTX_DEF); 4719 nfscl_initsessionslots(&dsp->nfsclds_sess); 4720 *dspp = dsp; 4721 } else 4722 free(dsp, M_NFSCLDS); 4723 } 4724 error = nd->nd_repstat; 4725 nfsmout: 4726 mbuf_freem(nd->nd_mrep); 4727 return (error); 4728 } 4729 4730 /* 4731 * Do the NFSv4.1 Create Session. 4732 */ 4733 int 4734 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, 4735 struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred, 4736 NFSPROC_T *p) 4737 { 4738 uint32_t crflags, maxval, *tl; 4739 struct nfsrv_descript nfsd; 4740 struct nfsrv_descript *nd = &nfsd; 4741 int error, irdcnt; 4742 4743 /* Make sure nm_rsize, nm_wsize is set. */ 4744 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0) 4745 nmp->nm_rsize = NFS_MAXBSIZE; 4746 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0) 4747 nmp->nm_wsize = NFS_MAXBSIZE; 4748 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, 0, 4749 0); 4750 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4751 *tl++ = sep->nfsess_clientid.lval[0]; 4752 *tl++ = sep->nfsess_clientid.lval[1]; 4753 *tl++ = txdr_unsigned(sequenceid); 4754 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); 4755 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0) 4756 crflags |= NFSV4CRSESS_CONNBACKCHAN; 4757 *tl = txdr_unsigned(crflags); 4758 4759 /* Fill in fore channel attributes. */ 4760 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4761 *tl++ = 0; /* Header pad size */ 4762 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);/* Max request size */ 4763 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);/* Max reply size */ 4764 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4765 *tl++ = txdr_unsigned(20); /* Max operations */ 4766 *tl++ = txdr_unsigned(64); /* Max slots */ 4767 *tl = 0; /* No rdma ird */ 4768 4769 /* Fill in back channel attributes. */ 4770 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4771 *tl++ = 0; /* Header pad size */ 4772 *tl++ = txdr_unsigned(10000); /* Max request size */ 4773 *tl++ = txdr_unsigned(10000); /* Max response size */ 4774 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4775 *tl++ = txdr_unsigned(4); /* Max operations */ 4776 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ 4777 *tl = 0; /* No rdma ird */ 4778 4779 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); 4780 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ 4781 4782 /* Allow AUTH_SYS callbacks as uid, gid == 0. */ 4783 *tl++ = txdr_unsigned(1); /* Auth_sys only */ 4784 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ 4785 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ 4786 *tl++ = 0; /* Null machine name */ 4787 *tl++ = 0; /* Uid == 0 */ 4788 *tl++ = 0; /* Gid == 0 */ 4789 *tl = 0; /* No additional gids */ 4790 nd->nd_flag |= ND_USEGSSNAME; 4791 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, 4792 NFS_VER4, NULL, 1, NULL, NULL); 4793 if (error != 0) 4794 return (error); 4795 if (nd->nd_repstat == 0) { 4796 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 4797 2 * NFSX_UNSIGNED); 4798 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); 4799 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4800 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); 4801 crflags = fxdr_unsigned(uint32_t, *tl); 4802 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { 4803 NFSLOCKMNT(nmp); 4804 nmp->nm_state |= NFSSTA_SESSPERSIST; 4805 NFSUNLOCKMNT(nmp); 4806 } 4807 4808 /* Get the fore channel slot count. */ 4809 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4810 tl++; /* Skip the header pad size. */ 4811 4812 /* Make sure nm_wsize is small enough. */ 4813 maxval = fxdr_unsigned(uint32_t, *tl++); 4814 while (maxval < nmp->nm_wsize + NFS_MAXXDR) { 4815 if (nmp->nm_wsize > 8096) 4816 nmp->nm_wsize /= 2; 4817 else 4818 break; 4819 } 4820 4821 /* Make sure nm_rsize is small enough. */ 4822 maxval = fxdr_unsigned(uint32_t, *tl++); 4823 while (maxval < nmp->nm_rsize + NFS_MAXXDR) { 4824 if (nmp->nm_rsize > 8096) 4825 nmp->nm_rsize /= 2; 4826 else 4827 break; 4828 } 4829 4830 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); 4831 tl++; 4832 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); 4833 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); 4834 irdcnt = fxdr_unsigned(int, *tl); 4835 if (irdcnt > 0) 4836 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 4837 4838 /* and the back channel slot count. */ 4839 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4840 tl += 5; 4841 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 4842 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 4843 } 4844 error = nd->nd_repstat; 4845 nfsmout: 4846 mbuf_freem(nd->nd_mrep); 4847 return (error); 4848 } 4849 4850 /* 4851 * Do the NFSv4.1 Destroy Session. 4852 */ 4853 int 4854 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp, 4855 struct ucred *cred, NFSPROC_T *p) 4856 { 4857 uint32_t *tl; 4858 struct nfsrv_descript nfsd; 4859 struct nfsrv_descript *nd = &nfsd; 4860 int error; 4861 struct nfsclsession *tsep; 4862 4863 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0, 4864 0); 4865 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4866 tsep = nfsmnt_mdssession(nmp); 4867 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID); 4868 nd->nd_flag |= ND_USEGSSNAME; 4869 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4870 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4871 if (error != 0) 4872 return (error); 4873 error = nd->nd_repstat; 4874 mbuf_freem(nd->nd_mrep); 4875 return (error); 4876 } 4877 4878 /* 4879 * Do the NFSv4.1 Destroy Client. 4880 */ 4881 int 4882 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 4883 struct ucred *cred, NFSPROC_T *p) 4884 { 4885 uint32_t *tl; 4886 struct nfsrv_descript nfsd; 4887 struct nfsrv_descript *nd = &nfsd; 4888 int error; 4889 struct nfsclsession *tsep; 4890 4891 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0, 4892 0); 4893 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4894 tsep = nfsmnt_mdssession(nmp); 4895 *tl++ = tsep->nfsess_clientid.lval[0]; 4896 *tl = tsep->nfsess_clientid.lval[1]; 4897 nd->nd_flag |= ND_USEGSSNAME; 4898 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4899 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4900 if (error != 0) 4901 return (error); 4902 error = nd->nd_repstat; 4903 mbuf_freem(nd->nd_mrep); 4904 return (error); 4905 } 4906 4907 /* 4908 * Do the NFSv4.1 LayoutGet. 4909 */ 4910 static int 4911 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 4912 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype, 4913 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep, 4914 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p, 4915 void *stuff) 4916 { 4917 struct nfsrv_descript nfsd, *nd = &nfsd; 4918 int error; 4919 4920 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0, 4921 0); 4922 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, 4923 layouttype, layoutlen, 0); 4924 nd->nd_flag |= ND_USEGSSNAME; 4925 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4926 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4927 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); 4928 if (error != 0) 4929 return (error); 4930 if (nd->nd_repstat == 0) 4931 error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp); 4932 if (error == 0 && nd->nd_repstat != 0) 4933 error = nd->nd_repstat; 4934 mbuf_freem(nd->nd_mrep); 4935 return (error); 4936 } 4937 4938 /* 4939 * Do the NFSv4.1 Get Device Info. 4940 */ 4941 int 4942 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 4943 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 4944 NFSPROC_T *p) 4945 { 4946 uint32_t cnt, *tl, vers, minorvers; 4947 struct nfsrv_descript nfsd; 4948 struct nfsrv_descript *nd = &nfsd; 4949 struct sockaddr_in sin, ssin; 4950 struct sockaddr_in6 sin6, ssin6; 4951 struct nfsclds *dsp = NULL, **dspp, **gotdspp; 4952 struct nfscldevinfo *ndi; 4953 int addrcnt = 0, bitcnt, error, gotvers, i, isudp, j, stripecnt; 4954 uint8_t stripeindex; 4955 sa_family_t af, safilled; 4956 4957 *ndip = NULL; 4958 ndi = NULL; 4959 gotdspp = NULL; 4960 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0, 4961 0); 4962 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 4963 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 4964 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4965 *tl++ = txdr_unsigned(layouttype); 4966 *tl++ = txdr_unsigned(100000); 4967 if (notifybitsp != NULL && *notifybitsp != 0) { 4968 *tl = txdr_unsigned(1); /* One word of bits. */ 4969 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4970 *tl = txdr_unsigned(*notifybitsp); 4971 } else 4972 *tl = txdr_unsigned(0); 4973 nd->nd_flag |= ND_USEGSSNAME; 4974 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4975 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4976 if (error != 0) 4977 return (error); 4978 if (nd->nd_repstat == 0) { 4979 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4980 if (layouttype != fxdr_unsigned(int, *tl)) 4981 printf("EEK! devinfo layout type not same!\n"); 4982 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) { 4983 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4984 stripecnt = fxdr_unsigned(int, *tl); 4985 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 4986 if (stripecnt < 1 || stripecnt > 4096) { 4987 printf("pNFS File layout devinfo stripecnt %d:" 4988 " out of range\n", stripecnt); 4989 error = NFSERR_BADXDR; 4990 goto nfsmout; 4991 } 4992 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * 4993 NFSX_UNSIGNED); 4994 addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 4995 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 4996 if (addrcnt < 1 || addrcnt > 128) { 4997 printf("NFS devinfo addrcnt %d: out of range\n", 4998 addrcnt); 4999 error = NFSERR_BADXDR; 5000 goto nfsmout; 5001 } 5002 5003 /* 5004 * Now we know how many stripe indices and addresses, so 5005 * we can allocate the structure the correct size. 5006 */ 5007 i = (stripecnt * sizeof(uint8_t)) / 5008 sizeof(struct nfsclds *) + 1; 5009 NFSCL_DEBUG(4, "stripeindices=%d\n", i); 5010 ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 5011 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | 5012 M_ZERO); 5013 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5014 NFSX_V4DEVICEID); 5015 ndi->nfsdi_refcnt = 0; 5016 ndi->nfsdi_flags = NFSDI_FILELAYOUT; 5017 ndi->nfsdi_stripecnt = stripecnt; 5018 ndi->nfsdi_addrcnt = addrcnt; 5019 /* Fill in the stripe indices. */ 5020 for (i = 0; i < stripecnt; i++) { 5021 stripeindex = fxdr_unsigned(uint8_t, *tl++); 5022 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 5023 if (stripeindex >= addrcnt) { 5024 printf("pNFS File Layout devinfo" 5025 " stripeindex %d: too big\n", 5026 (int)stripeindex); 5027 error = NFSERR_BADXDR; 5028 goto nfsmout; 5029 } 5030 nfsfldi_setstripeindex(ndi, i, stripeindex); 5031 } 5032 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 5033 /* For Flex File, we only get one address list. */ 5034 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *), 5035 M_NFSDEVINFO, M_WAITOK | M_ZERO); 5036 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5037 NFSX_V4DEVICEID); 5038 ndi->nfsdi_refcnt = 0; 5039 ndi->nfsdi_flags = NFSDI_FLEXFILE; 5040 addrcnt = ndi->nfsdi_addrcnt = 1; 5041 } 5042 5043 /* Now, dissect the server address(es). */ 5044 safilled = AF_UNSPEC; 5045 for (i = 0; i < addrcnt; i++) { 5046 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5047 cnt = fxdr_unsigned(uint32_t, *tl); 5048 if (cnt == 0) { 5049 printf("NFS devinfo 0 len addrlist\n"); 5050 error = NFSERR_BADXDR; 5051 goto nfsmout; 5052 } 5053 dspp = nfsfldi_addr(ndi, i); 5054 safilled = AF_UNSPEC; 5055 for (j = 0; j < cnt; j++) { 5056 error = nfsv4_getipaddr(nd, &sin, &sin6, &af, 5057 &isudp); 5058 if (error != 0 && error != EPERM) { 5059 error = NFSERR_BADXDR; 5060 goto nfsmout; 5061 } 5062 if (error == 0 && isudp == 0) { 5063 /* 5064 * The priority is: 5065 * - Same address family. 5066 * Save the address and dspp, so that 5067 * the connection can be done after 5068 * parsing is complete. 5069 */ 5070 if (safilled == AF_UNSPEC || 5071 (af == nmp->nm_nam->sa_family && 5072 safilled != nmp->nm_nam->sa_family) 5073 ) { 5074 if (af == AF_INET) 5075 ssin = sin; 5076 else 5077 ssin6 = sin6; 5078 safilled = af; 5079 gotdspp = dspp; 5080 } 5081 } 5082 } 5083 } 5084 5085 gotvers = NFS_VER4; /* Always NFSv4 for File Layout. */ 5086 /* For Flex File, we will take one of the versions to use. */ 5087 if (layouttype == NFSLAYOUT_FLEXFILE) { 5088 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5089 j = fxdr_unsigned(int, *tl); 5090 if (j < 1 || j > NFSDEV_MAXVERS) { 5091 printf("pNFS: too many versions\n"); 5092 error = NFSERR_BADXDR; 5093 goto nfsmout; 5094 } 5095 gotvers = 0; 5096 for (i = 0; i < j; i++) { 5097 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED); 5098 vers = fxdr_unsigned(uint32_t, *tl++); 5099 minorvers = fxdr_unsigned(uint32_t, *tl++); 5100 if ((vers == NFS_VER4 && minorvers == 5101 NFSV41_MINORVERSION) || (vers == NFS_VER3 && 5102 gotvers == 0)) { 5103 gotvers = vers; 5104 /* We'll take this one. */ 5105 ndi->nfsdi_versindex = i; 5106 ndi->nfsdi_vers = vers; 5107 ndi->nfsdi_minorvers = minorvers; 5108 ndi->nfsdi_rsize = fxdr_unsigned( 5109 uint32_t, *tl++); 5110 ndi->nfsdi_wsize = fxdr_unsigned( 5111 uint32_t, *tl++); 5112 if (*tl == newnfs_true) 5113 ndi->nfsdi_flags |= 5114 NFSDI_TIGHTCOUPLED; 5115 else 5116 ndi->nfsdi_flags &= 5117 ~NFSDI_TIGHTCOUPLED; 5118 } 5119 } 5120 if (gotvers == 0) { 5121 printf("pNFS: no NFSv3 or NFSv4.1\n"); 5122 error = NFSERR_BADXDR; 5123 goto nfsmout; 5124 } 5125 } 5126 5127 /* And the notify bits. */ 5128 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5129 bitcnt = fxdr_unsigned(int, *tl); 5130 if (bitcnt > 0) { 5131 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5132 if (notifybitsp != NULL) 5133 *notifybitsp = 5134 fxdr_unsigned(uint32_t, *tl); 5135 } 5136 if (safilled != AF_UNSPEC) { 5137 KASSERT(ndi != NULL, ("ndi is NULL")); 5138 *ndip = ndi; 5139 } else 5140 error = EPERM; 5141 if (error == 0) { 5142 /* 5143 * Now we can do a TCP connection for the correct 5144 * NFS version and IP address. 5145 */ 5146 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled, 5147 gotvers, &dsp, p); 5148 } 5149 if (error == 0) { 5150 KASSERT(gotdspp != NULL, ("gotdspp is NULL")); 5151 *gotdspp = dsp; 5152 } 5153 } 5154 if (nd->nd_repstat != 0 && error == 0) 5155 error = nd->nd_repstat; 5156 nfsmout: 5157 if (error != 0 && ndi != NULL) 5158 nfscl_freedevinfo(ndi); 5159 mbuf_freem(nd->nd_mrep); 5160 return (error); 5161 } 5162 5163 /* 5164 * Do the NFSv4.1 LayoutCommit. 5165 */ 5166 int 5167 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5168 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5169 int layouttype, struct ucred *cred, NFSPROC_T *p, void *stuff) 5170 { 5171 uint32_t *tl; 5172 struct nfsrv_descript nfsd, *nd = &nfsd; 5173 int error; 5174 5175 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL, 5176 0, 0); 5177 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5178 NFSX_STATEID); 5179 txdr_hyper(off, tl); 5180 tl += 2; 5181 txdr_hyper(len, tl); 5182 tl += 2; 5183 if (reclaim != 0) 5184 *tl++ = newnfs_true; 5185 else 5186 *tl++ = newnfs_false; 5187 *tl++ = txdr_unsigned(stateidp->seqid); 5188 *tl++ = stateidp->other[0]; 5189 *tl++ = stateidp->other[1]; 5190 *tl++ = stateidp->other[2]; 5191 *tl++ = newnfs_true; 5192 if (lastbyte < off) 5193 lastbyte = off; 5194 else if (lastbyte >= (off + len)) 5195 lastbyte = off + len - 1; 5196 txdr_hyper(lastbyte, tl); 5197 tl += 2; 5198 *tl++ = newnfs_false; 5199 *tl++ = txdr_unsigned(layouttype); 5200 /* All supported layouts are 0 length. */ 5201 *tl = txdr_unsigned(0); 5202 nd->nd_flag |= ND_USEGSSNAME; 5203 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5204 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5205 if (error != 0) 5206 return (error); 5207 error = nd->nd_repstat; 5208 mbuf_freem(nd->nd_mrep); 5209 return (error); 5210 } 5211 5212 /* 5213 * Do the NFSv4.1 LayoutReturn. 5214 */ 5215 int 5216 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5217 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5218 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5219 uint32_t stat, uint32_t op, char *devid) 5220 { 5221 uint32_t *tl; 5222 struct nfsrv_descript nfsd, *nd = &nfsd; 5223 uint64_t tu64; 5224 int error; 5225 5226 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL, 5227 0, 0); 5228 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5229 if (reclaim != 0) 5230 *tl++ = newnfs_true; 5231 else 5232 *tl++ = newnfs_false; 5233 *tl++ = txdr_unsigned(layouttype); 5234 *tl++ = txdr_unsigned(iomode); 5235 *tl = txdr_unsigned(layoutreturn); 5236 if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5237 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5238 NFSX_UNSIGNED); 5239 txdr_hyper(offset, tl); 5240 tl += 2; 5241 txdr_hyper(len, tl); 5242 tl += 2; 5243 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5244 *tl++ = txdr_unsigned(stateidp->seqid); 5245 *tl++ = stateidp->other[0]; 5246 *tl++ = stateidp->other[1]; 5247 *tl++ = stateidp->other[2]; 5248 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) 5249 *tl = txdr_unsigned(0); 5250 else if (layouttype == NFSLAYOUT_FLEXFILE) { 5251 if (stat != 0) { 5252 *tl = txdr_unsigned(2 * NFSX_HYPER + 5253 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5254 NFSX_UNSIGNED); 5255 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 5256 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5257 NFSX_UNSIGNED); 5258 *tl++ = txdr_unsigned(1); /* One error. */ 5259 tu64 = 0; /* Offset. */ 5260 txdr_hyper(tu64, tl); tl += 2; 5261 tu64 = UINT64_MAX; /* Length. */ 5262 txdr_hyper(tu64, tl); tl += 2; 5263 NFSBCOPY(stateidp, tl, NFSX_STATEID); 5264 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5265 *tl++ = txdr_unsigned(1); /* One error. */ 5266 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5267 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5268 *tl++ = txdr_unsigned(stat); 5269 *tl++ = txdr_unsigned(op); 5270 } else { 5271 *tl = txdr_unsigned(2 * NFSX_UNSIGNED); 5272 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5273 /* No ioerrs. */ 5274 *tl++ = 0; 5275 } 5276 *tl = 0; /* No stats yet. */ 5277 } 5278 } 5279 nd->nd_flag |= ND_USEGSSNAME; 5280 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5281 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5282 if (error != 0) 5283 return (error); 5284 if (nd->nd_repstat == 0) { 5285 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5286 if (*tl != 0) { 5287 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5288 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5289 stateidp->other[0] = *tl++; 5290 stateidp->other[1] = *tl++; 5291 stateidp->other[2] = *tl; 5292 } 5293 } else 5294 error = nd->nd_repstat; 5295 nfsmout: 5296 mbuf_freem(nd->nd_mrep); 5297 return (error); 5298 } 5299 5300 /* 5301 * Acquire a layout and devinfo, if possible. The caller must have acquired 5302 * a reference count on the nfsclclient structure before calling this. 5303 * Return the layout in lypp with a reference count on it, if successful. 5304 */ 5305 static int 5306 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 5307 int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off, 5308 struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 5309 { 5310 struct nfscllayout *lyp; 5311 struct nfsclflayout *flp; 5312 struct nfsclflayouthead flh; 5313 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose; 5314 nfsv4stateid_t stateid; 5315 struct nfsclsession *tsep; 5316 5317 *lypp = NULL; 5318 if (NFSHASFLEXFILE(nmp)) 5319 layouttype = NFSLAYOUT_FLEXFILE; 5320 else 5321 layouttype = NFSLAYOUT_NFSV4_1_FILES; 5322 /* 5323 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 5324 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 5325 * flp == NULL. 5326 */ 5327 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 5328 off, &flp, &recalled); 5329 islocked = 0; 5330 if (lyp == NULL || flp == NULL) { 5331 if (recalled != 0) 5332 return (EIO); 5333 LIST_INIT(&flh); 5334 tsep = nfsmnt_mdssession(nmp); 5335 layoutlen = tsep->nfsess_maxcache - 5336 (NFSX_STATEID + 3 * NFSX_UNSIGNED); 5337 if (lyp == NULL) { 5338 stateid.seqid = 0; 5339 stateid.other[0] = stateidp->other[0]; 5340 stateid.other[1] = stateidp->other[1]; 5341 stateid.other[2] = stateidp->other[2]; 5342 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5343 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, 5344 (uint64_t)0, layouttype, layoutlen, &stateid, 5345 &retonclose, &flh, cred, p, NULL); 5346 } else { 5347 islocked = 1; 5348 stateid.seqid = lyp->nfsly_stateid.seqid; 5349 stateid.other[0] = lyp->nfsly_stateid.other[0]; 5350 stateid.other[1] = lyp->nfsly_stateid.other[1]; 5351 stateid.other[2] = lyp->nfsly_stateid.other[2]; 5352 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5353 nfhp->nfh_len, iomode, off, UINT64_MAX, 5354 (uint64_t)0, layouttype, layoutlen, &stateid, 5355 &retonclose, &flh, cred, p, NULL); 5356 } 5357 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, 5358 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, 5359 &flh, layouttype, error, NULL, cred, p); 5360 if (error == 0) 5361 *lypp = lyp; 5362 else if (islocked != 0) 5363 nfscl_rellayout(lyp, 1); 5364 } else 5365 *lypp = lyp; 5366 return (error); 5367 } 5368 5369 /* 5370 * Do a TCP connection plus exchange id and create session. 5371 * If successful, a "struct nfsclds" is linked into the list for the 5372 * mount point and a pointer to it is returned. 5373 */ 5374 static int 5375 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin, 5376 struct sockaddr_in6 *sin6, sa_family_t af, int vers, struct nfsclds **dspp, 5377 NFSPROC_T *p) 5378 { 5379 struct sockaddr_in *msad, *sad; 5380 struct sockaddr_in6 *msad6, *sad6; 5381 struct nfsclclient *clp; 5382 struct nfssockreq *nrp; 5383 struct nfsclds *dsp, *tdsp; 5384 int error; 5385 enum nfsclds_state retv; 5386 uint32_t sequenceid; 5387 5388 KASSERT(nmp->nm_sockreq.nr_cred != NULL, 5389 ("nfsrpc_fillsa: NULL nr_cred")); 5390 NFSLOCKCLSTATE(); 5391 clp = nmp->nm_clp; 5392 NFSUNLOCKCLSTATE(); 5393 if (clp == NULL) 5394 return (EPERM); 5395 if (af == AF_INET) { 5396 NFSLOCKMNT(nmp); 5397 /* 5398 * Check to see if we already have a session for this 5399 * address that is usable for a DS. 5400 * Note that the MDS's address is in a different place 5401 * than the sessions already acquired for DS's. 5402 */ 5403 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 5404 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5405 while (tdsp != NULL) { 5406 if (msad != NULL && msad->sin_family == AF_INET && 5407 sin->sin_addr.s_addr == msad->sin_addr.s_addr && 5408 sin->sin_port == msad->sin_port && 5409 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5410 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5411 *dspp = tdsp; 5412 NFSUNLOCKMNT(nmp); 5413 NFSCL_DEBUG(4, "fnd same addr\n"); 5414 return (0); 5415 } 5416 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5417 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5418 msad = (struct sockaddr_in *) 5419 tdsp->nfsclds_sockp->nr_nam; 5420 else 5421 msad = NULL; 5422 } 5423 NFSUNLOCKMNT(nmp); 5424 5425 /* No IP address match, so look for new/trunked one. */ 5426 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 5427 sad->sin_len = sizeof(*sad); 5428 sad->sin_family = AF_INET; 5429 sad->sin_port = sin->sin_port; 5430 sad->sin_addr.s_addr = sin->sin_addr.s_addr; 5431 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5432 nrp->nr_nam = (struct sockaddr *)sad; 5433 } else if (af == AF_INET6) { 5434 NFSLOCKMNT(nmp); 5435 /* 5436 * Check to see if we already have a session for this 5437 * address that is usable for a DS. 5438 * Note that the MDS's address is in a different place 5439 * than the sessions already acquired for DS's. 5440 */ 5441 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 5442 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5443 while (tdsp != NULL) { 5444 if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 5445 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 5446 &msad6->sin6_addr) && 5447 sin6->sin6_port == msad6->sin6_port && 5448 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5449 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5450 *dspp = tdsp; 5451 NFSUNLOCKMNT(nmp); 5452 return (0); 5453 } 5454 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5455 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5456 msad6 = (struct sockaddr_in6 *) 5457 tdsp->nfsclds_sockp->nr_nam; 5458 else 5459 msad6 = NULL; 5460 } 5461 NFSUNLOCKMNT(nmp); 5462 5463 /* No IP address match, so look for new/trunked one. */ 5464 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 5465 sad6->sin6_len = sizeof(*sad6); 5466 sad6->sin6_family = AF_INET6; 5467 sad6->sin6_port = sin6->sin6_port; 5468 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr, 5469 sizeof(struct in6_addr)); 5470 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5471 nrp->nr_nam = (struct sockaddr *)sad6; 5472 } else 5473 return (EPERM); 5474 5475 nrp->nr_sotype = SOCK_STREAM; 5476 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 5477 nrp->nr_prog = NFS_PROG; 5478 nrp->nr_vers = vers; 5479 5480 /* 5481 * Use the credentials that were used for the mount, which are 5482 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 5483 * Ref. counting the credentials with crhold() is probably not 5484 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 5485 * unmount, but I did it anyhow. 5486 */ 5487 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 5488 error = newnfs_connect(nmp, nrp, NULL, p, 0); 5489 NFSCL_DEBUG(3, "DS connect=%d\n", error); 5490 5491 dsp = NULL; 5492 /* Now, do the exchangeid and create session. */ 5493 if (error == 0) { 5494 if (vers == NFS_VER4) { 5495 error = nfsrpc_exchangeid(nmp, clp, nrp, 5496 NFSV4EXCH_USEPNFSDS, &dsp, nrp->nr_cred, p); 5497 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 5498 if (error != 0) 5499 newnfs_disconnect(nrp); 5500 } else { 5501 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, 5502 M_WAITOK | M_ZERO); 5503 dsp->nfsclds_flags |= NFSCLDS_DS; 5504 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */ 5505 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 5506 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 5507 NULL, MTX_DEF); 5508 } 5509 } 5510 if (error == 0) { 5511 dsp->nfsclds_sockp = nrp; 5512 if (vers == NFS_VER4) { 5513 NFSLOCKMNT(nmp); 5514 retv = nfscl_getsameserver(nmp, dsp, &tdsp, 5515 &sequenceid); 5516 NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 5517 if (retv == NFSDSP_USETHISSESSION && 5518 nfscl_dssameconn != 0) { 5519 NFSLOCKDS(tdsp); 5520 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN; 5521 NFSUNLOCKDS(tdsp); 5522 NFSUNLOCKMNT(nmp); 5523 /* 5524 * If there is already a session for this 5525 * server, use it. 5526 */ 5527 (void)newnfs_disconnect(nrp); 5528 nfscl_freenfsclds(dsp); 5529 *dspp = tdsp; 5530 return (0); 5531 } 5532 if (retv == NFSDSP_NOTFOUND) 5533 sequenceid = 5534 dsp->nfsclds_sess.nfsess_sequenceid; 5535 NFSUNLOCKMNT(nmp); 5536 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 5537 nrp, sequenceid, 0, nrp->nr_cred, p); 5538 NFSCL_DEBUG(3, "DS createsess=%d\n", error); 5539 } 5540 } else { 5541 NFSFREECRED(nrp->nr_cred); 5542 NFSFREEMUTEX(&nrp->nr_mtx); 5543 free(nrp->nr_nam, M_SONAME); 5544 free(nrp, M_NFSSOCKREQ); 5545 } 5546 if (error == 0) { 5547 NFSCL_DEBUG(3, "add DS session\n"); 5548 /* 5549 * Put it at the end of the list. That way the list 5550 * is ordered by when the entry was added. This matters 5551 * since the one done first is the one that should be 5552 * used for sequencid'ing any subsequent create sessions. 5553 */ 5554 NFSLOCKMNT(nmp); 5555 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 5556 NFSUNLOCKMNT(nmp); 5557 *dspp = dsp; 5558 } else if (dsp != NULL) { 5559 newnfs_disconnect(nrp); 5560 nfscl_freenfsclds(dsp); 5561 } 5562 return (error); 5563 } 5564 5565 /* 5566 * Do the NFSv4.1 Reclaim Complete. 5567 */ 5568 int 5569 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 5570 { 5571 uint32_t *tl; 5572 struct nfsrv_descript nfsd; 5573 struct nfsrv_descript *nd = &nfsd; 5574 int error; 5575 5576 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0, 5577 0); 5578 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5579 *tl = newnfs_false; 5580 nd->nd_flag |= ND_USEGSSNAME; 5581 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5582 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5583 if (error != 0) 5584 return (error); 5585 error = nd->nd_repstat; 5586 mbuf_freem(nd->nd_mrep); 5587 return (error); 5588 } 5589 5590 /* 5591 * Initialize the slot tables for a session. 5592 */ 5593 static void 5594 nfscl_initsessionslots(struct nfsclsession *sep) 5595 { 5596 int i; 5597 5598 for (i = 0; i < NFSV4_CBSLOTS; i++) { 5599 if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 5600 m_freem(sep->nfsess_cbslots[i].nfssl_reply); 5601 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 5602 } 5603 for (i = 0; i < 64; i++) 5604 sep->nfsess_slotseq[i] = 0; 5605 sep->nfsess_slots = 0; 5606 } 5607 5608 /* 5609 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 5610 */ 5611 int 5612 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5613 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) 5614 { 5615 struct nfsnode *np = VTONFS(vp); 5616 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5617 struct nfscllayout *layp; 5618 struct nfscldevinfo *dip; 5619 struct nfsclflayout *rflp; 5620 struct mbuf *m; 5621 struct nfsclwritedsdorpc *drpc, *tdrpc; 5622 nfsv4stateid_t stateid; 5623 struct ucred *newcred; 5624 uint64_t lastbyte, len, off, oresid, xfer; 5625 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo; 5626 void *lckp; 5627 uint8_t *dev; 5628 void *iovbase = NULL; 5629 size_t iovlen = 0; 5630 off_t offs = 0; 5631 ssize_t resid = 0; 5632 5633 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 5634 (np->n_flag & NNOLAYOUT) != 0) 5635 return (EIO); 5636 /* Now, get a reference cnt on the clientid for this mount. */ 5637 if (nfscl_getref(nmp) == 0) 5638 return (EIO); 5639 5640 /* Find an appropriate stateid. */ 5641 newcred = NFSNEWCRED(cred); 5642 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 5643 rwaccess, 1, newcred, p, &stateid, &lckp); 5644 if (error != 0) { 5645 NFSFREECRED(newcred); 5646 nfscl_relref(nmp); 5647 return (error); 5648 } 5649 /* Search for a layout for this file. */ 5650 off = uiop->uio_offset; 5651 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 5652 np->n_fhp->nfh_len, off, &rflp, &recalled); 5653 if (layp == NULL || rflp == NULL) { 5654 if (recalled != 0) { 5655 NFSFREECRED(newcred); 5656 nfscl_relref(nmp); 5657 return (EIO); 5658 } 5659 if (layp != NULL) { 5660 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 5661 layp = NULL; 5662 } 5663 /* Try and get a Layout, if it is supported. */ 5664 if (rwaccess == NFSV4OPEN_ACCESSWRITE || 5665 (np->n_flag & NWRITEOPENED) != 0) 5666 iolaymode = NFSLAYOUTIOMODE_RW; 5667 else 5668 iolaymode = NFSLAYOUTIOMODE_READ; 5669 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 5670 NULL, &stateid, off, &layp, newcred, p); 5671 if (error != 0) { 5672 NFSLOCKNODE(np); 5673 np->n_flag |= NNOLAYOUT; 5674 NFSUNLOCKNODE(np); 5675 if (lckp != NULL) 5676 nfscl_lockderef(lckp); 5677 NFSFREECRED(newcred); 5678 if (layp != NULL) 5679 nfscl_rellayout(layp, 0); 5680 nfscl_relref(nmp); 5681 return (error); 5682 } 5683 } 5684 5685 /* 5686 * Loop around finding a layout that works for the first part of 5687 * this I/O operation, and then call the function that actually 5688 * does the RPC. 5689 */ 5690 eof = 0; 5691 len = (uint64_t)uiop->uio_resid; 5692 while (len > 0 && error == 0 && eof == 0) { 5693 off = uiop->uio_offset; 5694 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 5695 if (error == 0) { 5696 oresid = xfer = (uint64_t)uiop->uio_resid; 5697 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 5698 xfer = rflp->nfsfl_end - rflp->nfsfl_off; 5699 /* 5700 * For Flex File layout with mirrored DSs, select one 5701 * of them at random for reads. For writes and commits, 5702 * do all mirrors. 5703 */ 5704 m = NULL; 5705 tdrpc = drpc = NULL; 5706 firstmirror = 0; 5707 mirrorcnt = 1; 5708 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 && 5709 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) { 5710 if (rwaccess == NFSV4OPEN_ACCESSREAD) { 5711 firstmirror = arc4random() % mirrorcnt; 5712 mirrorcnt = firstmirror + 1; 5713 } else { 5714 if (docommit == 0) { 5715 /* 5716 * Save values, so uiop can be 5717 * rolled back upon a write 5718 * error. 5719 */ 5720 offs = uiop->uio_offset; 5721 resid = uiop->uio_resid; 5722 iovbase = 5723 uiop->uio_iov->iov_base; 5724 iovlen = uiop->uio_iov->iov_len; 5725 m = nfsm_uiombuflist(uiop, len, 5726 NULL, NULL); 5727 } 5728 tdrpc = drpc = malloc(sizeof(*drpc) * 5729 (mirrorcnt - 1), M_TEMP, M_WAITOK | 5730 M_ZERO); 5731 } 5732 } 5733 for (i = firstmirror; i < mirrorcnt && error == 0; i++){ 5734 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { 5735 dev = rflp->nfsfl_ffm[i].dev; 5736 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 5737 rflp->nfsfl_ffm[i].devp); 5738 } else { 5739 dev = rflp->nfsfl_dev; 5740 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 5741 rflp->nfsfl_devp); 5742 } 5743 if (dip != NULL) { 5744 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE) 5745 != 0) 5746 error = nfscl_dofflayoutio(vp, 5747 uiop, iomode, must_commit, 5748 &eof, &stateid, rwaccess, 5749 dip, layp, rflp, off, xfer, 5750 i, docommit, m, tdrpc, 5751 newcred, p); 5752 else 5753 error = nfscl_doflayoutio(vp, 5754 uiop, iomode, must_commit, 5755 &eof, &stateid, rwaccess, 5756 dip, layp, rflp, off, xfer, 5757 docommit, newcred, p); 5758 nfscl_reldevinfo(dip); 5759 } else 5760 error = EIO; 5761 tdrpc++; 5762 } 5763 if (m != NULL) 5764 m_freem(m); 5765 tdrpc = drpc; 5766 timo = hz / 50; /* Wait for 20msec. */ 5767 if (timo < 1) 5768 timo = 1; 5769 for (i = firstmirror; i < mirrorcnt - 1 && 5770 tdrpc != NULL; i++, tdrpc++) { 5771 /* 5772 * For the unused drpc entries, both inprog and 5773 * err == 0, so this loop won't break. 5774 */ 5775 while (tdrpc->inprog != 0 && tdrpc->done == 0) 5776 tsleep(&tdrpc->tsk, PVFS, "clrpcio", 5777 timo); 5778 if (error == 0 && tdrpc->err != 0) 5779 error = tdrpc->err; 5780 } 5781 free(drpc, M_TEMP); 5782 if (error == 0) { 5783 if (mirrorcnt > 1 && rwaccess == 5784 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 5785 NFSLOCKCLSTATE(); 5786 layp->nfsly_flags |= NFSLY_WRITTEN; 5787 NFSUNLOCKCLSTATE(); 5788 } 5789 lastbyte = off + xfer - 1; 5790 NFSLOCKCLSTATE(); 5791 if (lastbyte > layp->nfsly_lastbyte) 5792 layp->nfsly_lastbyte = lastbyte; 5793 NFSUNLOCKCLSTATE(); 5794 } else if (error == NFSERR_OPENMODE && 5795 rwaccess == NFSV4OPEN_ACCESSREAD) { 5796 NFSLOCKMNT(nmp); 5797 nmp->nm_state |= NFSSTA_OPENMODE; 5798 NFSUNLOCKMNT(nmp); 5799 } else 5800 error = EIO; 5801 if (error == 0) 5802 len -= (oresid - (uint64_t)uiop->uio_resid); 5803 else if (mirrorcnt > 1 && rwaccess == 5804 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 5805 /* 5806 * In case the rpc gets retried, roll the 5807 * uio fields changed by nfsm_uiombuflist() 5808 * back. 5809 */ 5810 uiop->uio_offset = offs; 5811 uiop->uio_resid = resid; 5812 uiop->uio_iov->iov_base = iovbase; 5813 uiop->uio_iov->iov_len = iovlen; 5814 } 5815 } 5816 } 5817 if (lckp != NULL) 5818 nfscl_lockderef(lckp); 5819 NFSFREECRED(newcred); 5820 nfscl_rellayout(layp, 0); 5821 nfscl_relref(nmp); 5822 return (error); 5823 } 5824 5825 /* 5826 * Make a copy of the mbuf chain and add an mbuf for null padding, as required. 5827 */ 5828 static struct mbuf * 5829 nfsm_copym(struct mbuf *m, int off, int xfer) 5830 { 5831 struct mbuf *m2, *m3, *m4; 5832 uint32_t *tl; 5833 int rem; 5834 5835 m2 = m_copym(m, off, xfer, M_WAITOK); 5836 rem = NFSM_RNDUP(xfer) - xfer; 5837 if (rem > 0) { 5838 /* 5839 * The zero padding to a multiple of 4 bytes is required by 5840 * the XDR. So that the mbufs copied by reference aren't 5841 * modified, add an mbuf with the zero'd bytes to the list. 5842 * rem will be a maximum of 3, so one zero'd uint32_t is 5843 * sufficient. 5844 */ 5845 m3 = m2; 5846 while (m3->m_next != NULL) 5847 m3 = m3->m_next; 5848 NFSMGET(m4); 5849 tl = NFSMTOD(m4, uint32_t *); 5850 *tl = 0; 5851 mbuf_setlen(m4, rem); 5852 mbuf_setnext(m3, m4); 5853 } 5854 return (m2); 5855 } 5856 5857 /* 5858 * Find a file layout that will handle the first bytes of the requested 5859 * range and return the information from it needed to the I/O operation. 5860 */ 5861 int 5862 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 5863 struct nfsclflayout **retflpp) 5864 { 5865 struct nfsclflayout *flp, *nflp, *rflp; 5866 uint32_t rw; 5867 5868 rflp = NULL; 5869 rw = rwaccess; 5870 /* For reading, do the Read list first and then the Write list. */ 5871 do { 5872 if (rw == NFSV4OPEN_ACCESSREAD) 5873 flp = LIST_FIRST(&lyp->nfsly_flayread); 5874 else 5875 flp = LIST_FIRST(&lyp->nfsly_flayrw); 5876 while (flp != NULL) { 5877 nflp = LIST_NEXT(flp, nfsfl_list); 5878 if (flp->nfsfl_off > off) 5879 break; 5880 if (flp->nfsfl_end > off && 5881 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 5882 rflp = flp; 5883 flp = nflp; 5884 } 5885 if (rw == NFSV4OPEN_ACCESSREAD) 5886 rw = NFSV4OPEN_ACCESSWRITE; 5887 else 5888 rw = 0; 5889 } while (rw != 0); 5890 if (rflp != NULL) { 5891 /* This one covers the most bytes starting at off. */ 5892 *retflpp = rflp; 5893 return (0); 5894 } 5895 return (EIO); 5896 } 5897 5898 /* 5899 * Do I/O using an NFSv4.1 file layout. 5900 */ 5901 static int 5902 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5903 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 5904 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 5905 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) 5906 { 5907 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 5908 int commit_thru_mds, error, stripe_index, stripe_pos; 5909 struct nfsnode *np; 5910 struct nfsfh *fhp; 5911 struct nfsclds **dspp; 5912 5913 np = VTONFS(vp); 5914 rel_off = off - flp->nfsfl_patoff; 5915 stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff; 5916 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 5917 dp->nfsdi_stripecnt; 5918 transfer = stripe_unit_size - (rel_off % stripe_unit_size); 5919 error = 0; 5920 5921 /* Loop around, doing I/O for each stripe unit. */ 5922 while (len > 0 && error == 0) { 5923 stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 5924 dspp = nfsfldi_addr(dp, stripe_index); 5925 if (len > transfer && docommit == 0) 5926 xfer = transfer; 5927 else 5928 xfer = len; 5929 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 5930 /* Dense layout. */ 5931 if (stripe_pos >= flp->nfsfl_fhcnt) 5932 return (EIO); 5933 fhp = flp->nfsfl_fh[stripe_pos]; 5934 io_off = (rel_off / (stripe_unit_size * 5935 dp->nfsdi_stripecnt)) * stripe_unit_size + 5936 rel_off % stripe_unit_size; 5937 } else { 5938 /* Sparse layout. */ 5939 if (flp->nfsfl_fhcnt > 1) { 5940 if (stripe_index >= flp->nfsfl_fhcnt) 5941 return (EIO); 5942 fhp = flp->nfsfl_fh[stripe_index]; 5943 } else if (flp->nfsfl_fhcnt == 1) 5944 fhp = flp->nfsfl_fh[0]; 5945 else 5946 fhp = np->n_fhp; 5947 io_off = off; 5948 } 5949 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { 5950 commit_thru_mds = 1; 5951 if (docommit != 0) 5952 error = EIO; 5953 } else { 5954 commit_thru_mds = 0; 5955 mtx_lock(&np->n_mtx); 5956 np->n_flag |= NDSCOMMIT; 5957 mtx_unlock(&np->n_mtx); 5958 } 5959 if (docommit != 0) { 5960 if (error == 0) 5961 error = nfsrpc_commitds(vp, io_off, xfer, 5962 *dspp, fhp, 0, 0, cred, p); 5963 if (error == 0) { 5964 /* 5965 * Set both eof and uio_resid = 0 to end any 5966 * loops. 5967 */ 5968 *eofp = 1; 5969 uiop->uio_resid = 0; 5970 } else { 5971 mtx_lock(&np->n_mtx); 5972 np->n_flag &= ~NDSCOMMIT; 5973 mtx_unlock(&np->n_mtx); 5974 } 5975 } else if (rwflag == NFSV4OPEN_ACCESSREAD) 5976 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 5977 io_off, xfer, fhp, 0, 0, 0, cred, p); 5978 else { 5979 error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 5980 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 5981 0, 0, 0, cred, p); 5982 if (error == 0) { 5983 NFSLOCKCLSTATE(); 5984 lyp->nfsly_flags |= NFSLY_WRITTEN; 5985 NFSUNLOCKCLSTATE(); 5986 } 5987 } 5988 if (error == 0) { 5989 transfer = stripe_unit_size; 5990 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 5991 len -= xfer; 5992 off += xfer; 5993 } 5994 } 5995 return (error); 5996 } 5997 5998 /* 5999 * Do I/O using an NFSv4.1 flex file layout. 6000 */ 6001 static int 6002 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6003 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6004 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6005 uint64_t len, int mirror, int docommit, struct mbuf *mp, 6006 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6007 { 6008 uint64_t transfer, xfer; 6009 int error, rel_off; 6010 struct nfsnode *np; 6011 struct nfsfh *fhp; 6012 struct nfsclds **dspp; 6013 struct ucred *tcred; 6014 struct mbuf *m; 6015 6016 np = VTONFS(vp); 6017 error = 0; 6018 rel_off = 0; 6019 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, 6020 (uintmax_t)len); 6021 /* Loop around, doing I/O for each stripe unit. */ 6022 while (len > 0 && error == 0) { 6023 dspp = nfsfldi_addr(dp, 0); 6024 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex]; 6025 stateidp = &flp->nfsfl_ffm[mirror].st; 6026 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n", 6027 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid); 6028 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) { 6029 tcred = NFSNEWCRED(cred); 6030 tcred->cr_uid = flp->nfsfl_ffm[mirror].user; 6031 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group; 6032 tcred->cr_ngroups = 1; 6033 } else 6034 tcred = cred; 6035 if (rwflag == NFSV4OPEN_ACCESSREAD) 6036 transfer = dp->nfsdi_rsize; 6037 else 6038 transfer = dp->nfsdi_wsize; 6039 mtx_lock(&np->n_mtx); 6040 np->n_flag |= NDSCOMMIT; 6041 mtx_unlock(&np->n_mtx); 6042 if (len > transfer && docommit == 0) 6043 xfer = transfer; 6044 else 6045 xfer = len; 6046 if (docommit != 0) { 6047 if (error == 0) { 6048 /* 6049 * Do last mirrored DS commit with this thread. 6050 */ 6051 if (mirror < flp->nfsfl_mirrorcnt - 1) 6052 error = nfsio_commitds(vp, off, xfer, 6053 *dspp, fhp, dp->nfsdi_vers, 6054 dp->nfsdi_minorvers, drpc, tcred, 6055 p); 6056 else 6057 error = nfsrpc_commitds(vp, off, xfer, 6058 *dspp, fhp, dp->nfsdi_vers, 6059 dp->nfsdi_minorvers, tcred, p); 6060 NFSCL_DEBUG(4, "commitds=%d\n", error); 6061 if (error != 0 && error != EACCES && error != 6062 ESTALE) { 6063 NFSCL_DEBUG(4, 6064 "DS layreterr for commit\n"); 6065 nfscl_dserr(NFSV4OP_COMMIT, error, dp, 6066 lyp, *dspp); 6067 } 6068 } 6069 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error); 6070 if (error == 0) { 6071 /* 6072 * Set both eof and uio_resid = 0 to end any 6073 * loops. 6074 */ 6075 *eofp = 1; 6076 uiop->uio_resid = 0; 6077 } else { 6078 mtx_lock(&np->n_mtx); 6079 np->n_flag &= ~NDSCOMMIT; 6080 mtx_unlock(&np->n_mtx); 6081 } 6082 } else if (rwflag == NFSV4OPEN_ACCESSREAD) { 6083 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6084 off, xfer, fhp, 1, dp->nfsdi_vers, 6085 dp->nfsdi_minorvers, tcred, p); 6086 NFSCL_DEBUG(4, "readds=%d\n", error); 6087 if (error != 0 && error != EACCES && error != ESTALE) { 6088 NFSCL_DEBUG(4, "DS layreterr for read\n"); 6089 nfscl_dserr(NFSV4OP_READ, error, dp, lyp, 6090 *dspp); 6091 } 6092 } else { 6093 if (flp->nfsfl_mirrorcnt == 1) { 6094 error = nfsrpc_writeds(vp, uiop, iomode, 6095 must_commit, stateidp, *dspp, off, xfer, 6096 fhp, 0, 1, dp->nfsdi_vers, 6097 dp->nfsdi_minorvers, tcred, p); 6098 if (error == 0) { 6099 NFSLOCKCLSTATE(); 6100 lyp->nfsly_flags |= NFSLY_WRITTEN; 6101 NFSUNLOCKCLSTATE(); 6102 } 6103 } else { 6104 m = nfsm_copym(mp, rel_off, xfer); 6105 NFSCL_DEBUG(4, "mcopy reloff=%d xfer=%jd\n", 6106 rel_off, (uintmax_t)xfer); 6107 /* 6108 * Do last write to a mirrored DS with this 6109 * thread. 6110 */ 6111 if (mirror < flp->nfsfl_mirrorcnt - 1) 6112 error = nfsio_writedsmir(vp, iomode, 6113 must_commit, stateidp, *dspp, off, 6114 xfer, fhp, m, dp->nfsdi_vers, 6115 dp->nfsdi_minorvers, drpc, tcred, 6116 p); 6117 else 6118 error = nfsrpc_writedsmir(vp, iomode, 6119 must_commit, stateidp, *dspp, off, 6120 xfer, fhp, m, dp->nfsdi_vers, 6121 dp->nfsdi_minorvers, tcred, p); 6122 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); 6123 if (error != 0 && error != EACCES && error != 6124 ESTALE) { 6125 NFSCL_DEBUG(4, 6126 "DS layreterr for write\n"); 6127 nfscl_dserr(NFSV4OP_WRITE, error, dp, 6128 lyp, *dspp); 6129 } 6130 } 6131 } 6132 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error); 6133 if (error == 0) { 6134 len -= xfer; 6135 off += xfer; 6136 rel_off += xfer; 6137 } 6138 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) 6139 NFSFREECRED(tcred); 6140 } 6141 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error); 6142 return (error); 6143 } 6144 6145 /* 6146 * The actual read RPC done to a DS. 6147 */ 6148 static int 6149 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 6150 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex, 6151 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) 6152 { 6153 uint32_t *tl; 6154 int attrflag, error, retlen; 6155 struct nfsrv_descript nfsd; 6156 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6157 struct nfsrv_descript *nd = &nfsd; 6158 struct nfssockreq *nrp; 6159 struct nfsvattr na; 6160 6161 nd->nd_mrep = NULL; 6162 if (vers == 0 || vers == NFS_VER4) { 6163 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, 6164 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6165 vers = NFS_VER4; 6166 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers); 6167 if (flex != 0) 6168 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6169 else 6170 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6171 } else { 6172 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh, 6173 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6174 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n"); 6175 } 6176 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 6177 txdr_hyper(io_off, tl); 6178 *(tl + 2) = txdr_unsigned(len); 6179 nrp = dsp->nfsclds_sockp; 6180 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp); 6181 if (nrp == NULL) 6182 /* If NULL, use the MDS socket. */ 6183 nrp = &nmp->nm_sockreq; 6184 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6185 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6186 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat, 6187 error); 6188 if (error != 0) 6189 return (error); 6190 if (vers == NFS_VER3) { 6191 error = nfscl_postop_attr(nd, &na, &attrflag, NULL); 6192 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error); 6193 if (error != 0) 6194 goto nfsmout; 6195 } 6196 if (nd->nd_repstat != 0) { 6197 error = nd->nd_repstat; 6198 goto nfsmout; 6199 } 6200 if (vers == NFS_VER3) { 6201 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6202 *eofp = fxdr_unsigned(int, *(tl + 1)); 6203 } else { 6204 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6205 *eofp = fxdr_unsigned(int, *tl); 6206 } 6207 NFSM_STRSIZ(retlen, len); 6208 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp); 6209 error = nfsm_mbufuio(nd, uiop, retlen); 6210 nfsmout: 6211 if (nd->nd_mrep != NULL) 6212 mbuf_freem(nd->nd_mrep); 6213 return (error); 6214 } 6215 6216 /* 6217 * The actual write RPC done to a DS. 6218 */ 6219 static int 6220 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6221 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6222 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers, 6223 struct ucred *cred, NFSPROC_T *p) 6224 { 6225 uint32_t *tl; 6226 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6227 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC; 6228 int32_t backup; 6229 struct nfsrv_descript nfsd; 6230 struct nfsrv_descript *nd = &nfsd; 6231 struct nfssockreq *nrp; 6232 struct nfsvattr na; 6233 6234 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 6235 nd->nd_mrep = NULL; 6236 if (vers == 0 || vers == NFS_VER4) { 6237 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6238 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6239 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers); 6240 vers = NFS_VER4; 6241 if (flex != 0) 6242 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6243 else 6244 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6245 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6246 } else { 6247 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6248 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6249 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n"); 6250 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6251 } 6252 txdr_hyper(io_off, tl); 6253 tl += 2; 6254 if (vers == NFS_VER3) 6255 *tl++ = txdr_unsigned(len); 6256 *tl++ = txdr_unsigned(*iomode); 6257 *tl = txdr_unsigned(len); 6258 nfsm_uiombuf(nd, uiop, len); 6259 nrp = dsp->nfsclds_sockp; 6260 if (nrp == NULL) 6261 /* If NULL, use the MDS socket. */ 6262 nrp = &nmp->nm_sockreq; 6263 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6264 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6265 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error, 6266 nd->nd_repstat); 6267 if (error != 0) 6268 return (error); 6269 if (nd->nd_repstat != 0) { 6270 /* 6271 * In case the rpc gets retried, roll 6272 * the uio fileds changed by nfsm_uiombuf() 6273 * back. 6274 */ 6275 uiop->uio_offset -= len; 6276 uio_uio_resid_add(uiop, len); 6277 uio_iov_base_add(uiop, -len); 6278 uio_iov_len_add(uiop, len); 6279 error = nd->nd_repstat; 6280 } else { 6281 if (vers == NFS_VER3) { 6282 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6283 NULL); 6284 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error); 6285 if (error != 0) 6286 goto nfsmout; 6287 } 6288 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6289 rlen = fxdr_unsigned(int, *tl++); 6290 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen); 6291 if (rlen == 0) { 6292 error = NFSERR_IO; 6293 goto nfsmout; 6294 } else if (rlen < len) { 6295 backup = len - rlen; 6296 uio_iov_base_add(uiop, -(backup)); 6297 uio_iov_len_add(uiop, backup); 6298 uiop->uio_offset -= backup; 6299 uio_uio_resid_add(uiop, backup); 6300 len = rlen; 6301 } 6302 commit = fxdr_unsigned(int, *tl++); 6303 6304 /* 6305 * Return the lowest commitment level 6306 * obtained by any of the RPCs. 6307 */ 6308 if (committed == NFSWRITE_FILESYNC) 6309 committed = commit; 6310 else if (committed == NFSWRITE_DATASYNC && 6311 commit == NFSWRITE_UNSTABLE) 6312 committed = commit; 6313 if (commit_thru_mds != 0) { 6314 NFSLOCKMNT(nmp); 6315 if (!NFSHASWRITEVERF(nmp)) { 6316 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6317 NFSSETWRITEVERF(nmp); 6318 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 6319 *must_commit = 1; 6320 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6321 } 6322 NFSUNLOCKMNT(nmp); 6323 } else { 6324 NFSLOCKDS(dsp); 6325 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6326 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6327 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6328 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6329 *must_commit = 1; 6330 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6331 } 6332 NFSUNLOCKDS(dsp); 6333 } 6334 } 6335 nfsmout: 6336 if (nd->nd_mrep != NULL) 6337 mbuf_freem(nd->nd_mrep); 6338 *iomode = committed; 6339 if (nd->nd_repstat != 0 && error == 0) 6340 error = nd->nd_repstat; 6341 return (error); 6342 } 6343 6344 /* 6345 * The actual write RPC done to a DS. 6346 * This variant is called from a separate kernel process for mirrors. 6347 * Any short write is considered an IO error. 6348 */ 6349 static int 6350 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6351 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6352 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6353 struct ucred *cred, NFSPROC_T *p) 6354 { 6355 uint32_t *tl; 6356 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6357 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen; 6358 struct nfsrv_descript nfsd; 6359 struct nfsrv_descript *nd = &nfsd; 6360 struct nfssockreq *nrp; 6361 struct nfsvattr na; 6362 6363 nd->nd_mrep = NULL; 6364 if (vers == 0 || vers == NFS_VER4) { 6365 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6366 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6367 vers = NFS_VER4; 6368 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n", 6369 minorvers); 6370 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6371 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6372 } else { 6373 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6374 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6375 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n"); 6376 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6377 } 6378 txdr_hyper(io_off, tl); 6379 tl += 2; 6380 if (vers == NFS_VER3) 6381 *tl++ = txdr_unsigned(len); 6382 *tl++ = txdr_unsigned(*iomode); 6383 *tl = txdr_unsigned(len); 6384 if (len > 0) { 6385 /* Put data in mbuf chain. */ 6386 nd->nd_mb->m_next = m; 6387 /* Set nd_mb and nd_bpos to end of data. */ 6388 while (m->m_next != NULL) 6389 m = m->m_next; 6390 nd->nd_mb = m; 6391 nd->nd_bpos = mtod(m, char *) + m->m_len; 6392 NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len); 6393 } 6394 nrp = dsp->nfsclds_sockp; 6395 if (nrp == NULL) 6396 /* If NULL, use the MDS socket. */ 6397 nrp = &nmp->nm_sockreq; 6398 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6399 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6400 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error, 6401 nd->nd_repstat); 6402 if (error != 0) 6403 return (error); 6404 if (nd->nd_repstat != 0) 6405 error = nd->nd_repstat; 6406 else { 6407 if (vers == NFS_VER3) { 6408 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6409 NULL); 6410 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n", 6411 error); 6412 if (error != 0) 6413 goto nfsmout; 6414 } 6415 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6416 rlen = fxdr_unsigned(int, *tl++); 6417 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, 6418 rlen); 6419 if (rlen != len) { 6420 error = NFSERR_IO; 6421 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", 6422 len, rlen); 6423 goto nfsmout; 6424 } 6425 commit = fxdr_unsigned(int, *tl++); 6426 6427 /* 6428 * Return the lowest commitment level 6429 * obtained by any of the RPCs. 6430 */ 6431 if (committed == NFSWRITE_FILESYNC) 6432 committed = commit; 6433 else if (committed == NFSWRITE_DATASYNC && 6434 commit == NFSWRITE_UNSTABLE) 6435 committed = commit; 6436 NFSLOCKDS(dsp); 6437 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6438 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6439 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6440 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6441 *must_commit = 1; 6442 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6443 } 6444 NFSUNLOCKDS(dsp); 6445 } 6446 nfsmout: 6447 if (nd->nd_mrep != NULL) 6448 mbuf_freem(nd->nd_mrep); 6449 *iomode = committed; 6450 if (nd->nd_repstat != 0 && error == 0) 6451 error = nd->nd_repstat; 6452 return (error); 6453 } 6454 6455 /* 6456 * Start up the thread that will execute nfsrpc_writedsmir(). 6457 */ 6458 static void 6459 start_writedsmir(void *arg, int pending) 6460 { 6461 struct nfsclwritedsdorpc *drpc; 6462 6463 drpc = (struct nfsclwritedsdorpc *)arg; 6464 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode, 6465 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len, 6466 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred, 6467 drpc->p); 6468 drpc->done = 1; 6469 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err); 6470 } 6471 6472 /* 6473 * Set up the write DS mirror call for the pNFS I/O thread. 6474 */ 6475 static int 6476 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6477 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len, 6478 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6479 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6480 { 6481 int error, ret; 6482 6483 error = 0; 6484 drpc->done = 0; 6485 drpc->vp = vp; 6486 drpc->iomode = *iomode; 6487 drpc->must_commit = *must_commit; 6488 drpc->stateidp = stateidp; 6489 drpc->dsp = dsp; 6490 drpc->off = off; 6491 drpc->len = len; 6492 drpc->fhp = fhp; 6493 drpc->m = m; 6494 drpc->vers = vers; 6495 drpc->minorvers = minorvers; 6496 drpc->cred = cred; 6497 drpc->p = p; 6498 drpc->inprog = 0; 6499 ret = EIO; 6500 if (nfs_pnfsiothreads != 0) { 6501 ret = nfs_pnfsio(start_writedsmir, drpc); 6502 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret); 6503 } 6504 if (ret != 0) 6505 error = nfsrpc_writedsmir(vp, iomode, must_commit, stateidp, 6506 dsp, off, len, fhp, m, vers, minorvers, cred, p); 6507 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error); 6508 return (error); 6509 } 6510 6511 /* 6512 * Free up the nfsclds structure. 6513 */ 6514 void 6515 nfscl_freenfsclds(struct nfsclds *dsp) 6516 { 6517 int i; 6518 6519 if (dsp == NULL) 6520 return; 6521 if (dsp->nfsclds_sockp != NULL) { 6522 NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 6523 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 6524 free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 6525 free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 6526 } 6527 NFSFREEMUTEX(&dsp->nfsclds_mtx); 6528 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 6529 for (i = 0; i < NFSV4_CBSLOTS; i++) { 6530 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 6531 m_freem( 6532 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 6533 } 6534 free(dsp, M_NFSCLDS); 6535 } 6536 6537 static enum nfsclds_state 6538 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 6539 struct nfsclds **retdspp, uint32_t *sequencep) 6540 { 6541 struct nfsclds *dsp; 6542 int fndseq; 6543 6544 /* 6545 * Search the list of nfsclds structures for one with the same 6546 * server. 6547 */ 6548 fndseq = 0; 6549 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 6550 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 6551 dsp->nfsclds_servownlen != 0 && 6552 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 6553 dsp->nfsclds_servownlen) && 6554 dsp->nfsclds_sess.nfsess_defunct == 0) { 6555 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 6556 TAILQ_FIRST(&nmp->nm_sess), dsp, 6557 dsp->nfsclds_flags); 6558 if (fndseq == 0) { 6559 /* Get sequenceid# from first entry. */ 6560 *sequencep = 6561 dsp->nfsclds_sess.nfsess_sequenceid; 6562 fndseq = 1; 6563 } 6564 /* Server major id matches. */ 6565 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 6566 *retdspp = dsp; 6567 return (NFSDSP_USETHISSESSION); 6568 } 6569 6570 } 6571 } 6572 if (fndseq != 0) 6573 return (NFSDSP_SEQTHISSESSION); 6574 return (NFSDSP_NOTFOUND); 6575 } 6576 6577 /* 6578 * NFS commit rpc to a NFSv4.1 DS. 6579 */ 6580 static int 6581 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 6582 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, 6583 NFSPROC_T *p) 6584 { 6585 uint32_t *tl; 6586 struct nfsrv_descript nfsd, *nd = &nfsd; 6587 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6588 struct nfssockreq *nrp; 6589 struct nfsvattr na; 6590 int attrflag, error; 6591 6592 nd->nd_mrep = NULL; 6593 if (vers == 0 || vers == NFS_VER4) { 6594 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, 6595 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6596 vers = NFS_VER4; 6597 } else 6598 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh, 6599 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6600 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers, 6601 minorvers); 6602 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 6603 txdr_hyper(offset, tl); 6604 tl += 2; 6605 *tl = txdr_unsigned(cnt); 6606 nrp = dsp->nfsclds_sockp; 6607 if (nrp == NULL) 6608 /* If NULL, use the MDS socket. */ 6609 nrp = &nmp->nm_sockreq; 6610 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6611 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6612 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error, 6613 nd->nd_repstat); 6614 if (error != 0) 6615 return (error); 6616 if (nd->nd_repstat == 0) { 6617 if (vers == NFS_VER3) { 6618 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6619 NULL); 6620 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error); 6621 if (error != 0) 6622 goto nfsmout; 6623 } 6624 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 6625 NFSLOCKDS(dsp); 6626 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6627 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6628 error = NFSERR_STALEWRITEVERF; 6629 } 6630 NFSUNLOCKDS(dsp); 6631 } 6632 nfsmout: 6633 if (error == 0 && nd->nd_repstat != 0) 6634 error = nd->nd_repstat; 6635 mbuf_freem(nd->nd_mrep); 6636 return (error); 6637 } 6638 6639 /* 6640 * Start up the thread that will execute nfsrpc_commitds(). 6641 */ 6642 static void 6643 start_commitds(void *arg, int pending) 6644 { 6645 struct nfsclwritedsdorpc *drpc; 6646 6647 drpc = (struct nfsclwritedsdorpc *)arg; 6648 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len, 6649 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, 6650 drpc->p); 6651 drpc->done = 1; 6652 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err); 6653 } 6654 6655 /* 6656 * Set up the commit DS mirror call for the pNFS I/O thread. 6657 */ 6658 static int 6659 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 6660 struct nfsfh *fhp, int vers, int minorvers, 6661 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6662 { 6663 int error, ret; 6664 6665 error = 0; 6666 drpc->done = 0; 6667 drpc->vp = vp; 6668 drpc->off = offset; 6669 drpc->len = cnt; 6670 drpc->dsp = dsp; 6671 drpc->fhp = fhp; 6672 drpc->vers = vers; 6673 drpc->minorvers = minorvers; 6674 drpc->cred = cred; 6675 drpc->p = p; 6676 drpc->inprog = 0; 6677 ret = EIO; 6678 if (nfs_pnfsiothreads != 0) { 6679 ret = nfs_pnfsio(start_commitds, drpc); 6680 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret); 6681 } 6682 if (ret != 0) 6683 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers, 6684 minorvers, cred, p); 6685 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error); 6686 return (error); 6687 } 6688 6689 /* 6690 * Set up the XDR arguments for the LayoutGet operation. 6691 */ 6692 static void 6693 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, 6694 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype, 6695 int layoutlen, int usecurstateid) 6696 { 6697 uint32_t *tl; 6698 6699 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 6700 NFSX_STATEID); 6701 *tl++ = newnfs_false; /* Don't signal availability. */ 6702 *tl++ = txdr_unsigned(layouttype); 6703 *tl++ = txdr_unsigned(iomode); 6704 txdr_hyper(offset, tl); 6705 tl += 2; 6706 txdr_hyper(len, tl); 6707 tl += 2; 6708 txdr_hyper(minlen, tl); 6709 tl += 2; 6710 if (usecurstateid != 0) { 6711 /* Special stateid for Current stateid. */ 6712 *tl++ = txdr_unsigned(1); 6713 *tl++ = 0; 6714 *tl++ = 0; 6715 *tl++ = 0; 6716 } else { 6717 *tl++ = txdr_unsigned(stateidp->seqid); 6718 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 6719 *tl++ = stateidp->other[0]; 6720 *tl++ = stateidp->other[1]; 6721 *tl++ = stateidp->other[2]; 6722 } 6723 *tl = txdr_unsigned(layoutlen); 6724 } 6725 6726 /* 6727 * Parse the reply for a successful LayoutGet operation. 6728 */ 6729 static int 6730 nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, 6731 int *retonclosep, struct nfsclflayouthead *flhp) 6732 { 6733 uint32_t *tl; 6734 struct nfsclflayout *flp, *prevflp, *tflp; 6735 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen; 6736 int m, mirrorcnt; 6737 uint64_t retlen, off; 6738 struct nfsfh *nfhp; 6739 uint8_t *cp; 6740 uid_t user; 6741 gid_t grp; 6742 6743 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n"); 6744 error = 0; 6745 flp = NULL; 6746 gotiomode = -1; 6747 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 6748 if (*tl++ != 0) 6749 *retonclosep = 1; 6750 else 6751 *retonclosep = 0; 6752 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 6753 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 6754 (int)stateidp->seqid); 6755 stateidp->other[0] = *tl++; 6756 stateidp->other[1] = *tl++; 6757 stateidp->other[2] = *tl++; 6758 cnt = fxdr_unsigned(int, *tl); 6759 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 6760 if (cnt <= 0 || cnt > 10000) { 6761 /* Don't accept more than 10000 layouts in reply. */ 6762 error = NFSERR_BADXDR; 6763 goto nfsmout; 6764 } 6765 for (i = 0; i < cnt; i++) { 6766 /* Dissect to the layout type. */ 6767 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 6768 3 * NFSX_UNSIGNED); 6769 off = fxdr_hyper(tl); tl += 2; 6770 retlen = fxdr_hyper(tl); tl += 2; 6771 iomode = fxdr_unsigned(int, *tl++); 6772 laytype = fxdr_unsigned(int, *tl); 6773 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype, 6774 (uintmax_t)off, (uintmax_t)retlen, iomode); 6775 /* Ignore length of layout body for now. */ 6776 if (laytype == NFSLAYOUT_NFSV4_1_FILES) { 6777 /* Parse the File layout up to fhcnt. */ 6778 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + 6779 NFSX_HYPER + NFSX_V4DEVICEID); 6780 fhcnt = fxdr_unsigned(int, *(tl + 4 + 6781 NFSX_V4DEVICEID / NFSX_UNSIGNED)); 6782 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 6783 if (fhcnt < 0 || fhcnt > 100) { 6784 /* Don't accept more than 100 file handles. */ 6785 error = NFSERR_BADXDR; 6786 goto nfsmout; 6787 } 6788 if (fhcnt > 0) 6789 flp = malloc(sizeof(*flp) + fhcnt * 6790 sizeof(struct nfsfh *), M_NFSFLAYOUT, 6791 M_WAITOK); 6792 else 6793 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, 6794 M_WAITOK); 6795 flp->nfsfl_flags = NFSFL_FILE; 6796 flp->nfsfl_fhcnt = 0; 6797 flp->nfsfl_devp = NULL; 6798 flp->nfsfl_off = off; 6799 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 6800 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 6801 else 6802 flp->nfsfl_end = flp->nfsfl_off + retlen; 6803 flp->nfsfl_iomode = iomode; 6804 if (gotiomode == -1) 6805 gotiomode = flp->nfsfl_iomode; 6806 /* Ignore layout body length for now. */ 6807 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 6808 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 6809 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 6810 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 6811 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 6812 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 6813 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n", 6814 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff); 6815 for (j = 0; j < fhcnt; j++) { 6816 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6817 nfhlen = fxdr_unsigned(int, *tl); 6818 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 6819 error = NFSERR_BADXDR; 6820 goto nfsmout; 6821 } 6822 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, 6823 M_NFSFH, M_WAITOK); 6824 flp->nfsfl_fh[j] = nfhp; 6825 flp->nfsfl_fhcnt++; 6826 nfhp->nfh_len = nfhlen; 6827 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 6828 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 6829 } 6830 } else if (laytype == NFSLAYOUT_FLEXFILE) { 6831 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 6832 NFSX_HYPER); 6833 mirrorcnt = fxdr_unsigned(int, *(tl + 2)); 6834 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt); 6835 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) { 6836 error = NFSERR_BADXDR; 6837 goto nfsmout; 6838 } 6839 flp = malloc(sizeof(*flp) + mirrorcnt * 6840 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK); 6841 flp->nfsfl_flags = NFSFL_FLEXFILE; 6842 flp->nfsfl_mirrorcnt = mirrorcnt; 6843 for (j = 0; j < mirrorcnt; j++) 6844 flp->nfsfl_ffm[j].devp = NULL; 6845 flp->nfsfl_off = off; 6846 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 6847 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 6848 else 6849 flp->nfsfl_end = flp->nfsfl_off + retlen; 6850 flp->nfsfl_iomode = iomode; 6851 if (gotiomode == -1) 6852 gotiomode = flp->nfsfl_iomode; 6853 flp->nfsfl_stripeunit = fxdr_hyper(tl); 6854 NFSCL_DEBUG(4, "stripeunit=%ju\n", 6855 (uintmax_t)flp->nfsfl_stripeunit); 6856 for (j = 0; j < mirrorcnt; j++) { 6857 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6858 k = fxdr_unsigned(int, *tl); 6859 if (k < 1 || k > 128) { 6860 error = NFSERR_BADXDR; 6861 goto nfsmout; 6862 } 6863 NFSCL_DEBUG(4, "servercnt=%d\n", k); 6864 for (l = 0; l < k; l++) { 6865 NFSM_DISSECT(tl, uint32_t *, 6866 NFSX_V4DEVICEID + NFSX_STATEID + 6867 2 * NFSX_UNSIGNED); 6868 if (l == 0) { 6869 /* Just use the first server. */ 6870 NFSBCOPY(tl, 6871 flp->nfsfl_ffm[j].dev, 6872 NFSX_V4DEVICEID); 6873 tl += (NFSX_V4DEVICEID / 6874 NFSX_UNSIGNED); 6875 tl++; 6876 flp->nfsfl_ffm[j].st.seqid = 6877 *tl++; 6878 flp->nfsfl_ffm[j].st.other[0] = 6879 *tl++; 6880 flp->nfsfl_ffm[j].st.other[1] = 6881 *tl++; 6882 flp->nfsfl_ffm[j].st.other[2] = 6883 *tl++; 6884 NFSCL_DEBUG(4, "st.seqid=%u " 6885 "st.o0=0x%x st.o1=0x%x " 6886 "st.o2=0x%x\n", 6887 flp->nfsfl_ffm[j].st.seqid, 6888 flp->nfsfl_ffm[j].st.other[0], 6889 flp->nfsfl_ffm[j].st.other[1], 6890 flp->nfsfl_ffm[j].st.other[2]); 6891 } else 6892 tl += ((NFSX_V4DEVICEID + 6893 NFSX_STATEID + 6894 NFSX_UNSIGNED) / 6895 NFSX_UNSIGNED); 6896 fhcnt = fxdr_unsigned(int, *tl); 6897 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 6898 if (fhcnt < 1 || 6899 fhcnt > NFSDEV_MAXVERS) { 6900 error = NFSERR_BADXDR; 6901 goto nfsmout; 6902 } 6903 for (m = 0; m < fhcnt; m++) { 6904 NFSM_DISSECT(tl, uint32_t *, 6905 NFSX_UNSIGNED); 6906 nfhlen = fxdr_unsigned(int, 6907 *tl); 6908 NFSCL_DEBUG(4, "nfhlen=%d\n", 6909 nfhlen); 6910 if (nfhlen <= 0 || nfhlen > 6911 NFSX_V4FHMAX) { 6912 error = NFSERR_BADXDR; 6913 goto nfsmout; 6914 } 6915 NFSM_DISSECT(cp, uint8_t *, 6916 NFSM_RNDUP(nfhlen)); 6917 if (l == 0) { 6918 flp->nfsfl_ffm[j].fhcnt 6919 = fhcnt; 6920 nfhp = malloc( 6921 sizeof(*nfhp) + 6922 nfhlen - 1, M_NFSFH, 6923 M_WAITOK); 6924 flp->nfsfl_ffm[j].fh[m] 6925 = nfhp; 6926 nfhp->nfh_len = nfhlen; 6927 NFSBCOPY(cp, 6928 nfhp->nfh_fh, 6929 nfhlen); 6930 NFSCL_DEBUG(4, 6931 "got fh\n"); 6932 } 6933 } 6934 /* Now, get the ffsd_user/ffds_group. */ 6935 error = nfsrv_parseug(nd, 0, &user, 6936 &grp, curthread); 6937 NFSCL_DEBUG(4, "after parseu=%d\n", 6938 error); 6939 if (error == 0) 6940 error = nfsrv_parseug(nd, 1, 6941 &user, &grp, curthread); 6942 NFSCL_DEBUG(4, "aft parseg=%d\n", 6943 grp); 6944 if (error != 0) 6945 goto nfsmout; 6946 NFSCL_DEBUG(4, "user=%d group=%d\n", 6947 user, grp); 6948 if (l == 0) { 6949 flp->nfsfl_ffm[j].user = user; 6950 flp->nfsfl_ffm[j].group = grp; 6951 NFSCL_DEBUG(4, 6952 "usr=%d grp=%d\n", user, 6953 grp); 6954 } 6955 } 6956 } 6957 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6958 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++); 6959 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl); 6960 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n", 6961 flp->nfsfl_fflags, flp->nfsfl_statshint); 6962 } else { 6963 error = NFSERR_BADXDR; 6964 goto nfsmout; 6965 } 6966 if (flp->nfsfl_iomode == gotiomode) { 6967 /* Keep the list in increasing offset order. */ 6968 tflp = LIST_FIRST(flhp); 6969 prevflp = NULL; 6970 while (tflp != NULL && 6971 tflp->nfsfl_off < flp->nfsfl_off) { 6972 prevflp = tflp; 6973 tflp = LIST_NEXT(tflp, nfsfl_list); 6974 } 6975 if (prevflp == NULL) 6976 LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 6977 else 6978 LIST_INSERT_AFTER(prevflp, flp, 6979 nfsfl_list); 6980 NFSCL_DEBUG(4, "flp inserted\n"); 6981 } else { 6982 printf("nfscl_layoutget(): got wrong iomode\n"); 6983 nfscl_freeflayout(flp); 6984 } 6985 flp = NULL; 6986 } 6987 nfsmout: 6988 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error); 6989 if (error != 0 && flp != NULL) 6990 nfscl_freeflayout(flp); 6991 return (error); 6992 } 6993 6994 /* 6995 * Parse a user/group digit string. 6996 */ 6997 static int 6998 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp, 6999 NFSPROC_T *p) 7000 { 7001 uint32_t *tl; 7002 char *cp, *str, str0[NFSV4_SMALLSTR + 1]; 7003 uint32_t len = 0; 7004 int error = 0; 7005 7006 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7007 len = fxdr_unsigned(uint32_t, *tl); 7008 str = NULL; 7009 if (len > NFSV4_OPAQUELIMIT) { 7010 error = NFSERR_BADXDR; 7011 goto nfsmout; 7012 } 7013 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len); 7014 if (len == 0) { 7015 if (dogrp != 0) 7016 *gidp = GID_NOGROUP; 7017 else 7018 *uidp = UID_NOBODY; 7019 return (0); 7020 } 7021 if (len > NFSV4_SMALLSTR) 7022 str = malloc(len + 1, M_TEMP, M_WAITOK); 7023 else 7024 str = str0; 7025 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len)); 7026 NFSBCOPY(cp, str, len); 7027 str[len] = '\0'; 7028 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str); 7029 if (dogrp != 0) 7030 error = nfsv4_strtogid(nd, str, len, gidp); 7031 else 7032 error = nfsv4_strtouid(nd, str, len, uidp); 7033 nfsmout: 7034 if (len > NFSV4_SMALLSTR) 7035 free(str, M_TEMP); 7036 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error); 7037 return (error); 7038 } 7039 7040 /* 7041 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), 7042 * so that it does both an Open and a Layoutget. 7043 */ 7044 static int 7045 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7046 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7047 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7048 struct ucred *cred, NFSPROC_T *p) 7049 { 7050 struct nfscllayout *lyp; 7051 struct nfsclflayout *flp; 7052 struct nfsclflayouthead flh; 7053 int error, islocked, layoutlen, recalled, retonclose, usecurstateid; 7054 int layouttype, laystat; 7055 nfsv4stateid_t stateid; 7056 struct nfsclsession *tsep; 7057 7058 error = 0; 7059 if (NFSHASFLEXFILE(nmp)) 7060 layouttype = NFSLAYOUT_FLEXFILE; 7061 else 7062 layouttype = NFSLAYOUT_NFSV4_1_FILES; 7063 /* 7064 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 7065 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 7066 * flp == NULL. 7067 */ 7068 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp, 7069 &recalled); 7070 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); 7071 if (lyp == NULL) 7072 islocked = 0; 7073 else if (flp != NULL) 7074 islocked = 1; 7075 else 7076 islocked = 2; 7077 if ((lyp == NULL || flp == NULL) && recalled == 0) { 7078 LIST_INIT(&flh); 7079 tsep = nfsmnt_mdssession(nmp); 7080 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 7081 3 * NFSX_UNSIGNED); 7082 if (lyp == NULL) 7083 usecurstateid = 1; 7084 else { 7085 usecurstateid = 0; 7086 stateid.seqid = lyp->nfsly_stateid.seqid; 7087 stateid.other[0] = lyp->nfsly_stateid.other[0]; 7088 stateid.other[1] = lyp->nfsly_stateid.other[1]; 7089 stateid.other[2] = lyp->nfsly_stateid.other[2]; 7090 } 7091 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, 7092 newfhp, newfhlen, mode, op, name, namelen, 7093 dpp, &stateid, usecurstateid, layouttype, layoutlen, 7094 &retonclose, &flh, &laystat, cred, p); 7095 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", 7096 laystat, error); 7097 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, 7098 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, 7099 &islocked, cred, p); 7100 } else 7101 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, 7102 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); 7103 if (islocked == 2) 7104 nfscl_rellayout(lyp, 1); 7105 else if (islocked == 1) 7106 nfscl_rellayout(lyp, 0); 7107 return (error); 7108 } 7109 7110 /* 7111 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS 7112 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are 7113 * handled by nfsrpc_openrpc(). 7114 * For the case where op == NULL, dvp is the directory. When op != NULL, it 7115 * can be NULL. 7116 */ 7117 static int 7118 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7119 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7120 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7121 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, 7122 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, 7123 int *laystatp, struct ucred *cred, NFSPROC_T *p) 7124 { 7125 uint32_t *tl; 7126 struct nfsrv_descript nfsd, *nd = &nfsd; 7127 struct nfscldeleg *ndp = NULL; 7128 struct nfsvattr nfsva; 7129 struct nfsclsession *tsep; 7130 uint32_t rflags, deleg; 7131 nfsattrbit_t attrbits; 7132 int error, ret, acesize, limitby, iomode; 7133 7134 *dpp = NULL; 7135 *laystatp = ENXIO; 7136 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL, 7137 0, 0); 7138 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 7139 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 7140 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 7141 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 7142 tsep = nfsmnt_mdssession(nmp); 7143 *tl++ = tsep->nfsess_clientid.lval[0]; 7144 *tl = tsep->nfsess_clientid.lval[1]; 7145 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 7146 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7147 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 7148 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 7149 nfsm_strtom(nd, name, namelen); 7150 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7151 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7152 NFSZERO_ATTRBIT(&attrbits); 7153 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 7154 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 7155 nfsrv_putattrbit(nd, &attrbits); 7156 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7157 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 7158 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) 7159 iomode = NFSLAYOUTIOMODE_RW; 7160 else 7161 iomode = NFSLAYOUTIOMODE_READ; 7162 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, 7163 layouttype, layoutlen, usecurstateid); 7164 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 7165 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 7166 if (error != 0) 7167 return (error); 7168 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 7169 if (nd->nd_repstat != 0) 7170 *laystatp = nd->nd_repstat; 7171 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7172 /* ND_NOMOREDATA will be set if the Open operation failed. */ 7173 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7174 6 * NFSX_UNSIGNED); 7175 op->nfso_stateid.seqid = *tl++; 7176 op->nfso_stateid.other[0] = *tl++; 7177 op->nfso_stateid.other[1] = *tl++; 7178 op->nfso_stateid.other[2] = *tl; 7179 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 7180 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 7181 if (error != 0) 7182 goto nfsmout; 7183 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 7184 deleg = fxdr_unsigned(u_int32_t, *tl); 7185 if (deleg == NFSV4OPEN_DELEGATEREAD || 7186 deleg == NFSV4OPEN_DELEGATEWRITE) { 7187 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 7188 NFSCLFLAGS_FIRSTDELEG)) 7189 op->nfso_own->nfsow_clp->nfsc_flags |= 7190 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 7191 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, 7192 M_NFSCLDELEG, M_WAITOK); 7193 LIST_INIT(&ndp->nfsdl_owner); 7194 LIST_INIT(&ndp->nfsdl_lock); 7195 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 7196 ndp->nfsdl_fhlen = newfhlen; 7197 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 7198 newnfs_copyincred(cred, &ndp->nfsdl_cred); 7199 nfscl_lockinit(&ndp->nfsdl_rwlock); 7200 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7201 NFSX_UNSIGNED); 7202 ndp->nfsdl_stateid.seqid = *tl++; 7203 ndp->nfsdl_stateid.other[0] = *tl++; 7204 ndp->nfsdl_stateid.other[1] = *tl++; 7205 ndp->nfsdl_stateid.other[2] = *tl++; 7206 ret = fxdr_unsigned(int, *tl); 7207 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 7208 ndp->nfsdl_flags = NFSCLDL_WRITE; 7209 /* 7210 * Indicates how much the file can grow. 7211 */ 7212 NFSM_DISSECT(tl, u_int32_t *, 7213 3 * NFSX_UNSIGNED); 7214 limitby = fxdr_unsigned(int, *tl++); 7215 switch (limitby) { 7216 case NFSV4OPEN_LIMITSIZE: 7217 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 7218 break; 7219 case NFSV4OPEN_LIMITBLOCKS: 7220 ndp->nfsdl_sizelimit = 7221 fxdr_unsigned(u_int64_t, *tl++); 7222 ndp->nfsdl_sizelimit *= 7223 fxdr_unsigned(u_int64_t, *tl); 7224 break; 7225 default: 7226 error = NFSERR_BADXDR; 7227 goto nfsmout; 7228 }; 7229 } else 7230 ndp->nfsdl_flags = NFSCLDL_READ; 7231 if (ret != 0) 7232 ndp->nfsdl_flags |= NFSCLDL_RECALL; 7233 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 7234 &acesize, p); 7235 if (error != 0) 7236 goto nfsmout; 7237 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 7238 error = NFSERR_BADXDR; 7239 goto nfsmout; 7240 } 7241 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || 7242 nfscl_assumeposixlocks) 7243 op->nfso_posixlock = 1; 7244 else 7245 op->nfso_posixlock = 0; 7246 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7247 /* If the 2nd element == NFS_OK, the Getattr succeeded. */ 7248 if (*++tl == 0) { 7249 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 7250 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 7251 NULL, NULL, NULL, p, cred); 7252 if (error != 0) 7253 goto nfsmout; 7254 if (ndp != NULL) { 7255 ndp->nfsdl_change = nfsva.na_filerev; 7256 ndp->nfsdl_modtime = nfsva.na_mtime; 7257 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 7258 *dpp = ndp; 7259 ndp = NULL; 7260 } 7261 /* 7262 * At this point, the Open has succeeded, so set 7263 * nd_repstat = NFS_OK. If the Layoutget failed, 7264 * this function just won't return a layout. 7265 */ 7266 if (nd->nd_repstat == 0) { 7267 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7268 *laystatp = fxdr_unsigned(int, *++tl); 7269 if (*laystatp == 0) { 7270 error = nfsrv_parselayoutget(nd, 7271 stateidp, retonclosep, flhp); 7272 if (error != 0) 7273 *laystatp = error; 7274 } 7275 } else 7276 nd->nd_repstat = 0; /* Return 0 for Open. */ 7277 } 7278 } 7279 if (nd->nd_repstat != 0 && error == 0) 7280 error = nd->nd_repstat; 7281 nfsmout: 7282 free(ndp, M_NFSCLDELEG); 7283 mbuf_freem(nd->nd_mrep); 7284 return (error); 7285 } 7286 7287 /* 7288 * Similar nfsrpc_createv4(), but also does the LayoutGet operation. 7289 * Used only for mounts with pNFS enabled. 7290 */ 7291 static int 7292 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 7293 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 7294 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 7295 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 7296 int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp, 7297 int usecurstateid, int layouttype, int layoutlen, int *retonclosep, 7298 struct nfsclflayouthead *flhp, int *laystatp) 7299 { 7300 uint32_t *tl; 7301 int error = 0, deleg, newone, ret, acesize, limitby; 7302 struct nfsrv_descript nfsd, *nd = &nfsd; 7303 struct nfsclopen *op; 7304 struct nfscldeleg *dp = NULL; 7305 struct nfsnode *np; 7306 struct nfsfh *nfhp; 7307 struct nfsclsession *tsep; 7308 nfsattrbit_t attrbits; 7309 nfsv4stateid_t stateid; 7310 struct nfsmount *nmp; 7311 7312 nmp = VFSTONFS(dvp->v_mount); 7313 np = VTONFS(dvp); 7314 *laystatp = ENXIO; 7315 *unlockedp = 0; 7316 *nfhpp = NULL; 7317 *dpp = NULL; 7318 *attrflagp = 0; 7319 *dattrflagp = 0; 7320 if (namelen > NFS_MAXNAMLEN) 7321 return (ENAMETOOLONG); 7322 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp); 7323 /* 7324 * For V4, this is actually an Open op. 7325 */ 7326 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 7327 *tl++ = txdr_unsigned(owp->nfsow_seqid); 7328 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 7329 NFSV4OPEN_ACCESSREAD); 7330 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 7331 tsep = nfsmnt_mdssession(nmp); 7332 *tl++ = tsep->nfsess_clientid.lval[0]; 7333 *tl = tsep->nfsess_clientid.lval[1]; 7334 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 7335 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7336 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 7337 if ((fmode & O_EXCL) != 0) { 7338 if (NFSHASSESSPERSIST(nmp)) { 7339 /* Use GUARDED for persistent sessions. */ 7340 *tl = txdr_unsigned(NFSCREATE_GUARDED); 7341 nfscl_fillsattr(nd, vap, dvp, 0, 0); 7342 } else { 7343 /* Otherwise, use EXCLUSIVE4_1. */ 7344 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 7345 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 7346 *tl++ = cverf.lval[0]; 7347 *tl = cverf.lval[1]; 7348 nfscl_fillsattr(nd, vap, dvp, 0, 0); 7349 } 7350 } else { 7351 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 7352 nfscl_fillsattr(nd, vap, dvp, 0, 0); 7353 } 7354 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7355 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 7356 nfsm_strtom(nd, name, namelen); 7357 /* Get the new file's handle and attributes, plus save the FH. */ 7358 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 7359 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); 7360 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 7361 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7362 NFSGETATTR_ATTRBIT(&attrbits); 7363 nfsrv_putattrbit(nd, &attrbits); 7364 /* Get the directory's post-op attributes. */ 7365 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7366 *tl = txdr_unsigned(NFSV4OP_PUTFH); 7367 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 7368 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7369 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7370 nfsrv_putattrbit(nd, &attrbits); 7371 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7372 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); 7373 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 7374 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, 7375 layouttype, layoutlen, usecurstateid); 7376 error = nfscl_request(nd, dvp, p, cred, dstuff); 7377 if (error != 0) 7378 return (error); 7379 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, 7380 error); 7381 if (nd->nd_repstat != 0) 7382 *laystatp = nd->nd_repstat; 7383 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 7384 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7385 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); 7386 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7387 6 * NFSX_UNSIGNED); 7388 stateid.seqid = *tl++; 7389 stateid.other[0] = *tl++; 7390 stateid.other[1] = *tl++; 7391 stateid.other[2] = *tl; 7392 nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 7393 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 7394 deleg = fxdr_unsigned(int, *tl); 7395 if (deleg == NFSV4OPEN_DELEGATEREAD || 7396 deleg == NFSV4OPEN_DELEGATEWRITE) { 7397 if (!(owp->nfsow_clp->nfsc_flags & 7398 NFSCLFLAGS_FIRSTDELEG)) 7399 owp->nfsow_clp->nfsc_flags |= 7400 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 7401 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, 7402 M_NFSCLDELEG, M_WAITOK); 7403 LIST_INIT(&dp->nfsdl_owner); 7404 LIST_INIT(&dp->nfsdl_lock); 7405 dp->nfsdl_clp = owp->nfsow_clp; 7406 newnfs_copyincred(cred, &dp->nfsdl_cred); 7407 nfscl_lockinit(&dp->nfsdl_rwlock); 7408 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7409 NFSX_UNSIGNED); 7410 dp->nfsdl_stateid.seqid = *tl++; 7411 dp->nfsdl_stateid.other[0] = *tl++; 7412 dp->nfsdl_stateid.other[1] = *tl++; 7413 dp->nfsdl_stateid.other[2] = *tl++; 7414 ret = fxdr_unsigned(int, *tl); 7415 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 7416 dp->nfsdl_flags = NFSCLDL_WRITE; 7417 /* 7418 * Indicates how much the file can grow. 7419 */ 7420 NFSM_DISSECT(tl, u_int32_t *, 7421 3 * NFSX_UNSIGNED); 7422 limitby = fxdr_unsigned(int, *tl++); 7423 switch (limitby) { 7424 case NFSV4OPEN_LIMITSIZE: 7425 dp->nfsdl_sizelimit = fxdr_hyper(tl); 7426 break; 7427 case NFSV4OPEN_LIMITBLOCKS: 7428 dp->nfsdl_sizelimit = 7429 fxdr_unsigned(u_int64_t, *tl++); 7430 dp->nfsdl_sizelimit *= 7431 fxdr_unsigned(u_int64_t, *tl); 7432 break; 7433 default: 7434 error = NFSERR_BADXDR; 7435 goto nfsmout; 7436 }; 7437 } else { 7438 dp->nfsdl_flags = NFSCLDL_READ; 7439 } 7440 if (ret != 0) 7441 dp->nfsdl_flags |= NFSCLDL_RECALL; 7442 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 7443 &acesize, p); 7444 if (error != 0) 7445 goto nfsmout; 7446 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 7447 error = NFSERR_BADXDR; 7448 goto nfsmout; 7449 } 7450 7451 /* Now, we should have the status for the SaveFH. */ 7452 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7453 if (*++tl == 0) { 7454 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); 7455 /* 7456 * Now, process the GetFH and Getattr for the newly 7457 * created file. nfscl_mtofh() will set 7458 * ND_NOMOREDATA if these weren't successful. 7459 */ 7460 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 7461 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); 7462 if (error != 0) 7463 goto nfsmout; 7464 } else 7465 nd->nd_flag |= ND_NOMOREDATA; 7466 /* Now we have the PutFH and Getattr for the directory. */ 7467 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7468 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7469 if (*++tl != 0) 7470 nd->nd_flag |= ND_NOMOREDATA; 7471 else { 7472 NFSM_DISSECT(tl, uint32_t *, 2 * 7473 NFSX_UNSIGNED); 7474 if (*++tl != 0) 7475 nd->nd_flag |= ND_NOMOREDATA; 7476 } 7477 } 7478 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7479 /* Load the directory attributes. */ 7480 error = nfsm_loadattr(nd, dnap); 7481 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); 7482 if (error != 0) 7483 goto nfsmout; 7484 *dattrflagp = 1; 7485 if (dp != NULL && *attrflagp != 0) { 7486 dp->nfsdl_change = nnap->na_filerev; 7487 dp->nfsdl_modtime = nnap->na_mtime; 7488 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 7489 } 7490 /* 7491 * We can now complete the Open state. 7492 */ 7493 nfhp = *nfhpp; 7494 if (dp != NULL) { 7495 dp->nfsdl_fhlen = nfhp->nfh_len; 7496 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, 7497 nfhp->nfh_len); 7498 } 7499 /* 7500 * Get an Open structure that will be 7501 * attached to the OpenOwner, acquired already. 7502 */ 7503 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 7504 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 7505 cred, p, NULL, &op, &newone, NULL, 0); 7506 if (error != 0) 7507 goto nfsmout; 7508 op->nfso_stateid = stateid; 7509 newnfs_copyincred(cred, &op->nfso_cred); 7510 7511 nfscl_openrelease(nmp, op, error, newone); 7512 *unlockedp = 1; 7513 7514 /* Now, handle the RestoreFH and LayoutGet. */ 7515 if (nd->nd_repstat == 0) { 7516 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 7517 *laystatp = fxdr_unsigned(int, *(tl + 3)); 7518 if (*laystatp == 0) { 7519 error = nfsrv_parselayoutget(nd, 7520 stateidp, retonclosep, flhp); 7521 if (error != 0) 7522 *laystatp = error; 7523 } 7524 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", 7525 error); 7526 } else 7527 nd->nd_repstat = 0; 7528 } 7529 } 7530 if (nd->nd_repstat != 0 && error == 0) 7531 error = nd->nd_repstat; 7532 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) 7533 nfscl_initiate_recovery(owp->nfsow_clp); 7534 nfsmout: 7535 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); 7536 if (error == 0) 7537 *dpp = dp; 7538 else 7539 free(dp, M_NFSCLDELEG); 7540 mbuf_freem(nd->nd_mrep); 7541 return (error); 7542 } 7543 7544 /* 7545 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. 7546 */ 7547 static int 7548 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 7549 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 7550 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 7551 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 7552 int *dattrflagp, void *dstuff, int *unlockedp) 7553 { 7554 struct nfscllayout *lyp; 7555 struct nfsclflayouthead flh; 7556 struct nfsfh *nfhp; 7557 struct nfsclsession *tsep; 7558 struct nfsmount *nmp; 7559 nfsv4stateid_t stateid; 7560 int error, layoutlen, layouttype, retonclose, laystat; 7561 7562 error = 0; 7563 nmp = VFSTONFS(dvp->v_mount); 7564 if (NFSHASFLEXFILE(nmp)) 7565 layouttype = NFSLAYOUT_FLEXFILE; 7566 else 7567 layouttype = NFSLAYOUT_NFSV4_1_FILES; 7568 LIST_INIT(&flh); 7569 tsep = nfsmnt_mdssession(nmp); 7570 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); 7571 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, 7572 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 7573 dstuff, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose, 7574 &flh, &laystat); 7575 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", 7576 laystat, error); 7577 lyp = NULL; 7578 if (laystat == 0) { 7579 nfhp = *nfhpp; 7580 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, 7581 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, 7582 layouttype, laystat, NULL, cred, p); 7583 } else 7584 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, 7585 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, 7586 cred, p); 7587 if (laystat == 0) 7588 nfscl_rellayout(lyp, 0); 7589 return (error); 7590 } 7591 7592 /* 7593 * Process the results of a layoutget() operation. 7594 */ 7595 static int 7596 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, 7597 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, 7598 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype, 7599 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) 7600 { 7601 struct nfsclflayout *tflp; 7602 struct nfscldevinfo *dip; 7603 uint8_t *dev; 7604 int i, mirrorcnt; 7605 7606 if (laystat == NFSERR_UNKNLAYOUTTYPE) { 7607 NFSLOCKMNT(nmp); 7608 if (!NFSHASFLEXFILE(nmp)) { 7609 /* Switch to using Flex File Layout. */ 7610 nmp->nm_state |= NFSSTA_FLEXFILE; 7611 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 7612 /* Disable pNFS. */ 7613 NFSCL_DEBUG(1, "disable PNFS\n"); 7614 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE); 7615 } 7616 NFSUNLOCKMNT(nmp); 7617 } 7618 if (laystat == 0) { 7619 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); 7620 LIST_FOREACH(tflp, flhp, nfsfl_list) { 7621 if (layouttype == NFSLAYOUT_FLEXFILE) 7622 mirrorcnt = tflp->nfsfl_mirrorcnt; 7623 else 7624 mirrorcnt = 1; 7625 for (i = 0; i < mirrorcnt; i++) { 7626 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp); 7627 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); 7628 if (laystat != 0) { 7629 if (layouttype == NFSLAYOUT_FLEXFILE) 7630 dev = tflp->nfsfl_ffm[i].dev; 7631 else 7632 dev = tflp->nfsfl_dev; 7633 laystat = nfsrpc_getdeviceinfo(nmp, dev, 7634 layouttype, notifybit, &dip, cred, 7635 p); 7636 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", 7637 laystat); 7638 if (laystat != 0) 7639 goto out; 7640 laystat = nfscl_adddevinfo(nmp, dip, i, 7641 tflp); 7642 if (laystat != 0) 7643 printf("nfsrpc_layoutgetresout" 7644 ": cannot add\n"); 7645 } 7646 } 7647 } 7648 } 7649 out: 7650 if (laystat == 0) { 7651 /* 7652 * nfscl_layout() always returns with the nfsly_lock 7653 * set to a refcnt (shared lock). 7654 * Passing in dvp is sufficient, since it is only used to 7655 * get the fsid for the file system. 7656 */ 7657 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, 7658 layouttype, retonclose, flhp, lypp, cred, p); 7659 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", 7660 laystat); 7661 if (laystat == 0 && islockedp != NULL) 7662 *islockedp = 1; 7663 } 7664 return (laystat); 7665 } 7666 7667