1 /*- 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Rick Macklem at The University of Guelph. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 4. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 /* 38 * Rpc op calls, generally called from the vnode op calls or through the 39 * buffer cache, for NFS v2, 3 and 4. 40 * These do not normally make any changes to vnode arguments or use 41 * structures that might change between the VFS variants. The returned 42 * arguments are all at the end, after the NFSPROC_T *p one. 43 */ 44 45 #ifndef APPLEKEXT 46 #include "opt_inet6.h" 47 48 #include <fs/nfs/nfsport.h> 49 #include <sys/sysctl.h> 50 51 SYSCTL_DECL(_vfs_nfs); 52 53 static int nfsignore_eexist = 0; 54 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW, 55 &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink"); 56 57 /* 58 * Global variables 59 */ 60 extern int nfs_numnfscbd; 61 extern struct timeval nfsboottime; 62 extern u_int32_t newnfs_false, newnfs_true; 63 extern nfstype nfsv34_type[9]; 64 extern int nfsrv_useacl; 65 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 66 extern int nfscl_debuglevel; 67 NFSCLSTATEMUTEX; 68 int nfstest_outofseq = 0; 69 int nfscl_assumeposixlocks = 1; 70 int nfscl_enablecallb = 0; 71 short nfsv4_cbport = NFSV4_CBPORT; 72 int nfstest_openallsetattr = 0; 73 #endif /* !APPLEKEXT */ 74 75 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 76 77 /* 78 * nfscl_getsameserver() can return one of three values: 79 * NFSDSP_USETHISSESSION - Use this session for the DS. 80 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new 81 * session. 82 * NFSDSP_NOTFOUND - No matching server was found. 83 */ 84 enum nfsclds_state { 85 NFSDSP_USETHISSESSION = 0, 86 NFSDSP_SEQTHISSESSION = 1, 87 NFSDSP_NOTFOUND = 2, 88 }; 89 90 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, 91 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); 92 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, 93 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *); 94 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, 95 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, 96 void *); 97 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, 98 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, 99 struct nfsvattr *, struct nfsfh **, int *, int *, void *); 100 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, 101 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, 102 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, 103 int *, void *, int *); 104 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, 105 struct nfscllockowner *, u_int64_t, u_int64_t, 106 u_int32_t, struct ucred *, NFSPROC_T *, int); 107 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, 108 struct acl *, nfsv4stateid_t *, void *); 109 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int, 110 uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **, 111 struct ucred *, NFSPROC_T *); 112 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_storage *, 113 struct nfsclds **, NFSPROC_T *); 114 static void nfscl_initsessionslots(struct nfsclsession *); 115 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *, 116 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, 117 struct nfsclflayout *, uint64_t, uint64_t, struct ucred *, NFSPROC_T *); 118 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *, 119 struct nfsclds *, uint64_t, int, struct nfsfh *, struct ucred *, 120 NFSPROC_T *); 121 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *, 122 nfsv4stateid_t *, struct nfsclds *, uint64_t, int, 123 struct nfsfh *, int, struct ucred *, NFSPROC_T *); 124 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *, 125 struct nfsclds *, struct nfsclds **); 126 #ifdef notyet 127 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, 128 struct nfsfh *, struct ucred *, NFSPROC_T *, void *); 129 #endif 130 131 /* 132 * nfs null call from vfs. 133 */ 134 APPLESTATIC int 135 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) 136 { 137 int error; 138 struct nfsrv_descript nfsd, *nd = &nfsd; 139 140 NFSCL_REQSTART(nd, NFSPROC_NULL, vp); 141 error = nfscl_request(nd, vp, p, cred, NULL); 142 if (nd->nd_repstat && !error) 143 error = nd->nd_repstat; 144 mbuf_freem(nd->nd_mrep); 145 return (error); 146 } 147 148 /* 149 * nfs access rpc op. 150 * For nfs version 3 and 4, use the access rpc to check accessibility. If file 151 * modes are changed on the server, accesses might still fail later. 152 */ 153 APPLESTATIC int 154 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, 155 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 156 { 157 int error; 158 u_int32_t mode, rmode; 159 160 if (acmode & VREAD) 161 mode = NFSACCESS_READ; 162 else 163 mode = 0; 164 if (vnode_vtype(vp) == VDIR) { 165 if (acmode & VWRITE) 166 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | 167 NFSACCESS_DELETE); 168 if (acmode & VEXEC) 169 mode |= NFSACCESS_LOOKUP; 170 } else { 171 if (acmode & VWRITE) 172 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 173 if (acmode & VEXEC) 174 mode |= NFSACCESS_EXECUTE; 175 } 176 177 /* 178 * Now, just call nfsrpc_accessrpc() to do the actual RPC. 179 */ 180 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode, 181 NULL); 182 183 /* 184 * The NFS V3 spec does not clarify whether or not 185 * the returned access bits can be a superset of 186 * the ones requested, so... 187 */ 188 if (!error && (rmode & mode) != mode) 189 error = EACCES; 190 return (error); 191 } 192 193 /* 194 * The actual rpc, separated out for Darwin. 195 */ 196 APPLESTATIC int 197 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, 198 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep, 199 void *stuff) 200 { 201 u_int32_t *tl; 202 u_int32_t supported, rmode; 203 int error; 204 struct nfsrv_descript nfsd, *nd = &nfsd; 205 nfsattrbit_t attrbits; 206 207 *attrflagp = 0; 208 supported = mode; 209 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp); 210 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 211 *tl = txdr_unsigned(mode); 212 if (nd->nd_flag & ND_NFSV4) { 213 /* 214 * And do a Getattr op. 215 */ 216 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 217 *tl = txdr_unsigned(NFSV4OP_GETATTR); 218 NFSGETATTR_ATTRBIT(&attrbits); 219 (void) nfsrv_putattrbit(nd, &attrbits); 220 } 221 error = nfscl_request(nd, vp, p, cred, stuff); 222 if (error) 223 return (error); 224 if (nd->nd_flag & ND_NFSV3) { 225 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 226 if (error) 227 goto nfsmout; 228 } 229 if (!nd->nd_repstat) { 230 if (nd->nd_flag & ND_NFSV4) { 231 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 232 supported = fxdr_unsigned(u_int32_t, *tl++); 233 } else { 234 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 235 } 236 rmode = fxdr_unsigned(u_int32_t, *tl); 237 if (nd->nd_flag & ND_NFSV4) 238 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 239 240 /* 241 * It's not obvious what should be done about 242 * unsupported access modes. For now, be paranoid 243 * and clear the unsupported ones. 244 */ 245 rmode &= supported; 246 *rmodep = rmode; 247 } else 248 error = nd->nd_repstat; 249 nfsmout: 250 mbuf_freem(nd->nd_mrep); 251 return (error); 252 } 253 254 /* 255 * nfs open rpc 256 */ 257 APPLESTATIC int 258 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) 259 { 260 struct nfsclopen *op; 261 struct nfscldeleg *dp; 262 struct nfsfh *nfhp; 263 struct nfsnode *np = VTONFS(vp); 264 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 265 u_int32_t mode, clidrev; 266 int ret, newone, error, expireret = 0, retrycnt; 267 268 /* 269 * For NFSv4, Open Ops are only done on Regular Files. 270 */ 271 if (vnode_vtype(vp) != VREG) 272 return (0); 273 mode = 0; 274 if (amode & FREAD) 275 mode |= NFSV4OPEN_ACCESSREAD; 276 if (amode & FWRITE) 277 mode |= NFSV4OPEN_ACCESSWRITE; 278 nfhp = np->n_fhp; 279 280 retrycnt = 0; 281 #ifdef notdef 282 { char name[100]; int namel; 283 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99; 284 bcopy(NFS4NODENAME(np->n_v4), name, namel); 285 name[namel] = '\0'; 286 printf("rpcopen p=0x%x name=%s",p->p_pid,name); 287 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]); 288 else printf(" fhl=0\n"); 289 } 290 #endif 291 do { 292 dp = NULL; 293 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, 294 cred, p, NULL, &op, &newone, &ret, 1); 295 if (error) { 296 return (error); 297 } 298 if (nmp->nm_clp != NULL) 299 clidrev = nmp->nm_clp->nfsc_clientidrev; 300 else 301 clidrev = 0; 302 if (ret == NFSCLOPEN_DOOPEN) { 303 if (np->n_v4 != NULL) { 304 error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data, 305 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 306 np->n_fhp->nfh_len, mode, op, 307 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, 308 0, 0x0, cred, p, 0, 0); 309 if (dp != NULL) { 310 #ifdef APPLE 311 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); 312 #else 313 NFSLOCKNODE(np); 314 np->n_flag &= ~NDELEGMOD; 315 /* 316 * Invalidate the attribute cache, so that 317 * attributes that pre-date the issue of a 318 * delegation are not cached, since the 319 * cached attributes will remain valid while 320 * the delegation is held. 321 */ 322 NFSINVALATTRCACHE(np); 323 NFSUNLOCKNODE(np); 324 #endif 325 (void) nfscl_deleg(nmp->nm_mountp, 326 op->nfso_own->nfsow_clp, 327 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); 328 } 329 } else { 330 error = EIO; 331 } 332 newnfs_copyincred(cred, &op->nfso_cred); 333 } else if (ret == NFSCLOPEN_SETCRED) 334 /* 335 * This is a new local open on a delegation. It needs 336 * to have credentials so that an open can be done 337 * against the server during recovery. 338 */ 339 newnfs_copyincred(cred, &op->nfso_cred); 340 341 /* 342 * nfso_opencnt is the count of how many VOP_OPEN()s have 343 * been done on this Open successfully and a VOP_CLOSE() 344 * is expected for each of these. 345 * If error is non-zero, don't increment it, since the Open 346 * hasn't succeeded yet. 347 */ 348 if (!error) 349 op->nfso_opencnt++; 350 nfscl_openrelease(op, error, newone); 351 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 352 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 353 error == NFSERR_BADSESSION) { 354 (void) nfs_catnap(PZERO, error, "nfs_open"); 355 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 356 && clidrev != 0) { 357 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 358 retrycnt++; 359 } 360 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 361 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 362 error == NFSERR_BADSESSION || 363 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 364 expireret == 0 && clidrev != 0 && retrycnt < 4)); 365 if (error && retrycnt >= 4) 366 error = EIO; 367 return (error); 368 } 369 370 /* 371 * the actual open rpc 372 */ 373 APPLESTATIC int 374 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, 375 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 376 u_int8_t *name, int namelen, struct nfscldeleg **dpp, 377 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, 378 int syscred, int recursed) 379 { 380 u_int32_t *tl; 381 struct nfsrv_descript nfsd, *nd = &nfsd; 382 struct nfscldeleg *dp, *ndp = NULL; 383 struct nfsvattr nfsva; 384 u_int32_t rflags, deleg; 385 nfsattrbit_t attrbits; 386 int error, ret, acesize, limitby; 387 388 dp = *dpp; 389 *dpp = NULL; 390 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL); 391 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 392 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 393 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 394 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 395 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 396 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 397 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 398 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 399 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 400 if (reclaim) { 401 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); 402 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 403 *tl = txdr_unsigned(delegtype); 404 } else { 405 if (dp != NULL) { 406 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); 407 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 408 if (NFSHASNFSV4N(nmp)) 409 *tl++ = 0; 410 else 411 *tl++ = dp->nfsdl_stateid.seqid; 412 *tl++ = dp->nfsdl_stateid.other[0]; 413 *tl++ = dp->nfsdl_stateid.other[1]; 414 *tl = dp->nfsdl_stateid.other[2]; 415 } else { 416 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 417 } 418 (void) nfsm_strtom(nd, name, namelen); 419 } 420 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 421 *tl = txdr_unsigned(NFSV4OP_GETATTR); 422 NFSZERO_ATTRBIT(&attrbits); 423 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 424 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 425 (void) nfsrv_putattrbit(nd, &attrbits); 426 if (syscred) 427 nd->nd_flag |= ND_USEGSSNAME; 428 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 429 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 430 if (error) 431 return (error); 432 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 433 if (!nd->nd_repstat) { 434 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 435 6 * NFSX_UNSIGNED); 436 op->nfso_stateid.seqid = *tl++; 437 op->nfso_stateid.other[0] = *tl++; 438 op->nfso_stateid.other[1] = *tl++; 439 op->nfso_stateid.other[2] = *tl; 440 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 441 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 442 if (error) 443 goto nfsmout; 444 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 445 deleg = fxdr_unsigned(u_int32_t, *tl); 446 if (deleg == NFSV4OPEN_DELEGATEREAD || 447 deleg == NFSV4OPEN_DELEGATEWRITE) { 448 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 449 NFSCLFLAGS_FIRSTDELEG)) 450 op->nfso_own->nfsow_clp->nfsc_flags |= 451 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 452 MALLOC(ndp, struct nfscldeleg *, 453 sizeof (struct nfscldeleg) + newfhlen, 454 M_NFSCLDELEG, M_WAITOK); 455 LIST_INIT(&ndp->nfsdl_owner); 456 LIST_INIT(&ndp->nfsdl_lock); 457 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 458 ndp->nfsdl_fhlen = newfhlen; 459 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 460 newnfs_copyincred(cred, &ndp->nfsdl_cred); 461 nfscl_lockinit(&ndp->nfsdl_rwlock); 462 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 463 NFSX_UNSIGNED); 464 ndp->nfsdl_stateid.seqid = *tl++; 465 ndp->nfsdl_stateid.other[0] = *tl++; 466 ndp->nfsdl_stateid.other[1] = *tl++; 467 ndp->nfsdl_stateid.other[2] = *tl++; 468 ret = fxdr_unsigned(int, *tl); 469 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 470 ndp->nfsdl_flags = NFSCLDL_WRITE; 471 /* 472 * Indicates how much the file can grow. 473 */ 474 NFSM_DISSECT(tl, u_int32_t *, 475 3 * NFSX_UNSIGNED); 476 limitby = fxdr_unsigned(int, *tl++); 477 switch (limitby) { 478 case NFSV4OPEN_LIMITSIZE: 479 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 480 break; 481 case NFSV4OPEN_LIMITBLOCKS: 482 ndp->nfsdl_sizelimit = 483 fxdr_unsigned(u_int64_t, *tl++); 484 ndp->nfsdl_sizelimit *= 485 fxdr_unsigned(u_int64_t, *tl); 486 break; 487 default: 488 error = NFSERR_BADXDR; 489 goto nfsmout; 490 }; 491 } else { 492 ndp->nfsdl_flags = NFSCLDL_READ; 493 } 494 if (ret) 495 ndp->nfsdl_flags |= NFSCLDL_RECALL; 496 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 497 &acesize, p); 498 if (error) 499 goto nfsmout; 500 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 501 error = NFSERR_BADXDR; 502 goto nfsmout; 503 } 504 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 505 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 506 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 507 NULL, NULL, NULL, p, cred); 508 if (error) 509 goto nfsmout; 510 if (ndp != NULL) { 511 ndp->nfsdl_change = nfsva.na_filerev; 512 ndp->nfsdl_modtime = nfsva.na_mtime; 513 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 514 } 515 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { 516 do { 517 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, 518 cred, p); 519 if (ret == NFSERR_DELAY) 520 (void) nfs_catnap(PZERO, ret, "nfs_open"); 521 } while (ret == NFSERR_DELAY); 522 error = ret; 523 } 524 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || 525 nfscl_assumeposixlocks) 526 op->nfso_posixlock = 1; 527 else 528 op->nfso_posixlock = 0; 529 530 /* 531 * If the server is handing out delegations, but we didn't 532 * get one because an OpenConfirm was required, try the 533 * Open again, to get a delegation. This is a harmless no-op, 534 * from a server's point of view. 535 */ 536 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && 537 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) 538 && !error && dp == NULL && ndp == NULL && !recursed) { 539 do { 540 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, 541 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, 542 cred, p, syscred, 1); 543 if (ret == NFSERR_DELAY) 544 (void) nfs_catnap(PZERO, ret, "nfs_open2"); 545 } while (ret == NFSERR_DELAY); 546 if (ret) { 547 if (ndp != NULL) { 548 FREE((caddr_t)ndp, M_NFSCLDELEG); 549 ndp = NULL; 550 } 551 if (ret == NFSERR_STALECLIENTID || 552 ret == NFSERR_STALEDONTRECOVER || 553 ret == NFSERR_BADSESSION) 554 error = ret; 555 } 556 } 557 } 558 if (nd->nd_repstat != 0 && error == 0) 559 error = nd->nd_repstat; 560 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) 561 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 562 nfsmout: 563 if (!error) 564 *dpp = ndp; 565 else if (ndp != NULL) 566 FREE((caddr_t)ndp, M_NFSCLDELEG); 567 mbuf_freem(nd->nd_mrep); 568 return (error); 569 } 570 571 /* 572 * open downgrade rpc 573 */ 574 APPLESTATIC int 575 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, 576 struct ucred *cred, NFSPROC_T *p) 577 { 578 u_int32_t *tl; 579 struct nfsrv_descript nfsd, *nd = &nfsd; 580 int error; 581 582 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp); 583 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 584 if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp)))) 585 *tl++ = 0; 586 else 587 *tl++ = op->nfso_stateid.seqid; 588 *tl++ = op->nfso_stateid.other[0]; 589 *tl++ = op->nfso_stateid.other[1]; 590 *tl++ = op->nfso_stateid.other[2]; 591 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 592 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 593 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 594 error = nfscl_request(nd, vp, p, cred, NULL); 595 if (error) 596 return (error); 597 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 598 if (!nd->nd_repstat) { 599 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 600 op->nfso_stateid.seqid = *tl++; 601 op->nfso_stateid.other[0] = *tl++; 602 op->nfso_stateid.other[1] = *tl++; 603 op->nfso_stateid.other[2] = *tl; 604 } 605 if (nd->nd_repstat && error == 0) 606 error = nd->nd_repstat; 607 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) 608 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 609 nfsmout: 610 mbuf_freem(nd->nd_mrep); 611 return (error); 612 } 613 614 /* 615 * V4 Close operation. 616 */ 617 APPLESTATIC int 618 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) 619 { 620 struct nfsclclient *clp; 621 int error; 622 623 if (vnode_vtype(vp) != VREG) 624 return (0); 625 if (doclose) 626 error = nfscl_doclose(vp, &clp, p); 627 else 628 error = nfscl_getclose(vp, &clp); 629 if (error) 630 return (error); 631 632 nfscl_clientrelease(clp); 633 return (0); 634 } 635 636 /* 637 * Close the open. 638 */ 639 APPLESTATIC void 640 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p) 641 { 642 struct nfsrv_descript nfsd, *nd = &nfsd; 643 struct nfscllockowner *lp, *nlp; 644 struct nfscllock *lop, *nlop; 645 struct ucred *tcred; 646 u_int64_t off = 0, len = 0; 647 u_int32_t type = NFSV4LOCKT_READ; 648 int error, do_unlock, trycnt; 649 650 tcred = newnfs_getcred(); 651 newnfs_copycred(&op->nfso_cred, tcred); 652 /* 653 * (Theoretically this could be done in the same 654 * compound as the close, but having multiple 655 * sequenced Ops in the same compound might be 656 * too scary for some servers.) 657 */ 658 if (op->nfso_posixlock) { 659 off = 0; 660 len = NFS64BITSSET; 661 type = NFSV4LOCKT_READ; 662 } 663 664 /* 665 * Since this function is only called from VOP_INACTIVE(), no 666 * other thread will be manipulating this Open. As such, the 667 * lock lists are not being changed by other threads, so it should 668 * be safe to do this without locking. 669 */ 670 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 671 do_unlock = 1; 672 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 673 if (op->nfso_posixlock == 0) { 674 off = lop->nfslo_first; 675 len = lop->nfslo_end - lop->nfslo_first; 676 if (lop->nfslo_type == F_WRLCK) 677 type = NFSV4LOCKT_WRITE; 678 else 679 type = NFSV4LOCKT_READ; 680 } 681 if (do_unlock) { 682 trycnt = 0; 683 do { 684 error = nfsrpc_locku(nd, nmp, lp, off, 685 len, type, tcred, p, 0); 686 if ((nd->nd_repstat == NFSERR_GRACE || 687 nd->nd_repstat == NFSERR_DELAY) && 688 error == 0) 689 (void) nfs_catnap(PZERO, 690 (int)nd->nd_repstat, 691 "nfs_close"); 692 } while ((nd->nd_repstat == NFSERR_GRACE || 693 nd->nd_repstat == NFSERR_DELAY) && 694 error == 0 && trycnt++ < 5); 695 if (op->nfso_posixlock) 696 do_unlock = 0; 697 } 698 nfscl_freelock(lop, 0); 699 } 700 /* 701 * Do a ReleaseLockOwner. 702 * The lock owner name nfsl_owner may be used by other opens for 703 * other files but the lock_owner4 name that nfsrpc_rellockown() 704 * puts on the wire has the file handle for this file appended 705 * to it, so it can be done now. 706 */ 707 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh, 708 lp->nfsl_open->nfso_fhlen, tcred, p); 709 } 710 711 /* 712 * There could be other Opens for different files on the same 713 * OpenOwner, so locking is required. 714 */ 715 NFSLOCKCLSTATE(); 716 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 717 NFSUNLOCKCLSTATE(); 718 do { 719 error = nfscl_tryclose(op, tcred, nmp, p); 720 if (error == NFSERR_GRACE) 721 (void) nfs_catnap(PZERO, error, "nfs_close"); 722 } while (error == NFSERR_GRACE); 723 NFSLOCKCLSTATE(); 724 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); 725 726 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) 727 nfscl_freelockowner(lp, 0); 728 nfscl_freeopen(op, 0); 729 NFSUNLOCKCLSTATE(); 730 NFSFREECRED(tcred); 731 } 732 733 /* 734 * The actual Close RPC. 735 */ 736 APPLESTATIC int 737 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp, 738 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p, 739 int syscred) 740 { 741 u_int32_t *tl; 742 int error; 743 744 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh, 745 op->nfso_fhlen, NULL, NULL); 746 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 747 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 748 if (NFSHASNFSV4N(nmp)) 749 *tl++ = 0; 750 else 751 *tl++ = op->nfso_stateid.seqid; 752 *tl++ = op->nfso_stateid.other[0]; 753 *tl++ = op->nfso_stateid.other[1]; 754 *tl = op->nfso_stateid.other[2]; 755 if (syscred) 756 nd->nd_flag |= ND_USEGSSNAME; 757 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 758 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 759 if (error) 760 return (error); 761 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 762 if (nd->nd_repstat == 0) 763 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 764 error = nd->nd_repstat; 765 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) 766 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 767 nfsmout: 768 mbuf_freem(nd->nd_mrep); 769 return (error); 770 } 771 772 /* 773 * V4 Open Confirm RPC. 774 */ 775 APPLESTATIC int 776 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen, 777 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) 778 { 779 u_int32_t *tl; 780 struct nfsrv_descript nfsd, *nd = &nfsd; 781 struct nfsmount *nmp; 782 int error; 783 784 nmp = VFSTONFS(vnode_mount(vp)); 785 if (NFSHASNFSV4N(nmp)) 786 return (0); /* No confirmation for NFSv4.1. */ 787 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL); 788 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 789 *tl++ = op->nfso_stateid.seqid; 790 *tl++ = op->nfso_stateid.other[0]; 791 *tl++ = op->nfso_stateid.other[1]; 792 *tl++ = op->nfso_stateid.other[2]; 793 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid); 794 error = nfscl_request(nd, vp, p, cred, NULL); 795 if (error) 796 return (error); 797 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 798 if (!nd->nd_repstat) { 799 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 800 op->nfso_stateid.seqid = *tl++; 801 op->nfso_stateid.other[0] = *tl++; 802 op->nfso_stateid.other[1] = *tl++; 803 op->nfso_stateid.other[2] = *tl; 804 } 805 error = nd->nd_repstat; 806 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) 807 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 808 nfsmout: 809 mbuf_freem(nd->nd_mrep); 810 return (error); 811 } 812 813 /* 814 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs() 815 * when a mount has just occurred and when the server replies NFSERR_EXPIRED. 816 */ 817 APPLESTATIC int 818 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim, 819 struct ucred *cred, NFSPROC_T *p) 820 { 821 u_int32_t *tl; 822 struct nfsrv_descript nfsd; 823 struct nfsrv_descript *nd = &nfsd; 824 nfsattrbit_t attrbits; 825 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9]; 826 u_short port; 827 int error, isinet6 = 0, callblen; 828 nfsquad_t confirm; 829 u_int32_t lease; 830 static u_int32_t rev = 0; 831 struct nfsclds *dsp, *ndsp, *tdsp; 832 struct in6_addr a6; 833 834 if (nfsboottime.tv_sec == 0) 835 NFSSETBOOTTIME(nfsboottime); 836 clp->nfsc_rev = rev++; 837 if (NFSHASNFSV4N(nmp)) { 838 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 839 NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p); 840 NFSCL_DEBUG(1, "aft exch=%d\n", error); 841 if (error == 0) { 842 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 843 &nmp->nm_sockreq, 844 dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p); 845 if (error == 0) { 846 NFSLOCKMNT(nmp); 847 TAILQ_FOREACH_SAFE(tdsp, &nmp->nm_sess, 848 nfsclds_list, ndsp) 849 nfscl_freenfsclds(tdsp); 850 TAILQ_INIT(&nmp->nm_sess); 851 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, 852 nfsclds_list); 853 NFSUNLOCKMNT(nmp); 854 } else 855 nfscl_freenfsclds(dsp); 856 NFSCL_DEBUG(1, "aft createsess=%d\n", error); 857 } 858 if (error == 0 && reclaim == 0) { 859 error = nfsrpc_reclaimcomplete(nmp, cred, p); 860 NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error); 861 if (error == NFSERR_COMPLETEALREADY || 862 error == NFSERR_NOTSUPP) 863 /* Ignore this error. */ 864 error = 0; 865 } 866 return (error); 867 } 868 869 /* 870 * Allocate a single session structure for NFSv4.0, because some of 871 * the fields are used by NFSv4.0 although it doesn't do a session. 872 */ 873 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO); 874 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 875 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); 876 NFSLOCKMNT(nmp); 877 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list); 878 NFSUNLOCKMNT(nmp); 879 880 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL); 881 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 882 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 883 *tl = txdr_unsigned(clp->nfsc_rev); 884 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 885 886 /* 887 * set up the callback address 888 */ 889 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 890 *tl = txdr_unsigned(NFS_CALLBCKPROG); 891 callblen = strlen(nfsv4_callbackaddr); 892 if (callblen == 0) 893 cp = nfscl_getmyip(nmp, &a6, &isinet6); 894 if (nfscl_enablecallb && nfs_numnfscbd > 0 && 895 (callblen > 0 || cp != NULL)) { 896 port = htons(nfsv4_cbport); 897 cp2 = (u_int8_t *)&port; 898 #ifdef INET6 899 if ((callblen > 0 && 900 strchr(nfsv4_callbackaddr, ':')) || isinet6) { 901 char ip6buf[INET6_ADDRSTRLEN], *ip6add; 902 903 (void) nfsm_strtom(nd, "tcp6", 4); 904 if (callblen == 0) { 905 ip6_sprintf(ip6buf, (struct in6_addr *)cp); 906 ip6add = ip6buf; 907 } else { 908 ip6add = nfsv4_callbackaddr; 909 } 910 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", 911 ip6add, cp2[0], cp2[1]); 912 } else 913 #endif 914 { 915 (void) nfsm_strtom(nd, "tcp", 3); 916 if (callblen == 0) 917 snprintf(addr, INET6_ADDRSTRLEN + 9, 918 "%d.%d.%d.%d.%d.%d", cp[0], cp[1], 919 cp[2], cp[3], cp2[0], cp2[1]); 920 else 921 snprintf(addr, INET6_ADDRSTRLEN + 9, 922 "%s.%d.%d", nfsv4_callbackaddr, 923 cp2[0], cp2[1]); 924 } 925 (void) nfsm_strtom(nd, addr, strlen(addr)); 926 } else { 927 (void) nfsm_strtom(nd, "tcp", 3); 928 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11); 929 } 930 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 931 *tl = txdr_unsigned(clp->nfsc_cbident); 932 nd->nd_flag |= ND_USEGSSNAME; 933 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 934 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 935 if (error) 936 return (error); 937 if (nd->nd_repstat == 0) { 938 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 939 NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0] = *tl++; 940 NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1] = *tl++; 941 confirm.lval[0] = *tl++; 942 confirm.lval[1] = *tl; 943 mbuf_freem(nd->nd_mrep); 944 nd->nd_mrep = NULL; 945 946 /* 947 * and confirm it. 948 */ 949 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL, 950 NULL); 951 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 952 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 953 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 954 *tl++ = confirm.lval[0]; 955 *tl = confirm.lval[1]; 956 nd->nd_flag |= ND_USEGSSNAME; 957 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 958 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 959 if (error) 960 return (error); 961 mbuf_freem(nd->nd_mrep); 962 nd->nd_mrep = NULL; 963 if (nd->nd_repstat == 0) { 964 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh, 965 nmp->nm_fhsize, NULL, NULL); 966 NFSZERO_ATTRBIT(&attrbits); 967 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 968 (void) nfsrv_putattrbit(nd, &attrbits); 969 nd->nd_flag |= ND_USEGSSNAME; 970 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 971 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 972 if (error) 973 return (error); 974 if (nd->nd_repstat == 0) { 975 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL, 976 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred); 977 if (error) 978 goto nfsmout; 979 clp->nfsc_renew = NFSCL_RENEW(lease); 980 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 981 clp->nfsc_clientidrev++; 982 if (clp->nfsc_clientidrev == 0) 983 clp->nfsc_clientidrev++; 984 } 985 } 986 } 987 error = nd->nd_repstat; 988 nfsmout: 989 mbuf_freem(nd->nd_mrep); 990 return (error); 991 } 992 993 /* 994 * nfs getattr call. 995 */ 996 APPLESTATIC int 997 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 998 struct nfsvattr *nap, void *stuff) 999 { 1000 struct nfsrv_descript nfsd, *nd = &nfsd; 1001 int error; 1002 nfsattrbit_t attrbits; 1003 1004 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 1005 if (nd->nd_flag & ND_NFSV4) { 1006 NFSGETATTR_ATTRBIT(&attrbits); 1007 (void) nfsrv_putattrbit(nd, &attrbits); 1008 } 1009 error = nfscl_request(nd, vp, p, cred, stuff); 1010 if (error) 1011 return (error); 1012 if (!nd->nd_repstat) 1013 error = nfsm_loadattr(nd, nap); 1014 else 1015 error = nd->nd_repstat; 1016 mbuf_freem(nd->nd_mrep); 1017 return (error); 1018 } 1019 1020 /* 1021 * nfs getattr call with non-vnode arguemnts. 1022 */ 1023 APPLESTATIC int 1024 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, 1025 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp, 1026 uint32_t *leasep) 1027 { 1028 struct nfsrv_descript nfsd, *nd = &nfsd; 1029 int error, vers = NFS_VER2; 1030 nfsattrbit_t attrbits; 1031 1032 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL); 1033 if (nd->nd_flag & ND_NFSV4) { 1034 vers = NFS_VER4; 1035 NFSGETATTR_ATTRBIT(&attrbits); 1036 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 1037 (void) nfsrv_putattrbit(nd, &attrbits); 1038 } else if (nd->nd_flag & ND_NFSV3) { 1039 vers = NFS_VER3; 1040 } 1041 if (syscred) 1042 nd->nd_flag |= ND_USEGSSNAME; 1043 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 1044 NFS_PROG, vers, NULL, 1, xidp, NULL); 1045 if (error) 1046 return (error); 1047 if (nd->nd_repstat == 0) { 1048 if ((nd->nd_flag & ND_NFSV4) != 0) 1049 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 1050 NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL, 1051 NULL, NULL); 1052 else 1053 error = nfsm_loadattr(nd, nap); 1054 } else 1055 error = nd->nd_repstat; 1056 mbuf_freem(nd->nd_mrep); 1057 return (error); 1058 } 1059 1060 /* 1061 * Do an nfs setattr operation. 1062 */ 1063 APPLESTATIC int 1064 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, 1065 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp, 1066 void *stuff) 1067 { 1068 int error, expireret = 0, openerr, retrycnt; 1069 u_int32_t clidrev = 0, mode; 1070 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1071 struct nfsfh *nfhp; 1072 nfsv4stateid_t stateid; 1073 void *lckp; 1074 1075 if (nmp->nm_clp != NULL) 1076 clidrev = nmp->nm_clp->nfsc_clientidrev; 1077 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size)) 1078 mode = NFSV4OPEN_ACCESSWRITE; 1079 else 1080 mode = NFSV4OPEN_ACCESSREAD; 1081 retrycnt = 0; 1082 do { 1083 lckp = NULL; 1084 openerr = 1; 1085 if (NFSHASNFSV4(nmp)) { 1086 nfhp = VTONFS(vp)->n_fhp; 1087 error = nfscl_getstateid(vp, nfhp->nfh_fh, 1088 nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp); 1089 if (error && vnode_vtype(vp) == VREG && 1090 (mode == NFSV4OPEN_ACCESSWRITE || 1091 nfstest_openallsetattr)) { 1092 /* 1093 * No Open stateid, so try and open the file 1094 * now. 1095 */ 1096 if (mode == NFSV4OPEN_ACCESSWRITE) 1097 openerr = nfsrpc_open(vp, FWRITE, cred, 1098 p); 1099 else 1100 openerr = nfsrpc_open(vp, FREAD, cred, 1101 p); 1102 if (!openerr) 1103 (void) nfscl_getstateid(vp, 1104 nfhp->nfh_fh, nfhp->nfh_len, 1105 mode, 0, cred, p, &stateid, &lckp); 1106 } 1107 } 1108 if (vap != NULL) 1109 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p, 1110 rnap, attrflagp, stuff); 1111 else 1112 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid, 1113 stuff); 1114 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) 1115 nfscl_initiate_recovery(nmp->nm_clp); 1116 if (lckp != NULL) 1117 nfscl_lockderef(lckp); 1118 if (!openerr) 1119 (void) nfsrpc_close(vp, 0, p); 1120 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1121 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1122 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1123 (void) nfs_catnap(PZERO, error, "nfs_setattr"); 1124 } else if ((error == NFSERR_EXPIRED || 1125 error == NFSERR_BADSTATEID) && clidrev != 0) { 1126 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1127 } 1128 retrycnt++; 1129 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1130 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1131 error == NFSERR_BADSESSION || 1132 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1133 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1134 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1135 if (error && retrycnt >= 4) 1136 error = EIO; 1137 return (error); 1138 } 1139 1140 static int 1141 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, 1142 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 1143 struct nfsvattr *rnap, int *attrflagp, void *stuff) 1144 { 1145 u_int32_t *tl; 1146 struct nfsrv_descript nfsd, *nd = &nfsd; 1147 int error; 1148 nfsattrbit_t attrbits; 1149 1150 *attrflagp = 0; 1151 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp); 1152 if (nd->nd_flag & ND_NFSV4) 1153 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1154 vap->va_type = vnode_vtype(vp); 1155 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0); 1156 if (nd->nd_flag & ND_NFSV3) { 1157 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1158 *tl = newnfs_false; 1159 } else if (nd->nd_flag & ND_NFSV4) { 1160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1161 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1162 NFSGETATTR_ATTRBIT(&attrbits); 1163 (void) nfsrv_putattrbit(nd, &attrbits); 1164 } 1165 error = nfscl_request(nd, vp, p, cred, stuff); 1166 if (error) 1167 return (error); 1168 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1169 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff); 1170 if ((nd->nd_flag & ND_NFSV4) && !error) 1171 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1172 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error) 1173 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff); 1174 mbuf_freem(nd->nd_mrep); 1175 if (nd->nd_repstat && !error) 1176 error = nd->nd_repstat; 1177 return (error); 1178 } 1179 1180 /* 1181 * nfs lookup rpc 1182 */ 1183 APPLESTATIC int 1184 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, 1185 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, 1186 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff) 1187 { 1188 u_int32_t *tl; 1189 struct nfsrv_descript nfsd, *nd = &nfsd; 1190 struct nfsmount *nmp; 1191 struct nfsnode *np; 1192 struct nfsfh *nfhp; 1193 nfsattrbit_t attrbits; 1194 int error = 0, lookupp = 0; 1195 1196 *attrflagp = 0; 1197 *dattrflagp = 0; 1198 if (vnode_vtype(dvp) != VDIR) 1199 return (ENOTDIR); 1200 nmp = VFSTONFS(vnode_mount(dvp)); 1201 if (len > NFS_MAXNAMLEN) 1202 return (ENAMETOOLONG); 1203 if (NFSHASNFSV4(nmp) && len == 1 && 1204 name[0] == '.') { 1205 /* 1206 * Just return the current dir's fh. 1207 */ 1208 np = VTONFS(dvp); 1209 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1210 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1211 nfhp->nfh_len = np->n_fhp->nfh_len; 1212 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1213 *nfhpp = nfhp; 1214 return (0); 1215 } 1216 if (NFSHASNFSV4(nmp) && len == 2 && 1217 name[0] == '.' && name[1] == '.') { 1218 lookupp = 1; 1219 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp); 1220 } else { 1221 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp); 1222 (void) nfsm_strtom(nd, name, len); 1223 } 1224 if (nd->nd_flag & ND_NFSV4) { 1225 NFSGETATTR_ATTRBIT(&attrbits); 1226 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1227 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1228 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1229 (void) nfsrv_putattrbit(nd, &attrbits); 1230 } 1231 error = nfscl_request(nd, dvp, p, cred, stuff); 1232 if (error) 1233 return (error); 1234 if (nd->nd_repstat) { 1235 /* 1236 * When an NFSv4 Lookupp returns ENOENT, it means that 1237 * the lookup is at the root of an fs, so return this dir. 1238 */ 1239 if (nd->nd_repstat == NFSERR_NOENT && lookupp) { 1240 np = VTONFS(dvp); 1241 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1242 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1243 nfhp->nfh_len = np->n_fhp->nfh_len; 1244 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1245 *nfhpp = nfhp; 1246 mbuf_freem(nd->nd_mrep); 1247 return (0); 1248 } 1249 if (nd->nd_flag & ND_NFSV3) 1250 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1251 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 1252 ND_NFSV4) { 1253 /* Load the directory attributes. */ 1254 error = nfsm_loadattr(nd, dnap); 1255 if (error == 0) 1256 *dattrflagp = 1; 1257 } 1258 goto nfsmout; 1259 } 1260 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 1261 /* Load the directory attributes. */ 1262 error = nfsm_loadattr(nd, dnap); 1263 if (error != 0) 1264 goto nfsmout; 1265 *dattrflagp = 1; 1266 /* Skip over the Lookup and GetFH operation status values. */ 1267 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1268 } 1269 error = nfsm_getfh(nd, nfhpp); 1270 if (error) 1271 goto nfsmout; 1272 1273 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1274 if ((nd->nd_flag & ND_NFSV3) && !error) 1275 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1276 nfsmout: 1277 mbuf_freem(nd->nd_mrep); 1278 if (!error && nd->nd_repstat) 1279 error = nd->nd_repstat; 1280 return (error); 1281 } 1282 1283 /* 1284 * Do a readlink rpc. 1285 */ 1286 APPLESTATIC int 1287 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, 1288 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1289 { 1290 u_int32_t *tl; 1291 struct nfsrv_descript nfsd, *nd = &nfsd; 1292 struct nfsnode *np = VTONFS(vp); 1293 nfsattrbit_t attrbits; 1294 int error, len, cangetattr = 1; 1295 1296 *attrflagp = 0; 1297 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp); 1298 if (nd->nd_flag & ND_NFSV4) { 1299 /* 1300 * And do a Getattr op. 1301 */ 1302 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1303 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1304 NFSGETATTR_ATTRBIT(&attrbits); 1305 (void) nfsrv_putattrbit(nd, &attrbits); 1306 } 1307 error = nfscl_request(nd, vp, p, cred, stuff); 1308 if (error) 1309 return (error); 1310 if (nd->nd_flag & ND_NFSV3) 1311 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1312 if (!nd->nd_repstat && !error) { 1313 NFSM_STRSIZ(len, NFS_MAXPATHLEN); 1314 /* 1315 * This seems weird to me, but must have been added to 1316 * FreeBSD for some reason. The only thing I can think of 1317 * is that there was/is some server that replies with 1318 * more link data than it should? 1319 */ 1320 if (len == NFS_MAXPATHLEN) { 1321 NFSLOCKNODE(np); 1322 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { 1323 len = np->n_size; 1324 cangetattr = 0; 1325 } 1326 NFSUNLOCKNODE(np); 1327 } 1328 error = nfsm_mbufuio(nd, uiop, len); 1329 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) 1330 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1331 } 1332 if (nd->nd_repstat && !error) 1333 error = nd->nd_repstat; 1334 nfsmout: 1335 mbuf_freem(nd->nd_mrep); 1336 return (error); 1337 } 1338 1339 /* 1340 * Read operation. 1341 */ 1342 APPLESTATIC int 1343 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, 1344 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1345 { 1346 int error, expireret = 0, retrycnt; 1347 u_int32_t clidrev = 0; 1348 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1349 struct nfsnode *np = VTONFS(vp); 1350 struct ucred *newcred; 1351 struct nfsfh *nfhp = NULL; 1352 nfsv4stateid_t stateid; 1353 void *lckp; 1354 1355 if (nmp->nm_clp != NULL) 1356 clidrev = nmp->nm_clp->nfsc_clientidrev; 1357 newcred = cred; 1358 if (NFSHASNFSV4(nmp)) { 1359 nfhp = np->n_fhp; 1360 newcred = NFSNEWCRED(cred); 1361 } 1362 retrycnt = 0; 1363 do { 1364 lckp = NULL; 1365 if (NFSHASNFSV4(nmp)) 1366 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1367 NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid, 1368 &lckp); 1369 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, 1370 attrflagp, stuff); 1371 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) 1372 nfscl_initiate_recovery(nmp->nm_clp); 1373 if (lckp != NULL) 1374 nfscl_lockderef(lckp); 1375 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1376 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1377 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1378 (void) nfs_catnap(PZERO, error, "nfs_read"); 1379 } else if ((error == NFSERR_EXPIRED || 1380 error == NFSERR_BADSTATEID) && clidrev != 0) { 1381 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1382 } 1383 retrycnt++; 1384 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1385 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1386 error == NFSERR_BADSESSION || 1387 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1388 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1389 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1390 if (error && retrycnt >= 4) 1391 error = EIO; 1392 if (NFSHASNFSV4(nmp)) 1393 NFSFREECRED(newcred); 1394 return (error); 1395 } 1396 1397 /* 1398 * The actual read RPC. 1399 */ 1400 static int 1401 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, 1402 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, 1403 int *attrflagp, void *stuff) 1404 { 1405 u_int32_t *tl; 1406 int error = 0, len, retlen, tsiz, eof = 0; 1407 struct nfsrv_descript nfsd; 1408 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1409 struct nfsrv_descript *nd = &nfsd; 1410 int rsize; 1411 off_t tmp_off; 1412 1413 *attrflagp = 0; 1414 tsiz = uio_uio_resid(uiop); 1415 tmp_off = uiop->uio_offset + tsiz; 1416 NFSLOCKMNT(nmp); 1417 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1418 NFSUNLOCKMNT(nmp); 1419 return (EFBIG); 1420 } 1421 rsize = nmp->nm_rsize; 1422 NFSUNLOCKMNT(nmp); 1423 nd->nd_mrep = NULL; 1424 while (tsiz > 0) { 1425 *attrflagp = 0; 1426 len = (tsiz > rsize) ? rsize : tsiz; 1427 NFSCL_REQSTART(nd, NFSPROC_READ, vp); 1428 if (nd->nd_flag & ND_NFSV4) 1429 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1430 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1431 if (nd->nd_flag & ND_NFSV2) { 1432 *tl++ = txdr_unsigned(uiop->uio_offset); 1433 *tl++ = txdr_unsigned(len); 1434 *tl = 0; 1435 } else { 1436 txdr_hyper(uiop->uio_offset, tl); 1437 *(tl + 2) = txdr_unsigned(len); 1438 } 1439 /* 1440 * Since I can't do a Getattr for NFSv4 for Write, there 1441 * doesn't seem any point in doing one here, either. 1442 * (See the comment in nfsrpc_writerpc() for more info.) 1443 */ 1444 error = nfscl_request(nd, vp, p, cred, stuff); 1445 if (error) 1446 return (error); 1447 if (nd->nd_flag & ND_NFSV3) { 1448 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1449 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { 1450 error = nfsm_loadattr(nd, nap); 1451 if (!error) 1452 *attrflagp = 1; 1453 } 1454 if (nd->nd_repstat || error) { 1455 if (!error) 1456 error = nd->nd_repstat; 1457 goto nfsmout; 1458 } 1459 if (nd->nd_flag & ND_NFSV3) { 1460 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1461 eof = fxdr_unsigned(int, *(tl + 1)); 1462 } else if (nd->nd_flag & ND_NFSV4) { 1463 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1464 eof = fxdr_unsigned(int, *tl); 1465 } 1466 NFSM_STRSIZ(retlen, len); 1467 error = nfsm_mbufuio(nd, uiop, retlen); 1468 if (error) 1469 goto nfsmout; 1470 mbuf_freem(nd->nd_mrep); 1471 nd->nd_mrep = NULL; 1472 tsiz -= retlen; 1473 if (!(nd->nd_flag & ND_NFSV2)) { 1474 if (eof || retlen == 0) 1475 tsiz = 0; 1476 } else if (retlen < len) 1477 tsiz = 0; 1478 } 1479 return (0); 1480 nfsmout: 1481 if (nd->nd_mrep != NULL) 1482 mbuf_freem(nd->nd_mrep); 1483 return (error); 1484 } 1485 1486 /* 1487 * nfs write operation 1488 * When called_from_strategy != 0, it should return EIO for an error that 1489 * indicates recovery is in progress, so that the buffer will be left 1490 * dirty and be written back to the server later. If it loops around, 1491 * the recovery thread could get stuck waiting for the buffer and recovery 1492 * will then deadlock. 1493 */ 1494 APPLESTATIC int 1495 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 1496 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 1497 void *stuff, int called_from_strategy) 1498 { 1499 int error, expireret = 0, retrycnt, nostateid; 1500 u_int32_t clidrev = 0; 1501 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1502 struct nfsnode *np = VTONFS(vp); 1503 struct ucred *newcred; 1504 struct nfsfh *nfhp = NULL; 1505 nfsv4stateid_t stateid; 1506 void *lckp; 1507 1508 *must_commit = 0; 1509 if (nmp->nm_clp != NULL) 1510 clidrev = nmp->nm_clp->nfsc_clientidrev; 1511 newcred = cred; 1512 if (NFSHASNFSV4(nmp)) { 1513 newcred = NFSNEWCRED(cred); 1514 nfhp = np->n_fhp; 1515 } 1516 retrycnt = 0; 1517 do { 1518 lckp = NULL; 1519 nostateid = 0; 1520 if (NFSHASNFSV4(nmp)) { 1521 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1522 NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid, 1523 &lckp); 1524 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 1525 stateid.other[2] == 0) { 1526 nostateid = 1; 1527 NFSCL_DEBUG(1, "stateid0 in write\n"); 1528 } 1529 } 1530 1531 /* 1532 * If there is no stateid for NFSv4, it means this is an 1533 * extraneous write after close. Basically a poorly 1534 * implemented buffer cache. Just don't do the write. 1535 */ 1536 if (nostateid) 1537 error = 0; 1538 else 1539 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, 1540 newcred, &stateid, p, nap, attrflagp, stuff); 1541 if (error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION) 1542 nfscl_initiate_recovery(nmp->nm_clp); 1543 if (lckp != NULL) 1544 nfscl_lockderef(lckp); 1545 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1546 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1547 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1548 (void) nfs_catnap(PZERO, error, "nfs_write"); 1549 } else if ((error == NFSERR_EXPIRED || 1550 error == NFSERR_BADSTATEID) && clidrev != 0) { 1551 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1552 } 1553 retrycnt++; 1554 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 1555 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1556 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || 1557 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1558 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1559 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1560 if (error != 0 && (retrycnt >= 4 || 1561 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1562 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0))) 1563 error = EIO; 1564 if (NFSHASNFSV4(nmp)) 1565 NFSFREECRED(newcred); 1566 return (error); 1567 } 1568 1569 /* 1570 * The actual write RPC. 1571 */ 1572 static int 1573 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, 1574 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, 1575 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1576 { 1577 u_int32_t *tl; 1578 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1579 struct nfsnode *np = VTONFS(vp); 1580 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; 1581 int wccflag = 0, wsize; 1582 int32_t backup; 1583 struct nfsrv_descript nfsd; 1584 struct nfsrv_descript *nd = &nfsd; 1585 nfsattrbit_t attrbits; 1586 off_t tmp_off; 1587 1588 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 1589 *attrflagp = 0; 1590 tsiz = uio_uio_resid(uiop); 1591 tmp_off = uiop->uio_offset + tsiz; 1592 NFSLOCKMNT(nmp); 1593 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1594 NFSUNLOCKMNT(nmp); 1595 return (EFBIG); 1596 } 1597 wsize = nmp->nm_wsize; 1598 NFSUNLOCKMNT(nmp); 1599 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ 1600 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ 1601 while (tsiz > 0) { 1602 *attrflagp = 0; 1603 len = (tsiz > wsize) ? wsize : tsiz; 1604 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); 1605 if (nd->nd_flag & ND_NFSV4) { 1606 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1607 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); 1608 txdr_hyper(uiop->uio_offset, tl); 1609 tl += 2; 1610 *tl++ = txdr_unsigned(*iomode); 1611 *tl = txdr_unsigned(len); 1612 } else if (nd->nd_flag & ND_NFSV3) { 1613 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); 1614 txdr_hyper(uiop->uio_offset, tl); 1615 tl += 2; 1616 *tl++ = txdr_unsigned(len); 1617 *tl++ = txdr_unsigned(*iomode); 1618 *tl = txdr_unsigned(len); 1619 } else { 1620 u_int32_t x; 1621 1622 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1623 /* 1624 * Not sure why someone changed this, since the 1625 * RFC clearly states that "beginoffset" and 1626 * "totalcount" are ignored, but it wouldn't 1627 * surprise me if there's a busted server out there. 1628 */ 1629 /* Set both "begin" and "current" to non-garbage. */ 1630 x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1631 *tl++ = x; /* "begin offset" */ 1632 *tl++ = x; /* "current offset" */ 1633 x = txdr_unsigned(len); 1634 *tl++ = x; /* total to this offset */ 1635 *tl = x; /* size of this write */ 1636 1637 } 1638 nfsm_uiombuf(nd, uiop, len); 1639 /* 1640 * Although it is tempting to do a normal Getattr Op in the 1641 * NFSv4 compound, the result can be a nearly hung client 1642 * system if the Getattr asks for Owner and/or OwnerGroup. 1643 * It occurs when the client can't map either the Owner or 1644 * Owner_group name in the Getattr reply to a uid/gid. When 1645 * there is a cache miss, the kernel does an upcall to the 1646 * nfsuserd. Then, it can try and read the local /etc/passwd 1647 * or /etc/group file. It can then block in getnewbuf(), 1648 * waiting for dirty writes to be pushed to the NFS server. 1649 * The only reason this doesn't result in a complete 1650 * deadlock, is that the upcall times out and allows 1651 * the write to complete. However, progress is so slow 1652 * that it might just as well be deadlocked. 1653 * As such, we get the rest of the attributes, but not 1654 * Owner or Owner_group. 1655 * nb: nfscl_loadattrcache() needs to be told that these 1656 * partial attributes from a write rpc are being 1657 * passed in, via a argument flag. 1658 */ 1659 if (nd->nd_flag & ND_NFSV4) { 1660 NFSWRITEGETATTR_ATTRBIT(&attrbits); 1661 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1662 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1663 (void) nfsrv_putattrbit(nd, &attrbits); 1664 } 1665 error = nfscl_request(nd, vp, p, cred, stuff); 1666 if (error) 1667 return (error); 1668 if (nd->nd_repstat) { 1669 /* 1670 * In case the rpc gets retried, roll 1671 * the uio fileds changed by nfsm_uiombuf() 1672 * back. 1673 */ 1674 uiop->uio_offset -= len; 1675 uio_uio_resid_add(uiop, len); 1676 uio_iov_base_add(uiop, -len); 1677 uio_iov_len_add(uiop, len); 1678 } 1679 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1680 error = nfscl_wcc_data(nd, vp, nap, attrflagp, 1681 &wccflag, stuff); 1682 if (error) 1683 goto nfsmout; 1684 } 1685 if (!nd->nd_repstat) { 1686 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1687 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1688 + NFSX_VERF); 1689 rlen = fxdr_unsigned(int, *tl++); 1690 if (rlen == 0) { 1691 error = NFSERR_IO; 1692 goto nfsmout; 1693 } else if (rlen < len) { 1694 backup = len - rlen; 1695 uio_iov_base_add(uiop, -(backup)); 1696 uio_iov_len_add(uiop, backup); 1697 uiop->uio_offset -= backup; 1698 uio_uio_resid_add(uiop, backup); 1699 len = rlen; 1700 } 1701 commit = fxdr_unsigned(int, *tl++); 1702 1703 /* 1704 * Return the lowest committment level 1705 * obtained by any of the RPCs. 1706 */ 1707 if (committed == NFSWRITE_FILESYNC) 1708 committed = commit; 1709 else if (committed == NFSWRITE_DATASYNC && 1710 commit == NFSWRITE_UNSTABLE) 1711 committed = commit; 1712 NFSLOCKMNT(nmp); 1713 if (!NFSHASWRITEVERF(nmp)) { 1714 NFSBCOPY((caddr_t)tl, 1715 (caddr_t)&nmp->nm_verf[0], 1716 NFSX_VERF); 1717 NFSSETWRITEVERF(nmp); 1718 } else if (NFSBCMP(tl, nmp->nm_verf, 1719 NFSX_VERF)) { 1720 *must_commit = 1; 1721 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 1722 } 1723 NFSUNLOCKMNT(nmp); 1724 } 1725 if (nd->nd_flag & ND_NFSV4) 1726 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1727 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 1728 error = nfsm_loadattr(nd, nap); 1729 if (!error) 1730 *attrflagp = NFS_LATTR_NOSHRINK; 1731 } 1732 } else { 1733 error = nd->nd_repstat; 1734 } 1735 if (error) 1736 goto nfsmout; 1737 NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4)); 1738 mbuf_freem(nd->nd_mrep); 1739 nd->nd_mrep = NULL; 1740 tsiz -= len; 1741 } 1742 nfsmout: 1743 if (nd->nd_mrep != NULL) 1744 mbuf_freem(nd->nd_mrep); 1745 *iomode = committed; 1746 if (nd->nd_repstat && !error) 1747 error = nd->nd_repstat; 1748 return (error); 1749 } 1750 1751 /* 1752 * nfs mknod rpc 1753 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1754 * mode set to specify the file type and the size field for rdev. 1755 */ 1756 APPLESTATIC int 1757 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1758 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p, 1759 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1760 int *attrflagp, int *dattrflagp, void *dstuff) 1761 { 1762 u_int32_t *tl; 1763 int error = 0; 1764 struct nfsrv_descript nfsd, *nd = &nfsd; 1765 nfsattrbit_t attrbits; 1766 1767 *nfhpp = NULL; 1768 *attrflagp = 0; 1769 *dattrflagp = 0; 1770 if (namelen > NFS_MAXNAMLEN) 1771 return (ENAMETOOLONG); 1772 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp); 1773 if (nd->nd_flag & ND_NFSV4) { 1774 if (vtyp == VBLK || vtyp == VCHR) { 1775 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1776 *tl++ = vtonfsv34_type(vtyp); 1777 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1778 *tl = txdr_unsigned(NFSMINOR(rdev)); 1779 } else { 1780 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1781 *tl = vtonfsv34_type(vtyp); 1782 } 1783 } 1784 (void) nfsm_strtom(nd, name, namelen); 1785 if (nd->nd_flag & ND_NFSV3) { 1786 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1787 *tl = vtonfsv34_type(vtyp); 1788 } 1789 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1790 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1791 if ((nd->nd_flag & ND_NFSV3) && 1792 (vtyp == VCHR || vtyp == VBLK)) { 1793 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1794 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1795 *tl = txdr_unsigned(NFSMINOR(rdev)); 1796 } 1797 if (nd->nd_flag & ND_NFSV4) { 1798 NFSGETATTR_ATTRBIT(&attrbits); 1799 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1800 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1801 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1802 (void) nfsrv_putattrbit(nd, &attrbits); 1803 } 1804 if (nd->nd_flag & ND_NFSV2) 1805 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 1806 error = nfscl_request(nd, dvp, p, cred, dstuff); 1807 if (error) 1808 return (error); 1809 if (nd->nd_flag & ND_NFSV4) 1810 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1811 if (!nd->nd_repstat) { 1812 if (nd->nd_flag & ND_NFSV4) { 1813 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1814 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1815 if (error) 1816 goto nfsmout; 1817 } 1818 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1819 if (error) 1820 goto nfsmout; 1821 } 1822 if (nd->nd_flag & ND_NFSV3) 1823 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1824 if (!error && nd->nd_repstat) 1825 error = nd->nd_repstat; 1826 nfsmout: 1827 mbuf_freem(nd->nd_mrep); 1828 return (error); 1829 } 1830 1831 /* 1832 * nfs file create call 1833 * Mostly just call the approriate routine. (I separated out v4, so that 1834 * error recovery wouldn't be as difficult.) 1835 */ 1836 APPLESTATIC int 1837 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1838 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1839 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1840 int *attrflagp, int *dattrflagp, void *dstuff) 1841 { 1842 int error = 0, newone, expireret = 0, retrycnt, unlocked; 1843 struct nfsclowner *owp; 1844 struct nfscldeleg *dp; 1845 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp)); 1846 u_int32_t clidrev; 1847 1848 if (NFSHASNFSV4(nmp)) { 1849 retrycnt = 0; 1850 do { 1851 dp = NULL; 1852 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 1853 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 1854 NULL, 1); 1855 if (error) 1856 return (error); 1857 if (nmp->nm_clp != NULL) 1858 clidrev = nmp->nm_clp->nfsc_clientidrev; 1859 else 1860 clidrev = 0; 1861 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode, 1862 owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1863 dstuff, &unlocked); 1864 /* 1865 * There is no need to invalidate cached attributes here, 1866 * since new post-delegation issue attributes are always 1867 * returned by nfsrpc_createv4() and these will update the 1868 * attribute cache. 1869 */ 1870 if (dp != NULL) 1871 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 1872 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 1873 nfscl_ownerrelease(owp, error, newone, unlocked); 1874 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1875 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1876 error == NFSERR_BADSESSION) { 1877 (void) nfs_catnap(PZERO, error, "nfs_open"); 1878 } else if ((error == NFSERR_EXPIRED || 1879 error == NFSERR_BADSTATEID) && clidrev != 0) { 1880 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1881 retrycnt++; 1882 } 1883 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1884 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1885 error == NFSERR_BADSESSION || 1886 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1887 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1888 if (error && retrycnt >= 4) 1889 error = EIO; 1890 } else { 1891 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 1892 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1893 dstuff); 1894 } 1895 return (error); 1896 } 1897 1898 /* 1899 * The create rpc for v2 and 3. 1900 */ 1901 static int 1902 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1903 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1904 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1905 int *attrflagp, int *dattrflagp, void *dstuff) 1906 { 1907 u_int32_t *tl; 1908 int error = 0; 1909 struct nfsrv_descript nfsd, *nd = &nfsd; 1910 1911 *nfhpp = NULL; 1912 *attrflagp = 0; 1913 *dattrflagp = 0; 1914 if (namelen > NFS_MAXNAMLEN) 1915 return (ENAMETOOLONG); 1916 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1917 (void) nfsm_strtom(nd, name, namelen); 1918 if (nd->nd_flag & ND_NFSV3) { 1919 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1920 if (fmode & O_EXCL) { 1921 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 1922 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1923 *tl++ = cverf.lval[0]; 1924 *tl = cverf.lval[1]; 1925 } else { 1926 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 1927 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1928 } 1929 } else { 1930 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 1931 } 1932 error = nfscl_request(nd, dvp, p, cred, dstuff); 1933 if (error) 1934 return (error); 1935 if (nd->nd_repstat == 0) { 1936 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1937 if (error) 1938 goto nfsmout; 1939 } 1940 if (nd->nd_flag & ND_NFSV3) 1941 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1942 if (nd->nd_repstat != 0 && error == 0) 1943 error = nd->nd_repstat; 1944 nfsmout: 1945 mbuf_freem(nd->nd_mrep); 1946 return (error); 1947 } 1948 1949 static int 1950 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1951 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 1952 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 1953 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 1954 int *dattrflagp, void *dstuff, int *unlockedp) 1955 { 1956 u_int32_t *tl; 1957 int error = 0, deleg, newone, ret, acesize, limitby; 1958 struct nfsrv_descript nfsd, *nd = &nfsd; 1959 struct nfsclopen *op; 1960 struct nfscldeleg *dp = NULL; 1961 struct nfsnode *np; 1962 struct nfsfh *nfhp; 1963 nfsattrbit_t attrbits; 1964 nfsv4stateid_t stateid; 1965 u_int32_t rflags; 1966 struct nfsmount *nmp; 1967 1968 nmp = VFSTONFS(dvp->v_mount); 1969 np = VTONFS(dvp); 1970 *unlockedp = 0; 1971 *nfhpp = NULL; 1972 *dpp = NULL; 1973 *attrflagp = 0; 1974 *dattrflagp = 0; 1975 if (namelen > NFS_MAXNAMLEN) 1976 return (ENAMETOOLONG); 1977 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1978 /* 1979 * For V4, this is actually an Open op. 1980 */ 1981 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1982 *tl++ = txdr_unsigned(owp->nfsow_seqid); 1983 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 1984 NFSV4OPEN_ACCESSREAD); 1985 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 1986 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 1987 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 1988 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 1989 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1990 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 1991 if (fmode & O_EXCL) { 1992 if (NFSHASNFSV4N(nmp)) { 1993 if (NFSHASSESSPERSIST(nmp)) { 1994 /* Use GUARDED for persistent sessions. */ 1995 *tl = txdr_unsigned(NFSCREATE_GUARDED); 1996 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1997 } else { 1998 /* Otherwise, use EXCLUSIVE4_1. */ 1999 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 2000 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2001 *tl++ = cverf.lval[0]; 2002 *tl = cverf.lval[1]; 2003 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2004 } 2005 } else { 2006 /* NFSv4.0 */ 2007 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2008 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2009 *tl++ = cverf.lval[0]; 2010 *tl = cverf.lval[1]; 2011 } 2012 } else { 2013 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2014 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2015 } 2016 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2017 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 2018 (void) nfsm_strtom(nd, name, namelen); 2019 /* Get the new file's handle and attributes. */ 2020 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2021 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2022 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2023 NFSGETATTR_ATTRBIT(&attrbits); 2024 (void) nfsrv_putattrbit(nd, &attrbits); 2025 /* Get the directory's post-op attributes. */ 2026 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2027 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2028 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 2029 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2030 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2031 (void) nfsrv_putattrbit(nd, &attrbits); 2032 error = nfscl_request(nd, dvp, p, cred, dstuff); 2033 if (error) 2034 return (error); 2035 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 2036 if (nd->nd_repstat == 0) { 2037 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2038 6 * NFSX_UNSIGNED); 2039 stateid.seqid = *tl++; 2040 stateid.other[0] = *tl++; 2041 stateid.other[1] = *tl++; 2042 stateid.other[2] = *tl; 2043 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 2044 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2045 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2046 deleg = fxdr_unsigned(int, *tl); 2047 if (deleg == NFSV4OPEN_DELEGATEREAD || 2048 deleg == NFSV4OPEN_DELEGATEWRITE) { 2049 if (!(owp->nfsow_clp->nfsc_flags & 2050 NFSCLFLAGS_FIRSTDELEG)) 2051 owp->nfsow_clp->nfsc_flags |= 2052 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 2053 MALLOC(dp, struct nfscldeleg *, 2054 sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 2055 M_NFSCLDELEG, M_WAITOK); 2056 LIST_INIT(&dp->nfsdl_owner); 2057 LIST_INIT(&dp->nfsdl_lock); 2058 dp->nfsdl_clp = owp->nfsow_clp; 2059 newnfs_copyincred(cred, &dp->nfsdl_cred); 2060 nfscl_lockinit(&dp->nfsdl_rwlock); 2061 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2062 NFSX_UNSIGNED); 2063 dp->nfsdl_stateid.seqid = *tl++; 2064 dp->nfsdl_stateid.other[0] = *tl++; 2065 dp->nfsdl_stateid.other[1] = *tl++; 2066 dp->nfsdl_stateid.other[2] = *tl++; 2067 ret = fxdr_unsigned(int, *tl); 2068 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 2069 dp->nfsdl_flags = NFSCLDL_WRITE; 2070 /* 2071 * Indicates how much the file can grow. 2072 */ 2073 NFSM_DISSECT(tl, u_int32_t *, 2074 3 * NFSX_UNSIGNED); 2075 limitby = fxdr_unsigned(int, *tl++); 2076 switch (limitby) { 2077 case NFSV4OPEN_LIMITSIZE: 2078 dp->nfsdl_sizelimit = fxdr_hyper(tl); 2079 break; 2080 case NFSV4OPEN_LIMITBLOCKS: 2081 dp->nfsdl_sizelimit = 2082 fxdr_unsigned(u_int64_t, *tl++); 2083 dp->nfsdl_sizelimit *= 2084 fxdr_unsigned(u_int64_t, *tl); 2085 break; 2086 default: 2087 error = NFSERR_BADXDR; 2088 goto nfsmout; 2089 }; 2090 } else { 2091 dp->nfsdl_flags = NFSCLDL_READ; 2092 } 2093 if (ret) 2094 dp->nfsdl_flags |= NFSCLDL_RECALL; 2095 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 2096 &acesize, p); 2097 if (error) 2098 goto nfsmout; 2099 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 2100 error = NFSERR_BADXDR; 2101 goto nfsmout; 2102 } 2103 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2104 if (error) 2105 goto nfsmout; 2106 /* Get rid of the PutFH and Getattr status values. */ 2107 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2108 /* Load the directory attributes. */ 2109 error = nfsm_loadattr(nd, dnap); 2110 if (error) 2111 goto nfsmout; 2112 *dattrflagp = 1; 2113 if (dp != NULL && *attrflagp) { 2114 dp->nfsdl_change = nnap->na_filerev; 2115 dp->nfsdl_modtime = nnap->na_mtime; 2116 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 2117 } 2118 /* 2119 * We can now complete the Open state. 2120 */ 2121 nfhp = *nfhpp; 2122 if (dp != NULL) { 2123 dp->nfsdl_fhlen = nfhp->nfh_len; 2124 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 2125 } 2126 /* 2127 * Get an Open structure that will be 2128 * attached to the OpenOwner, acquired already. 2129 */ 2130 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 2131 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 2132 cred, p, NULL, &op, &newone, NULL, 0); 2133 if (error) 2134 goto nfsmout; 2135 op->nfso_stateid = stateid; 2136 newnfs_copyincred(cred, &op->nfso_cred); 2137 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 2138 do { 2139 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 2140 nfhp->nfh_len, op, cred, p); 2141 if (ret == NFSERR_DELAY) 2142 (void) nfs_catnap(PZERO, ret, "nfs_create"); 2143 } while (ret == NFSERR_DELAY); 2144 error = ret; 2145 } 2146 2147 /* 2148 * If the server is handing out delegations, but we didn't 2149 * get one because an OpenConfirm was required, try the 2150 * Open again, to get a delegation. This is a harmless no-op, 2151 * from a server's point of view. 2152 */ 2153 if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 2154 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 2155 !error && dp == NULL) { 2156 do { 2157 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp, 2158 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 2159 nfhp->nfh_fh, nfhp->nfh_len, 2160 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2161 name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2162 if (ret == NFSERR_DELAY) 2163 (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2164 } while (ret == NFSERR_DELAY); 2165 if (ret) { 2166 if (dp != NULL) { 2167 FREE((caddr_t)dp, M_NFSCLDELEG); 2168 dp = NULL; 2169 } 2170 if (ret == NFSERR_STALECLIENTID || 2171 ret == NFSERR_STALEDONTRECOVER || 2172 ret == NFSERR_BADSESSION) 2173 error = ret; 2174 } 2175 } 2176 nfscl_openrelease(op, error, newone); 2177 *unlockedp = 1; 2178 } 2179 if (nd->nd_repstat != 0 && error == 0) 2180 error = nd->nd_repstat; 2181 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) 2182 nfscl_initiate_recovery(owp->nfsow_clp); 2183 nfsmout: 2184 if (!error) 2185 *dpp = dp; 2186 else if (dp != NULL) 2187 FREE((caddr_t)dp, M_NFSCLDELEG); 2188 mbuf_freem(nd->nd_mrep); 2189 return (error); 2190 } 2191 2192 /* 2193 * Nfs remove rpc 2194 */ 2195 APPLESTATIC int 2196 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2197 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, 2198 void *dstuff) 2199 { 2200 u_int32_t *tl; 2201 struct nfsrv_descript nfsd, *nd = &nfsd; 2202 struct nfsnode *np; 2203 struct nfsmount *nmp; 2204 nfsv4stateid_t dstateid; 2205 int error, ret = 0, i; 2206 2207 *dattrflagp = 0; 2208 if (namelen > NFS_MAXNAMLEN) 2209 return (ENAMETOOLONG); 2210 nmp = VFSTONFS(vnode_mount(dvp)); 2211 tryagain: 2212 if (NFSHASNFSV4(nmp) && ret == 0) { 2213 ret = nfscl_removedeleg(vp, p, &dstateid); 2214 if (ret == 1) { 2215 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp); 2216 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2217 NFSX_UNSIGNED); 2218 if (NFSHASNFSV4N(nmp)) 2219 *tl++ = 0; 2220 else 2221 *tl++ = dstateid.seqid; 2222 *tl++ = dstateid.other[0]; 2223 *tl++ = dstateid.other[1]; 2224 *tl++ = dstateid.other[2]; 2225 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2226 np = VTONFS(dvp); 2227 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2228 np->n_fhp->nfh_len, 0); 2229 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2230 *tl = txdr_unsigned(NFSV4OP_REMOVE); 2231 } 2232 } else { 2233 ret = 0; 2234 } 2235 if (ret == 0) 2236 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp); 2237 (void) nfsm_strtom(nd, name, namelen); 2238 error = nfscl_request(nd, dvp, p, cred, dstuff); 2239 if (error) 2240 return (error); 2241 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2242 /* For NFSv4, parse out any Delereturn replies. */ 2243 if (ret > 0 && nd->nd_repstat != 0 && 2244 (nd->nd_flag & ND_NOMOREDATA)) { 2245 /* 2246 * If the Delegreturn failed, try again without 2247 * it. The server will Recall, as required. 2248 */ 2249 mbuf_freem(nd->nd_mrep); 2250 goto tryagain; 2251 } 2252 for (i = 0; i < (ret * 2); i++) { 2253 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2254 ND_NFSV4) { 2255 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2256 if (*(tl + 1)) 2257 nd->nd_flag |= ND_NOMOREDATA; 2258 } 2259 } 2260 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2261 } 2262 if (nd->nd_repstat && !error) 2263 error = nd->nd_repstat; 2264 nfsmout: 2265 mbuf_freem(nd->nd_mrep); 2266 return (error); 2267 } 2268 2269 /* 2270 * Do an nfs rename rpc. 2271 */ 2272 APPLESTATIC int 2273 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2274 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2275 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2276 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff) 2277 { 2278 u_int32_t *tl; 2279 struct nfsrv_descript nfsd, *nd = &nfsd; 2280 struct nfsmount *nmp; 2281 struct nfsnode *np; 2282 nfsattrbit_t attrbits; 2283 nfsv4stateid_t fdstateid, tdstateid; 2284 int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2285 2286 *fattrflagp = 0; 2287 *tattrflagp = 0; 2288 nmp = VFSTONFS(vnode_mount(fdvp)); 2289 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2290 return (ENAMETOOLONG); 2291 tryagain: 2292 if (NFSHASNFSV4(nmp) && ret == 0) { 2293 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2294 &tdstateid, &gottd, p); 2295 if (gotfd && gottd) { 2296 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp); 2297 } else if (gotfd) { 2298 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp); 2299 } else if (gottd) { 2300 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp); 2301 } 2302 if (gotfd) { 2303 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2304 if (NFSHASNFSV4N(nmp)) 2305 *tl++ = 0; 2306 else 2307 *tl++ = fdstateid.seqid; 2308 *tl++ = fdstateid.other[0]; 2309 *tl++ = fdstateid.other[1]; 2310 *tl = fdstateid.other[2]; 2311 if (gottd) { 2312 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2313 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2314 np = VTONFS(tvp); 2315 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2316 np->n_fhp->nfh_len, 0); 2317 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2318 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2319 } 2320 } 2321 if (gottd) { 2322 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2323 if (NFSHASNFSV4N(nmp)) 2324 *tl++ = 0; 2325 else 2326 *tl++ = tdstateid.seqid; 2327 *tl++ = tdstateid.other[0]; 2328 *tl++ = tdstateid.other[1]; 2329 *tl = tdstateid.other[2]; 2330 } 2331 if (ret > 0) { 2332 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2333 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2334 np = VTONFS(fdvp); 2335 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2336 np->n_fhp->nfh_len, 0); 2337 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2338 *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2339 } 2340 } else { 2341 ret = 0; 2342 } 2343 if (ret == 0) 2344 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp); 2345 if (nd->nd_flag & ND_NFSV4) { 2346 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2347 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2348 NFSWCCATTR_ATTRBIT(&attrbits); 2349 (void) nfsrv_putattrbit(nd, &attrbits); 2350 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2351 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2352 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2353 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2354 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2355 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2356 (void) nfsrv_putattrbit(nd, &attrbits); 2357 nd->nd_flag |= ND_V4WCCATTR; 2358 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2359 *tl = txdr_unsigned(NFSV4OP_RENAME); 2360 } 2361 (void) nfsm_strtom(nd, fnameptr, fnamelen); 2362 if (!(nd->nd_flag & ND_NFSV4)) 2363 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2364 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2365 (void) nfsm_strtom(nd, tnameptr, tnamelen); 2366 error = nfscl_request(nd, fdvp, p, cred, fstuff); 2367 if (error) 2368 return (error); 2369 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2370 /* For NFSv4, parse out any Delereturn replies. */ 2371 if (ret > 0 && nd->nd_repstat != 0 && 2372 (nd->nd_flag & ND_NOMOREDATA)) { 2373 /* 2374 * If the Delegreturn failed, try again without 2375 * it. The server will Recall, as required. 2376 */ 2377 mbuf_freem(nd->nd_mrep); 2378 goto tryagain; 2379 } 2380 for (i = 0; i < (ret * 2); i++) { 2381 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2382 ND_NFSV4) { 2383 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2384 if (*(tl + 1)) { 2385 if (i == 0 && ret > 1) { 2386 /* 2387 * If the Delegreturn failed, try again 2388 * without it. The server will Recall, as 2389 * required. 2390 * If ret > 1, the first iteration of this 2391 * loop is the second DelegReturn result. 2392 */ 2393 mbuf_freem(nd->nd_mrep); 2394 goto tryagain; 2395 } else { 2396 nd->nd_flag |= ND_NOMOREDATA; 2397 } 2398 } 2399 } 2400 } 2401 /* Now, the first wcc attribute reply. */ 2402 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2403 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2404 if (*(tl + 1)) 2405 nd->nd_flag |= ND_NOMOREDATA; 2406 } 2407 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, 2408 fstuff); 2409 /* and the second wcc attribute reply. */ 2410 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2411 !error) { 2412 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2413 if (*(tl + 1)) 2414 nd->nd_flag |= ND_NOMOREDATA; 2415 } 2416 if (!error) 2417 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2418 NULL, tstuff); 2419 } 2420 if (nd->nd_repstat && !error) 2421 error = nd->nd_repstat; 2422 nfsmout: 2423 mbuf_freem(nd->nd_mrep); 2424 return (error); 2425 } 2426 2427 /* 2428 * nfs hard link create rpc 2429 */ 2430 APPLESTATIC int 2431 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2432 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2433 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2434 { 2435 u_int32_t *tl; 2436 struct nfsrv_descript nfsd, *nd = &nfsd; 2437 nfsattrbit_t attrbits; 2438 int error = 0; 2439 2440 *attrflagp = 0; 2441 *dattrflagp = 0; 2442 if (namelen > NFS_MAXNAMLEN) 2443 return (ENAMETOOLONG); 2444 NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2445 if (nd->nd_flag & ND_NFSV4) { 2446 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2447 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2448 } 2449 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2450 VTONFS(dvp)->n_fhp->nfh_len, 0); 2451 if (nd->nd_flag & ND_NFSV4) { 2452 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2453 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2454 NFSWCCATTR_ATTRBIT(&attrbits); 2455 (void) nfsrv_putattrbit(nd, &attrbits); 2456 nd->nd_flag |= ND_V4WCCATTR; 2457 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2458 *tl = txdr_unsigned(NFSV4OP_LINK); 2459 } 2460 (void) nfsm_strtom(nd, name, namelen); 2461 error = nfscl_request(nd, vp, p, cred, dstuff); 2462 if (error) 2463 return (error); 2464 if (nd->nd_flag & ND_NFSV3) { 2465 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2466 if (!error) 2467 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2468 NULL, dstuff); 2469 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2470 /* 2471 * First, parse out the PutFH and Getattr result. 2472 */ 2473 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2474 if (!(*(tl + 1))) 2475 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2476 if (*(tl + 1)) 2477 nd->nd_flag |= ND_NOMOREDATA; 2478 /* 2479 * Get the pre-op attributes. 2480 */ 2481 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2482 } 2483 if (nd->nd_repstat && !error) 2484 error = nd->nd_repstat; 2485 nfsmout: 2486 mbuf_freem(nd->nd_mrep); 2487 return (error); 2488 } 2489 2490 /* 2491 * nfs symbolic link create rpc 2492 */ 2493 APPLESTATIC int 2494 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target, 2495 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2496 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2497 int *dattrflagp, void *dstuff) 2498 { 2499 u_int32_t *tl; 2500 struct nfsrv_descript nfsd, *nd = &nfsd; 2501 struct nfsmount *nmp; 2502 int slen, error = 0; 2503 2504 *nfhpp = NULL; 2505 *attrflagp = 0; 2506 *dattrflagp = 0; 2507 nmp = VFSTONFS(vnode_mount(dvp)); 2508 slen = strlen(target); 2509 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2510 return (ENAMETOOLONG); 2511 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2512 if (nd->nd_flag & ND_NFSV4) { 2513 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2514 *tl = txdr_unsigned(NFLNK); 2515 (void) nfsm_strtom(nd, target, slen); 2516 } 2517 (void) nfsm_strtom(nd, name, namelen); 2518 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2519 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2520 if (!(nd->nd_flag & ND_NFSV4)) 2521 (void) nfsm_strtom(nd, target, slen); 2522 if (nd->nd_flag & ND_NFSV2) 2523 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2524 error = nfscl_request(nd, dvp, p, cred, dstuff); 2525 if (error) 2526 return (error); 2527 if (nd->nd_flag & ND_NFSV4) 2528 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2529 if ((nd->nd_flag & ND_NFSV3) && !error) { 2530 if (!nd->nd_repstat) 2531 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2532 if (!error) 2533 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2534 NULL, dstuff); 2535 } 2536 if (nd->nd_repstat && !error) 2537 error = nd->nd_repstat; 2538 mbuf_freem(nd->nd_mrep); 2539 /* 2540 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2541 * Only do this if vfs.nfs.ignore_eexist is set. 2542 * Never do this for NFSv4.1 or later minor versions, since sessions 2543 * should guarantee "exactly once" RPC semantics. 2544 */ 2545 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2546 nmp->nm_minorvers == 0)) 2547 error = 0; 2548 return (error); 2549 } 2550 2551 /* 2552 * nfs make dir rpc 2553 */ 2554 APPLESTATIC int 2555 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2556 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2557 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2558 int *dattrflagp, void *dstuff) 2559 { 2560 u_int32_t *tl; 2561 struct nfsrv_descript nfsd, *nd = &nfsd; 2562 nfsattrbit_t attrbits; 2563 int error = 0; 2564 struct nfsfh *fhp; 2565 struct nfsmount *nmp; 2566 2567 *nfhpp = NULL; 2568 *attrflagp = 0; 2569 *dattrflagp = 0; 2570 nmp = VFSTONFS(vnode_mount(dvp)); 2571 fhp = VTONFS(dvp)->n_fhp; 2572 if (namelen > NFS_MAXNAMLEN) 2573 return (ENAMETOOLONG); 2574 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 2575 if (nd->nd_flag & ND_NFSV4) { 2576 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2577 *tl = txdr_unsigned(NFDIR); 2578 } 2579 (void) nfsm_strtom(nd, name, namelen); 2580 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2581 if (nd->nd_flag & ND_NFSV4) { 2582 NFSGETATTR_ATTRBIT(&attrbits); 2583 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2584 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2585 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2586 (void) nfsrv_putattrbit(nd, &attrbits); 2587 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2588 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2589 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0); 2590 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2591 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2592 (void) nfsrv_putattrbit(nd, &attrbits); 2593 } 2594 error = nfscl_request(nd, dvp, p, cred, dstuff); 2595 if (error) 2596 return (error); 2597 if (nd->nd_flag & ND_NFSV4) 2598 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2599 if (!nd->nd_repstat && !error) { 2600 if (nd->nd_flag & ND_NFSV4) { 2601 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2602 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2603 } 2604 if (!error) 2605 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2606 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 2607 /* Get rid of the PutFH and Getattr status values. */ 2608 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2609 /* Load the directory attributes. */ 2610 error = nfsm_loadattr(nd, dnap); 2611 if (error == 0) 2612 *dattrflagp = 1; 2613 } 2614 } 2615 if ((nd->nd_flag & ND_NFSV3) && !error) 2616 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2617 if (nd->nd_repstat && !error) 2618 error = nd->nd_repstat; 2619 nfsmout: 2620 mbuf_freem(nd->nd_mrep); 2621 /* 2622 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2623 * Only do this if vfs.nfs.ignore_eexist is set. 2624 * Never do this for NFSv4.1 or later minor versions, since sessions 2625 * should guarantee "exactly once" RPC semantics. 2626 */ 2627 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2628 nmp->nm_minorvers == 0)) 2629 error = 0; 2630 return (error); 2631 } 2632 2633 /* 2634 * nfs remove directory call 2635 */ 2636 APPLESTATIC int 2637 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 2638 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 2639 { 2640 struct nfsrv_descript nfsd, *nd = &nfsd; 2641 int error = 0; 2642 2643 *dattrflagp = 0; 2644 if (namelen > NFS_MAXNAMLEN) 2645 return (ENAMETOOLONG); 2646 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 2647 (void) nfsm_strtom(nd, name, namelen); 2648 error = nfscl_request(nd, dvp, p, cred, dstuff); 2649 if (error) 2650 return (error); 2651 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2652 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2653 if (nd->nd_repstat && !error) 2654 error = nd->nd_repstat; 2655 mbuf_freem(nd->nd_mrep); 2656 /* 2657 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2658 */ 2659 if (error == ENOENT) 2660 error = 0; 2661 return (error); 2662 } 2663 2664 /* 2665 * Readdir rpc. 2666 * Always returns with either uio_resid unchanged, if you are at the 2667 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 2668 * filled in. 2669 * I felt this would allow caching of directory blocks more easily 2670 * than returning a pertially filled block. 2671 * Directory offset cookies: 2672 * Oh my, what to do with them... 2673 * I can think of three ways to deal with them: 2674 * 1 - have the layer above these RPCs maintain a map between logical 2675 * directory byte offsets and the NFS directory offset cookies 2676 * 2 - pass the opaque directory offset cookies up into userland 2677 * and let the libc functions deal with them, via the system call 2678 * 3 - return them to userland in the "struct dirent", so future versions 2679 * of libc can use them and do whatever is necessary to amke things work 2680 * above these rpc calls, in the meantime 2681 * For now, I do #3 by "hiding" the directory offset cookies after the 2682 * d_name field in struct dirent. This is space inside d_reclen that 2683 * will be ignored by anything that doesn't know about them. 2684 * The directory offset cookies are filled in as the last 8 bytes of 2685 * each directory entry, after d_name. Someday, the userland libc 2686 * functions may be able to use these. In the meantime, it satisfies 2687 * OpenBSD's requirements for cookies being returned. 2688 * If expects the directory offset cookie for the read to be in uio_offset 2689 * and returns the one for the next entry after this directory block in 2690 * there, as well. 2691 */ 2692 APPLESTATIC int 2693 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2694 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2695 int *eofp, void *stuff) 2696 { 2697 int len, left; 2698 struct dirent *dp = NULL; 2699 u_int32_t *tl; 2700 nfsquad_t cookie, ncookie; 2701 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2702 struct nfsnode *dnp = VTONFS(vp); 2703 struct nfsvattr nfsva; 2704 struct nfsrv_descript nfsd, *nd = &nfsd; 2705 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2706 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 2707 long dotfileid, dotdotfileid = 0; 2708 u_int32_t fakefileno = 0xffffffff, rderr; 2709 char *cp; 2710 nfsattrbit_t attrbits, dattrbits; 2711 u_int32_t *tl2 = NULL; 2712 size_t tresid; 2713 2714 KASSERT(uiop->uio_iovcnt == 1 && 2715 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2716 ("nfs readdirrpc bad uio")); 2717 2718 /* 2719 * There is no point in reading a lot more than uio_resid, however 2720 * adding one additional DIRBLKSIZ makes sense. Since uio_resid 2721 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 2722 * will never make readsize > nm_readdirsize. 2723 */ 2724 readsize = nmp->nm_readdirsize; 2725 if (readsize > uio_uio_resid(uiop)) 2726 readsize = uio_uio_resid(uiop) + DIRBLKSIZ; 2727 2728 *attrflagp = 0; 2729 if (eofp) 2730 *eofp = 0; 2731 tresid = uio_uio_resid(uiop); 2732 cookie.lval[0] = cookiep->nfsuquad[0]; 2733 cookie.lval[1] = cookiep->nfsuquad[1]; 2734 nd->nd_mrep = NULL; 2735 2736 /* 2737 * For NFSv4, first create the "." and ".." entries. 2738 */ 2739 if (NFSHASNFSV4(nmp)) { 2740 reqsize = 6 * NFSX_UNSIGNED; 2741 NFSGETATTR_ATTRBIT(&dattrbits); 2742 NFSZERO_ATTRBIT(&attrbits); 2743 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2744 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 2745 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2746 NFSATTRBIT_MOUNTEDONFILEID)) { 2747 NFSSETBIT_ATTRBIT(&attrbits, 2748 NFSATTRBIT_MOUNTEDONFILEID); 2749 gotmnton = 1; 2750 } else { 2751 /* 2752 * Must fake it. Use the fileno, except when the 2753 * fsid is != to that of the directory. For that 2754 * case, generate a fake fileno that is not the same. 2755 */ 2756 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2757 gotmnton = 0; 2758 } 2759 2760 /* 2761 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2762 */ 2763 if (uiop->uio_offset == 0) { 2764 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2765 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2766 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2767 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2768 (void) nfsrv_putattrbit(nd, &attrbits); 2769 error = nfscl_request(nd, vp, p, cred, stuff); 2770 if (error) 2771 return (error); 2772 dotfileid = 0; /* Fake out the compiler. */ 2773 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 2774 error = nfsm_loadattr(nd, &nfsva); 2775 if (error != 0) 2776 goto nfsmout; 2777 dotfileid = nfsva.na_fileid; 2778 } 2779 if (nd->nd_repstat == 0) { 2780 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2781 len = fxdr_unsigned(int, *(tl + 4)); 2782 if (len > 0 && len <= NFSX_V4FHMAX) 2783 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2784 else 2785 error = EPERM; 2786 if (!error) { 2787 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2788 nfsva.na_mntonfileno = 0xffffffff; 2789 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2790 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2791 NULL, NULL, NULL, p, cred); 2792 if (error) { 2793 dotdotfileid = dotfileid; 2794 } else if (gotmnton) { 2795 if (nfsva.na_mntonfileno != 0xffffffff) 2796 dotdotfileid = nfsva.na_mntonfileno; 2797 else 2798 dotdotfileid = nfsva.na_fileid; 2799 } else if (nfsva.na_filesid[0] == 2800 dnp->n_vattr.na_filesid[0] && 2801 nfsva.na_filesid[1] == 2802 dnp->n_vattr.na_filesid[1]) { 2803 dotdotfileid = nfsva.na_fileid; 2804 } else { 2805 do { 2806 fakefileno--; 2807 } while (fakefileno == 2808 nfsva.na_fileid); 2809 dotdotfileid = fakefileno; 2810 } 2811 } 2812 } else if (nd->nd_repstat == NFSERR_NOENT) { 2813 /* 2814 * Lookupp returns NFSERR_NOENT when we are 2815 * at the root, so just use the current dir. 2816 */ 2817 nd->nd_repstat = 0; 2818 dotdotfileid = dotfileid; 2819 } else { 2820 error = nd->nd_repstat; 2821 } 2822 mbuf_freem(nd->nd_mrep); 2823 if (error) 2824 return (error); 2825 nd->nd_mrep = NULL; 2826 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2827 dp->d_type = DT_DIR; 2828 dp->d_fileno = dotfileid; 2829 dp->d_namlen = 1; 2830 dp->d_name[0] = '.'; 2831 dp->d_name[1] = '\0'; 2832 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2833 /* 2834 * Just make these offset cookie 0. 2835 */ 2836 tl = (u_int32_t *)&dp->d_name[4]; 2837 *tl++ = 0; 2838 *tl = 0; 2839 blksiz += dp->d_reclen; 2840 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2841 uiop->uio_offset += dp->d_reclen; 2842 uio_iov_base_add(uiop, dp->d_reclen); 2843 uio_iov_len_add(uiop, -(dp->d_reclen)); 2844 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2845 dp->d_type = DT_DIR; 2846 dp->d_fileno = dotdotfileid; 2847 dp->d_namlen = 2; 2848 dp->d_name[0] = '.'; 2849 dp->d_name[1] = '.'; 2850 dp->d_name[2] = '\0'; 2851 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2852 /* 2853 * Just make these offset cookie 0. 2854 */ 2855 tl = (u_int32_t *)&dp->d_name[4]; 2856 *tl++ = 0; 2857 *tl = 0; 2858 blksiz += dp->d_reclen; 2859 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2860 uiop->uio_offset += dp->d_reclen; 2861 uio_iov_base_add(uiop, dp->d_reclen); 2862 uio_iov_len_add(uiop, -(dp->d_reclen)); 2863 } 2864 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 2865 } else { 2866 reqsize = 5 * NFSX_UNSIGNED; 2867 } 2868 2869 2870 /* 2871 * Loop around doing readdir rpc's of size readsize. 2872 * The stopping criteria is EOF or buffer full. 2873 */ 2874 while (more_dirs && bigenough) { 2875 *attrflagp = 0; 2876 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 2877 if (nd->nd_flag & ND_NFSV2) { 2878 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2879 *tl++ = cookie.lval[1]; 2880 *tl = txdr_unsigned(readsize); 2881 } else { 2882 NFSM_BUILD(tl, u_int32_t *, reqsize); 2883 *tl++ = cookie.lval[0]; 2884 *tl++ = cookie.lval[1]; 2885 if (cookie.qval == 0) { 2886 *tl++ = 0; 2887 *tl++ = 0; 2888 } else { 2889 NFSLOCKNODE(dnp); 2890 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 2891 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 2892 NFSUNLOCKNODE(dnp); 2893 } 2894 if (nd->nd_flag & ND_NFSV4) { 2895 *tl++ = txdr_unsigned(readsize); 2896 *tl = txdr_unsigned(readsize); 2897 (void) nfsrv_putattrbit(nd, &attrbits); 2898 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2899 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2900 (void) nfsrv_putattrbit(nd, &dattrbits); 2901 } else { 2902 *tl = txdr_unsigned(readsize); 2903 } 2904 } 2905 error = nfscl_request(nd, vp, p, cred, stuff); 2906 if (error) 2907 return (error); 2908 if (!(nd->nd_flag & ND_NFSV2)) { 2909 if (nd->nd_flag & ND_NFSV3) 2910 error = nfscl_postop_attr(nd, nap, attrflagp, 2911 stuff); 2912 if (!nd->nd_repstat && !error) { 2913 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 2914 NFSLOCKNODE(dnp); 2915 dnp->n_cookieverf.nfsuquad[0] = *tl++; 2916 dnp->n_cookieverf.nfsuquad[1] = *tl; 2917 NFSUNLOCKNODE(dnp); 2918 } 2919 } 2920 if (nd->nd_repstat || error) { 2921 if (!error) 2922 error = nd->nd_repstat; 2923 goto nfsmout; 2924 } 2925 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2926 more_dirs = fxdr_unsigned(int, *tl); 2927 if (!more_dirs) 2928 tryformoredirs = 0; 2929 2930 /* loop thru the dir entries, doctoring them to 4bsd form */ 2931 while (more_dirs && bigenough) { 2932 if (nd->nd_flag & ND_NFSV4) { 2933 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2934 ncookie.lval[0] = *tl++; 2935 ncookie.lval[1] = *tl++; 2936 len = fxdr_unsigned(int, *tl); 2937 } else if (nd->nd_flag & ND_NFSV3) { 2938 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2939 nfsva.na_fileid = fxdr_hyper(tl); 2940 tl += 2; 2941 len = fxdr_unsigned(int, *tl); 2942 } else { 2943 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2944 nfsva.na_fileid = 2945 fxdr_unsigned(long, *tl++); 2946 len = fxdr_unsigned(int, *tl); 2947 } 2948 if (len <= 0 || len > NFS_MAXNAMLEN) { 2949 error = EBADRPC; 2950 goto nfsmout; 2951 } 2952 tlen = NFSM_RNDUP(len); 2953 if (tlen == len) 2954 tlen += 4; /* To ensure null termination */ 2955 left = DIRBLKSIZ - blksiz; 2956 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) { 2957 dp->d_reclen += left; 2958 uio_iov_base_add(uiop, left); 2959 uio_iov_len_add(uiop, -(left)); 2960 uio_uio_resid_add(uiop, -(left)); 2961 uiop->uio_offset += left; 2962 blksiz = 0; 2963 } 2964 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 2965 bigenough = 0; 2966 if (bigenough) { 2967 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2968 dp->d_namlen = len; 2969 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 2970 dp->d_type = DT_UNKNOWN; 2971 blksiz += dp->d_reclen; 2972 if (blksiz == DIRBLKSIZ) 2973 blksiz = 0; 2974 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 2975 uiop->uio_offset += DIRHDSIZ; 2976 uio_iov_base_add(uiop, DIRHDSIZ); 2977 uio_iov_len_add(uiop, -(DIRHDSIZ)); 2978 error = nfsm_mbufuio(nd, uiop, len); 2979 if (error) 2980 goto nfsmout; 2981 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2982 tlen -= len; 2983 *cp = '\0'; /* null terminate */ 2984 cp += tlen; /* points to cookie storage */ 2985 tl2 = (u_int32_t *)cp; 2986 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 2987 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 2988 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 2989 uiop->uio_offset += (tlen + NFSX_HYPER); 2990 } else { 2991 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2992 if (error) 2993 goto nfsmout; 2994 } 2995 if (nd->nd_flag & ND_NFSV4) { 2996 rderr = 0; 2997 nfsva.na_mntonfileno = 0xffffffff; 2998 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2999 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3000 NULL, NULL, &rderr, p, cred); 3001 if (error) 3002 goto nfsmout; 3003 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3004 } else if (nd->nd_flag & ND_NFSV3) { 3005 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3006 ncookie.lval[0] = *tl++; 3007 ncookie.lval[1] = *tl++; 3008 } else { 3009 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3010 ncookie.lval[0] = 0; 3011 ncookie.lval[1] = *tl++; 3012 } 3013 if (bigenough) { 3014 if (nd->nd_flag & ND_NFSV4) { 3015 if (rderr) { 3016 dp->d_fileno = 0; 3017 } else { 3018 if (gotmnton) { 3019 if (nfsva.na_mntonfileno != 0xffffffff) 3020 dp->d_fileno = nfsva.na_mntonfileno; 3021 else 3022 dp->d_fileno = nfsva.na_fileid; 3023 } else if (nfsva.na_filesid[0] == 3024 dnp->n_vattr.na_filesid[0] && 3025 nfsva.na_filesid[1] == 3026 dnp->n_vattr.na_filesid[1]) { 3027 dp->d_fileno = nfsva.na_fileid; 3028 } else { 3029 do { 3030 fakefileno--; 3031 } while (fakefileno == 3032 nfsva.na_fileid); 3033 dp->d_fileno = fakefileno; 3034 } 3035 dp->d_type = vtonfs_dtype(nfsva.na_type); 3036 } 3037 } else { 3038 dp->d_fileno = nfsva.na_fileid; 3039 } 3040 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3041 ncookie.lval[0]; 3042 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3043 ncookie.lval[1]; 3044 } 3045 more_dirs = fxdr_unsigned(int, *tl); 3046 } 3047 /* 3048 * If at end of rpc data, get the eof boolean 3049 */ 3050 if (!more_dirs) { 3051 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3052 eof = fxdr_unsigned(int, *tl); 3053 if (tryformoredirs) 3054 more_dirs = !eof; 3055 if (nd->nd_flag & ND_NFSV4) { 3056 error = nfscl_postop_attr(nd, nap, attrflagp, 3057 stuff); 3058 if (error) 3059 goto nfsmout; 3060 } 3061 } 3062 mbuf_freem(nd->nd_mrep); 3063 nd->nd_mrep = NULL; 3064 } 3065 /* 3066 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3067 * by increasing d_reclen for the last record. 3068 */ 3069 if (blksiz > 0) { 3070 left = DIRBLKSIZ - blksiz; 3071 dp->d_reclen += left; 3072 uio_iov_base_add(uiop, left); 3073 uio_iov_len_add(uiop, -(left)); 3074 uio_uio_resid_add(uiop, -(left)); 3075 uiop->uio_offset += left; 3076 } 3077 3078 /* 3079 * If returning no data, assume end of file. 3080 * If not bigenough, return not end of file, since you aren't 3081 * returning all the data 3082 * Otherwise, return the eof flag from the server. 3083 */ 3084 if (eofp) { 3085 if (tresid == ((size_t)(uio_uio_resid(uiop)))) 3086 *eofp = 1; 3087 else if (!bigenough) 3088 *eofp = 0; 3089 else 3090 *eofp = eof; 3091 } 3092 3093 /* 3094 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3095 */ 3096 while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) { 3097 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 3098 dp->d_type = DT_UNKNOWN; 3099 dp->d_fileno = 0; 3100 dp->d_namlen = 0; 3101 dp->d_name[0] = '\0'; 3102 tl = (u_int32_t *)&dp->d_name[4]; 3103 *tl++ = cookie.lval[0]; 3104 *tl = cookie.lval[1]; 3105 dp->d_reclen = DIRBLKSIZ; 3106 uio_iov_base_add(uiop, DIRBLKSIZ); 3107 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3108 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3109 uiop->uio_offset += DIRBLKSIZ; 3110 } 3111 3112 nfsmout: 3113 if (nd->nd_mrep != NULL) 3114 mbuf_freem(nd->nd_mrep); 3115 return (error); 3116 } 3117 3118 #ifndef APPLE 3119 /* 3120 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 3121 * (Also used for NFS V4 when mount flag set.) 3122 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 3123 */ 3124 APPLESTATIC int 3125 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3126 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3127 int *eofp, void *stuff) 3128 { 3129 int len, left; 3130 struct dirent *dp = NULL; 3131 u_int32_t *tl; 3132 vnode_t newvp = NULLVP; 3133 struct nfsrv_descript nfsd, *nd = &nfsd; 3134 struct nameidata nami, *ndp = &nami; 3135 struct componentname *cnp = &ndp->ni_cnd; 3136 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3137 struct nfsnode *dnp = VTONFS(vp), *np; 3138 struct nfsvattr nfsva; 3139 struct nfsfh *nfhp; 3140 nfsquad_t cookie, ncookie; 3141 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3142 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 3143 int isdotdot = 0, unlocknewvp = 0; 3144 long dotfileid, dotdotfileid = 0, fileno = 0; 3145 char *cp; 3146 nfsattrbit_t attrbits, dattrbits; 3147 size_t tresid; 3148 u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr; 3149 struct timespec dctime; 3150 3151 KASSERT(uiop->uio_iovcnt == 1 && 3152 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 3153 ("nfs readdirplusrpc bad uio")); 3154 timespecclear(&dctime); 3155 *attrflagp = 0; 3156 if (eofp != NULL) 3157 *eofp = 0; 3158 ndp->ni_dvp = vp; 3159 nd->nd_mrep = NULL; 3160 cookie.lval[0] = cookiep->nfsuquad[0]; 3161 cookie.lval[1] = cookiep->nfsuquad[1]; 3162 tresid = uio_uio_resid(uiop); 3163 3164 /* 3165 * For NFSv4, first create the "." and ".." entries. 3166 */ 3167 if (NFSHASNFSV4(nmp)) { 3168 NFSGETATTR_ATTRBIT(&dattrbits); 3169 NFSZERO_ATTRBIT(&attrbits); 3170 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3171 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3172 NFSATTRBIT_MOUNTEDONFILEID)) { 3173 NFSSETBIT_ATTRBIT(&attrbits, 3174 NFSATTRBIT_MOUNTEDONFILEID); 3175 gotmnton = 1; 3176 } else { 3177 /* 3178 * Must fake it. Use the fileno, except when the 3179 * fsid is != to that of the directory. For that 3180 * case, generate a fake fileno that is not the same. 3181 */ 3182 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3183 gotmnton = 0; 3184 } 3185 3186 /* 3187 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3188 */ 3189 if (uiop->uio_offset == 0) { 3190 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3191 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3192 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3193 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3194 (void) nfsrv_putattrbit(nd, &attrbits); 3195 error = nfscl_request(nd, vp, p, cred, stuff); 3196 if (error) 3197 return (error); 3198 dotfileid = 0; /* Fake out the compiler. */ 3199 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3200 error = nfsm_loadattr(nd, &nfsva); 3201 if (error != 0) 3202 goto nfsmout; 3203 dctime = nfsva.na_ctime; 3204 dotfileid = nfsva.na_fileid; 3205 } 3206 if (nd->nd_repstat == 0) { 3207 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3208 len = fxdr_unsigned(int, *(tl + 4)); 3209 if (len > 0 && len <= NFSX_V4FHMAX) 3210 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3211 else 3212 error = EPERM; 3213 if (!error) { 3214 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3215 nfsva.na_mntonfileno = 0xffffffff; 3216 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3217 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3218 NULL, NULL, NULL, p, cred); 3219 if (error) { 3220 dotdotfileid = dotfileid; 3221 } else if (gotmnton) { 3222 if (nfsva.na_mntonfileno != 0xffffffff) 3223 dotdotfileid = nfsva.na_mntonfileno; 3224 else 3225 dotdotfileid = nfsva.na_fileid; 3226 } else if (nfsva.na_filesid[0] == 3227 dnp->n_vattr.na_filesid[0] && 3228 nfsva.na_filesid[1] == 3229 dnp->n_vattr.na_filesid[1]) { 3230 dotdotfileid = nfsva.na_fileid; 3231 } else { 3232 do { 3233 fakefileno--; 3234 } while (fakefileno == 3235 nfsva.na_fileid); 3236 dotdotfileid = fakefileno; 3237 } 3238 } 3239 } else if (nd->nd_repstat == NFSERR_NOENT) { 3240 /* 3241 * Lookupp returns NFSERR_NOENT when we are 3242 * at the root, so just use the current dir. 3243 */ 3244 nd->nd_repstat = 0; 3245 dotdotfileid = dotfileid; 3246 } else { 3247 error = nd->nd_repstat; 3248 } 3249 mbuf_freem(nd->nd_mrep); 3250 if (error) 3251 return (error); 3252 nd->nd_mrep = NULL; 3253 dp = (struct dirent *)uio_iov_base(uiop); 3254 dp->d_type = DT_DIR; 3255 dp->d_fileno = dotfileid; 3256 dp->d_namlen = 1; 3257 dp->d_name[0] = '.'; 3258 dp->d_name[1] = '\0'; 3259 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3260 /* 3261 * Just make these offset cookie 0. 3262 */ 3263 tl = (u_int32_t *)&dp->d_name[4]; 3264 *tl++ = 0; 3265 *tl = 0; 3266 blksiz += dp->d_reclen; 3267 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3268 uiop->uio_offset += dp->d_reclen; 3269 uio_iov_base_add(uiop, dp->d_reclen); 3270 uio_iov_len_add(uiop, -(dp->d_reclen)); 3271 dp = (struct dirent *)uio_iov_base(uiop); 3272 dp->d_type = DT_DIR; 3273 dp->d_fileno = dotdotfileid; 3274 dp->d_namlen = 2; 3275 dp->d_name[0] = '.'; 3276 dp->d_name[1] = '.'; 3277 dp->d_name[2] = '\0'; 3278 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3279 /* 3280 * Just make these offset cookie 0. 3281 */ 3282 tl = (u_int32_t *)&dp->d_name[4]; 3283 *tl++ = 0; 3284 *tl = 0; 3285 blksiz += dp->d_reclen; 3286 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3287 uiop->uio_offset += dp->d_reclen; 3288 uio_iov_base_add(uiop, dp->d_reclen); 3289 uio_iov_len_add(uiop, -(dp->d_reclen)); 3290 } 3291 NFSREADDIRPLUS_ATTRBIT(&attrbits); 3292 if (gotmnton) 3293 NFSSETBIT_ATTRBIT(&attrbits, 3294 NFSATTRBIT_MOUNTEDONFILEID); 3295 } 3296 3297 /* 3298 * Loop around doing readdir rpc's of size nm_readdirsize. 3299 * The stopping criteria is EOF or buffer full. 3300 */ 3301 while (more_dirs && bigenough) { 3302 *attrflagp = 0; 3303 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3304 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3305 *tl++ = cookie.lval[0]; 3306 *tl++ = cookie.lval[1]; 3307 if (cookie.qval == 0) { 3308 *tl++ = 0; 3309 *tl++ = 0; 3310 } else { 3311 NFSLOCKNODE(dnp); 3312 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3313 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3314 NFSUNLOCKNODE(dnp); 3315 } 3316 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3317 *tl = txdr_unsigned(nmp->nm_readdirsize); 3318 if (nd->nd_flag & ND_NFSV4) { 3319 (void) nfsrv_putattrbit(nd, &attrbits); 3320 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3321 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3322 (void) nfsrv_putattrbit(nd, &dattrbits); 3323 } 3324 error = nfscl_request(nd, vp, p, cred, stuff); 3325 if (error) 3326 return (error); 3327 if (nd->nd_flag & ND_NFSV3) 3328 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3329 if (nd->nd_repstat || error) { 3330 if (!error) 3331 error = nd->nd_repstat; 3332 goto nfsmout; 3333 } 3334 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 3335 dctime = nap->na_ctime; 3336 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3337 NFSLOCKNODE(dnp); 3338 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3339 dnp->n_cookieverf.nfsuquad[1] = *tl++; 3340 NFSUNLOCKNODE(dnp); 3341 more_dirs = fxdr_unsigned(int, *tl); 3342 if (!more_dirs) 3343 tryformoredirs = 0; 3344 3345 /* loop thru the dir entries, doctoring them to 4bsd form */ 3346 while (more_dirs && bigenough) { 3347 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3348 if (nd->nd_flag & ND_NFSV4) { 3349 ncookie.lval[0] = *tl++; 3350 ncookie.lval[1] = *tl++; 3351 } else { 3352 fileno = fxdr_unsigned(long, *++tl); 3353 tl++; 3354 } 3355 len = fxdr_unsigned(int, *tl); 3356 if (len <= 0 || len > NFS_MAXNAMLEN) { 3357 error = EBADRPC; 3358 goto nfsmout; 3359 } 3360 tlen = NFSM_RNDUP(len); 3361 if (tlen == len) 3362 tlen += 4; /* To ensure null termination */ 3363 left = DIRBLKSIZ - blksiz; 3364 if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) { 3365 dp->d_reclen += left; 3366 uio_iov_base_add(uiop, left); 3367 uio_iov_len_add(uiop, -(left)); 3368 uio_uio_resid_add(uiop, -(left)); 3369 uiop->uio_offset += left; 3370 blksiz = 0; 3371 } 3372 if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 3373 bigenough = 0; 3374 if (bigenough) { 3375 dp = (struct dirent *)uio_iov_base(uiop); 3376 dp->d_namlen = len; 3377 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 3378 dp->d_type = DT_UNKNOWN; 3379 blksiz += dp->d_reclen; 3380 if (blksiz == DIRBLKSIZ) 3381 blksiz = 0; 3382 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3383 uiop->uio_offset += DIRHDSIZ; 3384 uio_iov_base_add(uiop, DIRHDSIZ); 3385 uio_iov_len_add(uiop, -(DIRHDSIZ)); 3386 cnp->cn_nameptr = uio_iov_base(uiop); 3387 cnp->cn_namelen = len; 3388 NFSCNHASHZERO(cnp); 3389 error = nfsm_mbufuio(nd, uiop, len); 3390 if (error) 3391 goto nfsmout; 3392 cp = uio_iov_base(uiop); 3393 tlen -= len; 3394 *cp = '\0'; 3395 cp += tlen; /* points to cookie storage */ 3396 tl2 = (u_int32_t *)cp; 3397 if (len == 2 && cnp->cn_nameptr[0] == '.' && 3398 cnp->cn_nameptr[1] == '.') 3399 isdotdot = 1; 3400 else 3401 isdotdot = 0; 3402 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3403 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3404 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3405 uiop->uio_offset += (tlen + NFSX_HYPER); 3406 } else { 3407 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3408 if (error) 3409 goto nfsmout; 3410 } 3411 nfhp = NULL; 3412 if (nd->nd_flag & ND_NFSV3) { 3413 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3414 ncookie.lval[0] = *tl++; 3415 ncookie.lval[1] = *tl++; 3416 attrflag = fxdr_unsigned(int, *tl); 3417 if (attrflag) { 3418 error = nfsm_loadattr(nd, &nfsva); 3419 if (error) 3420 goto nfsmout; 3421 } 3422 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3423 if (*tl) { 3424 error = nfsm_getfh(nd, &nfhp); 3425 if (error) 3426 goto nfsmout; 3427 } 3428 if (!attrflag && nfhp != NULL) { 3429 FREE((caddr_t)nfhp, M_NFSFH); 3430 nfhp = NULL; 3431 } 3432 } else { 3433 rderr = 0; 3434 nfsva.na_mntonfileno = 0xffffffff; 3435 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3436 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3437 NULL, NULL, &rderr, p, cred); 3438 if (error) 3439 goto nfsmout; 3440 } 3441 3442 if (bigenough) { 3443 if (nd->nd_flag & ND_NFSV4) { 3444 if (rderr) { 3445 dp->d_fileno = 0; 3446 } else if (gotmnton) { 3447 if (nfsva.na_mntonfileno != 0xffffffff) 3448 dp->d_fileno = nfsva.na_mntonfileno; 3449 else 3450 dp->d_fileno = nfsva.na_fileid; 3451 } else if (nfsva.na_filesid[0] == 3452 dnp->n_vattr.na_filesid[0] && 3453 nfsva.na_filesid[1] == 3454 dnp->n_vattr.na_filesid[1]) { 3455 dp->d_fileno = nfsva.na_fileid; 3456 } else { 3457 do { 3458 fakefileno--; 3459 } while (fakefileno == 3460 nfsva.na_fileid); 3461 dp->d_fileno = fakefileno; 3462 } 3463 } else { 3464 dp->d_fileno = fileno; 3465 } 3466 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3467 ncookie.lval[0]; 3468 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3469 ncookie.lval[1]; 3470 3471 if (nfhp != NULL) { 3472 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3473 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3474 VREF(vp); 3475 newvp = vp; 3476 unlocknewvp = 0; 3477 FREE((caddr_t)nfhp, M_NFSFH); 3478 np = dnp; 3479 } else if (isdotdot != 0) { 3480 /* 3481 * Skip doing a nfscl_nget() call for "..". 3482 * There's a race between acquiring the nfs 3483 * node here and lookups that look for the 3484 * directory being read (in the parent). 3485 * It would try to get a lock on ".." here, 3486 * owning the lock on the directory being 3487 * read. Lookup will hold the lock on ".." 3488 * and try to acquire the lock on the 3489 * directory being read. 3490 * If the directory is unlocked/relocked, 3491 * then there is a LOR with the buflock 3492 * vp is relocked. 3493 */ 3494 free(nfhp, M_NFSFH); 3495 } else { 3496 error = nfscl_nget(vnode_mount(vp), vp, 3497 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 3498 if (!error) { 3499 newvp = NFSTOV(np); 3500 unlocknewvp = 1; 3501 } 3502 } 3503 nfhp = NULL; 3504 if (newvp != NULLVP) { 3505 error = nfscl_loadattrcache(&newvp, 3506 &nfsva, NULL, NULL, 0, 0); 3507 if (error) { 3508 if (unlocknewvp) 3509 vput(newvp); 3510 else 3511 vrele(newvp); 3512 goto nfsmout; 3513 } 3514 dp->d_type = 3515 vtonfs_dtype(np->n_vattr.na_type); 3516 ndp->ni_vp = newvp; 3517 NFSCNHASH(cnp, HASHINIT); 3518 if (cnp->cn_namelen <= NCHNAMLEN && 3519 (newvp->v_type != VDIR || 3520 dctime.tv_sec != 0)) { 3521 cache_enter_time(ndp->ni_dvp, 3522 ndp->ni_vp, cnp, 3523 &nfsva.na_ctime, 3524 newvp->v_type != VDIR ? NULL : 3525 &dctime); 3526 } 3527 if (unlocknewvp) 3528 vput(newvp); 3529 else 3530 vrele(newvp); 3531 newvp = NULLVP; 3532 } 3533 } 3534 } else if (nfhp != NULL) { 3535 FREE((caddr_t)nfhp, M_NFSFH); 3536 } 3537 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3538 more_dirs = fxdr_unsigned(int, *tl); 3539 } 3540 /* 3541 * If at end of rpc data, get the eof boolean 3542 */ 3543 if (!more_dirs) { 3544 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3545 eof = fxdr_unsigned(int, *tl); 3546 if (tryformoredirs) 3547 more_dirs = !eof; 3548 if (nd->nd_flag & ND_NFSV4) { 3549 error = nfscl_postop_attr(nd, nap, attrflagp, 3550 stuff); 3551 if (error) 3552 goto nfsmout; 3553 } 3554 } 3555 mbuf_freem(nd->nd_mrep); 3556 nd->nd_mrep = NULL; 3557 } 3558 /* 3559 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3560 * by increasing d_reclen for the last record. 3561 */ 3562 if (blksiz > 0) { 3563 left = DIRBLKSIZ - blksiz; 3564 dp->d_reclen += left; 3565 uio_iov_base_add(uiop, left); 3566 uio_iov_len_add(uiop, -(left)); 3567 uio_uio_resid_add(uiop, -(left)); 3568 uiop->uio_offset += left; 3569 } 3570 3571 /* 3572 * If returning no data, assume end of file. 3573 * If not bigenough, return not end of file, since you aren't 3574 * returning all the data 3575 * Otherwise, return the eof flag from the server. 3576 */ 3577 if (eofp != NULL) { 3578 if (tresid == uio_uio_resid(uiop)) 3579 *eofp = 1; 3580 else if (!bigenough) 3581 *eofp = 0; 3582 else 3583 *eofp = eof; 3584 } 3585 3586 /* 3587 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3588 */ 3589 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3590 dp = (struct dirent *)uio_iov_base(uiop); 3591 dp->d_type = DT_UNKNOWN; 3592 dp->d_fileno = 0; 3593 dp->d_namlen = 0; 3594 dp->d_name[0] = '\0'; 3595 tl = (u_int32_t *)&dp->d_name[4]; 3596 *tl++ = cookie.lval[0]; 3597 *tl = cookie.lval[1]; 3598 dp->d_reclen = DIRBLKSIZ; 3599 uio_iov_base_add(uiop, DIRBLKSIZ); 3600 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3601 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3602 uiop->uio_offset += DIRBLKSIZ; 3603 } 3604 3605 nfsmout: 3606 if (nd->nd_mrep != NULL) 3607 mbuf_freem(nd->nd_mrep); 3608 return (error); 3609 } 3610 #endif /* !APPLE */ 3611 3612 /* 3613 * Nfs commit rpc 3614 */ 3615 APPLESTATIC int 3616 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 3617 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 3618 { 3619 u_int32_t *tl; 3620 struct nfsrv_descript nfsd, *nd = &nfsd; 3621 nfsattrbit_t attrbits; 3622 int error; 3623 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3624 3625 *attrflagp = 0; 3626 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 3627 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3628 txdr_hyper(offset, tl); 3629 tl += 2; 3630 *tl = txdr_unsigned(cnt); 3631 if (nd->nd_flag & ND_NFSV4) { 3632 /* 3633 * And do a Getattr op. 3634 */ 3635 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3636 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3637 NFSGETATTR_ATTRBIT(&attrbits); 3638 (void) nfsrv_putattrbit(nd, &attrbits); 3639 } 3640 error = nfscl_request(nd, vp, p, cred, stuff); 3641 if (error) 3642 return (error); 3643 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 3644 if (!error && !nd->nd_repstat) { 3645 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3646 NFSLOCKMNT(nmp); 3647 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { 3648 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 3649 nd->nd_repstat = NFSERR_STALEWRITEVERF; 3650 } 3651 NFSUNLOCKMNT(nmp); 3652 if (nd->nd_flag & ND_NFSV4) 3653 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3654 } 3655 nfsmout: 3656 if (!error && nd->nd_repstat) 3657 error = nd->nd_repstat; 3658 mbuf_freem(nd->nd_mrep); 3659 return (error); 3660 } 3661 3662 /* 3663 * NFS byte range lock rpc. 3664 * (Mostly just calls one of the three lower level RPC routines.) 3665 */ 3666 APPLESTATIC int 3667 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 3668 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3669 { 3670 struct nfscllockowner *lp; 3671 struct nfsclclient *clp; 3672 struct nfsfh *nfhp; 3673 struct nfsrv_descript nfsd, *nd = &nfsd; 3674 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3675 u_int64_t off, len; 3676 off_t start, end; 3677 u_int32_t clidrev = 0; 3678 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 3679 int callcnt, dorpc; 3680 3681 /* 3682 * Convert the flock structure into a start and end and do POSIX 3683 * bounds checking. 3684 */ 3685 switch (fl->l_whence) { 3686 case SEEK_SET: 3687 case SEEK_CUR: 3688 /* 3689 * Caller is responsible for adding any necessary offset 3690 * when SEEK_CUR is used. 3691 */ 3692 start = fl->l_start; 3693 off = fl->l_start; 3694 break; 3695 case SEEK_END: 3696 start = size + fl->l_start; 3697 off = size + fl->l_start; 3698 break; 3699 default: 3700 return (EINVAL); 3701 }; 3702 if (start < 0) 3703 return (EINVAL); 3704 if (fl->l_len != 0) { 3705 end = start + fl->l_len - 1; 3706 if (end < start) 3707 return (EINVAL); 3708 } 3709 3710 len = fl->l_len; 3711 if (len == 0) 3712 len = NFS64BITSSET; 3713 retrycnt = 0; 3714 do { 3715 nd->nd_repstat = 0; 3716 if (op == F_GETLK) { 3717 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3718 if (error) 3719 return (error); 3720 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 3721 if (!error) { 3722 clidrev = clp->nfsc_clientidrev; 3723 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 3724 p, id, flags); 3725 } else if (error == -1) { 3726 error = 0; 3727 } 3728 nfscl_clientrelease(clp); 3729 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 3730 /* 3731 * We must loop around for all lockowner cases. 3732 */ 3733 callcnt = 0; 3734 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3735 if (error) 3736 return (error); 3737 do { 3738 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 3739 clp, id, flags, &lp, &dorpc); 3740 /* 3741 * If it returns a NULL lp, we're done. 3742 */ 3743 if (lp == NULL) { 3744 if (callcnt == 0) 3745 nfscl_clientrelease(clp); 3746 else 3747 nfscl_releasealllocks(clp, vp, p, id, flags); 3748 return (error); 3749 } 3750 if (nmp->nm_clp != NULL) 3751 clidrev = nmp->nm_clp->nfsc_clientidrev; 3752 else 3753 clidrev = 0; 3754 /* 3755 * If the server doesn't support Posix lock semantics, 3756 * only allow locks on the entire file, since it won't 3757 * handle overlapping byte ranges. 3758 * There might still be a problem when a lock 3759 * upgrade/downgrade (read<->write) occurs, since the 3760 * server "might" expect an unlock first? 3761 */ 3762 if (dorpc && (lp->nfsl_open->nfso_posixlock || 3763 (off == 0 && len == NFS64BITSSET))) { 3764 /* 3765 * Since the lock records will go away, we must 3766 * wait for grace and delay here. 3767 */ 3768 do { 3769 error = nfsrpc_locku(nd, nmp, lp, off, len, 3770 NFSV4LOCKT_READ, cred, p, 0); 3771 if ((nd->nd_repstat == NFSERR_GRACE || 3772 nd->nd_repstat == NFSERR_DELAY) && 3773 error == 0) 3774 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3775 "nfs_advlock"); 3776 } while ((nd->nd_repstat == NFSERR_GRACE || 3777 nd->nd_repstat == NFSERR_DELAY) && error == 0); 3778 } 3779 callcnt++; 3780 } while (error == 0 && nd->nd_repstat == 0); 3781 nfscl_releasealllocks(clp, vp, p, id, flags); 3782 } else if (op == F_SETLK) { 3783 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 3784 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 3785 if (error || donelocally) { 3786 return (error); 3787 } 3788 if (nmp->nm_clp != NULL) 3789 clidrev = nmp->nm_clp->nfsc_clientidrev; 3790 else 3791 clidrev = 0; 3792 nfhp = VTONFS(vp)->n_fhp; 3793 if (!lp->nfsl_open->nfso_posixlock && 3794 (off != 0 || len != NFS64BITSSET)) { 3795 error = EINVAL; 3796 } else { 3797 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 3798 nfhp->nfh_len, lp, newone, reclaim, off, 3799 len, fl->l_type, cred, p, 0); 3800 } 3801 if (!error) 3802 error = nd->nd_repstat; 3803 nfscl_lockrelease(lp, error, newone); 3804 } else { 3805 error = EINVAL; 3806 } 3807 if (!error) 3808 error = nd->nd_repstat; 3809 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 3810 error == NFSERR_STALEDONTRECOVER || 3811 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3812 error == NFSERR_BADSESSION) { 3813 (void) nfs_catnap(PZERO, error, "nfs_advlock"); 3814 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 3815 && clidrev != 0) { 3816 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 3817 retrycnt++; 3818 } 3819 } while (error == NFSERR_GRACE || 3820 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3821 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 3822 error == NFSERR_BADSESSION || 3823 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 3824 expireret == 0 && clidrev != 0 && retrycnt < 4)); 3825 if (error && retrycnt >= 4) 3826 error = EIO; 3827 return (error); 3828 } 3829 3830 /* 3831 * The lower level routine for the LockT case. 3832 */ 3833 APPLESTATIC int 3834 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 3835 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 3836 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3837 { 3838 u_int32_t *tl; 3839 int error, type, size; 3840 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3841 struct nfsnode *np; 3842 struct nfsmount *nmp; 3843 3844 nmp = VFSTONFS(vp->v_mount); 3845 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 3846 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3847 if (fl->l_type == F_RDLCK) 3848 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3849 else 3850 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3851 txdr_hyper(off, tl); 3852 tl += 2; 3853 txdr_hyper(len, tl); 3854 tl += 2; 3855 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 3856 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 3857 nfscl_filllockowner(id, own, flags); 3858 np = VTONFS(vp); 3859 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 3860 np->n_fhp->nfh_len); 3861 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 3862 error = nfscl_request(nd, vp, p, cred, NULL); 3863 if (error) 3864 return (error); 3865 if (nd->nd_repstat == 0) { 3866 fl->l_type = F_UNLCK; 3867 } else if (nd->nd_repstat == NFSERR_DENIED) { 3868 nd->nd_repstat = 0; 3869 fl->l_whence = SEEK_SET; 3870 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3871 fl->l_start = fxdr_hyper(tl); 3872 tl += 2; 3873 len = fxdr_hyper(tl); 3874 tl += 2; 3875 if (len == NFS64BITSSET) 3876 fl->l_len = 0; 3877 else 3878 fl->l_len = len; 3879 type = fxdr_unsigned(int, *tl++); 3880 if (type == NFSV4LOCKT_WRITE) 3881 fl->l_type = F_WRLCK; 3882 else 3883 fl->l_type = F_RDLCK; 3884 /* 3885 * XXX For now, I have no idea what to do with the 3886 * conflicting lock_owner, so I'll just set the pid == 0 3887 * and skip over the lock_owner. 3888 */ 3889 fl->l_pid = (pid_t)0; 3890 tl += 2; 3891 size = fxdr_unsigned(int, *tl); 3892 if (size < 0 || size > NFSV4_OPAQUELIMIT) 3893 error = EBADRPC; 3894 if (!error) 3895 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3896 } else if (nd->nd_repstat == NFSERR_STALECLIENTID || 3897 nd->nd_repstat == NFSERR_BADSESSION) 3898 nfscl_initiate_recovery(clp); 3899 nfsmout: 3900 mbuf_freem(nd->nd_mrep); 3901 return (error); 3902 } 3903 3904 /* 3905 * Lower level function that performs the LockU RPC. 3906 */ 3907 static int 3908 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 3909 struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 3910 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 3911 { 3912 u_int32_t *tl; 3913 int error; 3914 3915 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 3916 lp->nfsl_open->nfso_fhlen, NULL, NULL); 3917 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3918 *tl++ = txdr_unsigned(type); 3919 *tl = txdr_unsigned(lp->nfsl_seqid); 3920 if (nfstest_outofseq && 3921 (arc4random() % nfstest_outofseq) == 0) 3922 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 3923 tl++; 3924 if (NFSHASNFSV4N(nmp)) 3925 *tl++ = 0; 3926 else 3927 *tl++ = lp->nfsl_stateid.seqid; 3928 *tl++ = lp->nfsl_stateid.other[0]; 3929 *tl++ = lp->nfsl_stateid.other[1]; 3930 *tl++ = lp->nfsl_stateid.other[2]; 3931 txdr_hyper(off, tl); 3932 tl += 2; 3933 txdr_hyper(len, tl); 3934 if (syscred) 3935 nd->nd_flag |= ND_USEGSSNAME; 3936 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 3937 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 3938 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 3939 if (error) 3940 return (error); 3941 if (nd->nd_repstat == 0) { 3942 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3943 lp->nfsl_stateid.seqid = *tl++; 3944 lp->nfsl_stateid.other[0] = *tl++; 3945 lp->nfsl_stateid.other[1] = *tl++; 3946 lp->nfsl_stateid.other[2] = *tl; 3947 } else if (nd->nd_repstat == NFSERR_STALESTATEID || 3948 nd->nd_repstat == NFSERR_BADSESSION) 3949 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 3950 nfsmout: 3951 mbuf_freem(nd->nd_mrep); 3952 return (error); 3953 } 3954 3955 /* 3956 * The actual Lock RPC. 3957 */ 3958 APPLESTATIC int 3959 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 3960 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 3961 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 3962 NFSPROC_T *p, int syscred) 3963 { 3964 u_int32_t *tl; 3965 int error, size; 3966 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3967 3968 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL); 3969 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3970 if (type == F_RDLCK) 3971 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3972 else 3973 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3974 *tl++ = txdr_unsigned(reclaim); 3975 txdr_hyper(off, tl); 3976 tl += 2; 3977 txdr_hyper(len, tl); 3978 tl += 2; 3979 if (newone) { 3980 *tl = newnfs_true; 3981 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3982 2 * NFSX_UNSIGNED + NFSX_HYPER); 3983 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 3984 if (NFSHASNFSV4N(nmp)) 3985 *tl++ = 0; 3986 else 3987 *tl++ = lp->nfsl_open->nfso_stateid.seqid; 3988 *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 3989 *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 3990 *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 3991 *tl++ = txdr_unsigned(lp->nfsl_seqid); 3992 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 3993 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 3994 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 3995 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 3996 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 3997 } else { 3998 *tl = newnfs_false; 3999 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 4000 if (NFSHASNFSV4N(nmp)) 4001 *tl++ = 0; 4002 else 4003 *tl++ = lp->nfsl_stateid.seqid; 4004 *tl++ = lp->nfsl_stateid.other[0]; 4005 *tl++ = lp->nfsl_stateid.other[1]; 4006 *tl++ = lp->nfsl_stateid.other[2]; 4007 *tl = txdr_unsigned(lp->nfsl_seqid); 4008 if (nfstest_outofseq && 4009 (arc4random() % nfstest_outofseq) == 0) 4010 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4011 } 4012 if (syscred) 4013 nd->nd_flag |= ND_USEGSSNAME; 4014 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 4015 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4016 if (error) 4017 return (error); 4018 if (newone) 4019 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 4020 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4021 if (nd->nd_repstat == 0) { 4022 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4023 lp->nfsl_stateid.seqid = *tl++; 4024 lp->nfsl_stateid.other[0] = *tl++; 4025 lp->nfsl_stateid.other[1] = *tl++; 4026 lp->nfsl_stateid.other[2] = *tl; 4027 } else if (nd->nd_repstat == NFSERR_DENIED) { 4028 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4029 size = fxdr_unsigned(int, *(tl + 7)); 4030 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4031 error = EBADRPC; 4032 if (!error) 4033 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4034 } else if (nd->nd_repstat == NFSERR_STALESTATEID || 4035 nd->nd_repstat == NFSERR_BADSESSION) 4036 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4037 nfsmout: 4038 mbuf_freem(nd->nd_mrep); 4039 return (error); 4040 } 4041 4042 /* 4043 * nfs statfs rpc 4044 * (always called with the vp for the mount point) 4045 */ 4046 APPLESTATIC int 4047 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 4048 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4049 void *stuff) 4050 { 4051 u_int32_t *tl = NULL; 4052 struct nfsrv_descript nfsd, *nd = &nfsd; 4053 struct nfsmount *nmp; 4054 nfsattrbit_t attrbits; 4055 int error; 4056 4057 *attrflagp = 0; 4058 nmp = VFSTONFS(vnode_mount(vp)); 4059 if (NFSHASNFSV4(nmp)) { 4060 /* 4061 * For V4, you actually do a getattr. 4062 */ 4063 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4064 NFSSTATFS_GETATTRBIT(&attrbits); 4065 (void) nfsrv_putattrbit(nd, &attrbits); 4066 nd->nd_flag |= ND_USEGSSNAME; 4067 error = nfscl_request(nd, vp, p, cred, stuff); 4068 if (error) 4069 return (error); 4070 if (nd->nd_repstat == 0) { 4071 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4072 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 4073 cred); 4074 if (!error) { 4075 nmp->nm_fsid[0] = nap->na_filesid[0]; 4076 nmp->nm_fsid[1] = nap->na_filesid[1]; 4077 NFSSETHASSETFSID(nmp); 4078 *attrflagp = 1; 4079 } 4080 } else { 4081 error = nd->nd_repstat; 4082 } 4083 if (error) 4084 goto nfsmout; 4085 } else { 4086 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 4087 error = nfscl_request(nd, vp, p, cred, stuff); 4088 if (error) 4089 return (error); 4090 if (nd->nd_flag & ND_NFSV3) { 4091 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4092 if (error) 4093 goto nfsmout; 4094 } 4095 if (nd->nd_repstat) { 4096 error = nd->nd_repstat; 4097 goto nfsmout; 4098 } 4099 NFSM_DISSECT(tl, u_int32_t *, 4100 NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 4101 } 4102 if (NFSHASNFSV3(nmp)) { 4103 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 4104 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 4105 sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 4106 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 4107 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 4108 sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 4109 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 4110 } else if (NFSHASNFSV4(nmp) == 0) { 4111 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 4112 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 4113 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 4114 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 4115 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 4116 } 4117 nfsmout: 4118 mbuf_freem(nd->nd_mrep); 4119 return (error); 4120 } 4121 4122 /* 4123 * nfs pathconf rpc 4124 */ 4125 APPLESTATIC int 4126 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 4127 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4128 void *stuff) 4129 { 4130 struct nfsrv_descript nfsd, *nd = &nfsd; 4131 struct nfsmount *nmp; 4132 u_int32_t *tl; 4133 nfsattrbit_t attrbits; 4134 int error; 4135 4136 *attrflagp = 0; 4137 nmp = VFSTONFS(vnode_mount(vp)); 4138 if (NFSHASNFSV4(nmp)) { 4139 /* 4140 * For V4, you actually do a getattr. 4141 */ 4142 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4143 NFSPATHCONF_GETATTRBIT(&attrbits); 4144 (void) nfsrv_putattrbit(nd, &attrbits); 4145 nd->nd_flag |= ND_USEGSSNAME; 4146 error = nfscl_request(nd, vp, p, cred, stuff); 4147 if (error) 4148 return (error); 4149 if (nd->nd_repstat == 0) { 4150 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4151 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 4152 cred); 4153 if (!error) 4154 *attrflagp = 1; 4155 } else { 4156 error = nd->nd_repstat; 4157 } 4158 } else { 4159 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 4160 error = nfscl_request(nd, vp, p, cred, stuff); 4161 if (error) 4162 return (error); 4163 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4164 if (nd->nd_repstat && !error) 4165 error = nd->nd_repstat; 4166 if (!error) { 4167 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 4168 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 4169 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 4170 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 4171 pc->pc_chownrestricted = 4172 fxdr_unsigned(u_int32_t, *tl++); 4173 pc->pc_caseinsensitive = 4174 fxdr_unsigned(u_int32_t, *tl++); 4175 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 4176 } 4177 } 4178 nfsmout: 4179 mbuf_freem(nd->nd_mrep); 4180 return (error); 4181 } 4182 4183 /* 4184 * nfs version 3 fsinfo rpc call 4185 */ 4186 APPLESTATIC int 4187 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 4188 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 4189 { 4190 u_int32_t *tl; 4191 struct nfsrv_descript nfsd, *nd = &nfsd; 4192 int error; 4193 4194 *attrflagp = 0; 4195 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 4196 error = nfscl_request(nd, vp, p, cred, stuff); 4197 if (error) 4198 return (error); 4199 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4200 if (nd->nd_repstat && !error) 4201 error = nd->nd_repstat; 4202 if (!error) { 4203 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 4204 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 4205 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 4206 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 4207 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 4208 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 4209 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 4210 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 4211 fsp->fs_maxfilesize = fxdr_hyper(tl); 4212 tl += 2; 4213 fxdr_nfsv3time(tl, &fsp->fs_timedelta); 4214 tl += 2; 4215 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 4216 } 4217 nfsmout: 4218 mbuf_freem(nd->nd_mrep); 4219 return (error); 4220 } 4221 4222 /* 4223 * This function performs the Renew RPC. 4224 */ 4225 APPLESTATIC int 4226 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, 4227 NFSPROC_T *p) 4228 { 4229 u_int32_t *tl; 4230 struct nfsrv_descript nfsd; 4231 struct nfsrv_descript *nd = &nfsd; 4232 struct nfsmount *nmp; 4233 int error; 4234 struct nfssockreq *nrp; 4235 4236 nmp = clp->nfsc_nmp; 4237 if (nmp == NULL) 4238 return (0); 4239 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, 4240 &dsp->nfsclds_sess); 4241 if (!NFSHASNFSV4N(nmp)) { 4242 /* NFSv4.1 just uses a Sequence Op and not a Renew. */ 4243 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4244 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 4245 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 4246 } 4247 nrp = dsp->nfsclds_sockp; 4248 if (nrp == NULL) 4249 /* If NULL, use the MDS socket. */ 4250 nrp = &nmp->nm_sockreq; 4251 nd->nd_flag |= ND_USEGSSNAME; 4252 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4253 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 4254 if (error) 4255 return (error); 4256 error = nd->nd_repstat; 4257 mbuf_freem(nd->nd_mrep); 4258 return (error); 4259 } 4260 4261 /* 4262 * This function performs the Releaselockowner RPC. 4263 */ 4264 APPLESTATIC int 4265 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4266 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4267 { 4268 struct nfsrv_descript nfsd, *nd = &nfsd; 4269 u_int32_t *tl; 4270 int error; 4271 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4272 4273 if (NFSHASNFSV4N(nmp)) { 4274 /* For NFSv4.1, do a FreeStateID. */ 4275 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, 4276 NULL); 4277 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); 4278 } else { 4279 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, 4280 NULL); 4281 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4282 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 4283 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 4284 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4285 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4286 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4287 } 4288 nd->nd_flag |= ND_USEGSSNAME; 4289 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4290 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4291 if (error) 4292 return (error); 4293 error = nd->nd_repstat; 4294 mbuf_freem(nd->nd_mrep); 4295 return (error); 4296 } 4297 4298 /* 4299 * This function performs the Compound to get the mount pt FH. 4300 */ 4301 APPLESTATIC int 4302 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4303 NFSPROC_T *p) 4304 { 4305 u_int32_t *tl; 4306 struct nfsrv_descript nfsd; 4307 struct nfsrv_descript *nd = &nfsd; 4308 u_char *cp, *cp2; 4309 int error, cnt, len, setnil; 4310 u_int32_t *opcntp; 4311 4312 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL); 4313 cp = dirpath; 4314 cnt = 0; 4315 do { 4316 setnil = 0; 4317 while (*cp == '/') 4318 cp++; 4319 cp2 = cp; 4320 while (*cp2 != '\0' && *cp2 != '/') 4321 cp2++; 4322 if (*cp2 == '/') { 4323 setnil = 1; 4324 *cp2 = '\0'; 4325 } 4326 if (cp2 != cp) { 4327 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4328 *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4329 nfsm_strtom(nd, cp, strlen(cp)); 4330 cnt++; 4331 } 4332 if (setnil) 4333 *cp2++ = '/'; 4334 cp = cp2; 4335 } while (*cp != '\0'); 4336 if (NFSHASNFSV4N(nmp)) 4337 /* Has a Sequence Op done by nfscl_reqstart(). */ 4338 *opcntp = txdr_unsigned(3 + cnt); 4339 else 4340 *opcntp = txdr_unsigned(2 + cnt); 4341 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4342 *tl = txdr_unsigned(NFSV4OP_GETFH); 4343 nd->nd_flag |= ND_USEGSSNAME; 4344 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4345 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4346 if (error) 4347 return (error); 4348 if (nd->nd_repstat == 0) { 4349 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4350 tl += (2 + 2 * cnt); 4351 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4352 len > NFSX_FHMAX) { 4353 nd->nd_repstat = NFSERR_BADXDR; 4354 } else { 4355 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4356 if (nd->nd_repstat == 0) 4357 nmp->nm_fhsize = len; 4358 } 4359 } 4360 error = nd->nd_repstat; 4361 nfsmout: 4362 mbuf_freem(nd->nd_mrep); 4363 return (error); 4364 } 4365 4366 /* 4367 * This function performs the Delegreturn RPC. 4368 */ 4369 APPLESTATIC int 4370 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4371 struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4372 { 4373 u_int32_t *tl; 4374 struct nfsrv_descript nfsd; 4375 struct nfsrv_descript *nd = &nfsd; 4376 int error; 4377 4378 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4379 dp->nfsdl_fhlen, NULL, NULL); 4380 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4381 if (NFSHASNFSV4N(nmp)) 4382 *tl++ = 0; 4383 else 4384 *tl++ = dp->nfsdl_stateid.seqid; 4385 *tl++ = dp->nfsdl_stateid.other[0]; 4386 *tl++ = dp->nfsdl_stateid.other[1]; 4387 *tl = dp->nfsdl_stateid.other[2]; 4388 if (syscred) 4389 nd->nd_flag |= ND_USEGSSNAME; 4390 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4391 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4392 if (error) 4393 return (error); 4394 error = nd->nd_repstat; 4395 mbuf_freem(nd->nd_mrep); 4396 return (error); 4397 } 4398 4399 /* 4400 * nfs getacl call. 4401 */ 4402 APPLESTATIC int 4403 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4404 struct acl *aclp, void *stuff) 4405 { 4406 struct nfsrv_descript nfsd, *nd = &nfsd; 4407 int error; 4408 nfsattrbit_t attrbits; 4409 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4410 4411 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4412 return (EOPNOTSUPP); 4413 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4414 NFSZERO_ATTRBIT(&attrbits); 4415 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4416 (void) nfsrv_putattrbit(nd, &attrbits); 4417 error = nfscl_request(nd, vp, p, cred, stuff); 4418 if (error) 4419 return (error); 4420 if (!nd->nd_repstat) 4421 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4422 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4423 else 4424 error = nd->nd_repstat; 4425 mbuf_freem(nd->nd_mrep); 4426 return (error); 4427 } 4428 4429 /* 4430 * nfs setacl call. 4431 */ 4432 APPLESTATIC int 4433 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4434 struct acl *aclp, void *stuff) 4435 { 4436 int error; 4437 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4438 4439 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4440 return (EOPNOTSUPP); 4441 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4442 return (error); 4443 } 4444 4445 /* 4446 * nfs setacl call. 4447 */ 4448 static int 4449 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4450 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 4451 { 4452 struct nfsrv_descript nfsd, *nd = &nfsd; 4453 int error; 4454 nfsattrbit_t attrbits; 4455 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4456 4457 if (!NFSHASNFSV4(nmp)) 4458 return (EOPNOTSUPP); 4459 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 4460 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 4461 NFSZERO_ATTRBIT(&attrbits); 4462 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4463 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0, 4464 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0); 4465 error = nfscl_request(nd, vp, p, cred, stuff); 4466 if (error) 4467 return (error); 4468 /* Don't care about the pre/postop attributes */ 4469 mbuf_freem(nd->nd_mrep); 4470 return (nd->nd_repstat); 4471 } 4472 4473 /* 4474 * Do the NFSv4.1 Exchange ID. 4475 */ 4476 int 4477 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, 4478 struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp, 4479 struct ucred *cred, NFSPROC_T *p) 4480 { 4481 uint32_t *tl, v41flags; 4482 struct nfsrv_descript nfsd; 4483 struct nfsrv_descript *nd = &nfsd; 4484 struct nfsclds *dsp; 4485 struct timespec verstime; 4486 int error, len; 4487 4488 *dspp = NULL; 4489 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL); 4490 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4491 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ 4492 *tl = txdr_unsigned(clp->nfsc_rev); 4493 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 4494 4495 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4496 *tl++ = txdr_unsigned(exchflags); 4497 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); 4498 4499 /* Set the implementation id4 */ 4500 *tl = txdr_unsigned(1); 4501 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4502 (void) nfsm_strtom(nd, version, strlen(version)); 4503 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4504 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4505 verstime.tv_nsec = 0; 4506 txdr_nfsv4time(&verstime, tl); 4507 nd->nd_flag |= ND_USEGSSNAME; 4508 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4509 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4510 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, 4511 (int)nd->nd_repstat); 4512 if (error != 0) 4513 return (error); 4514 if (nd->nd_repstat == 0) { 4515 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); 4516 len = fxdr_unsigned(int, *(tl + 7)); 4517 if (len < 0 || len > NFSV4_OPAQUELIMIT) { 4518 error = NFSERR_BADXDR; 4519 goto nfsmout; 4520 } 4521 dsp = malloc(sizeof(struct nfsclds) + len, M_NFSCLDS, 4522 M_WAITOK | M_ZERO); 4523 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; 4524 dsp->nfsclds_servownlen = len; 4525 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; 4526 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; 4527 dsp->nfsclds_sess.nfsess_sequenceid = 4528 fxdr_unsigned(uint32_t, *tl++); 4529 v41flags = fxdr_unsigned(uint32_t, *tl); 4530 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && 4531 NFSHASPNFSOPT(nmp)) { 4532 NFSCL_DEBUG(1, "set PNFS\n"); 4533 NFSLOCKMNT(nmp); 4534 nmp->nm_state |= NFSSTA_PNFS; 4535 NFSUNLOCKMNT(nmp); 4536 dsp->nfsclds_flags |= NFSCLDS_MDS; 4537 } 4538 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) 4539 dsp->nfsclds_flags |= NFSCLDS_DS; 4540 if (len > 0) 4541 nd->nd_repstat = nfsrv_mtostr(nd, 4542 dsp->nfsclds_serverown, len); 4543 if (nd->nd_repstat == 0) { 4544 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 4545 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 4546 NULL, MTX_DEF); 4547 nfscl_initsessionslots(&dsp->nfsclds_sess); 4548 *dspp = dsp; 4549 } else 4550 free(dsp, M_NFSCLDS); 4551 } 4552 error = nd->nd_repstat; 4553 nfsmout: 4554 mbuf_freem(nd->nd_mrep); 4555 return (error); 4556 } 4557 4558 /* 4559 * Do the NFSv4.1 Create Session. 4560 */ 4561 int 4562 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, 4563 struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred, 4564 NFSPROC_T *p) 4565 { 4566 uint32_t crflags, *tl; 4567 struct nfsrv_descript nfsd; 4568 struct nfsrv_descript *nd = &nfsd; 4569 int error, irdcnt; 4570 4571 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL); 4572 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4573 *tl++ = sep->nfsess_clientid.lval[0]; 4574 *tl++ = sep->nfsess_clientid.lval[1]; 4575 *tl++ = txdr_unsigned(sequenceid); 4576 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); 4577 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0) 4578 crflags |= NFSV4CRSESS_CONNBACKCHAN; 4579 *tl = txdr_unsigned(crflags); 4580 4581 /* Fill in fore channel attributes. */ 4582 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4583 *tl++ = 0; /* Header pad size */ 4584 *tl++ = txdr_unsigned(100000); /* Max request size */ 4585 *tl++ = txdr_unsigned(100000); /* Max response size */ 4586 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4587 *tl++ = txdr_unsigned(20); /* Max operations */ 4588 *tl++ = txdr_unsigned(64); /* Max slots */ 4589 *tl = 0; /* No rdma ird */ 4590 4591 /* Fill in back channel attributes. */ 4592 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4593 *tl++ = 0; /* Header pad size */ 4594 *tl++ = txdr_unsigned(10000); /* Max request size */ 4595 *tl++ = txdr_unsigned(10000); /* Max response size */ 4596 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4597 *tl++ = txdr_unsigned(4); /* Max operations */ 4598 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ 4599 *tl = 0; /* No rdma ird */ 4600 4601 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); 4602 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ 4603 4604 /* Allow AUTH_SYS callbacks as uid, gid == 0. */ 4605 *tl++ = txdr_unsigned(1); /* Auth_sys only */ 4606 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ 4607 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ 4608 *tl++ = 0; /* Null machine name */ 4609 *tl++ = 0; /* Uid == 0 */ 4610 *tl++ = 0; /* Gid == 0 */ 4611 *tl = 0; /* No additional gids */ 4612 nd->nd_flag |= ND_USEGSSNAME; 4613 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, 4614 NFS_VER4, NULL, 1, NULL, NULL); 4615 if (error != 0) 4616 return (error); 4617 if (nd->nd_repstat == 0) { 4618 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 4619 2 * NFSX_UNSIGNED); 4620 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); 4621 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4622 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); 4623 crflags = fxdr_unsigned(uint32_t, *tl); 4624 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { 4625 NFSLOCKMNT(nmp); 4626 nmp->nm_state |= NFSSTA_SESSPERSIST; 4627 NFSUNLOCKMNT(nmp); 4628 } 4629 4630 /* Get the fore channel slot count. */ 4631 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4632 tl += 3; /* Skip the other counts. */ 4633 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); 4634 tl++; 4635 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); 4636 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); 4637 irdcnt = fxdr_unsigned(int, *tl); 4638 if (irdcnt > 0) 4639 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 4640 4641 /* and the back channel slot count. */ 4642 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4643 tl += 5; 4644 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 4645 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 4646 } 4647 error = nd->nd_repstat; 4648 nfsmout: 4649 mbuf_freem(nd->nd_mrep); 4650 return (error); 4651 } 4652 4653 /* 4654 * Do the NFSv4.1 Destroy Session. 4655 */ 4656 int 4657 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp, 4658 struct ucred *cred, NFSPROC_T *p) 4659 { 4660 uint32_t *tl; 4661 struct nfsrv_descript nfsd; 4662 struct nfsrv_descript *nd = &nfsd; 4663 int error; 4664 4665 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL); 4666 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4667 bcopy(NFSMNT_MDSSESSION(nmp)->nfsess_sessionid, tl, NFSX_V4SESSIONID); 4668 nd->nd_flag |= ND_USEGSSNAME; 4669 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4670 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4671 if (error != 0) 4672 return (error); 4673 error = nd->nd_repstat; 4674 mbuf_freem(nd->nd_mrep); 4675 return (error); 4676 } 4677 4678 /* 4679 * Do the NFSv4.1 Destroy Client. 4680 */ 4681 int 4682 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 4683 struct ucred *cred, NFSPROC_T *p) 4684 { 4685 uint32_t *tl; 4686 struct nfsrv_descript nfsd; 4687 struct nfsrv_descript *nd = &nfsd; 4688 int error; 4689 4690 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL); 4691 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4692 *tl++ = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[0]; 4693 *tl = NFSMNT_MDSSESSION(nmp)->nfsess_clientid.lval[1]; 4694 nd->nd_flag |= ND_USEGSSNAME; 4695 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4696 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4697 if (error != 0) 4698 return (error); 4699 error = nd->nd_repstat; 4700 mbuf_freem(nd->nd_mrep); 4701 return (error); 4702 } 4703 4704 /* 4705 * Do the NFSv4.1 LayoutGet. 4706 */ 4707 int 4708 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 4709 uint64_t offset, uint64_t len, uint64_t minlen, int layoutlen, 4710 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp, 4711 struct ucred *cred, NFSPROC_T *p, void *stuff) 4712 { 4713 uint32_t *tl; 4714 struct nfsrv_descript nfsd, *nd = &nfsd; 4715 struct nfsfh *nfhp; 4716 struct nfsclflayout *flp, *prevflp, *tflp; 4717 int cnt, error, gotiomode, fhcnt, nfhlen, i, j; 4718 uint8_t *cp; 4719 uint64_t retlen; 4720 4721 flp = NULL; 4722 gotiomode = -1; 4723 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL); 4724 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 4725 NFSX_STATEID); 4726 *tl++ = newnfs_false; /* Don't signal availability. */ 4727 *tl++ = txdr_unsigned(NFSLAYOUT_NFSV4_1_FILES); 4728 *tl++ = txdr_unsigned(iomode); 4729 txdr_hyper(offset, tl); 4730 tl += 2; 4731 txdr_hyper(len, tl); 4732 tl += 2; 4733 txdr_hyper(minlen, tl); 4734 tl += 2; 4735 *tl++ = txdr_unsigned(stateidp->seqid); 4736 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 4737 *tl++ = stateidp->other[0]; 4738 *tl++ = stateidp->other[1]; 4739 *tl++ = stateidp->other[2]; 4740 *tl = txdr_unsigned(layoutlen); 4741 nd->nd_flag |= ND_USEGSSNAME; 4742 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4743 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4744 if (error != 0) 4745 return (error); 4746 if (nd->nd_repstat == 0) { 4747 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 4748 if (*tl++ != 0) 4749 *retonclosep = 1; 4750 else 4751 *retonclosep = 0; 4752 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 4753 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 4754 (int)stateidp->seqid); 4755 stateidp->other[0] = *tl++; 4756 stateidp->other[1] = *tl++; 4757 stateidp->other[2] = *tl++; 4758 cnt = fxdr_unsigned(int, *tl); 4759 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 4760 if (cnt <= 0 || cnt > 10000) { 4761 /* Don't accept more than 10000 layouts in reply. */ 4762 error = NFSERR_BADXDR; 4763 goto nfsmout; 4764 } 4765 for (i = 0; i < cnt; i++) { 4766 /* Dissect all the way to the file handle cnt. */ 4767 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_HYPER + 4768 6 * NFSX_UNSIGNED + NFSX_V4DEVICEID); 4769 fhcnt = fxdr_unsigned(int, *(tl + 11 + 4770 NFSX_V4DEVICEID / NFSX_UNSIGNED)); 4771 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 4772 if (fhcnt < 0 || fhcnt > 100) { 4773 /* Don't accept more than 100 file handles. */ 4774 error = NFSERR_BADXDR; 4775 goto nfsmout; 4776 } 4777 if (fhcnt > 1) 4778 flp = malloc(sizeof(*flp) + (fhcnt - 1) * 4779 sizeof(struct nfsfh *), 4780 M_NFSFLAYOUT, M_WAITOK); 4781 else 4782 flp = malloc(sizeof(*flp), 4783 M_NFSFLAYOUT, M_WAITOK); 4784 flp->nfsfl_flags = 0; 4785 flp->nfsfl_fhcnt = 0; 4786 flp->nfsfl_devp = NULL; 4787 flp->nfsfl_off = fxdr_hyper(tl); tl += 2; 4788 retlen = fxdr_hyper(tl); tl += 2; 4789 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 4790 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 4791 else 4792 flp->nfsfl_end = flp->nfsfl_off + retlen; 4793 flp->nfsfl_iomode = fxdr_unsigned(int, *tl++); 4794 if (gotiomode == -1) 4795 gotiomode = flp->nfsfl_iomode; 4796 NFSCL_DEBUG(4, "layg reqiom=%d retiom=%d\n", iomode, 4797 (int)flp->nfsfl_iomode); 4798 if (fxdr_unsigned(int, *tl++) != 4799 NFSLAYOUT_NFSV4_1_FILES) { 4800 printf("NFSv4.1: got non-files layout\n"); 4801 error = NFSERR_BADXDR; 4802 goto nfsmout; 4803 } 4804 NFSBCOPY(++tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 4805 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4806 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 4807 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 4808 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 4809 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 4810 if (fxdr_unsigned(int, *tl) != fhcnt) { 4811 printf("EEK! bad fhcnt\n"); 4812 error = NFSERR_BADXDR; 4813 goto nfsmout; 4814 } 4815 for (j = 0; j < fhcnt; j++) { 4816 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4817 nfhlen = fxdr_unsigned(int, *tl); 4818 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 4819 error = NFSERR_BADXDR; 4820 goto nfsmout; 4821 } 4822 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, 4823 M_NFSFH, M_WAITOK); 4824 flp->nfsfl_fh[j] = nfhp; 4825 flp->nfsfl_fhcnt++; 4826 nfhp->nfh_len = nfhlen; 4827 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 4828 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 4829 } 4830 if (flp->nfsfl_iomode == gotiomode) { 4831 /* Keep the list in increasing offset order. */ 4832 tflp = LIST_FIRST(flhp); 4833 prevflp = NULL; 4834 while (tflp != NULL && 4835 tflp->nfsfl_off < flp->nfsfl_off) { 4836 prevflp = tflp; 4837 tflp = LIST_NEXT(tflp, nfsfl_list); 4838 } 4839 if (prevflp == NULL) 4840 LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 4841 else 4842 LIST_INSERT_AFTER(prevflp, flp, 4843 nfsfl_list); 4844 } else { 4845 printf("nfscl_layoutget(): got wrong iomode\n"); 4846 nfscl_freeflayout(flp); 4847 } 4848 flp = NULL; 4849 } 4850 } 4851 if (nd->nd_repstat != 0 && error == 0) 4852 error = nd->nd_repstat; 4853 nfsmout: 4854 if (error != 0 && flp != NULL) 4855 nfscl_freeflayout(flp); 4856 mbuf_freem(nd->nd_mrep); 4857 return (error); 4858 } 4859 4860 /* 4861 * Do the NFSv4.1 Get Device Info. 4862 */ 4863 int 4864 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 4865 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 4866 NFSPROC_T *p) 4867 { 4868 uint32_t cnt, *tl; 4869 struct nfsrv_descript nfsd; 4870 struct nfsrv_descript *nd = &nfsd; 4871 struct sockaddr_storage ss; 4872 struct nfsclds *dsp = NULL, **dspp; 4873 struct nfscldevinfo *ndi; 4874 int addrcnt, bitcnt, error, i, isudp, j, pos, safilled, stripecnt; 4875 uint8_t stripeindex; 4876 4877 *ndip = NULL; 4878 ndi = NULL; 4879 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL); 4880 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 4881 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 4882 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4883 *tl++ = txdr_unsigned(layouttype); 4884 *tl++ = txdr_unsigned(100000); 4885 if (notifybitsp != NULL && *notifybitsp != 0) { 4886 *tl = txdr_unsigned(1); /* One word of bits. */ 4887 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4888 *tl = txdr_unsigned(*notifybitsp); 4889 } else 4890 *tl = txdr_unsigned(0); 4891 nd->nd_flag |= ND_USEGSSNAME; 4892 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4893 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4894 if (error != 0) 4895 return (error); 4896 if (nd->nd_repstat == 0) { 4897 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4898 if (layouttype != fxdr_unsigned(int, *tl++)) 4899 printf("EEK! devinfo layout type not same!\n"); 4900 stripecnt = fxdr_unsigned(int, *++tl); 4901 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 4902 if (stripecnt < 1 || stripecnt > 4096) { 4903 printf("NFS devinfo stripecnt %d: out of range\n", 4904 stripecnt); 4905 error = NFSERR_BADXDR; 4906 goto nfsmout; 4907 } 4908 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * NFSX_UNSIGNED); 4909 addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 4910 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 4911 if (addrcnt < 1 || addrcnt > 128) { 4912 printf("NFS devinfo addrcnt %d: out of range\n", 4913 addrcnt); 4914 error = NFSERR_BADXDR; 4915 goto nfsmout; 4916 } 4917 4918 /* 4919 * Now we know how many stripe indices and addresses, so 4920 * we can allocate the structure the correct size. 4921 */ 4922 i = (stripecnt * sizeof(uint8_t)) / sizeof(struct nfsclds *) 4923 + 1; 4924 NFSCL_DEBUG(4, "stripeindices=%d\n", i); 4925 ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 4926 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | M_ZERO); 4927 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, NFSX_V4DEVICEID); 4928 ndi->nfsdi_refcnt = 0; 4929 ndi->nfsdi_stripecnt = stripecnt; 4930 ndi->nfsdi_addrcnt = addrcnt; 4931 /* Fill in the stripe indices. */ 4932 for (i = 0; i < stripecnt; i++) { 4933 stripeindex = fxdr_unsigned(uint8_t, *tl++); 4934 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 4935 if (stripeindex >= addrcnt) { 4936 printf("NFS devinfo stripeindex %d: too big\n", 4937 (int)stripeindex); 4938 error = NFSERR_BADXDR; 4939 goto nfsmout; 4940 } 4941 nfsfldi_setstripeindex(ndi, i, stripeindex); 4942 } 4943 4944 /* Now, dissect the server address(es). */ 4945 safilled = 0; 4946 for (i = 0; i < addrcnt; i++) { 4947 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4948 cnt = fxdr_unsigned(uint32_t, *tl); 4949 if (cnt == 0) { 4950 printf("NFS devinfo 0 len addrlist\n"); 4951 error = NFSERR_BADXDR; 4952 goto nfsmout; 4953 } 4954 dspp = nfsfldi_addr(ndi, i); 4955 pos = arc4random() % cnt; /* Choose one. */ 4956 safilled = 0; 4957 for (j = 0; j < cnt; j++) { 4958 error = nfsv4_getipaddr(nd, &ss, &isudp); 4959 if (error != 0 && error != EPERM) { 4960 error = NFSERR_BADXDR; 4961 goto nfsmout; 4962 } 4963 if (error == 0 && isudp == 0) { 4964 /* 4965 * The algorithm is: 4966 * - use "pos" entry if it is of the 4967 * same af_family or none of them 4968 * is of the same af_family 4969 * else 4970 * - use the first one of the same 4971 * af_family. 4972 */ 4973 if ((safilled == 0 && ss.ss_family == 4974 nmp->nm_nam->sa_family) || 4975 (j == pos && 4976 (safilled == 0 || ss.ss_family == 4977 nmp->nm_nam->sa_family)) || 4978 (safilled == 1 && ss.ss_family == 4979 nmp->nm_nam->sa_family)) { 4980 error = nfsrpc_fillsa(nmp, &ss, 4981 &dsp, p); 4982 if (error == 0) { 4983 *dspp = dsp; 4984 if (ss.ss_family == 4985 nmp->nm_nam->sa_family) 4986 safilled = 2; 4987 else 4988 safilled = 1; 4989 } 4990 } 4991 } 4992 } 4993 if (safilled == 0) 4994 break; 4995 } 4996 4997 /* And the notify bits. */ 4998 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4999 if (safilled != 0) { 5000 bitcnt = fxdr_unsigned(int, *tl); 5001 if (bitcnt > 0) { 5002 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5003 if (notifybitsp != NULL) 5004 *notifybitsp = 5005 fxdr_unsigned(uint32_t, *tl); 5006 } 5007 *ndip = ndi; 5008 } else 5009 error = EPERM; 5010 } 5011 if (nd->nd_repstat != 0) 5012 error = nd->nd_repstat; 5013 nfsmout: 5014 if (error != 0 && ndi != NULL) 5015 nfscl_freedevinfo(ndi); 5016 mbuf_freem(nd->nd_mrep); 5017 return (error); 5018 } 5019 5020 /* 5021 * Do the NFSv4.1 LayoutCommit. 5022 */ 5023 int 5024 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5025 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5026 int layouttype, int layoutupdatecnt, uint8_t *layp, struct ucred *cred, 5027 NFSPROC_T *p, void *stuff) 5028 { 5029 uint32_t *tl; 5030 struct nfsrv_descript nfsd, *nd = &nfsd; 5031 int error, outcnt, i; 5032 uint8_t *cp; 5033 5034 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL); 5035 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5036 NFSX_STATEID); 5037 txdr_hyper(off, tl); 5038 tl += 2; 5039 txdr_hyper(len, tl); 5040 tl += 2; 5041 if (reclaim != 0) 5042 *tl++ = newnfs_true; 5043 else 5044 *tl++ = newnfs_false; 5045 *tl++ = txdr_unsigned(stateidp->seqid); 5046 *tl++ = stateidp->other[0]; 5047 *tl++ = stateidp->other[1]; 5048 *tl++ = stateidp->other[2]; 5049 *tl++ = newnfs_true; 5050 if (lastbyte < off) 5051 lastbyte = off; 5052 else if (lastbyte >= (off + len)) 5053 lastbyte = off + len - 1; 5054 txdr_hyper(lastbyte, tl); 5055 tl += 2; 5056 *tl++ = newnfs_false; 5057 *tl++ = txdr_unsigned(layouttype); 5058 *tl = txdr_unsigned(layoutupdatecnt); 5059 if (layoutupdatecnt > 0) { 5060 KASSERT(layouttype != NFSLAYOUT_NFSV4_1_FILES, 5061 ("Must be nil for Files Layout")); 5062 outcnt = NFSM_RNDUP(layoutupdatecnt); 5063 NFSM_BUILD(cp, uint8_t *, outcnt); 5064 NFSBCOPY(layp, cp, layoutupdatecnt); 5065 cp += layoutupdatecnt; 5066 for (i = 0; i < (outcnt - layoutupdatecnt); i++) 5067 *cp++ = 0x0; 5068 } 5069 nd->nd_flag |= ND_USEGSSNAME; 5070 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5071 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5072 if (error != 0) 5073 return (error); 5074 error = nd->nd_repstat; 5075 mbuf_freem(nd->nd_mrep); 5076 return (error); 5077 } 5078 5079 /* 5080 * Do the NFSv4.1 LayoutReturn. 5081 */ 5082 int 5083 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5084 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5085 uint64_t len, nfsv4stateid_t *stateidp, int layoutcnt, uint32_t *layp, 5086 struct ucred *cred, NFSPROC_T *p, void *stuff) 5087 { 5088 uint32_t *tl; 5089 struct nfsrv_descript nfsd, *nd = &nfsd; 5090 int error, outcnt, i; 5091 uint8_t *cp; 5092 5093 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL); 5094 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5095 if (reclaim != 0) 5096 *tl++ = newnfs_true; 5097 else 5098 *tl++ = newnfs_false; 5099 *tl++ = txdr_unsigned(layouttype); 5100 *tl++ = txdr_unsigned(iomode); 5101 *tl = txdr_unsigned(layoutreturn); 5102 if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5103 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5104 NFSX_UNSIGNED); 5105 txdr_hyper(offset, tl); 5106 tl += 2; 5107 txdr_hyper(len, tl); 5108 tl += 2; 5109 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5110 *tl++ = txdr_unsigned(stateidp->seqid); 5111 *tl++ = stateidp->other[0]; 5112 *tl++ = stateidp->other[1]; 5113 *tl++ = stateidp->other[2]; 5114 *tl = txdr_unsigned(layoutcnt); 5115 if (layoutcnt > 0) { 5116 outcnt = NFSM_RNDUP(layoutcnt); 5117 NFSM_BUILD(cp, uint8_t *, outcnt); 5118 NFSBCOPY(layp, cp, layoutcnt); 5119 cp += layoutcnt; 5120 for (i = 0; i < (outcnt - layoutcnt); i++) 5121 *cp++ = 0x0; 5122 } 5123 } 5124 nd->nd_flag |= ND_USEGSSNAME; 5125 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5126 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5127 if (error != 0) 5128 return (error); 5129 if (nd->nd_repstat == 0) { 5130 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5131 if (*tl != 0) { 5132 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5133 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5134 stateidp->other[0] = *tl++; 5135 stateidp->other[1] = *tl++; 5136 stateidp->other[2] = *tl; 5137 } 5138 } else 5139 error = nd->nd_repstat; 5140 nfsmout: 5141 mbuf_freem(nd->nd_mrep); 5142 return (error); 5143 } 5144 5145 /* 5146 * Acquire a layout and devinfo, if possible. The caller must have acquired 5147 * a reference count on the nfsclclient structure before calling this. 5148 * Return the layout in lypp with a reference count on it, if successful. 5149 */ 5150 static int 5151 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 5152 int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off, 5153 struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 5154 { 5155 struct nfscllayout *lyp; 5156 struct nfsclflayout *flp, *tflp; 5157 struct nfscldevinfo *dip; 5158 struct nfsclflayouthead flh; 5159 int error = 0, islocked, layoutlen, recalled, retonclose; 5160 nfsv4stateid_t stateid; 5161 5162 *lypp = NULL; 5163 /* 5164 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 5165 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 5166 * flp == NULL. 5167 */ 5168 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 5169 off, &flp, &recalled); 5170 islocked = 0; 5171 if (lyp == NULL || flp == NULL) { 5172 if (recalled != 0) 5173 return (EIO); 5174 LIST_INIT(&flh); 5175 layoutlen = NFSMNT_MDSSESSION(nmp)->nfsess_maxcache - 5176 (NFSX_STATEID + 3 * NFSX_UNSIGNED); 5177 if (lyp == NULL) { 5178 stateid.seqid = 0; 5179 stateid.other[0] = stateidp->other[0]; 5180 stateid.other[1] = stateidp->other[1]; 5181 stateid.other[2] = stateidp->other[2]; 5182 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5183 nfhp->nfh_len, iomode, (uint64_t)0, INT64_MAX, 5184 (uint64_t)0, layoutlen, &stateid, &retonclose, 5185 &flh, cred, p, NULL); 5186 } else { 5187 islocked = 1; 5188 stateid.seqid = lyp->nfsly_stateid.seqid; 5189 stateid.other[0] = lyp->nfsly_stateid.other[0]; 5190 stateid.other[1] = lyp->nfsly_stateid.other[1]; 5191 stateid.other[2] = lyp->nfsly_stateid.other[2]; 5192 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5193 nfhp->nfh_len, iomode, off, INT64_MAX, 5194 (uint64_t)0, layoutlen, &stateid, &retonclose, 5195 &flh, cred, p, NULL); 5196 } 5197 if (error == 0) 5198 LIST_FOREACH(tflp, &flh, nfsfl_list) { 5199 error = nfscl_adddevinfo(nmp, NULL, tflp); 5200 if (error != 0) { 5201 error = nfsrpc_getdeviceinfo(nmp, 5202 tflp->nfsfl_dev, 5203 NFSLAYOUT_NFSV4_1_FILES, 5204 notifybitsp, &dip, cred, p); 5205 if (error != 0) 5206 break; 5207 error = nfscl_adddevinfo(nmp, dip, 5208 tflp); 5209 if (error != 0) 5210 printf( 5211 "getlayout: cannot add\n"); 5212 } 5213 } 5214 if (error == 0) { 5215 /* 5216 * nfscl_layout() always returns with the nfsly_lock 5217 * set to a refcnt (shared lock). 5218 */ 5219 error = nfscl_layout(nmp, vp, nfhp->nfh_fh, 5220 nfhp->nfh_len, &stateid, retonclose, &flh, &lyp, 5221 cred, p); 5222 if (error == 0) 5223 *lypp = lyp; 5224 } else if (islocked != 0) 5225 nfsv4_unlock(&lyp->nfsly_lock, 0); 5226 } else 5227 *lypp = lyp; 5228 return (error); 5229 } 5230 5231 /* 5232 * Do a TCP connection plus exchange id and create session. 5233 * If successful, a "struct nfsclds" is linked into the list for the 5234 * mount point and a pointer to it is returned. 5235 */ 5236 static int 5237 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_storage *ssp, 5238 struct nfsclds **dspp, NFSPROC_T *p) 5239 { 5240 struct sockaddr_in *msad, *sad, *ssd; 5241 struct sockaddr_in6 *msad6, *sad6, *ssd6; 5242 struct nfsclclient *clp; 5243 struct nfssockreq *nrp; 5244 struct nfsclds *dsp, *tdsp; 5245 int error; 5246 enum nfsclds_state retv; 5247 uint32_t sequenceid; 5248 5249 KASSERT(nmp->nm_sockreq.nr_cred != NULL, 5250 ("nfsrpc_fillsa: NULL nr_cred")); 5251 NFSLOCKCLSTATE(); 5252 clp = nmp->nm_clp; 5253 NFSUNLOCKCLSTATE(); 5254 if (clp == NULL) 5255 return (EPERM); 5256 if (ssp->ss_family == AF_INET) { 5257 ssd = (struct sockaddr_in *)ssp; 5258 NFSLOCKMNT(nmp); 5259 5260 /* 5261 * Check to see if we already have a session for this 5262 * address that is usable for a DS. 5263 * Note that the MDS's address is in a different place 5264 * than the sessions already acquired for DS's. 5265 */ 5266 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 5267 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5268 while (tdsp != NULL) { 5269 if (msad != NULL && msad->sin_family == AF_INET && 5270 ssd->sin_addr.s_addr == msad->sin_addr.s_addr && 5271 ssd->sin_port == msad->sin_port && 5272 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) { 5273 *dspp = tdsp; 5274 NFSUNLOCKMNT(nmp); 5275 NFSCL_DEBUG(4, "fnd same addr\n"); 5276 return (0); 5277 } 5278 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5279 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5280 msad = (struct sockaddr_in *) 5281 tdsp->nfsclds_sockp->nr_nam; 5282 else 5283 msad = NULL; 5284 } 5285 NFSUNLOCKMNT(nmp); 5286 5287 /* No IP address match, so look for new/trunked one. */ 5288 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 5289 sad->sin_len = sizeof(*sad); 5290 sad->sin_family = AF_INET; 5291 sad->sin_port = ssd->sin_port; 5292 sad->sin_addr.s_addr = ssd->sin_addr.s_addr; 5293 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5294 nrp->nr_nam = (struct sockaddr *)sad; 5295 } else if (ssp->ss_family == AF_INET6) { 5296 ssd6 = (struct sockaddr_in6 *)ssp; 5297 NFSLOCKMNT(nmp); 5298 5299 /* 5300 * Check to see if we already have a session for this 5301 * address that is usable for a DS. 5302 * Note that the MDS's address is in a different place 5303 * than the sessions already acquired for DS's. 5304 */ 5305 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 5306 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5307 while (tdsp != NULL) { 5308 if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 5309 IN6_ARE_ADDR_EQUAL(&ssd6->sin6_addr, 5310 &msad6->sin6_addr) && 5311 ssd6->sin6_port == msad6->sin6_port && 5312 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0) { 5313 *dspp = tdsp; 5314 NFSUNLOCKMNT(nmp); 5315 return (0); 5316 } 5317 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5318 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5319 msad6 = (struct sockaddr_in6 *) 5320 tdsp->nfsclds_sockp->nr_nam; 5321 else 5322 msad6 = NULL; 5323 } 5324 NFSUNLOCKMNT(nmp); 5325 5326 /* No IP address match, so look for new/trunked one. */ 5327 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 5328 sad6->sin6_len = sizeof(*sad6); 5329 sad6->sin6_family = AF_INET6; 5330 sad6->sin6_port = ssd6->sin6_port; 5331 NFSBCOPY(&ssd6->sin6_addr, &sad6->sin6_addr, 5332 sizeof(struct in6_addr)); 5333 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5334 nrp->nr_nam = (struct sockaddr *)sad6; 5335 } else 5336 return (EPERM); 5337 5338 nrp->nr_sotype = SOCK_STREAM; 5339 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 5340 nrp->nr_prog = NFS_PROG; 5341 nrp->nr_vers = NFS_VER4; 5342 5343 /* 5344 * Use the credentials that were used for the mount, which are 5345 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 5346 * Ref. counting the credentials with crhold() is probably not 5347 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 5348 * unmount, but I did it anyhow. 5349 */ 5350 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 5351 error = newnfs_connect(nmp, nrp, NULL, p, 0); 5352 NFSCL_DEBUG(3, "DS connect=%d\n", error); 5353 5354 /* Now, do the exchangeid and create session. */ 5355 if (error == 0) 5356 error = nfsrpc_exchangeid(nmp, clp, nrp, NFSV4EXCH_USEPNFSDS, 5357 &dsp, nrp->nr_cred, p); 5358 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 5359 if (error == 0) { 5360 dsp->nfsclds_sockp = nrp; 5361 NFSLOCKMNT(nmp); 5362 retv = nfscl_getsameserver(nmp, dsp, &tdsp); 5363 NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 5364 if (retv == NFSDSP_USETHISSESSION) { 5365 NFSUNLOCKMNT(nmp); 5366 /* 5367 * If there is already a session for this server, 5368 * use it. 5369 */ 5370 (void)newnfs_disconnect(nrp); 5371 nfscl_freenfsclds(dsp); 5372 *dspp = tdsp; 5373 return (0); 5374 } 5375 if (retv == NFSDSP_SEQTHISSESSION) 5376 sequenceid = tdsp->nfsclds_sess.nfsess_sequenceid; 5377 else 5378 sequenceid = dsp->nfsclds_sess.nfsess_sequenceid; 5379 NFSUNLOCKMNT(nmp); 5380 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 5381 nrp, sequenceid, 0, nrp->nr_cred, p); 5382 NFSCL_DEBUG(3, "DS createsess=%d\n", error); 5383 } else { 5384 NFSFREECRED(nrp->nr_cred); 5385 NFSFREEMUTEX(&nrp->nr_mtx); 5386 free(nrp->nr_nam, M_SONAME); 5387 free(nrp, M_NFSSOCKREQ); 5388 } 5389 if (error == 0) { 5390 NFSCL_DEBUG(3, "add DS session\n"); 5391 /* 5392 * Put it at the end of the list. That way the list 5393 * is ordered by when the entry was added. This matters 5394 * since the one done first is the one that should be 5395 * used for sequencid'ing any subsequent create sessions. 5396 */ 5397 NFSLOCKMNT(nmp); 5398 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 5399 NFSUNLOCKMNT(nmp); 5400 *dspp = dsp; 5401 } else if (dsp != NULL) 5402 nfscl_freenfsclds(dsp); 5403 return (error); 5404 } 5405 5406 /* 5407 * Do the NFSv4.1 Reclaim Complete. 5408 */ 5409 int 5410 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 5411 { 5412 uint32_t *tl; 5413 struct nfsrv_descript nfsd; 5414 struct nfsrv_descript *nd = &nfsd; 5415 int error; 5416 5417 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL); 5418 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5419 *tl = newnfs_false; 5420 nd->nd_flag |= ND_USEGSSNAME; 5421 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5422 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5423 if (error != 0) 5424 return (error); 5425 error = nd->nd_repstat; 5426 mbuf_freem(nd->nd_mrep); 5427 return (error); 5428 } 5429 5430 /* 5431 * Initialize the slot tables for a session. 5432 */ 5433 static void 5434 nfscl_initsessionslots(struct nfsclsession *sep) 5435 { 5436 int i; 5437 5438 for (i = 0; i < NFSV4_CBSLOTS; i++) { 5439 if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 5440 m_freem(sep->nfsess_cbslots[i].nfssl_reply); 5441 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 5442 } 5443 for (i = 0; i < 64; i++) 5444 sep->nfsess_slotseq[i] = 0; 5445 sep->nfsess_slots = 0; 5446 } 5447 5448 /* 5449 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 5450 */ 5451 int 5452 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5453 uint32_t rwaccess, struct ucred *cred, NFSPROC_T *p) 5454 { 5455 struct nfsnode *np = VTONFS(vp); 5456 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5457 struct nfscllayout *layp; 5458 struct nfscldevinfo *dip; 5459 struct nfsclflayout *rflp; 5460 nfsv4stateid_t stateid; 5461 struct ucred *newcred; 5462 uint64_t lastbyte, len, off, oresid, xfer; 5463 int eof, error, iolaymode, recalled; 5464 void *lckp; 5465 5466 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 5467 (np->n_flag & NNOLAYOUT) != 0) 5468 return (EIO); 5469 /* Now, get a reference cnt on the clientid for this mount. */ 5470 if (nfscl_getref(nmp) == 0) 5471 return (EIO); 5472 5473 /* Find an appropriate stateid. */ 5474 newcred = NFSNEWCRED(cred); 5475 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 5476 rwaccess, 1, newcred, p, &stateid, &lckp); 5477 if (error != 0) { 5478 NFSFREECRED(newcred); 5479 nfscl_relref(nmp); 5480 return (error); 5481 } 5482 /* Search for a layout for this file. */ 5483 off = uiop->uio_offset; 5484 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 5485 np->n_fhp->nfh_len, off, &rflp, &recalled); 5486 if (layp == NULL || rflp == NULL) { 5487 if (recalled != 0) { 5488 NFSFREECRED(newcred); 5489 nfscl_relref(nmp); 5490 return (EIO); 5491 } 5492 if (layp != NULL) { 5493 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 5494 layp = NULL; 5495 } 5496 /* Try and get a Layout, if it is supported. */ 5497 if (rwaccess == NFSV4OPEN_ACCESSWRITE || 5498 (np->n_flag & NWRITEOPENED) != 0) 5499 iolaymode = NFSLAYOUTIOMODE_RW; 5500 else 5501 iolaymode = NFSLAYOUTIOMODE_READ; 5502 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 5503 NULL, &stateid, off, &layp, newcred, p); 5504 if (error != 0) { 5505 NFSLOCKNODE(np); 5506 np->n_flag |= NNOLAYOUT; 5507 NFSUNLOCKNODE(np); 5508 if (lckp != NULL) 5509 nfscl_lockderef(lckp); 5510 NFSFREECRED(newcred); 5511 if (layp != NULL) 5512 nfscl_rellayout(layp, 0); 5513 nfscl_relref(nmp); 5514 return (error); 5515 } 5516 } 5517 5518 /* 5519 * Loop around finding a layout that works for the first part of 5520 * this I/O operation, and then call the function that actually 5521 * does the RPC. 5522 */ 5523 eof = 0; 5524 len = (uint64_t)uiop->uio_resid; 5525 while (len > 0 && error == 0 && eof == 0) { 5526 off = uiop->uio_offset; 5527 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 5528 if (error == 0) { 5529 oresid = xfer = (uint64_t)uiop->uio_resid; 5530 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 5531 xfer = rflp->nfsfl_end - rflp->nfsfl_off; 5532 dip = nfscl_getdevinfo(nmp->nm_clp, rflp->nfsfl_dev, 5533 rflp->nfsfl_devp); 5534 if (dip != NULL) { 5535 error = nfscl_doflayoutio(vp, uiop, iomode, 5536 must_commit, &eof, &stateid, rwaccess, dip, 5537 layp, rflp, off, xfer, newcred, p); 5538 nfscl_reldevinfo(dip); 5539 lastbyte = off + xfer - 1; 5540 if (error == 0) { 5541 NFSLOCKCLSTATE(); 5542 if (lastbyte > layp->nfsly_lastbyte) 5543 layp->nfsly_lastbyte = lastbyte; 5544 NFSUNLOCKCLSTATE(); 5545 } 5546 } else 5547 error = EIO; 5548 if (error == 0) 5549 len -= (oresid - (uint64_t)uiop->uio_resid); 5550 } 5551 } 5552 if (lckp != NULL) 5553 nfscl_lockderef(lckp); 5554 NFSFREECRED(newcred); 5555 nfscl_rellayout(layp, 0); 5556 nfscl_relref(nmp); 5557 return (error); 5558 } 5559 5560 /* 5561 * Find a file layout that will handle the first bytes of the requested 5562 * range and return the information from it needed to to the I/O operation. 5563 */ 5564 int 5565 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 5566 struct nfsclflayout **retflpp) 5567 { 5568 struct nfsclflayout *flp, *nflp, *rflp; 5569 uint32_t rw; 5570 5571 rflp = NULL; 5572 rw = rwaccess; 5573 /* For reading, do the Read list first and then the Write list. */ 5574 do { 5575 if (rw == NFSV4OPEN_ACCESSREAD) 5576 flp = LIST_FIRST(&lyp->nfsly_flayread); 5577 else 5578 flp = LIST_FIRST(&lyp->nfsly_flayrw); 5579 while (flp != NULL) { 5580 nflp = LIST_NEXT(flp, nfsfl_list); 5581 if (flp->nfsfl_off > off) 5582 break; 5583 if (flp->nfsfl_end > off && 5584 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 5585 rflp = flp; 5586 flp = nflp; 5587 } 5588 if (rw == NFSV4OPEN_ACCESSREAD) 5589 rw = NFSV4OPEN_ACCESSWRITE; 5590 else 5591 rw = 0; 5592 } while (rw != 0); 5593 if (rflp != NULL) { 5594 /* This one covers the most bytes starting at off. */ 5595 *retflpp = rflp; 5596 return (0); 5597 } 5598 return (EIO); 5599 } 5600 5601 /* 5602 * Do I/O using an NFSv4.1 file layout. 5603 */ 5604 static int 5605 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5606 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 5607 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 5608 uint64_t len, struct ucred *cred, NFSPROC_T *p) 5609 { 5610 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 5611 int commit_thru_mds, error = 0, stripe_index, stripe_pos; 5612 struct nfsnode *np; 5613 struct nfsfh *fhp; 5614 struct nfsclds **dspp; 5615 5616 np = VTONFS(vp); 5617 rel_off = off - flp->nfsfl_patoff; 5618 stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff; 5619 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 5620 dp->nfsdi_stripecnt; 5621 transfer = stripe_unit_size - (rel_off % stripe_unit_size); 5622 5623 /* Loop around, doing I/O for each stripe unit. */ 5624 while (len > 0 && error == 0) { 5625 stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 5626 dspp = nfsfldi_addr(dp, stripe_index); 5627 if (len > transfer) 5628 xfer = transfer; 5629 else 5630 xfer = len; 5631 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 5632 /* Dense layout. */ 5633 if (stripe_pos >= flp->nfsfl_fhcnt) 5634 return (EIO); 5635 fhp = flp->nfsfl_fh[stripe_pos]; 5636 io_off = (rel_off / (stripe_unit_size * 5637 dp->nfsdi_stripecnt)) * stripe_unit_size + 5638 rel_off % stripe_unit_size; 5639 } else { 5640 /* Sparse layout. */ 5641 if (flp->nfsfl_fhcnt > 1) { 5642 if (stripe_index >= flp->nfsfl_fhcnt) 5643 return (EIO); 5644 fhp = flp->nfsfl_fh[stripe_index]; 5645 } else if (flp->nfsfl_fhcnt == 1) 5646 fhp = flp->nfsfl_fh[0]; 5647 else 5648 fhp = np->n_fhp; 5649 io_off = off; 5650 } 5651 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) 5652 commit_thru_mds = 1; 5653 else 5654 commit_thru_mds = 0; 5655 if (rwflag == FREAD) 5656 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 5657 io_off, xfer, fhp, cred, p); 5658 else { 5659 error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 5660 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 5661 cred, p); 5662 if (error == 0) { 5663 NFSLOCKCLSTATE(); 5664 lyp->nfsly_flags |= NFSLY_WRITTEN; 5665 NFSUNLOCKCLSTATE(); 5666 } 5667 } 5668 if (error == 0) { 5669 transfer = stripe_unit_size; 5670 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 5671 len -= xfer; 5672 off += xfer; 5673 } 5674 } 5675 return (error); 5676 } 5677 5678 /* 5679 * The actual read RPC done to a DS. 5680 */ 5681 static int 5682 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 5683 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, 5684 struct ucred *cred, NFSPROC_T *p) 5685 { 5686 uint32_t *tl; 5687 int error, retlen; 5688 struct nfsrv_descript nfsd; 5689 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5690 struct nfsrv_descript *nd = &nfsd; 5691 struct nfssockreq *nrp; 5692 5693 nd->nd_mrep = NULL; 5694 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, fhp->nfh_len, 5695 NULL, &dsp->nfsclds_sess); 5696 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 5697 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 5698 txdr_hyper(io_off, tl); 5699 *(tl + 2) = txdr_unsigned(len); 5700 nrp = dsp->nfsclds_sockp; 5701 if (nrp == NULL) 5702 /* If NULL, use the MDS socket. */ 5703 nrp = &nmp->nm_sockreq; 5704 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 5705 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 5706 if (error != 0) 5707 return (error); 5708 if (nd->nd_repstat != 0) { 5709 error = nd->nd_repstat; 5710 goto nfsmout; 5711 } 5712 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5713 *eofp = fxdr_unsigned(int, *tl); 5714 NFSM_STRSIZ(retlen, len); 5715 error = nfsm_mbufuio(nd, uiop, retlen); 5716 nfsmout: 5717 if (nd->nd_mrep != NULL) 5718 mbuf_freem(nd->nd_mrep); 5719 return (error); 5720 } 5721 5722 /* 5723 * The actual write RPC done to a DS. 5724 */ 5725 static int 5726 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5727 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 5728 struct nfsfh *fhp, int commit_thru_mds, struct ucred *cred, NFSPROC_T *p) 5729 { 5730 uint32_t *tl; 5731 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5732 int error, rlen, commit, committed = NFSWRITE_FILESYNC; 5733 int32_t backup; 5734 struct nfsrv_descript nfsd; 5735 struct nfsrv_descript *nd = &nfsd; 5736 struct nfssockreq *nrp; 5737 5738 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 5739 nd->nd_mrep = NULL; 5740 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, fhp->nfh_len, 5741 NULL, &dsp->nfsclds_sess); 5742 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 5743 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 5744 txdr_hyper(io_off, tl); 5745 tl += 2; 5746 *tl++ = txdr_unsigned(*iomode); 5747 *tl = txdr_unsigned(len); 5748 nfsm_uiombuf(nd, uiop, len); 5749 nrp = dsp->nfsclds_sockp; 5750 if (nrp == NULL) 5751 /* If NULL, use the MDS socket. */ 5752 nrp = &nmp->nm_sockreq; 5753 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 5754 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 5755 if (error != 0) 5756 return (error); 5757 if (nd->nd_repstat != 0) { 5758 /* 5759 * In case the rpc gets retried, roll 5760 * the uio fileds changed by nfsm_uiombuf() 5761 * back. 5762 */ 5763 uiop->uio_offset -= len; 5764 uio_uio_resid_add(uiop, len); 5765 uio_iov_base_add(uiop, -len); 5766 uio_iov_len_add(uiop, len); 5767 error = nd->nd_repstat; 5768 } else { 5769 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 5770 rlen = fxdr_unsigned(int, *tl++); 5771 if (rlen == 0) { 5772 error = NFSERR_IO; 5773 goto nfsmout; 5774 } else if (rlen < len) { 5775 backup = len - rlen; 5776 uio_iov_base_add(uiop, -(backup)); 5777 uio_iov_len_add(uiop, backup); 5778 uiop->uio_offset -= backup; 5779 uio_uio_resid_add(uiop, backup); 5780 len = rlen; 5781 } 5782 commit = fxdr_unsigned(int, *tl++); 5783 5784 /* 5785 * Return the lowest committment level 5786 * obtained by any of the RPCs. 5787 */ 5788 if (committed == NFSWRITE_FILESYNC) 5789 committed = commit; 5790 else if (committed == NFSWRITE_DATASYNC && 5791 commit == NFSWRITE_UNSTABLE) 5792 committed = commit; 5793 if (commit_thru_mds != 0) { 5794 NFSLOCKMNT(nmp); 5795 if (!NFSHASWRITEVERF(nmp)) { 5796 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 5797 NFSSETWRITEVERF(nmp); 5798 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 5799 *must_commit = 1; 5800 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 5801 } 5802 NFSUNLOCKMNT(nmp); 5803 } else { 5804 NFSLOCKDS(dsp); 5805 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 5806 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 5807 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 5808 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 5809 *must_commit = 1; 5810 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 5811 } 5812 NFSUNLOCKDS(dsp); 5813 } 5814 } 5815 nfsmout: 5816 if (nd->nd_mrep != NULL) 5817 mbuf_freem(nd->nd_mrep); 5818 *iomode = committed; 5819 if (nd->nd_repstat != 0 && error == 0) 5820 error = nd->nd_repstat; 5821 return (error); 5822 } 5823 5824 /* 5825 * Free up the nfsclds structure. 5826 */ 5827 void 5828 nfscl_freenfsclds(struct nfsclds *dsp) 5829 { 5830 int i; 5831 5832 if (dsp == NULL) 5833 return; 5834 if (dsp->nfsclds_sockp != NULL) { 5835 NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 5836 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 5837 free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 5838 free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 5839 } 5840 NFSFREEMUTEX(&dsp->nfsclds_mtx); 5841 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 5842 for (i = 0; i < NFSV4_CBSLOTS; i++) { 5843 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 5844 m_freem( 5845 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 5846 } 5847 free(dsp, M_NFSCLDS); 5848 } 5849 5850 static enum nfsclds_state 5851 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 5852 struct nfsclds **retdspp) 5853 { 5854 struct nfsclds *dsp, *cur_dsp; 5855 5856 /* 5857 * Search the list of nfsclds structures for one with the same 5858 * server. 5859 */ 5860 cur_dsp = NULL; 5861 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 5862 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 5863 dsp->nfsclds_servownlen != 0 && 5864 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 5865 dsp->nfsclds_servownlen)) { 5866 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 5867 TAILQ_FIRST(&nmp->nm_sess), dsp, 5868 dsp->nfsclds_flags); 5869 /* Server major id matches. */ 5870 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 5871 *retdspp = dsp; 5872 return (NFSDSP_USETHISSESSION); 5873 } 5874 5875 /* 5876 * Note the first match, so it can be used for 5877 * sequence'ing new sessions. 5878 */ 5879 if (cur_dsp == NULL) 5880 cur_dsp = dsp; 5881 } 5882 } 5883 if (cur_dsp != NULL) { 5884 *retdspp = cur_dsp; 5885 return (NFSDSP_SEQTHISSESSION); 5886 } 5887 return (NFSDSP_NOTFOUND); 5888 } 5889 5890 #ifdef notyet 5891 /* 5892 * NFS commit rpc to a DS. 5893 */ 5894 static int 5895 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 5896 struct nfsfh *fhp, struct ucred *cred, NFSPROC_T *p, void *stuff) 5897 { 5898 uint32_t *tl; 5899 struct nfsrv_descript nfsd, *nd = &nfsd; 5900 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5901 struct nfssockreq *nrp; 5902 int error; 5903 5904 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, fhp->nfh_len, 5905 NULL, &dsp->nfsclds_sess); 5906 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 5907 txdr_hyper(offset, tl); 5908 tl += 2; 5909 *tl = txdr_unsigned(cnt); 5910 nrp = dsp->nfsclds_sockp; 5911 if (nrp == NULL) 5912 /* If NULL, use the MDS socket. */ 5913 nrp = &nmp->nm_sockreq; 5914 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 5915 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 5916 if (error) 5917 return (error); 5918 if (nd->nd_repstat == 0) { 5919 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 5920 NFSLOCKDS(dsp); 5921 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 5922 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 5923 error = NFSERR_STALEWRITEVERF; 5924 } 5925 NFSUNLOCKDS(dsp); 5926 } 5927 nfsmout: 5928 if (error == 0 && nd->nd_repstat != 0) 5929 error = nd->nd_repstat; 5930 mbuf_freem(nd->nd_mrep); 5931 return (error); 5932 } 5933 #endif 5934 5935