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 <fs/nfs/nfsport.h> 47 48 /* 49 * Global variables 50 */ 51 extern int nfs_numnfscbd; 52 extern struct timeval nfsboottime; 53 extern u_int32_t newnfs_false, newnfs_true; 54 extern nfstype nfsv34_type[9]; 55 extern int nfsrv_useacl; 56 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 57 NFSCLSTATEMUTEX; 58 int nfstest_outofseq = 0; 59 int nfscl_assumeposixlocks = 1; 60 int nfscl_enablecallb = 0; 61 short nfsv4_cbport = NFSV4_CBPORT; 62 int nfstest_openallsetattr = 0; 63 #endif /* !APPLEKEXT */ 64 65 #define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) 66 67 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, 68 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); 69 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, 70 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *); 71 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, 72 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, 73 void *); 74 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, 75 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, 76 struct nfsvattr *, struct nfsfh **, int *, int *, void *); 77 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, 78 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, 79 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, 80 int *, void *, int *); 81 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, 82 struct nfscllockowner *, u_int64_t, u_int64_t, 83 u_int32_t, struct ucred *, NFSPROC_T *, int); 84 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, 85 struct acl *, nfsv4stateid_t *, void *); 86 87 /* 88 * nfs null call from vfs. 89 */ 90 APPLESTATIC int 91 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) 92 { 93 int error; 94 struct nfsrv_descript nfsd, *nd = &nfsd; 95 96 NFSCL_REQSTART(nd, NFSPROC_NULL, vp); 97 error = nfscl_request(nd, vp, p, cred, NULL); 98 if (nd->nd_repstat && !error) 99 error = nd->nd_repstat; 100 mbuf_freem(nd->nd_mrep); 101 return (error); 102 } 103 104 /* 105 * nfs access rpc op. 106 * For nfs version 3 and 4, use the access rpc to check accessibility. If file 107 * modes are changed on the server, accesses might still fail later. 108 */ 109 APPLESTATIC int 110 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, 111 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 112 { 113 int error; 114 u_int32_t mode, rmode; 115 116 if (acmode & VREAD) 117 mode = NFSACCESS_READ; 118 else 119 mode = 0; 120 if (vnode_vtype(vp) == VDIR) { 121 if (acmode & VWRITE) 122 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | 123 NFSACCESS_DELETE); 124 if (acmode & VEXEC) 125 mode |= NFSACCESS_LOOKUP; 126 } else { 127 if (acmode & VWRITE) 128 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 129 if (acmode & VEXEC) 130 mode |= NFSACCESS_EXECUTE; 131 } 132 133 /* 134 * Now, just call nfsrpc_accessrpc() to do the actual RPC. 135 */ 136 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode, 137 NULL); 138 139 /* 140 * The NFS V3 spec does not clarify whether or not 141 * the returned access bits can be a superset of 142 * the ones requested, so... 143 */ 144 if (!error && (rmode & mode) != mode) 145 error = EACCES; 146 return (error); 147 } 148 149 /* 150 * The actual rpc, separated out for Darwin. 151 */ 152 APPLESTATIC int 153 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, 154 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep, 155 void *stuff) 156 { 157 u_int32_t *tl; 158 u_int32_t supported, rmode; 159 int error; 160 struct nfsrv_descript nfsd, *nd = &nfsd; 161 nfsattrbit_t attrbits; 162 163 *attrflagp = 0; 164 supported = mode; 165 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp); 166 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 167 *tl = txdr_unsigned(mode); 168 if (nd->nd_flag & ND_NFSV4) { 169 /* 170 * And do a Getattr op. 171 */ 172 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 173 *tl = txdr_unsigned(NFSV4OP_GETATTR); 174 NFSGETATTR_ATTRBIT(&attrbits); 175 (void) nfsrv_putattrbit(nd, &attrbits); 176 } 177 error = nfscl_request(nd, vp, p, cred, stuff); 178 if (error) 179 return (error); 180 if (nd->nd_flag & ND_NFSV3) { 181 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 182 if (error) 183 goto nfsmout; 184 } 185 if (!nd->nd_repstat) { 186 if (nd->nd_flag & ND_NFSV4) { 187 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 188 supported = fxdr_unsigned(u_int32_t, *tl++); 189 } else { 190 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 191 } 192 rmode = fxdr_unsigned(u_int32_t, *tl); 193 if (nd->nd_flag & ND_NFSV4) 194 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 195 196 /* 197 * It's not obvious what should be done about 198 * unsupported access modes. For now, be paranoid 199 * and clear the unsupported ones. 200 */ 201 rmode &= supported; 202 *rmodep = rmode; 203 } else 204 error = nd->nd_repstat; 205 nfsmout: 206 mbuf_freem(nd->nd_mrep); 207 return (error); 208 } 209 210 /* 211 * nfs open rpc 212 */ 213 APPLESTATIC int 214 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) 215 { 216 struct nfsclopen *op; 217 struct nfscldeleg *dp; 218 struct nfsfh *nfhp; 219 struct nfsnode *np = VTONFS(vp); 220 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 221 u_int32_t mode, clidrev; 222 int ret, newone, error, expireret = 0, retrycnt; 223 224 /* 225 * For NFSv4, Open Ops are only done on Regular Files. 226 */ 227 if (vnode_vtype(vp) != VREG) 228 return (0); 229 mode = 0; 230 if (amode & FREAD) 231 mode |= NFSV4OPEN_ACCESSREAD; 232 if (amode & FWRITE) 233 mode |= NFSV4OPEN_ACCESSWRITE; 234 nfhp = np->n_fhp; 235 236 retrycnt = 0; 237 #ifdef notdef 238 { char name[100]; int namel; 239 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99; 240 bcopy(NFS4NODENAME(np->n_v4), name, namel); 241 name[namel] = '\0'; 242 printf("rpcopen p=0x%x name=%s",p->p_pid,name); 243 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]); 244 else printf(" fhl=0\n"); 245 } 246 #endif 247 do { 248 dp = NULL; 249 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, 250 cred, p, NULL, &op, &newone, &ret, 1); 251 if (error) { 252 return (error); 253 } 254 if (nmp->nm_clp != NULL) 255 clidrev = nmp->nm_clp->nfsc_clientidrev; 256 else 257 clidrev = 0; 258 if (ret == NFSCLOPEN_DOOPEN) { 259 if (np->n_v4 != NULL) { 260 error = nfsrpc_openrpc(nmp, vp, np->n_v4->n4_data, 261 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 262 np->n_fhp->nfh_len, mode, op, 263 NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &dp, 264 0, 0x0, cred, p, 0, 0); 265 if (dp != NULL) { 266 #ifdef APPLE 267 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); 268 #else 269 NFSLOCKNODE(np); 270 np->n_flag &= ~NDELEGMOD; 271 /* 272 * Invalidate the attribute cache, so that 273 * attributes that pre-date the issue of a 274 * delegation are not cached, since the 275 * cached attributes will remain valid while 276 * the delegation is held. 277 */ 278 NFSINVALATTRCACHE(np); 279 NFSUNLOCKNODE(np); 280 #endif 281 (void) nfscl_deleg(nmp->nm_mountp, 282 op->nfso_own->nfsow_clp, 283 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); 284 } 285 } else { 286 error = EIO; 287 } 288 newnfs_copyincred(cred, &op->nfso_cred); 289 } else if (ret == NFSCLOPEN_SETCRED) 290 /* 291 * This is a new local open on a delegation. It needs 292 * to have credentials so that an open can be done 293 * against the server during recovery. 294 */ 295 newnfs_copyincred(cred, &op->nfso_cred); 296 297 /* 298 * nfso_opencnt is the count of how many VOP_OPEN()s have 299 * been done on this Open successfully and a VOP_CLOSE() 300 * is expected for each of these. 301 * If error is non-zero, don't increment it, since the Open 302 * hasn't succeeded yet. 303 */ 304 if (!error) 305 op->nfso_opencnt++; 306 nfscl_openrelease(op, error, newone); 307 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 308 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) { 309 (void) nfs_catnap(PZERO, error, "nfs_open"); 310 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 311 && clidrev != 0) { 312 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 313 retrycnt++; 314 } 315 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 316 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 317 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 318 expireret == 0 && clidrev != 0 && retrycnt < 4)); 319 if (error && retrycnt >= 4) 320 error = EIO; 321 return (error); 322 } 323 324 /* 325 * the actual open rpc 326 */ 327 APPLESTATIC int 328 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, 329 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 330 u_int8_t *name, int namelen, struct nfscldeleg **dpp, 331 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, 332 int syscred, int recursed) 333 { 334 u_int32_t *tl; 335 struct nfsrv_descript nfsd, *nd = &nfsd; 336 struct nfscldeleg *dp, *ndp = NULL; 337 struct nfsvattr nfsva; 338 u_int32_t rflags, deleg; 339 nfsattrbit_t attrbits; 340 int error, ret, acesize, limitby; 341 342 dp = *dpp; 343 *dpp = NULL; 344 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL); 345 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 346 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 347 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 348 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 349 *tl++ = op->nfso_own->nfsow_clp->nfsc_clientid.lval[0]; 350 *tl = op->nfso_own->nfsow_clp->nfsc_clientid.lval[1]; 351 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 352 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 353 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 354 if (reclaim) { 355 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); 356 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 357 *tl = txdr_unsigned(delegtype); 358 } else { 359 if (dp != NULL) { 360 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); 361 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 362 *tl++ = dp->nfsdl_stateid.seqid; 363 *tl++ = dp->nfsdl_stateid.other[0]; 364 *tl++ = dp->nfsdl_stateid.other[1]; 365 *tl = dp->nfsdl_stateid.other[2]; 366 } else { 367 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 368 } 369 (void) nfsm_strtom(nd, name, namelen); 370 } 371 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 372 *tl = txdr_unsigned(NFSV4OP_GETATTR); 373 NFSZERO_ATTRBIT(&attrbits); 374 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 375 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 376 (void) nfsrv_putattrbit(nd, &attrbits); 377 if (syscred) 378 nd->nd_flag |= ND_USEGSSNAME; 379 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 380 NFS_PROG, NFS_VER4, NULL, 1, NULL); 381 if (error) 382 return (error); 383 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 384 if (!nd->nd_repstat) { 385 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 386 6 * NFSX_UNSIGNED); 387 op->nfso_stateid.seqid = *tl++; 388 op->nfso_stateid.other[0] = *tl++; 389 op->nfso_stateid.other[1] = *tl++; 390 op->nfso_stateid.other[2] = *tl; 391 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 392 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 393 if (error) 394 goto nfsmout; 395 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 396 deleg = fxdr_unsigned(u_int32_t, *tl); 397 if (deleg == NFSV4OPEN_DELEGATEREAD || 398 deleg == NFSV4OPEN_DELEGATEWRITE) { 399 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 400 NFSCLFLAGS_FIRSTDELEG)) 401 op->nfso_own->nfsow_clp->nfsc_flags |= 402 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 403 MALLOC(ndp, struct nfscldeleg *, 404 sizeof (struct nfscldeleg) + newfhlen, 405 M_NFSCLDELEG, M_WAITOK); 406 LIST_INIT(&ndp->nfsdl_owner); 407 LIST_INIT(&ndp->nfsdl_lock); 408 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 409 ndp->nfsdl_fhlen = newfhlen; 410 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 411 newnfs_copyincred(cred, &ndp->nfsdl_cred); 412 nfscl_lockinit(&ndp->nfsdl_rwlock); 413 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 414 NFSX_UNSIGNED); 415 ndp->nfsdl_stateid.seqid = *tl++; 416 ndp->nfsdl_stateid.other[0] = *tl++; 417 ndp->nfsdl_stateid.other[1] = *tl++; 418 ndp->nfsdl_stateid.other[2] = *tl++; 419 ret = fxdr_unsigned(int, *tl); 420 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 421 ndp->nfsdl_flags = NFSCLDL_WRITE; 422 /* 423 * Indicates how much the file can grow. 424 */ 425 NFSM_DISSECT(tl, u_int32_t *, 426 3 * NFSX_UNSIGNED); 427 limitby = fxdr_unsigned(int, *tl++); 428 switch (limitby) { 429 case NFSV4OPEN_LIMITSIZE: 430 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 431 break; 432 case NFSV4OPEN_LIMITBLOCKS: 433 ndp->nfsdl_sizelimit = 434 fxdr_unsigned(u_int64_t, *tl++); 435 ndp->nfsdl_sizelimit *= 436 fxdr_unsigned(u_int64_t, *tl); 437 break; 438 default: 439 error = NFSERR_BADXDR; 440 goto nfsmout; 441 }; 442 } else { 443 ndp->nfsdl_flags = NFSCLDL_READ; 444 } 445 if (ret) 446 ndp->nfsdl_flags |= NFSCLDL_RECALL; 447 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 448 &acesize, p); 449 if (error) 450 goto nfsmout; 451 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 452 error = NFSERR_BADXDR; 453 goto nfsmout; 454 } 455 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 456 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 457 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 458 NULL, NULL, NULL, p, cred); 459 if (error) 460 goto nfsmout; 461 if (ndp != NULL) { 462 ndp->nfsdl_change = nfsva.na_filerev; 463 ndp->nfsdl_modtime = nfsva.na_mtime; 464 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 465 } 466 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { 467 do { 468 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, 469 cred, p); 470 if (ret == NFSERR_DELAY) 471 (void) nfs_catnap(PZERO, ret, "nfs_open"); 472 } while (ret == NFSERR_DELAY); 473 error = ret; 474 } 475 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || 476 nfscl_assumeposixlocks) 477 op->nfso_posixlock = 1; 478 else 479 op->nfso_posixlock = 0; 480 481 /* 482 * If the server is handing out delegations, but we didn't 483 * get one because an OpenConfirm was required, try the 484 * Open again, to get a delegation. This is a harmless no-op, 485 * from a server's point of view. 486 */ 487 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && 488 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) 489 && !error && dp == NULL && ndp == NULL && !recursed) { 490 do { 491 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, 492 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, 493 cred, p, syscred, 1); 494 if (ret == NFSERR_DELAY) 495 (void) nfs_catnap(PZERO, ret, "nfs_open2"); 496 } while (ret == NFSERR_DELAY); 497 if (ret) { 498 if (ndp != NULL) 499 FREE((caddr_t)ndp, M_NFSCLDELEG); 500 if (ret == NFSERR_STALECLIENTID || 501 ret == NFSERR_STALEDONTRECOVER) 502 error = ret; 503 } 504 } 505 } 506 if (nd->nd_repstat != 0 && error == 0) 507 error = nd->nd_repstat; 508 if (error == NFSERR_STALECLIENTID) 509 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 510 nfsmout: 511 if (!error) 512 *dpp = ndp; 513 else if (ndp != NULL) 514 FREE((caddr_t)ndp, M_NFSCLDELEG); 515 mbuf_freem(nd->nd_mrep); 516 return (error); 517 } 518 519 /* 520 * open downgrade rpc 521 */ 522 APPLESTATIC int 523 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, 524 struct ucred *cred, NFSPROC_T *p) 525 { 526 u_int32_t *tl; 527 struct nfsrv_descript nfsd, *nd = &nfsd; 528 int error; 529 530 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp); 531 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 532 *tl++ = op->nfso_stateid.seqid; 533 *tl++ = op->nfso_stateid.other[0]; 534 *tl++ = op->nfso_stateid.other[1]; 535 *tl++ = op->nfso_stateid.other[2]; 536 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 537 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 538 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 539 error = nfscl_request(nd, vp, p, cred, NULL); 540 if (error) 541 return (error); 542 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 543 if (!nd->nd_repstat) { 544 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 545 op->nfso_stateid.seqid = *tl++; 546 op->nfso_stateid.other[0] = *tl++; 547 op->nfso_stateid.other[1] = *tl++; 548 op->nfso_stateid.other[2] = *tl; 549 } 550 if (nd->nd_repstat && error == 0) 551 error = nd->nd_repstat; 552 if (error == NFSERR_STALESTATEID) 553 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 554 nfsmout: 555 mbuf_freem(nd->nd_mrep); 556 return (error); 557 } 558 559 /* 560 * V4 Close operation. 561 */ 562 APPLESTATIC int 563 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) 564 { 565 struct nfsclclient *clp; 566 int error; 567 568 if (vnode_vtype(vp) != VREG) 569 return (0); 570 if (doclose) 571 error = nfscl_doclose(vp, &clp, p); 572 else 573 error = nfscl_getclose(vp, &clp); 574 if (error) 575 return (error); 576 577 nfscl_clientrelease(clp); 578 return (0); 579 } 580 581 /* 582 * Close the open. 583 */ 584 APPLESTATIC void 585 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p) 586 { 587 struct nfsrv_descript nfsd, *nd = &nfsd; 588 struct nfscllockowner *lp, *nlp; 589 struct nfscllock *lop, *nlop; 590 struct ucred *tcred; 591 u_int64_t off = 0, len = 0; 592 u_int32_t type = NFSV4LOCKT_READ; 593 int error, do_unlock, trycnt; 594 595 tcred = newnfs_getcred(); 596 newnfs_copycred(&op->nfso_cred, tcred); 597 /* 598 * (Theoretically this could be done in the same 599 * compound as the close, but having multiple 600 * sequenced Ops in the same compound might be 601 * too scary for some servers.) 602 */ 603 if (op->nfso_posixlock) { 604 off = 0; 605 len = NFS64BITSSET; 606 type = NFSV4LOCKT_READ; 607 } 608 609 /* 610 * Since this function is only called from VOP_INACTIVE(), no 611 * other thread will be manipulating this Open. As such, the 612 * lock lists are not being changed by other threads, so it should 613 * be safe to do this without locking. 614 */ 615 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 616 do_unlock = 1; 617 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 618 if (op->nfso_posixlock == 0) { 619 off = lop->nfslo_first; 620 len = lop->nfslo_end - lop->nfslo_first; 621 if (lop->nfslo_type == F_WRLCK) 622 type = NFSV4LOCKT_WRITE; 623 else 624 type = NFSV4LOCKT_READ; 625 } 626 if (do_unlock) { 627 trycnt = 0; 628 do { 629 error = nfsrpc_locku(nd, nmp, lp, off, 630 len, type, tcred, p, 0); 631 if ((nd->nd_repstat == NFSERR_GRACE || 632 nd->nd_repstat == NFSERR_DELAY) && 633 error == 0) 634 (void) nfs_catnap(PZERO, 635 (int)nd->nd_repstat, 636 "nfs_close"); 637 } while ((nd->nd_repstat == NFSERR_GRACE || 638 nd->nd_repstat == NFSERR_DELAY) && 639 error == 0 && trycnt++ < 5); 640 if (op->nfso_posixlock) 641 do_unlock = 0; 642 } 643 nfscl_freelock(lop, 0); 644 } 645 /* 646 * Do a ReleaseLockOwner. 647 * The lock owner name nfsl_owner may be used by other opens for 648 * other files but the lock_owner4 name that nfsrpc_rellockown() 649 * puts on the wire has the file handle for this file appended 650 * to it, so it can be done now. 651 */ 652 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh, 653 lp->nfsl_open->nfso_fhlen, tcred, p); 654 } 655 656 /* 657 * There could be other Opens for different files on the same 658 * OpenOwner, so locking is required. 659 */ 660 NFSLOCKCLSTATE(); 661 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 662 NFSUNLOCKCLSTATE(); 663 do { 664 error = nfscl_tryclose(op, tcred, nmp, p); 665 if (error == NFSERR_GRACE) 666 (void) nfs_catnap(PZERO, error, "nfs_close"); 667 } while (error == NFSERR_GRACE); 668 NFSLOCKCLSTATE(); 669 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); 670 671 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) 672 nfscl_freelockowner(lp, 0); 673 nfscl_freeopen(op, 0); 674 NFSUNLOCKCLSTATE(); 675 NFSFREECRED(tcred); 676 } 677 678 /* 679 * The actual Close RPC. 680 */ 681 APPLESTATIC int 682 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp, 683 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p, 684 int syscred) 685 { 686 u_int32_t *tl; 687 int error; 688 689 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh, 690 op->nfso_fhlen, NULL); 691 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 692 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 693 *tl++ = op->nfso_stateid.seqid; 694 *tl++ = op->nfso_stateid.other[0]; 695 *tl++ = op->nfso_stateid.other[1]; 696 *tl = op->nfso_stateid.other[2]; 697 if (syscred) 698 nd->nd_flag |= ND_USEGSSNAME; 699 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 700 NFS_PROG, NFS_VER4, NULL, 1, NULL); 701 if (error) 702 return (error); 703 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 704 if (nd->nd_repstat == 0) 705 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 706 error = nd->nd_repstat; 707 if (error == NFSERR_STALESTATEID) 708 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 709 nfsmout: 710 mbuf_freem(nd->nd_mrep); 711 return (error); 712 } 713 714 /* 715 * V4 Open Confirm RPC. 716 */ 717 APPLESTATIC int 718 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen, 719 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) 720 { 721 u_int32_t *tl; 722 struct nfsrv_descript nfsd, *nd = &nfsd; 723 int error; 724 725 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, VFSTONFS(vnode_mount(vp)), 726 nfhp, fhlen, NULL); 727 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 728 *tl++ = op->nfso_stateid.seqid; 729 *tl++ = op->nfso_stateid.other[0]; 730 *tl++ = op->nfso_stateid.other[1]; 731 *tl++ = op->nfso_stateid.other[2]; 732 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid); 733 error = nfscl_request(nd, vp, p, cred, NULL); 734 if (error) 735 return (error); 736 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 737 if (!nd->nd_repstat) { 738 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 739 op->nfso_stateid.seqid = *tl++; 740 op->nfso_stateid.other[0] = *tl++; 741 op->nfso_stateid.other[1] = *tl++; 742 op->nfso_stateid.other[2] = *tl; 743 } 744 error = nd->nd_repstat; 745 if (error == NFSERR_STALESTATEID) 746 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 747 nfsmout: 748 mbuf_freem(nd->nd_mrep); 749 return (error); 750 } 751 752 /* 753 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs() 754 * when a mount has just occurred and when the server replies NFSERR_EXPIRED. 755 */ 756 APPLESTATIC int 757 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, 758 struct ucred *cred, NFSPROC_T *p) 759 { 760 u_int32_t *tl; 761 struct nfsrv_descript nfsd; 762 struct nfsrv_descript *nd = &nfsd; 763 nfsattrbit_t attrbits; 764 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9]; 765 u_short port; 766 int error, isinet6 = 0, callblen; 767 nfsquad_t confirm; 768 u_int32_t lease; 769 static u_int32_t rev = 0; 770 771 if (nfsboottime.tv_sec == 0) 772 NFSSETBOOTTIME(nfsboottime); 773 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL); 774 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 775 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 776 *tl = txdr_unsigned(rev++); 777 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 778 779 /* 780 * set up the callback address 781 */ 782 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 783 *tl = txdr_unsigned(NFS_CALLBCKPROG); 784 callblen = strlen(nfsv4_callbackaddr); 785 if (callblen == 0) 786 cp = nfscl_getmyip(nmp, &isinet6); 787 if (nfscl_enablecallb && nfs_numnfscbd > 0 && 788 (callblen > 0 || cp != NULL)) { 789 port = htons(nfsv4_cbport); 790 cp2 = (u_int8_t *)&port; 791 #ifdef INET6 792 if ((callblen > 0 && 793 strchr(nfsv4_callbackaddr, ':')) || isinet6) { 794 char ip6buf[INET6_ADDRSTRLEN], *ip6add; 795 796 (void) nfsm_strtom(nd, "tcp6", 4); 797 if (callblen == 0) { 798 ip6_sprintf(ip6buf, (struct in6_addr *)cp); 799 ip6add = ip6buf; 800 } else { 801 ip6add = nfsv4_callbackaddr; 802 } 803 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", 804 ip6add, cp2[0], cp2[1]); 805 } else 806 #endif 807 { 808 (void) nfsm_strtom(nd, "tcp", 3); 809 if (callblen == 0) 810 snprintf(addr, INET6_ADDRSTRLEN + 9, 811 "%d.%d.%d.%d.%d.%d", cp[0], cp[1], 812 cp[2], cp[3], cp2[0], cp2[1]); 813 else 814 snprintf(addr, INET6_ADDRSTRLEN + 9, 815 "%s.%d.%d", nfsv4_callbackaddr, 816 cp2[0], cp2[1]); 817 } 818 (void) nfsm_strtom(nd, addr, strlen(addr)); 819 } else { 820 (void) nfsm_strtom(nd, "tcp", 3); 821 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11); 822 } 823 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 824 *tl = txdr_unsigned(clp->nfsc_cbident); 825 nd->nd_flag |= ND_USEGSSNAME; 826 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 827 NFS_PROG, NFS_VER4, NULL, 1, NULL); 828 if (error) 829 return (error); 830 if (nd->nd_repstat == 0) { 831 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 832 clp->nfsc_clientid.lval[0] = *tl++; 833 clp->nfsc_clientid.lval[1] = *tl++; 834 confirm.lval[0] = *tl++; 835 confirm.lval[1] = *tl; 836 mbuf_freem(nd->nd_mrep); 837 nd->nd_mrep = NULL; 838 839 /* 840 * and confirm it. 841 */ 842 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL); 843 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 844 *tl++ = clp->nfsc_clientid.lval[0]; 845 *tl++ = clp->nfsc_clientid.lval[1]; 846 *tl++ = confirm.lval[0]; 847 *tl = confirm.lval[1]; 848 nd->nd_flag |= ND_USEGSSNAME; 849 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 850 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL); 851 if (error) 852 return (error); 853 mbuf_freem(nd->nd_mrep); 854 nd->nd_mrep = NULL; 855 if (nd->nd_repstat == 0) { 856 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh, 857 nmp->nm_fhsize, NULL); 858 NFSZERO_ATTRBIT(&attrbits); 859 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 860 (void) nfsrv_putattrbit(nd, &attrbits); 861 nd->nd_flag |= ND_USEGSSNAME; 862 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 863 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL); 864 if (error) 865 return (error); 866 if (nd->nd_repstat == 0) { 867 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL, 868 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred); 869 if (error) 870 goto nfsmout; 871 clp->nfsc_renew = NFSCL_RENEW(lease); 872 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 873 clp->nfsc_clientidrev++; 874 if (clp->nfsc_clientidrev == 0) 875 clp->nfsc_clientidrev++; 876 } 877 } 878 } 879 error = nd->nd_repstat; 880 nfsmout: 881 mbuf_freem(nd->nd_mrep); 882 return (error); 883 } 884 885 /* 886 * nfs getattr call. 887 */ 888 APPLESTATIC int 889 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 890 struct nfsvattr *nap, void *stuff) 891 { 892 struct nfsrv_descript nfsd, *nd = &nfsd; 893 int error; 894 nfsattrbit_t attrbits; 895 896 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 897 if (nd->nd_flag & ND_NFSV4) { 898 NFSGETATTR_ATTRBIT(&attrbits); 899 (void) nfsrv_putattrbit(nd, &attrbits); 900 } 901 error = nfscl_request(nd, vp, p, cred, stuff); 902 if (error) 903 return (error); 904 if (!nd->nd_repstat) 905 error = nfsm_loadattr(nd, nap); 906 else 907 error = nd->nd_repstat; 908 mbuf_freem(nd->nd_mrep); 909 return (error); 910 } 911 912 /* 913 * nfs getattr call with non-vnode arguemnts. 914 */ 915 APPLESTATIC int 916 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, 917 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp) 918 { 919 struct nfsrv_descript nfsd, *nd = &nfsd; 920 int error, vers = NFS_VER2; 921 nfsattrbit_t attrbits; 922 923 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL); 924 if (nd->nd_flag & ND_NFSV4) { 925 vers = NFS_VER4; 926 NFSGETATTR_ATTRBIT(&attrbits); 927 (void) nfsrv_putattrbit(nd, &attrbits); 928 } else if (nd->nd_flag & ND_NFSV3) { 929 vers = NFS_VER3; 930 } 931 if (syscred) 932 nd->nd_flag |= ND_USEGSSNAME; 933 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 934 NFS_PROG, vers, NULL, 1, xidp); 935 if (error) 936 return (error); 937 if (!nd->nd_repstat) 938 error = nfsm_loadattr(nd, nap); 939 else 940 error = nd->nd_repstat; 941 mbuf_freem(nd->nd_mrep); 942 return (error); 943 } 944 945 /* 946 * Do an nfs setattr operation. 947 */ 948 APPLESTATIC int 949 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, 950 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp, 951 void *stuff) 952 { 953 int error, expireret = 0, openerr, retrycnt; 954 u_int32_t clidrev = 0, mode; 955 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 956 struct nfsfh *nfhp; 957 nfsv4stateid_t stateid; 958 void *lckp; 959 960 if (nmp->nm_clp != NULL) 961 clidrev = nmp->nm_clp->nfsc_clientidrev; 962 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size)) 963 mode = NFSV4OPEN_ACCESSWRITE; 964 else 965 mode = NFSV4OPEN_ACCESSREAD; 966 retrycnt = 0; 967 do { 968 lckp = NULL; 969 openerr = 1; 970 if (NFSHASNFSV4(nmp)) { 971 nfhp = VTONFS(vp)->n_fhp; 972 error = nfscl_getstateid(vp, nfhp->nfh_fh, 973 nfhp->nfh_len, mode, cred, p, &stateid, &lckp); 974 if (error && vnode_vtype(vp) == VREG && 975 (mode == NFSV4OPEN_ACCESSWRITE || 976 nfstest_openallsetattr)) { 977 /* 978 * No Open stateid, so try and open the file 979 * now. 980 */ 981 if (mode == NFSV4OPEN_ACCESSWRITE) 982 openerr = nfsrpc_open(vp, FWRITE, cred, 983 p); 984 else 985 openerr = nfsrpc_open(vp, FREAD, cred, 986 p); 987 if (!openerr) 988 (void) nfscl_getstateid(vp, 989 nfhp->nfh_fh, nfhp->nfh_len, 990 mode, cred, p, &stateid, &lckp); 991 } 992 } 993 if (vap != NULL) 994 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p, 995 rnap, attrflagp, stuff); 996 else 997 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid, 998 stuff); 999 if (error == NFSERR_STALESTATEID) 1000 nfscl_initiate_recovery(nmp->nm_clp); 1001 if (lckp != NULL) 1002 nfscl_lockderef(lckp); 1003 if (!openerr) 1004 (void) nfsrpc_close(vp, 0, p); 1005 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1006 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1007 error == NFSERR_OLDSTATEID) { 1008 (void) nfs_catnap(PZERO, error, "nfs_setattr"); 1009 } else if ((error == NFSERR_EXPIRED || 1010 error == NFSERR_BADSTATEID) && clidrev != 0) { 1011 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1012 } 1013 retrycnt++; 1014 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1015 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1016 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1017 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1018 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1019 if (error && retrycnt >= 4) 1020 error = EIO; 1021 return (error); 1022 } 1023 1024 static int 1025 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, 1026 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 1027 struct nfsvattr *rnap, int *attrflagp, void *stuff) 1028 { 1029 u_int32_t *tl; 1030 struct nfsrv_descript nfsd, *nd = &nfsd; 1031 int error; 1032 nfsattrbit_t attrbits; 1033 1034 *attrflagp = 0; 1035 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp); 1036 if (nd->nd_flag & ND_NFSV4) 1037 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1038 vap->va_type = vnode_vtype(vp); 1039 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0); 1040 if (nd->nd_flag & ND_NFSV3) { 1041 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1042 *tl = newnfs_false; 1043 } else if (nd->nd_flag & ND_NFSV4) { 1044 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1045 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1046 NFSGETATTR_ATTRBIT(&attrbits); 1047 (void) nfsrv_putattrbit(nd, &attrbits); 1048 } 1049 error = nfscl_request(nd, vp, p, cred, stuff); 1050 if (error) 1051 return (error); 1052 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1053 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff); 1054 if ((nd->nd_flag & ND_NFSV4) && !error) 1055 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1056 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error) 1057 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff); 1058 mbuf_freem(nd->nd_mrep); 1059 if (nd->nd_repstat && !error) 1060 error = nd->nd_repstat; 1061 return (error); 1062 } 1063 1064 /* 1065 * nfs lookup rpc 1066 */ 1067 APPLESTATIC int 1068 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, 1069 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, 1070 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff) 1071 { 1072 u_int32_t *tl; 1073 struct nfsrv_descript nfsd, *nd = &nfsd; 1074 struct nfsmount *nmp; 1075 struct nfsnode *np; 1076 struct nfsfh *nfhp; 1077 nfsattrbit_t attrbits; 1078 int error = 0, lookupp = 0; 1079 1080 *attrflagp = 0; 1081 *dattrflagp = 0; 1082 if (vnode_vtype(dvp) != VDIR) 1083 return (ENOTDIR); 1084 nmp = VFSTONFS(vnode_mount(dvp)); 1085 if (len > NFS_MAXNAMLEN) 1086 return (ENAMETOOLONG); 1087 if (NFSHASNFSV4(nmp) && len == 1 && 1088 name[0] == '.') { 1089 /* 1090 * Just return the current dir's fh. 1091 */ 1092 np = VTONFS(dvp); 1093 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1094 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1095 nfhp->nfh_len = np->n_fhp->nfh_len; 1096 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1097 *nfhpp = nfhp; 1098 return (0); 1099 } 1100 if (NFSHASNFSV4(nmp) && len == 2 && 1101 name[0] == '.' && name[1] == '.') { 1102 lookupp = 1; 1103 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp); 1104 } else { 1105 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp); 1106 (void) nfsm_strtom(nd, name, len); 1107 } 1108 if (nd->nd_flag & ND_NFSV4) { 1109 NFSGETATTR_ATTRBIT(&attrbits); 1110 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1111 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1112 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1113 (void) nfsrv_putattrbit(nd, &attrbits); 1114 } 1115 error = nfscl_request(nd, dvp, p, cred, stuff); 1116 if (error) 1117 return (error); 1118 if (nd->nd_repstat) { 1119 /* 1120 * When an NFSv4 Lookupp returns ENOENT, it means that 1121 * the lookup is at the root of an fs, so return this dir. 1122 */ 1123 if (nd->nd_repstat == NFSERR_NOENT && lookupp) { 1124 np = VTONFS(dvp); 1125 MALLOC(nfhp, struct nfsfh *, sizeof (struct nfsfh) + 1126 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1127 nfhp->nfh_len = np->n_fhp->nfh_len; 1128 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1129 *nfhpp = nfhp; 1130 mbuf_freem(nd->nd_mrep); 1131 return (0); 1132 } 1133 if (nd->nd_flag & ND_NFSV3) 1134 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1135 goto nfsmout; 1136 } 1137 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 1138 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1139 if (*(tl + 1)) { 1140 nd->nd_flag |= ND_NOMOREDATA; 1141 goto nfsmout; 1142 } 1143 } 1144 error = nfsm_getfh(nd, nfhpp); 1145 if (error) 1146 goto nfsmout; 1147 1148 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1149 if ((nd->nd_flag & ND_NFSV3) && !error) 1150 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1151 nfsmout: 1152 mbuf_freem(nd->nd_mrep); 1153 if (!error && nd->nd_repstat) 1154 error = nd->nd_repstat; 1155 return (error); 1156 } 1157 1158 /* 1159 * Do a readlink rpc. 1160 */ 1161 APPLESTATIC int 1162 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, 1163 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1164 { 1165 u_int32_t *tl; 1166 struct nfsrv_descript nfsd, *nd = &nfsd; 1167 struct nfsnode *np = VTONFS(vp); 1168 nfsattrbit_t attrbits; 1169 int error, len, cangetattr = 1; 1170 1171 *attrflagp = 0; 1172 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp); 1173 if (nd->nd_flag & ND_NFSV4) { 1174 /* 1175 * And do a Getattr op. 1176 */ 1177 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1178 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1179 NFSGETATTR_ATTRBIT(&attrbits); 1180 (void) nfsrv_putattrbit(nd, &attrbits); 1181 } 1182 error = nfscl_request(nd, vp, p, cred, stuff); 1183 if (error) 1184 return (error); 1185 if (nd->nd_flag & ND_NFSV3) 1186 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1187 if (!nd->nd_repstat && !error) { 1188 NFSM_STRSIZ(len, NFS_MAXPATHLEN); 1189 /* 1190 * This seems weird to me, but must have been added to 1191 * FreeBSD for some reason. The only thing I can think of 1192 * is that there was/is some server that replies with 1193 * more link data than it should? 1194 */ 1195 if (len == NFS_MAXPATHLEN) { 1196 NFSLOCKNODE(np); 1197 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { 1198 len = np->n_size; 1199 cangetattr = 0; 1200 } 1201 NFSUNLOCKNODE(np); 1202 } 1203 error = nfsm_mbufuio(nd, uiop, len); 1204 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) 1205 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1206 } 1207 if (nd->nd_repstat && !error) 1208 error = nd->nd_repstat; 1209 nfsmout: 1210 mbuf_freem(nd->nd_mrep); 1211 return (error); 1212 } 1213 1214 /* 1215 * Read operation. 1216 */ 1217 APPLESTATIC int 1218 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, 1219 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1220 { 1221 int error, expireret = 0, retrycnt; 1222 u_int32_t clidrev = 0; 1223 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1224 struct nfsnode *np = VTONFS(vp); 1225 struct ucred *newcred; 1226 struct nfsfh *nfhp = NULL; 1227 nfsv4stateid_t stateid; 1228 void *lckp; 1229 1230 if (nmp->nm_clp != NULL) 1231 clidrev = nmp->nm_clp->nfsc_clientidrev; 1232 newcred = cred; 1233 if (NFSHASNFSV4(nmp)) { 1234 nfhp = np->n_fhp; 1235 newcred = NFSNEWCRED(cred); 1236 } 1237 retrycnt = 0; 1238 do { 1239 lckp = NULL; 1240 if (NFSHASNFSV4(nmp)) 1241 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1242 NFSV4OPEN_ACCESSREAD, newcred, p, &stateid, &lckp); 1243 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, 1244 attrflagp, stuff); 1245 if (error == NFSERR_STALESTATEID) 1246 nfscl_initiate_recovery(nmp->nm_clp); 1247 if (lckp != NULL) 1248 nfscl_lockderef(lckp); 1249 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1250 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1251 error == NFSERR_OLDSTATEID) { 1252 (void) nfs_catnap(PZERO, error, "nfs_read"); 1253 } else if ((error == NFSERR_EXPIRED || 1254 error == NFSERR_BADSTATEID) && clidrev != 0) { 1255 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1256 } 1257 retrycnt++; 1258 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1259 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1260 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1261 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1262 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1263 if (error && retrycnt >= 4) 1264 error = EIO; 1265 if (NFSHASNFSV4(nmp)) 1266 NFSFREECRED(newcred); 1267 return (error); 1268 } 1269 1270 /* 1271 * The actual read RPC. 1272 */ 1273 static int 1274 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, 1275 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, 1276 int *attrflagp, void *stuff) 1277 { 1278 u_int32_t *tl; 1279 int error = 0, len, retlen, tsiz, eof = 0; 1280 struct nfsrv_descript nfsd; 1281 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1282 struct nfsrv_descript *nd = &nfsd; 1283 int rsize; 1284 off_t tmp_off; 1285 1286 *attrflagp = 0; 1287 tsiz = uio_uio_resid(uiop); 1288 tmp_off = uiop->uio_offset + tsiz; 1289 NFSLOCKMNT(nmp); 1290 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1291 NFSUNLOCKMNT(nmp); 1292 return (EFBIG); 1293 } 1294 rsize = nmp->nm_rsize; 1295 NFSUNLOCKMNT(nmp); 1296 nd->nd_mrep = NULL; 1297 while (tsiz > 0) { 1298 *attrflagp = 0; 1299 len = (tsiz > rsize) ? rsize : tsiz; 1300 NFSCL_REQSTART(nd, NFSPROC_READ, vp); 1301 if (nd->nd_flag & ND_NFSV4) 1302 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1303 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1304 if (nd->nd_flag & ND_NFSV2) { 1305 *tl++ = txdr_unsigned(uiop->uio_offset); 1306 *tl++ = txdr_unsigned(len); 1307 *tl = 0; 1308 } else { 1309 txdr_hyper(uiop->uio_offset, tl); 1310 *(tl + 2) = txdr_unsigned(len); 1311 } 1312 /* 1313 * Since I can't do a Getattr for NFSv4 for Write, there 1314 * doesn't seem any point in doing one here, either. 1315 * (See the comment in nfsrpc_writerpc() for more info.) 1316 */ 1317 error = nfscl_request(nd, vp, p, cred, stuff); 1318 if (error) 1319 return (error); 1320 if (nd->nd_flag & ND_NFSV3) { 1321 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1322 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { 1323 error = nfsm_loadattr(nd, nap); 1324 if (!error) 1325 *attrflagp = 1; 1326 } 1327 if (nd->nd_repstat || error) { 1328 if (!error) 1329 error = nd->nd_repstat; 1330 goto nfsmout; 1331 } 1332 if (nd->nd_flag & ND_NFSV3) { 1333 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1334 eof = fxdr_unsigned(int, *(tl + 1)); 1335 } else if (nd->nd_flag & ND_NFSV4) { 1336 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1337 eof = fxdr_unsigned(int, *tl); 1338 } 1339 NFSM_STRSIZ(retlen, rsize); 1340 error = nfsm_mbufuio(nd, uiop, retlen); 1341 if (error) 1342 goto nfsmout; 1343 mbuf_freem(nd->nd_mrep); 1344 nd->nd_mrep = NULL; 1345 tsiz -= retlen; 1346 if (!(nd->nd_flag & ND_NFSV2)) { 1347 if (eof || retlen == 0) 1348 tsiz = 0; 1349 } else if (retlen < len) 1350 tsiz = 0; 1351 } 1352 return (0); 1353 nfsmout: 1354 if (nd->nd_mrep != NULL) 1355 mbuf_freem(nd->nd_mrep); 1356 return (error); 1357 } 1358 1359 /* 1360 * nfs write operation 1361 * When called_from_strategy != 0, it should return EIO for an error that 1362 * indicates recovery is in progress, so that the buffer will be left 1363 * dirty and be written back to the server later. If it loops around, 1364 * the recovery thread could get stuck waiting for the buffer and recovery 1365 * will then deadlock. 1366 */ 1367 APPLESTATIC int 1368 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 1369 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 1370 void *stuff, int called_from_strategy) 1371 { 1372 int error, expireret = 0, retrycnt, nostateid; 1373 u_int32_t clidrev = 0; 1374 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1375 struct nfsnode *np = VTONFS(vp); 1376 struct ucred *newcred; 1377 struct nfsfh *nfhp = NULL; 1378 nfsv4stateid_t stateid; 1379 void *lckp; 1380 1381 *must_commit = 0; 1382 if (nmp->nm_clp != NULL) 1383 clidrev = nmp->nm_clp->nfsc_clientidrev; 1384 newcred = cred; 1385 if (NFSHASNFSV4(nmp)) { 1386 newcred = NFSNEWCRED(cred); 1387 nfhp = np->n_fhp; 1388 } 1389 retrycnt = 0; 1390 do { 1391 lckp = NULL; 1392 nostateid = 0; 1393 if (NFSHASNFSV4(nmp)) { 1394 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1395 NFSV4OPEN_ACCESSWRITE, newcred, p, &stateid, &lckp); 1396 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 1397 stateid.other[2] == 0) { 1398 nostateid = 1; 1399 printf("stateid0 in write\n"); 1400 } 1401 } 1402 1403 /* 1404 * If there is no stateid for NFSv4, it means this is an 1405 * extraneous write after close. Basically a poorly 1406 * implemented buffer cache. Just don't do the write. 1407 */ 1408 if (nostateid) 1409 error = 0; 1410 else 1411 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, 1412 newcred, &stateid, p, nap, attrflagp, stuff); 1413 if (error == NFSERR_STALESTATEID) 1414 nfscl_initiate_recovery(nmp->nm_clp); 1415 if (lckp != NULL) 1416 nfscl_lockderef(lckp); 1417 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1418 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1419 error == NFSERR_OLDSTATEID) { 1420 (void) nfs_catnap(PZERO, error, "nfs_write"); 1421 } else if ((error == NFSERR_EXPIRED || 1422 error == NFSERR_BADSTATEID) && clidrev != 0) { 1423 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1424 } 1425 retrycnt++; 1426 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 1427 ((error == NFSERR_STALESTATEID || 1428 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || 1429 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1430 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1431 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1432 if (error != 0 && (retrycnt >= 4 || 1433 ((error == NFSERR_STALESTATEID || 1434 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0))) 1435 error = EIO; 1436 if (NFSHASNFSV4(nmp)) 1437 NFSFREECRED(newcred); 1438 return (error); 1439 } 1440 1441 /* 1442 * The actual write RPC. 1443 */ 1444 static int 1445 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, 1446 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, 1447 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1448 { 1449 u_int32_t *tl; 1450 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1451 struct nfsnode *np = VTONFS(vp); 1452 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; 1453 int wccflag = 0, wsize; 1454 int32_t backup; 1455 struct nfsrv_descript nfsd; 1456 struct nfsrv_descript *nd = &nfsd; 1457 nfsattrbit_t attrbits; 1458 off_t tmp_off; 1459 1460 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 1461 *attrflagp = 0; 1462 tsiz = uio_uio_resid(uiop); 1463 tmp_off = uiop->uio_offset + tsiz; 1464 NFSLOCKMNT(nmp); 1465 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1466 NFSUNLOCKMNT(nmp); 1467 return (EFBIG); 1468 } 1469 wsize = nmp->nm_wsize; 1470 NFSUNLOCKMNT(nmp); 1471 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ 1472 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ 1473 while (tsiz > 0) { 1474 *attrflagp = 0; 1475 len = (tsiz > wsize) ? wsize : tsiz; 1476 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); 1477 if (nd->nd_flag & ND_NFSV4) { 1478 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1479 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); 1480 txdr_hyper(uiop->uio_offset, tl); 1481 tl += 2; 1482 *tl++ = txdr_unsigned(*iomode); 1483 *tl = txdr_unsigned(len); 1484 } else if (nd->nd_flag & ND_NFSV3) { 1485 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); 1486 txdr_hyper(uiop->uio_offset, tl); 1487 tl += 2; 1488 *tl++ = txdr_unsigned(len); 1489 *tl++ = txdr_unsigned(*iomode); 1490 *tl = txdr_unsigned(len); 1491 } else { 1492 u_int32_t x; 1493 1494 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1495 /* 1496 * Not sure why someone changed this, since the 1497 * RFC clearly states that "beginoffset" and 1498 * "totalcount" are ignored, but it wouldn't 1499 * surprise me if there's a busted server out there. 1500 */ 1501 /* Set both "begin" and "current" to non-garbage. */ 1502 x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1503 *tl++ = x; /* "begin offset" */ 1504 *tl++ = x; /* "current offset" */ 1505 x = txdr_unsigned(len); 1506 *tl++ = x; /* total to this offset */ 1507 *tl = x; /* size of this write */ 1508 1509 } 1510 nfsm_uiombuf(nd, uiop, len); 1511 /* 1512 * Although it is tempting to do a normal Getattr Op in the 1513 * NFSv4 compound, the result can be a nearly hung client 1514 * system if the Getattr asks for Owner and/or OwnerGroup. 1515 * It occurs when the client can't map either the Owner or 1516 * Owner_group name in the Getattr reply to a uid/gid. When 1517 * there is a cache miss, the kernel does an upcall to the 1518 * nfsuserd. Then, it can try and read the local /etc/passwd 1519 * or /etc/group file. It can then block in getnewbuf(), 1520 * waiting for dirty writes to be pushed to the NFS server. 1521 * The only reason this doesn't result in a complete 1522 * deadlock, is that the upcall times out and allows 1523 * the write to complete. However, progress is so slow 1524 * that it might just as well be deadlocked. 1525 * As such, we get the rest of the attributes, but not 1526 * Owner or Owner_group. 1527 * nb: nfscl_loadattrcache() needs to be told that these 1528 * partial attributes from a write rpc are being 1529 * passed in, via a argument flag. 1530 */ 1531 if (nd->nd_flag & ND_NFSV4) { 1532 NFSWRITEGETATTR_ATTRBIT(&attrbits); 1533 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1534 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1535 (void) nfsrv_putattrbit(nd, &attrbits); 1536 } 1537 error = nfscl_request(nd, vp, p, cred, stuff); 1538 if (error) 1539 return (error); 1540 if (nd->nd_repstat) { 1541 /* 1542 * In case the rpc gets retried, roll 1543 * the uio fileds changed by nfsm_uiombuf() 1544 * back. 1545 */ 1546 uiop->uio_offset -= len; 1547 uio_uio_resid_add(uiop, len); 1548 uio_iov_base_add(uiop, -len); 1549 uio_iov_len_add(uiop, len); 1550 } 1551 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1552 error = nfscl_wcc_data(nd, vp, nap, attrflagp, 1553 &wccflag, stuff); 1554 if (error) 1555 goto nfsmout; 1556 } 1557 if (!nd->nd_repstat) { 1558 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1559 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1560 + NFSX_VERF); 1561 rlen = fxdr_unsigned(int, *tl++); 1562 if (rlen == 0) { 1563 error = NFSERR_IO; 1564 goto nfsmout; 1565 } else if (rlen < len) { 1566 backup = len - rlen; 1567 uio_iov_base_add(uiop, -(backup)); 1568 uio_iov_len_add(uiop, backup); 1569 uiop->uio_offset -= backup; 1570 uio_uio_resid_add(uiop, backup); 1571 len = rlen; 1572 } 1573 commit = fxdr_unsigned(int, *tl++); 1574 1575 /* 1576 * Return the lowest committment level 1577 * obtained by any of the RPCs. 1578 */ 1579 if (committed == NFSWRITE_FILESYNC) 1580 committed = commit; 1581 else if (committed == NFSWRITE_DATASYNC && 1582 commit == NFSWRITE_UNSTABLE) 1583 committed = commit; 1584 NFSLOCKMNT(nmp); 1585 if (!NFSHASWRITEVERF(nmp)) { 1586 NFSBCOPY((caddr_t)tl, 1587 (caddr_t)&nmp->nm_verf[0], 1588 NFSX_VERF); 1589 NFSSETWRITEVERF(nmp); 1590 } else if (NFSBCMP(tl, nmp->nm_verf, 1591 NFSX_VERF)) { 1592 *must_commit = 1; 1593 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 1594 } 1595 NFSUNLOCKMNT(nmp); 1596 } 1597 if (nd->nd_flag & ND_NFSV4) 1598 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1599 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 1600 error = nfsm_loadattr(nd, nap); 1601 if (!error) 1602 *attrflagp = NFS_LATTR_NOSHRINK; 1603 } 1604 } else { 1605 error = nd->nd_repstat; 1606 } 1607 if (error) 1608 goto nfsmout; 1609 NFSWRITERPC_SETTIME(wccflag, np, (nd->nd_flag & ND_NFSV4)); 1610 mbuf_freem(nd->nd_mrep); 1611 nd->nd_mrep = NULL; 1612 tsiz -= len; 1613 } 1614 nfsmout: 1615 if (nd->nd_mrep != NULL) 1616 mbuf_freem(nd->nd_mrep); 1617 *iomode = committed; 1618 if (nd->nd_repstat && !error) 1619 error = nd->nd_repstat; 1620 return (error); 1621 } 1622 1623 /* 1624 * nfs mknod rpc 1625 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1626 * mode set to specify the file type and the size field for rdev. 1627 */ 1628 APPLESTATIC int 1629 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1630 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p, 1631 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1632 int *attrflagp, int *dattrflagp, void *dstuff) 1633 { 1634 u_int32_t *tl; 1635 int error = 0; 1636 struct nfsrv_descript nfsd, *nd = &nfsd; 1637 nfsattrbit_t attrbits; 1638 1639 *nfhpp = NULL; 1640 *attrflagp = 0; 1641 *dattrflagp = 0; 1642 if (namelen > NFS_MAXNAMLEN) 1643 return (ENAMETOOLONG); 1644 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp); 1645 if (nd->nd_flag & ND_NFSV4) { 1646 if (vtyp == VBLK || vtyp == VCHR) { 1647 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1648 *tl++ = vtonfsv34_type(vtyp); 1649 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1650 *tl = txdr_unsigned(NFSMINOR(rdev)); 1651 } else { 1652 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1653 *tl = vtonfsv34_type(vtyp); 1654 } 1655 } 1656 (void) nfsm_strtom(nd, name, namelen); 1657 if (nd->nd_flag & ND_NFSV3) { 1658 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1659 *tl = vtonfsv34_type(vtyp); 1660 } 1661 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1662 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1663 if ((nd->nd_flag & ND_NFSV3) && 1664 (vtyp == VCHR || vtyp == VBLK)) { 1665 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1666 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1667 *tl = txdr_unsigned(NFSMINOR(rdev)); 1668 } 1669 if (nd->nd_flag & ND_NFSV4) { 1670 NFSGETATTR_ATTRBIT(&attrbits); 1671 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1672 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1673 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1674 (void) nfsrv_putattrbit(nd, &attrbits); 1675 } 1676 if (nd->nd_flag & ND_NFSV2) 1677 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 1678 error = nfscl_request(nd, dvp, p, cred, dstuff); 1679 if (error) 1680 return (error); 1681 if (nd->nd_flag & ND_NFSV4) 1682 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1683 if (!nd->nd_repstat) { 1684 if (nd->nd_flag & ND_NFSV4) { 1685 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1686 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1687 if (error) 1688 goto nfsmout; 1689 } 1690 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1691 if (error) 1692 goto nfsmout; 1693 } 1694 if (nd->nd_flag & ND_NFSV3) 1695 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1696 if (!error && nd->nd_repstat) 1697 error = nd->nd_repstat; 1698 nfsmout: 1699 mbuf_freem(nd->nd_mrep); 1700 return (error); 1701 } 1702 1703 /* 1704 * nfs file create call 1705 * Mostly just call the approriate routine. (I separated out v4, so that 1706 * error recovery wouldn't be as difficult.) 1707 */ 1708 APPLESTATIC int 1709 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1710 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1711 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1712 int *attrflagp, int *dattrflagp, void *dstuff) 1713 { 1714 int error = 0, newone, expireret = 0, retrycnt, unlocked; 1715 struct nfsclowner *owp; 1716 struct nfscldeleg *dp; 1717 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp)); 1718 u_int32_t clidrev; 1719 1720 if (NFSHASNFSV4(nmp)) { 1721 retrycnt = 0; 1722 do { 1723 dp = NULL; 1724 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 1725 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 1726 NULL, 1); 1727 if (error) 1728 return (error); 1729 if (nmp->nm_clp != NULL) 1730 clidrev = nmp->nm_clp->nfsc_clientidrev; 1731 else 1732 clidrev = 0; 1733 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, fmode, 1734 owp, &dp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1735 dstuff, &unlocked); 1736 /* 1737 * There is no need to invalidate cached attributes here, 1738 * since new post-delegation issue attributes are always 1739 * returned by nfsrpc_createv4() and these will update the 1740 * attribute cache. 1741 */ 1742 if (dp != NULL) 1743 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 1744 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 1745 nfscl_ownerrelease(owp, error, newone, unlocked); 1746 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1747 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY) { 1748 (void) nfs_catnap(PZERO, error, "nfs_open"); 1749 } else if ((error == NFSERR_EXPIRED || 1750 error == NFSERR_BADSTATEID) && clidrev != 0) { 1751 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1752 retrycnt++; 1753 } 1754 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 1755 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1756 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1757 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1758 if (error && retrycnt >= 4) 1759 error = EIO; 1760 } else { 1761 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 1762 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 1763 dstuff); 1764 } 1765 return (error); 1766 } 1767 1768 /* 1769 * The create rpc for v2 and 3. 1770 */ 1771 static int 1772 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1773 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1774 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1775 int *attrflagp, int *dattrflagp, void *dstuff) 1776 { 1777 u_int32_t *tl; 1778 int error = 0; 1779 struct nfsrv_descript nfsd, *nd = &nfsd; 1780 1781 *nfhpp = NULL; 1782 *attrflagp = 0; 1783 *dattrflagp = 0; 1784 if (namelen > NFS_MAXNAMLEN) 1785 return (ENAMETOOLONG); 1786 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1787 (void) nfsm_strtom(nd, name, namelen); 1788 if (nd->nd_flag & ND_NFSV3) { 1789 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1790 if (fmode & O_EXCL) { 1791 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 1792 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1793 *tl++ = cverf.lval[0]; 1794 *tl = cverf.lval[1]; 1795 } else { 1796 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 1797 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1798 } 1799 } else { 1800 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 1801 } 1802 error = nfscl_request(nd, dvp, p, cred, dstuff); 1803 if (error) 1804 return (error); 1805 if (nd->nd_repstat == 0) { 1806 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1807 if (error) 1808 goto nfsmout; 1809 } 1810 if (nd->nd_flag & ND_NFSV3) 1811 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1812 if (nd->nd_repstat != 0 && error == 0) 1813 error = nd->nd_repstat; 1814 nfsmout: 1815 mbuf_freem(nd->nd_mrep); 1816 return (error); 1817 } 1818 1819 static int 1820 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1821 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 1822 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 1823 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 1824 int *dattrflagp, void *dstuff, int *unlockedp) 1825 { 1826 u_int32_t *tl; 1827 int error = 0, deleg, newone, ret, acesize, limitby; 1828 struct nfsrv_descript nfsd, *nd = &nfsd; 1829 struct nfsclopen *op; 1830 struct nfscldeleg *dp = NULL; 1831 struct nfsnode *np; 1832 struct nfsfh *nfhp; 1833 nfsattrbit_t attrbits; 1834 nfsv4stateid_t stateid; 1835 u_int32_t rflags; 1836 1837 *unlockedp = 0; 1838 *nfhpp = NULL; 1839 *dpp = NULL; 1840 *attrflagp = 0; 1841 *dattrflagp = 0; 1842 if (namelen > NFS_MAXNAMLEN) 1843 return (ENAMETOOLONG); 1844 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 1845 /* 1846 * For V4, this is actually an Open op. 1847 */ 1848 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1849 *tl++ = txdr_unsigned(owp->nfsow_seqid); 1850 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 1851 NFSV4OPEN_ACCESSREAD); 1852 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 1853 *tl++ = owp->nfsow_clp->nfsc_clientid.lval[0]; 1854 *tl = owp->nfsow_clp->nfsc_clientid.lval[1]; 1855 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 1856 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1857 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 1858 if (fmode & O_EXCL) { 1859 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 1860 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 1861 *tl++ = cverf.lval[0]; 1862 *tl = cverf.lval[1]; 1863 } else { 1864 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 1865 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1866 } 1867 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1868 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 1869 (void) nfsm_strtom(nd, name, namelen); 1870 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1871 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1872 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1873 NFSGETATTR_ATTRBIT(&attrbits); 1874 (void) nfsrv_putattrbit(nd, &attrbits); 1875 error = nfscl_request(nd, dvp, p, cred, dstuff); 1876 if (error) 1877 return (error); 1878 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1879 if (error) 1880 goto nfsmout; 1881 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 1882 if (nd->nd_repstat == 0) { 1883 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 1884 6 * NFSX_UNSIGNED); 1885 stateid.seqid = *tl++; 1886 stateid.other[0] = *tl++; 1887 stateid.other[1] = *tl++; 1888 stateid.other[2] = *tl; 1889 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 1890 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1891 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1892 deleg = fxdr_unsigned(int, *tl); 1893 if (deleg == NFSV4OPEN_DELEGATEREAD || 1894 deleg == NFSV4OPEN_DELEGATEWRITE) { 1895 if (!(owp->nfsow_clp->nfsc_flags & 1896 NFSCLFLAGS_FIRSTDELEG)) 1897 owp->nfsow_clp->nfsc_flags |= 1898 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 1899 MALLOC(dp, struct nfscldeleg *, 1900 sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 1901 M_NFSCLDELEG, M_WAITOK); 1902 LIST_INIT(&dp->nfsdl_owner); 1903 LIST_INIT(&dp->nfsdl_lock); 1904 dp->nfsdl_clp = owp->nfsow_clp; 1905 newnfs_copyincred(cred, &dp->nfsdl_cred); 1906 nfscl_lockinit(&dp->nfsdl_rwlock); 1907 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 1908 NFSX_UNSIGNED); 1909 dp->nfsdl_stateid.seqid = *tl++; 1910 dp->nfsdl_stateid.other[0] = *tl++; 1911 dp->nfsdl_stateid.other[1] = *tl++; 1912 dp->nfsdl_stateid.other[2] = *tl++; 1913 ret = fxdr_unsigned(int, *tl); 1914 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 1915 dp->nfsdl_flags = NFSCLDL_WRITE; 1916 /* 1917 * Indicates how much the file can grow. 1918 */ 1919 NFSM_DISSECT(tl, u_int32_t *, 1920 3 * NFSX_UNSIGNED); 1921 limitby = fxdr_unsigned(int, *tl++); 1922 switch (limitby) { 1923 case NFSV4OPEN_LIMITSIZE: 1924 dp->nfsdl_sizelimit = fxdr_hyper(tl); 1925 break; 1926 case NFSV4OPEN_LIMITBLOCKS: 1927 dp->nfsdl_sizelimit = 1928 fxdr_unsigned(u_int64_t, *tl++); 1929 dp->nfsdl_sizelimit *= 1930 fxdr_unsigned(u_int64_t, *tl); 1931 break; 1932 default: 1933 error = NFSERR_BADXDR; 1934 goto nfsmout; 1935 }; 1936 } else { 1937 dp->nfsdl_flags = NFSCLDL_READ; 1938 } 1939 if (ret) 1940 dp->nfsdl_flags |= NFSCLDL_RECALL; 1941 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 1942 &acesize, p); 1943 if (error) 1944 goto nfsmout; 1945 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 1946 error = NFSERR_BADXDR; 1947 goto nfsmout; 1948 } 1949 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1950 if (error) 1951 goto nfsmout; 1952 if (dp != NULL && *attrflagp) { 1953 dp->nfsdl_change = nnap->na_filerev; 1954 dp->nfsdl_modtime = nnap->na_mtime; 1955 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 1956 } 1957 /* 1958 * We can now complete the Open state. 1959 */ 1960 nfhp = *nfhpp; 1961 if (dp != NULL) { 1962 dp->nfsdl_fhlen = nfhp->nfh_len; 1963 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 1964 } 1965 /* 1966 * Get an Open structure that will be 1967 * attached to the OpenOwner, acquired already. 1968 */ 1969 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 1970 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 1971 cred, p, NULL, &op, &newone, NULL, 0); 1972 if (error) 1973 goto nfsmout; 1974 op->nfso_stateid = stateid; 1975 newnfs_copyincred(cred, &op->nfso_cred); 1976 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 1977 do { 1978 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 1979 nfhp->nfh_len, op, cred, p); 1980 if (ret == NFSERR_DELAY) 1981 (void) nfs_catnap(PZERO, ret, "nfs_create"); 1982 } while (ret == NFSERR_DELAY); 1983 error = ret; 1984 } 1985 1986 /* 1987 * If the server is handing out delegations, but we didn't 1988 * get one because an OpenConfirm was required, try the 1989 * Open again, to get a delegation. This is a harmless no-op, 1990 * from a server's point of view. 1991 */ 1992 if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 1993 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 1994 !error && dp == NULL) { 1995 np = VTONFS(dvp); 1996 do { 1997 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp, 1998 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 1999 nfhp->nfh_fh, nfhp->nfh_len, 2000 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2001 name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2002 if (ret == NFSERR_DELAY) 2003 (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2004 } while (ret == NFSERR_DELAY); 2005 if (ret) { 2006 if (dp != NULL) 2007 FREE((caddr_t)dp, M_NFSCLDELEG); 2008 if (ret == NFSERR_STALECLIENTID || 2009 ret == NFSERR_STALEDONTRECOVER) 2010 error = ret; 2011 } 2012 } 2013 nfscl_openrelease(op, error, newone); 2014 *unlockedp = 1; 2015 } 2016 if (nd->nd_repstat != 0 && error == 0) 2017 error = nd->nd_repstat; 2018 if (error == NFSERR_STALECLIENTID) 2019 nfscl_initiate_recovery(owp->nfsow_clp); 2020 nfsmout: 2021 if (!error) 2022 *dpp = dp; 2023 else if (dp != NULL) 2024 FREE((caddr_t)dp, M_NFSCLDELEG); 2025 mbuf_freem(nd->nd_mrep); 2026 return (error); 2027 } 2028 2029 /* 2030 * Nfs remove rpc 2031 */ 2032 APPLESTATIC int 2033 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2034 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, 2035 void *dstuff) 2036 { 2037 u_int32_t *tl; 2038 struct nfsrv_descript nfsd, *nd = &nfsd; 2039 struct nfsnode *np; 2040 struct nfsmount *nmp; 2041 nfsv4stateid_t dstateid; 2042 int error, ret = 0, i; 2043 2044 *dattrflagp = 0; 2045 if (namelen > NFS_MAXNAMLEN) 2046 return (ENAMETOOLONG); 2047 nmp = VFSTONFS(vnode_mount(dvp)); 2048 tryagain: 2049 if (NFSHASNFSV4(nmp) && ret == 0) { 2050 ret = nfscl_removedeleg(vp, p, &dstateid); 2051 if (ret == 1) { 2052 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp); 2053 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2054 NFSX_UNSIGNED); 2055 *tl++ = dstateid.seqid; 2056 *tl++ = dstateid.other[0]; 2057 *tl++ = dstateid.other[1]; 2058 *tl++ = dstateid.other[2]; 2059 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2060 np = VTONFS(dvp); 2061 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2062 np->n_fhp->nfh_len, 0); 2063 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2064 *tl = txdr_unsigned(NFSV4OP_REMOVE); 2065 } 2066 } else { 2067 ret = 0; 2068 } 2069 if (ret == 0) 2070 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp); 2071 (void) nfsm_strtom(nd, name, namelen); 2072 error = nfscl_request(nd, dvp, p, cred, dstuff); 2073 if (error) 2074 return (error); 2075 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2076 /* For NFSv4, parse out any Delereturn replies. */ 2077 if (ret > 0 && nd->nd_repstat != 0 && 2078 (nd->nd_flag & ND_NOMOREDATA)) { 2079 /* 2080 * If the Delegreturn failed, try again without 2081 * it. The server will Recall, as required. 2082 */ 2083 mbuf_freem(nd->nd_mrep); 2084 goto tryagain; 2085 } 2086 for (i = 0; i < (ret * 2); i++) { 2087 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2088 ND_NFSV4) { 2089 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2090 if (*(tl + 1)) 2091 nd->nd_flag |= ND_NOMOREDATA; 2092 } 2093 } 2094 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2095 } 2096 if (nd->nd_repstat && !error) 2097 error = nd->nd_repstat; 2098 nfsmout: 2099 mbuf_freem(nd->nd_mrep); 2100 return (error); 2101 } 2102 2103 /* 2104 * Do an nfs rename rpc. 2105 */ 2106 APPLESTATIC int 2107 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2108 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2109 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2110 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff) 2111 { 2112 u_int32_t *tl; 2113 struct nfsrv_descript nfsd, *nd = &nfsd; 2114 struct nfsmount *nmp; 2115 struct nfsnode *np; 2116 nfsattrbit_t attrbits; 2117 nfsv4stateid_t fdstateid, tdstateid; 2118 int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2119 2120 *fattrflagp = 0; 2121 *tattrflagp = 0; 2122 nmp = VFSTONFS(vnode_mount(fdvp)); 2123 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2124 return (ENAMETOOLONG); 2125 tryagain: 2126 if (NFSHASNFSV4(nmp) && ret == 0) { 2127 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2128 &tdstateid, &gottd, p); 2129 if (gotfd && gottd) { 2130 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp); 2131 } else if (gotfd) { 2132 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp); 2133 } else if (gottd) { 2134 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp); 2135 } 2136 if (gotfd) { 2137 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2138 *tl++ = fdstateid.seqid; 2139 *tl++ = fdstateid.other[0]; 2140 *tl++ = fdstateid.other[1]; 2141 *tl = fdstateid.other[2]; 2142 if (gottd) { 2143 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2144 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2145 np = VTONFS(tvp); 2146 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2147 np->n_fhp->nfh_len, 0); 2148 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2149 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2150 } 2151 } 2152 if (gottd) { 2153 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2154 *tl++ = tdstateid.seqid; 2155 *tl++ = tdstateid.other[0]; 2156 *tl++ = tdstateid.other[1]; 2157 *tl = tdstateid.other[2]; 2158 } 2159 if (ret > 0) { 2160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2161 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2162 np = VTONFS(fdvp); 2163 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2164 np->n_fhp->nfh_len, 0); 2165 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2166 *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2167 } 2168 } else { 2169 ret = 0; 2170 } 2171 if (ret == 0) 2172 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp); 2173 if (nd->nd_flag & ND_NFSV4) { 2174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2175 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2176 NFSWCCATTR_ATTRBIT(&attrbits); 2177 (void) nfsrv_putattrbit(nd, &attrbits); 2178 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2179 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2180 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2181 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2182 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2183 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2184 (void) nfsrv_putattrbit(nd, &attrbits); 2185 nd->nd_flag |= ND_V4WCCATTR; 2186 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2187 *tl = txdr_unsigned(NFSV4OP_RENAME); 2188 } 2189 (void) nfsm_strtom(nd, fnameptr, fnamelen); 2190 if (!(nd->nd_flag & ND_NFSV4)) 2191 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2192 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2193 (void) nfsm_strtom(nd, tnameptr, tnamelen); 2194 error = nfscl_request(nd, fdvp, p, cred, fstuff); 2195 if (error) 2196 return (error); 2197 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2198 /* For NFSv4, parse out any Delereturn replies. */ 2199 if (ret > 0 && nd->nd_repstat != 0 && 2200 (nd->nd_flag & ND_NOMOREDATA)) { 2201 /* 2202 * If the Delegreturn failed, try again without 2203 * it. The server will Recall, as required. 2204 */ 2205 mbuf_freem(nd->nd_mrep); 2206 goto tryagain; 2207 } 2208 for (i = 0; i < (ret * 2); i++) { 2209 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2210 ND_NFSV4) { 2211 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2212 if (*(tl + 1)) { 2213 if (i == 0 && ret > 1) { 2214 /* 2215 * If the Delegreturn failed, try again 2216 * without it. The server will Recall, as 2217 * required. 2218 * If ret > 1, the first iteration of this 2219 * loop is the second DelegReturn result. 2220 */ 2221 mbuf_freem(nd->nd_mrep); 2222 goto tryagain; 2223 } else { 2224 nd->nd_flag |= ND_NOMOREDATA; 2225 } 2226 } 2227 } 2228 } 2229 /* Now, the first wcc attribute reply. */ 2230 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2231 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2232 if (*(tl + 1)) 2233 nd->nd_flag |= ND_NOMOREDATA; 2234 } 2235 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, 2236 fstuff); 2237 /* and the second wcc attribute reply. */ 2238 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2239 !error) { 2240 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2241 if (*(tl + 1)) 2242 nd->nd_flag |= ND_NOMOREDATA; 2243 } 2244 if (!error) 2245 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2246 NULL, tstuff); 2247 } 2248 if (nd->nd_repstat && !error) 2249 error = nd->nd_repstat; 2250 nfsmout: 2251 mbuf_freem(nd->nd_mrep); 2252 return (error); 2253 } 2254 2255 /* 2256 * nfs hard link create rpc 2257 */ 2258 APPLESTATIC int 2259 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2260 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2261 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2262 { 2263 u_int32_t *tl; 2264 struct nfsrv_descript nfsd, *nd = &nfsd; 2265 nfsattrbit_t attrbits; 2266 int error = 0; 2267 2268 *attrflagp = 0; 2269 *dattrflagp = 0; 2270 if (namelen > NFS_MAXNAMLEN) 2271 return (ENAMETOOLONG); 2272 NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2273 if (nd->nd_flag & ND_NFSV4) { 2274 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2275 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2276 } 2277 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2278 VTONFS(dvp)->n_fhp->nfh_len, 0); 2279 if (nd->nd_flag & ND_NFSV4) { 2280 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2281 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2282 NFSWCCATTR_ATTRBIT(&attrbits); 2283 (void) nfsrv_putattrbit(nd, &attrbits); 2284 nd->nd_flag |= ND_V4WCCATTR; 2285 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2286 *tl = txdr_unsigned(NFSV4OP_LINK); 2287 } 2288 (void) nfsm_strtom(nd, name, namelen); 2289 error = nfscl_request(nd, vp, p, cred, dstuff); 2290 if (error) 2291 return (error); 2292 if (nd->nd_flag & ND_NFSV3) { 2293 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2294 if (!error) 2295 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2296 NULL, dstuff); 2297 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2298 /* 2299 * First, parse out the PutFH and Getattr result. 2300 */ 2301 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2302 if (!(*(tl + 1))) 2303 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2304 if (*(tl + 1)) 2305 nd->nd_flag |= ND_NOMOREDATA; 2306 /* 2307 * Get the pre-op attributes. 2308 */ 2309 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2310 } 2311 if (nd->nd_repstat && !error) 2312 error = nd->nd_repstat; 2313 nfsmout: 2314 mbuf_freem(nd->nd_mrep); 2315 return (error); 2316 } 2317 2318 /* 2319 * nfs symbolic link create rpc 2320 */ 2321 APPLESTATIC int 2322 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target, 2323 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2324 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2325 int *dattrflagp, void *dstuff) 2326 { 2327 u_int32_t *tl; 2328 struct nfsrv_descript nfsd, *nd = &nfsd; 2329 struct nfsmount *nmp; 2330 int slen, error = 0; 2331 2332 *nfhpp = NULL; 2333 *attrflagp = 0; 2334 *dattrflagp = 0; 2335 nmp = VFSTONFS(vnode_mount(dvp)); 2336 slen = strlen(target); 2337 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2338 return (ENAMETOOLONG); 2339 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2340 if (nd->nd_flag & ND_NFSV4) { 2341 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2342 *tl = txdr_unsigned(NFLNK); 2343 (void) nfsm_strtom(nd, target, slen); 2344 } 2345 (void) nfsm_strtom(nd, name, namelen); 2346 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2347 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2348 if (!(nd->nd_flag & ND_NFSV4)) 2349 (void) nfsm_strtom(nd, target, slen); 2350 if (nd->nd_flag & ND_NFSV2) 2351 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2352 error = nfscl_request(nd, dvp, p, cred, dstuff); 2353 if (error) 2354 return (error); 2355 if (nd->nd_flag & ND_NFSV4) 2356 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2357 if ((nd->nd_flag & ND_NFSV3) && !error) { 2358 if (!nd->nd_repstat) 2359 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2360 if (!error) 2361 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2362 NULL, dstuff); 2363 } 2364 if (nd->nd_repstat && !error) 2365 error = nd->nd_repstat; 2366 mbuf_freem(nd->nd_mrep); 2367 /* 2368 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2369 */ 2370 if (error == EEXIST) 2371 error = 0; 2372 return (error); 2373 } 2374 2375 /* 2376 * nfs make dir rpc 2377 */ 2378 APPLESTATIC int 2379 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2380 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2381 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2382 int *dattrflagp, void *dstuff) 2383 { 2384 u_int32_t *tl; 2385 struct nfsrv_descript nfsd, *nd = &nfsd; 2386 nfsattrbit_t attrbits; 2387 int error = 0; 2388 2389 *nfhpp = NULL; 2390 *attrflagp = 0; 2391 *dattrflagp = 0; 2392 if (namelen > NFS_MAXNAMLEN) 2393 return (ENAMETOOLONG); 2394 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 2395 if (nd->nd_flag & ND_NFSV4) { 2396 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2397 *tl = txdr_unsigned(NFDIR); 2398 } 2399 (void) nfsm_strtom(nd, name, namelen); 2400 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2401 if (nd->nd_flag & ND_NFSV4) { 2402 NFSGETATTR_ATTRBIT(&attrbits); 2403 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2404 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2405 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2406 (void) nfsrv_putattrbit(nd, &attrbits); 2407 } 2408 error = nfscl_request(nd, dvp, p, cred, dstuff); 2409 if (error) 2410 return (error); 2411 if (nd->nd_flag & ND_NFSV4) 2412 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2413 if (!nd->nd_repstat && !error) { 2414 if (nd->nd_flag & ND_NFSV4) { 2415 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2416 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2417 } 2418 if (!error) 2419 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2420 } 2421 if ((nd->nd_flag & ND_NFSV3) && !error) 2422 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2423 if (nd->nd_repstat && !error) 2424 error = nd->nd_repstat; 2425 nfsmout: 2426 mbuf_freem(nd->nd_mrep); 2427 /* 2428 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry. 2429 */ 2430 if (error == EEXIST) 2431 error = 0; 2432 return (error); 2433 } 2434 2435 /* 2436 * nfs remove directory call 2437 */ 2438 APPLESTATIC int 2439 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 2440 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 2441 { 2442 struct nfsrv_descript nfsd, *nd = &nfsd; 2443 int error = 0; 2444 2445 *dattrflagp = 0; 2446 if (namelen > NFS_MAXNAMLEN) 2447 return (ENAMETOOLONG); 2448 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 2449 (void) nfsm_strtom(nd, name, namelen); 2450 error = nfscl_request(nd, dvp, p, cred, dstuff); 2451 if (error) 2452 return (error); 2453 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2454 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2455 if (nd->nd_repstat && !error) 2456 error = nd->nd_repstat; 2457 mbuf_freem(nd->nd_mrep); 2458 /* 2459 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2460 */ 2461 if (error == ENOENT) 2462 error = 0; 2463 return (error); 2464 } 2465 2466 /* 2467 * Readdir rpc. 2468 * Always returns with either uio_resid unchanged, if you are at the 2469 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 2470 * filled in. 2471 * I felt this would allow caching of directory blocks more easily 2472 * than returning a pertially filled block. 2473 * Directory offset cookies: 2474 * Oh my, what to do with them... 2475 * I can think of three ways to deal with them: 2476 * 1 - have the layer above these RPCs maintain a map between logical 2477 * directory byte offsets and the NFS directory offset cookies 2478 * 2 - pass the opaque directory offset cookies up into userland 2479 * and let the libc functions deal with them, via the system call 2480 * 3 - return them to userland in the "struct dirent", so future versions 2481 * of libc can use them and do whatever is necessary to amke things work 2482 * above these rpc calls, in the meantime 2483 * For now, I do #3 by "hiding" the directory offset cookies after the 2484 * d_name field in struct dirent. This is space inside d_reclen that 2485 * will be ignored by anything that doesn't know about them. 2486 * The directory offset cookies are filled in as the last 8 bytes of 2487 * each directory entry, after d_name. Someday, the userland libc 2488 * functions may be able to use these. In the meantime, it satisfies 2489 * OpenBSD's requirements for cookies being returned. 2490 * If expects the directory offset cookie for the read to be in uio_offset 2491 * and returns the one for the next entry after this directory block in 2492 * there, as well. 2493 */ 2494 APPLESTATIC int 2495 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2496 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2497 int *eofp, void *stuff) 2498 { 2499 int len, left; 2500 struct dirent *dp = NULL; 2501 u_int32_t *tl; 2502 nfsquad_t cookie, ncookie; 2503 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2504 struct nfsnode *dnp = VTONFS(vp); 2505 struct nfsvattr nfsva; 2506 struct nfsrv_descript nfsd, *nd = &nfsd; 2507 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2508 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 2509 long dotfileid, dotdotfileid = 0; 2510 u_int32_t fakefileno = 0xffffffff, rderr; 2511 char *cp; 2512 nfsattrbit_t attrbits, dattrbits; 2513 u_int32_t *tl2 = NULL; 2514 size_t tresid; 2515 2516 KASSERT(uiop->uio_iovcnt == 1 && 2517 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2518 ("nfs readdirrpc bad uio")); 2519 2520 /* 2521 * There is no point in reading a lot more than uio_resid, however 2522 * adding one additional DIRBLKSIZ makes sense. Since uio_resid 2523 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 2524 * will never make readsize > nm_readdirsize. 2525 */ 2526 readsize = nmp->nm_readdirsize; 2527 if (readsize > uio_uio_resid(uiop)) 2528 readsize = uio_uio_resid(uiop) + DIRBLKSIZ; 2529 2530 *attrflagp = 0; 2531 if (eofp) 2532 *eofp = 0; 2533 tresid = uio_uio_resid(uiop); 2534 cookie.lval[0] = cookiep->nfsuquad[0]; 2535 cookie.lval[1] = cookiep->nfsuquad[1]; 2536 nd->nd_mrep = NULL; 2537 2538 /* 2539 * For NFSv4, first create the "." and ".." entries. 2540 */ 2541 if (NFSHASNFSV4(nmp)) { 2542 reqsize = 6 * NFSX_UNSIGNED; 2543 NFSGETATTR_ATTRBIT(&dattrbits); 2544 NFSZERO_ATTRBIT(&attrbits); 2545 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2546 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 2547 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2548 NFSATTRBIT_MOUNTEDONFILEID)) { 2549 NFSSETBIT_ATTRBIT(&attrbits, 2550 NFSATTRBIT_MOUNTEDONFILEID); 2551 gotmnton = 1; 2552 } else { 2553 /* 2554 * Must fake it. Use the fileno, except when the 2555 * fsid is != to that of the directory. For that 2556 * case, generate a fake fileno that is not the same. 2557 */ 2558 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2559 gotmnton = 0; 2560 } 2561 2562 /* 2563 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2564 */ 2565 if (uiop->uio_offset == 0) { 2566 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 2567 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred); 2568 #else 2569 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p); 2570 #endif 2571 if (error) 2572 return (error); 2573 dotfileid = nfsva.na_fileid; 2574 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2575 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2576 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2577 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2578 (void) nfsrv_putattrbit(nd, &attrbits); 2579 error = nfscl_request(nd, vp, p, cred, stuff); 2580 if (error) 2581 return (error); 2582 if (nd->nd_repstat == 0) { 2583 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2584 len = fxdr_unsigned(int, *(tl + 2)); 2585 if (len > 0 && len <= NFSX_V4FHMAX) 2586 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2587 else 2588 error = EPERM; 2589 if (!error) { 2590 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2591 nfsva.na_mntonfileno = 0xffffffff; 2592 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2593 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2594 NULL, NULL, NULL, p, cred); 2595 if (error) { 2596 dotdotfileid = dotfileid; 2597 } else if (gotmnton) { 2598 if (nfsva.na_mntonfileno != 0xffffffff) 2599 dotdotfileid = nfsva.na_mntonfileno; 2600 else 2601 dotdotfileid = nfsva.na_fileid; 2602 } else if (nfsva.na_filesid[0] == 2603 dnp->n_vattr.na_filesid[0] && 2604 nfsva.na_filesid[1] == 2605 dnp->n_vattr.na_filesid[1]) { 2606 dotdotfileid = nfsva.na_fileid; 2607 } else { 2608 do { 2609 fakefileno--; 2610 } while (fakefileno == 2611 nfsva.na_fileid); 2612 dotdotfileid = fakefileno; 2613 } 2614 } 2615 } else if (nd->nd_repstat == NFSERR_NOENT) { 2616 /* 2617 * Lookupp returns NFSERR_NOENT when we are 2618 * at the root, so just use the current dir. 2619 */ 2620 nd->nd_repstat = 0; 2621 dotdotfileid = dotfileid; 2622 } else { 2623 error = nd->nd_repstat; 2624 } 2625 mbuf_freem(nd->nd_mrep); 2626 if (error) 2627 return (error); 2628 nd->nd_mrep = NULL; 2629 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2630 dp->d_type = DT_DIR; 2631 dp->d_fileno = dotfileid; 2632 dp->d_namlen = 1; 2633 dp->d_name[0] = '.'; 2634 dp->d_name[1] = '\0'; 2635 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2636 /* 2637 * Just make these offset cookie 0. 2638 */ 2639 tl = (u_int32_t *)&dp->d_name[4]; 2640 *tl++ = 0; 2641 *tl = 0; 2642 blksiz += dp->d_reclen; 2643 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2644 uiop->uio_offset += dp->d_reclen; 2645 uio_iov_base_add(uiop, dp->d_reclen); 2646 uio_iov_len_add(uiop, -(dp->d_reclen)); 2647 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2648 dp->d_type = DT_DIR; 2649 dp->d_fileno = dotdotfileid; 2650 dp->d_namlen = 2; 2651 dp->d_name[0] = '.'; 2652 dp->d_name[1] = '.'; 2653 dp->d_name[2] = '\0'; 2654 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 2655 /* 2656 * Just make these offset cookie 0. 2657 */ 2658 tl = (u_int32_t *)&dp->d_name[4]; 2659 *tl++ = 0; 2660 *tl = 0; 2661 blksiz += dp->d_reclen; 2662 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2663 uiop->uio_offset += dp->d_reclen; 2664 uio_iov_base_add(uiop, dp->d_reclen); 2665 uio_iov_len_add(uiop, -(dp->d_reclen)); 2666 } 2667 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 2668 } else { 2669 reqsize = 5 * NFSX_UNSIGNED; 2670 } 2671 2672 2673 /* 2674 * Loop around doing readdir rpc's of size readsize. 2675 * The stopping criteria is EOF or buffer full. 2676 */ 2677 while (more_dirs && bigenough) { 2678 *attrflagp = 0; 2679 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 2680 if (nd->nd_flag & ND_NFSV2) { 2681 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2682 *tl++ = cookie.lval[1]; 2683 *tl = txdr_unsigned(readsize); 2684 } else { 2685 NFSM_BUILD(tl, u_int32_t *, reqsize); 2686 *tl++ = cookie.lval[0]; 2687 *tl++ = cookie.lval[1]; 2688 if (cookie.qval == 0) { 2689 *tl++ = 0; 2690 *tl++ = 0; 2691 } else { 2692 NFSLOCKNODE(dnp); 2693 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 2694 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 2695 NFSUNLOCKNODE(dnp); 2696 } 2697 if (nd->nd_flag & ND_NFSV4) { 2698 *tl++ = txdr_unsigned(readsize); 2699 *tl = txdr_unsigned(readsize); 2700 (void) nfsrv_putattrbit(nd, &attrbits); 2701 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2702 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2703 (void) nfsrv_putattrbit(nd, &dattrbits); 2704 } else { 2705 *tl = txdr_unsigned(readsize); 2706 } 2707 } 2708 error = nfscl_request(nd, vp, p, cred, stuff); 2709 if (error) 2710 return (error); 2711 if (!(nd->nd_flag & ND_NFSV2)) { 2712 if (nd->nd_flag & ND_NFSV3) 2713 error = nfscl_postop_attr(nd, nap, attrflagp, 2714 stuff); 2715 if (!nd->nd_repstat && !error) { 2716 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 2717 NFSLOCKNODE(dnp); 2718 dnp->n_cookieverf.nfsuquad[0] = *tl++; 2719 dnp->n_cookieverf.nfsuquad[1] = *tl; 2720 NFSUNLOCKNODE(dnp); 2721 } 2722 } 2723 if (nd->nd_repstat || error) { 2724 if (!error) 2725 error = nd->nd_repstat; 2726 goto nfsmout; 2727 } 2728 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2729 more_dirs = fxdr_unsigned(int, *tl); 2730 if (!more_dirs) 2731 tryformoredirs = 0; 2732 2733 /* loop thru the dir entries, doctoring them to 4bsd form */ 2734 while (more_dirs && bigenough) { 2735 if (nd->nd_flag & ND_NFSV4) { 2736 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2737 ncookie.lval[0] = *tl++; 2738 ncookie.lval[1] = *tl++; 2739 len = fxdr_unsigned(int, *tl); 2740 } else if (nd->nd_flag & ND_NFSV3) { 2741 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2742 nfsva.na_fileid = fxdr_hyper(tl); 2743 tl += 2; 2744 len = fxdr_unsigned(int, *tl); 2745 } else { 2746 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2747 nfsva.na_fileid = 2748 fxdr_unsigned(long, *tl++); 2749 len = fxdr_unsigned(int, *tl); 2750 } 2751 if (len <= 0 || len > NFS_MAXNAMLEN) { 2752 error = EBADRPC; 2753 goto nfsmout; 2754 } 2755 tlen = NFSM_RNDUP(len); 2756 if (tlen == len) 2757 tlen += 4; /* To ensure null termination */ 2758 left = DIRBLKSIZ - blksiz; 2759 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) { 2760 dp->d_reclen += left; 2761 uio_iov_base_add(uiop, left); 2762 uio_iov_len_add(uiop, -(left)); 2763 uio_uio_resid_add(uiop, -(left)); 2764 uiop->uio_offset += left; 2765 blksiz = 0; 2766 } 2767 if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 2768 bigenough = 0; 2769 if (bigenough) { 2770 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2771 dp->d_namlen = len; 2772 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 2773 dp->d_type = DT_UNKNOWN; 2774 blksiz += dp->d_reclen; 2775 if (blksiz == DIRBLKSIZ) 2776 blksiz = 0; 2777 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 2778 uiop->uio_offset += DIRHDSIZ; 2779 uio_iov_base_add(uiop, DIRHDSIZ); 2780 uio_iov_len_add(uiop, -(DIRHDSIZ)); 2781 error = nfsm_mbufuio(nd, uiop, len); 2782 if (error) 2783 goto nfsmout; 2784 cp = CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2785 tlen -= len; 2786 *cp = '\0'; /* null terminate */ 2787 cp += tlen; /* points to cookie storage */ 2788 tl2 = (u_int32_t *)cp; 2789 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 2790 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 2791 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 2792 uiop->uio_offset += (tlen + NFSX_HYPER); 2793 } else { 2794 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2795 if (error) 2796 goto nfsmout; 2797 } 2798 if (nd->nd_flag & ND_NFSV4) { 2799 rderr = 0; 2800 nfsva.na_mntonfileno = 0xffffffff; 2801 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2802 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2803 NULL, NULL, &rderr, p, cred); 2804 if (error) 2805 goto nfsmout; 2806 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2807 } else if (nd->nd_flag & ND_NFSV3) { 2808 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 2809 ncookie.lval[0] = *tl++; 2810 ncookie.lval[1] = *tl++; 2811 } else { 2812 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2813 ncookie.lval[0] = 0; 2814 ncookie.lval[1] = *tl++; 2815 } 2816 if (bigenough) { 2817 if (nd->nd_flag & ND_NFSV4) { 2818 if (rderr) { 2819 dp->d_fileno = 0; 2820 } else { 2821 if (gotmnton) { 2822 if (nfsva.na_mntonfileno != 0xffffffff) 2823 dp->d_fileno = nfsva.na_mntonfileno; 2824 else 2825 dp->d_fileno = nfsva.na_fileid; 2826 } else if (nfsva.na_filesid[0] == 2827 dnp->n_vattr.na_filesid[0] && 2828 nfsva.na_filesid[1] == 2829 dnp->n_vattr.na_filesid[1]) { 2830 dp->d_fileno = nfsva.na_fileid; 2831 } else { 2832 do { 2833 fakefileno--; 2834 } while (fakefileno == 2835 nfsva.na_fileid); 2836 dp->d_fileno = fakefileno; 2837 } 2838 dp->d_type = vtonfs_dtype(nfsva.na_type); 2839 } 2840 } else { 2841 dp->d_fileno = nfsva.na_fileid; 2842 } 2843 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 2844 ncookie.lval[0]; 2845 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 2846 ncookie.lval[1]; 2847 } 2848 more_dirs = fxdr_unsigned(int, *tl); 2849 } 2850 /* 2851 * If at end of rpc data, get the eof boolean 2852 */ 2853 if (!more_dirs) { 2854 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2855 eof = fxdr_unsigned(int, *tl); 2856 if (tryformoredirs) 2857 more_dirs = !eof; 2858 if (nd->nd_flag & ND_NFSV4) { 2859 error = nfscl_postop_attr(nd, nap, attrflagp, 2860 stuff); 2861 if (error) 2862 goto nfsmout; 2863 } 2864 } 2865 mbuf_freem(nd->nd_mrep); 2866 nd->nd_mrep = NULL; 2867 } 2868 /* 2869 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 2870 * by increasing d_reclen for the last record. 2871 */ 2872 if (blksiz > 0) { 2873 left = DIRBLKSIZ - blksiz; 2874 dp->d_reclen += left; 2875 uio_iov_base_add(uiop, left); 2876 uio_iov_len_add(uiop, -(left)); 2877 uio_uio_resid_add(uiop, -(left)); 2878 uiop->uio_offset += left; 2879 } 2880 2881 /* 2882 * If returning no data, assume end of file. 2883 * If not bigenough, return not end of file, since you aren't 2884 * returning all the data 2885 * Otherwise, return the eof flag from the server. 2886 */ 2887 if (eofp) { 2888 if (tresid == ((size_t)(uio_uio_resid(uiop)))) 2889 *eofp = 1; 2890 else if (!bigenough) 2891 *eofp = 0; 2892 else 2893 *eofp = eof; 2894 } 2895 2896 /* 2897 * Add extra empty records to any remaining DIRBLKSIZ chunks. 2898 */ 2899 while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) { 2900 dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop)); 2901 dp->d_type = DT_UNKNOWN; 2902 dp->d_fileno = 0; 2903 dp->d_namlen = 0; 2904 dp->d_name[0] = '\0'; 2905 tl = (u_int32_t *)&dp->d_name[4]; 2906 *tl++ = cookie.lval[0]; 2907 *tl = cookie.lval[1]; 2908 dp->d_reclen = DIRBLKSIZ; 2909 uio_iov_base_add(uiop, DIRBLKSIZ); 2910 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 2911 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 2912 uiop->uio_offset += DIRBLKSIZ; 2913 } 2914 2915 nfsmout: 2916 if (nd->nd_mrep != NULL) 2917 mbuf_freem(nd->nd_mrep); 2918 return (error); 2919 } 2920 2921 #ifndef APPLE 2922 /* 2923 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 2924 * (Also used for NFS V4 when mount flag set.) 2925 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 2926 */ 2927 APPLESTATIC int 2928 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2929 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2930 int *eofp, void *stuff) 2931 { 2932 int len, left; 2933 struct dirent *dp = NULL; 2934 u_int32_t *tl; 2935 vnode_t newvp = NULLVP; 2936 struct nfsrv_descript nfsd, *nd = &nfsd; 2937 struct nameidata nami, *ndp = &nami; 2938 struct componentname *cnp = &ndp->ni_cnd; 2939 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2940 struct nfsnode *dnp = VTONFS(vp), *np; 2941 struct nfsvattr nfsva; 2942 struct nfsfh *nfhp; 2943 nfsquad_t cookie, ncookie; 2944 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2945 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 2946 int isdotdot = 0, unlocknewvp = 0; 2947 long dotfileid, dotdotfileid = 0, fileno = 0; 2948 char *cp; 2949 nfsattrbit_t attrbits, dattrbits; 2950 size_t tresid; 2951 u_int32_t *tl2 = NULL, fakefileno = 0xffffffff, rderr; 2952 2953 KASSERT(uiop->uio_iovcnt == 1 && 2954 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2955 ("nfs readdirplusrpc bad uio")); 2956 *attrflagp = 0; 2957 if (eofp != NULL) 2958 *eofp = 0; 2959 ndp->ni_dvp = vp; 2960 nd->nd_mrep = NULL; 2961 cookie.lval[0] = cookiep->nfsuquad[0]; 2962 cookie.lval[1] = cookiep->nfsuquad[1]; 2963 tresid = uio_uio_resid(uiop); 2964 2965 /* 2966 * For NFSv4, first create the "." and ".." entries. 2967 */ 2968 if (NFSHASNFSV4(nmp)) { 2969 NFSGETATTR_ATTRBIT(&dattrbits); 2970 NFSZERO_ATTRBIT(&attrbits); 2971 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2972 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2973 NFSATTRBIT_MOUNTEDONFILEID)) { 2974 NFSSETBIT_ATTRBIT(&attrbits, 2975 NFSATTRBIT_MOUNTEDONFILEID); 2976 gotmnton = 1; 2977 } else { 2978 /* 2979 * Must fake it. Use the fileno, except when the 2980 * fsid is != to that of the directory. For that 2981 * case, generate a fake fileno that is not the same. 2982 */ 2983 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2984 gotmnton = 0; 2985 } 2986 2987 /* 2988 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2989 */ 2990 if (uiop->uio_offset == 0) { 2991 #if defined(__FreeBSD_version) && __FreeBSD_version >= 800000 2992 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred); 2993 #else 2994 error = VOP_GETATTR(vp, &nfsva.na_vattr, cred, p); 2995 #endif 2996 if (error) 2997 return (error); 2998 dotfileid = nfsva.na_fileid; 2999 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3000 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3001 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3002 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3003 (void) nfsrv_putattrbit(nd, &attrbits); 3004 error = nfscl_request(nd, vp, p, cred, stuff); 3005 if (error) 3006 return (error); 3007 if (nd->nd_repstat == 0) { 3008 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3009 len = fxdr_unsigned(int, *(tl + 2)); 3010 if (len > 0 && len <= NFSX_V4FHMAX) 3011 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3012 else 3013 error = EPERM; 3014 if (!error) { 3015 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3016 nfsva.na_mntonfileno = 0xffffffff; 3017 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3018 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3019 NULL, NULL, NULL, p, cred); 3020 if (error) { 3021 dotdotfileid = dotfileid; 3022 } else if (gotmnton) { 3023 if (nfsva.na_mntonfileno != 0xffffffff) 3024 dotdotfileid = nfsva.na_mntonfileno; 3025 else 3026 dotdotfileid = nfsva.na_fileid; 3027 } else if (nfsva.na_filesid[0] == 3028 dnp->n_vattr.na_filesid[0] && 3029 nfsva.na_filesid[1] == 3030 dnp->n_vattr.na_filesid[1]) { 3031 dotdotfileid = nfsva.na_fileid; 3032 } else { 3033 do { 3034 fakefileno--; 3035 } while (fakefileno == 3036 nfsva.na_fileid); 3037 dotdotfileid = fakefileno; 3038 } 3039 } 3040 } else if (nd->nd_repstat == NFSERR_NOENT) { 3041 /* 3042 * Lookupp returns NFSERR_NOENT when we are 3043 * at the root, so just use the current dir. 3044 */ 3045 nd->nd_repstat = 0; 3046 dotdotfileid = dotfileid; 3047 } else { 3048 error = nd->nd_repstat; 3049 } 3050 mbuf_freem(nd->nd_mrep); 3051 if (error) 3052 return (error); 3053 nd->nd_mrep = NULL; 3054 dp = (struct dirent *)uio_iov_base(uiop); 3055 dp->d_type = DT_DIR; 3056 dp->d_fileno = dotfileid; 3057 dp->d_namlen = 1; 3058 dp->d_name[0] = '.'; 3059 dp->d_name[1] = '\0'; 3060 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3061 /* 3062 * Just make these offset cookie 0. 3063 */ 3064 tl = (u_int32_t *)&dp->d_name[4]; 3065 *tl++ = 0; 3066 *tl = 0; 3067 blksiz += dp->d_reclen; 3068 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3069 uiop->uio_offset += dp->d_reclen; 3070 uio_iov_base_add(uiop, dp->d_reclen); 3071 uio_iov_len_add(uiop, -(dp->d_reclen)); 3072 dp = (struct dirent *)uio_iov_base(uiop); 3073 dp->d_type = DT_DIR; 3074 dp->d_fileno = dotdotfileid; 3075 dp->d_namlen = 2; 3076 dp->d_name[0] = '.'; 3077 dp->d_name[1] = '.'; 3078 dp->d_name[2] = '\0'; 3079 dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER; 3080 /* 3081 * Just make these offset cookie 0. 3082 */ 3083 tl = (u_int32_t *)&dp->d_name[4]; 3084 *tl++ = 0; 3085 *tl = 0; 3086 blksiz += dp->d_reclen; 3087 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3088 uiop->uio_offset += dp->d_reclen; 3089 uio_iov_base_add(uiop, dp->d_reclen); 3090 uio_iov_len_add(uiop, -(dp->d_reclen)); 3091 } 3092 NFSREADDIRPLUS_ATTRBIT(&attrbits); 3093 if (gotmnton) 3094 NFSSETBIT_ATTRBIT(&attrbits, 3095 NFSATTRBIT_MOUNTEDONFILEID); 3096 } 3097 3098 /* 3099 * Loop around doing readdir rpc's of size nm_readdirsize. 3100 * The stopping criteria is EOF or buffer full. 3101 */ 3102 while (more_dirs && bigenough) { 3103 *attrflagp = 0; 3104 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3105 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3106 *tl++ = cookie.lval[0]; 3107 *tl++ = cookie.lval[1]; 3108 if (cookie.qval == 0) { 3109 *tl++ = 0; 3110 *tl++ = 0; 3111 } else { 3112 NFSLOCKNODE(dnp); 3113 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3114 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3115 NFSUNLOCKNODE(dnp); 3116 } 3117 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3118 *tl = txdr_unsigned(nmp->nm_readdirsize); 3119 if (nd->nd_flag & ND_NFSV4) { 3120 (void) nfsrv_putattrbit(nd, &attrbits); 3121 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3122 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3123 (void) nfsrv_putattrbit(nd, &dattrbits); 3124 } 3125 error = nfscl_request(nd, vp, p, cred, stuff); 3126 if (error) 3127 return (error); 3128 if (nd->nd_flag & ND_NFSV3) 3129 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3130 if (nd->nd_repstat || error) { 3131 if (!error) 3132 error = nd->nd_repstat; 3133 goto nfsmout; 3134 } 3135 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3136 NFSLOCKNODE(dnp); 3137 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3138 dnp->n_cookieverf.nfsuquad[1] = *tl++; 3139 NFSUNLOCKNODE(dnp); 3140 more_dirs = fxdr_unsigned(int, *tl); 3141 if (!more_dirs) 3142 tryformoredirs = 0; 3143 3144 /* loop thru the dir entries, doctoring them to 4bsd form */ 3145 while (more_dirs && bigenough) { 3146 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3147 if (nd->nd_flag & ND_NFSV4) { 3148 ncookie.lval[0] = *tl++; 3149 ncookie.lval[1] = *tl++; 3150 } else { 3151 fileno = fxdr_unsigned(long, *++tl); 3152 tl++; 3153 } 3154 len = fxdr_unsigned(int, *tl); 3155 if (len <= 0 || len > NFS_MAXNAMLEN) { 3156 error = EBADRPC; 3157 goto nfsmout; 3158 } 3159 tlen = NFSM_RNDUP(len); 3160 if (tlen == len) 3161 tlen += 4; /* To ensure null termination */ 3162 left = DIRBLKSIZ - blksiz; 3163 if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) { 3164 dp->d_reclen += left; 3165 uio_iov_base_add(uiop, left); 3166 uio_iov_len_add(uiop, -(left)); 3167 uio_uio_resid_add(uiop, -(left)); 3168 uiop->uio_offset += left; 3169 blksiz = 0; 3170 } 3171 if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop)) 3172 bigenough = 0; 3173 if (bigenough) { 3174 dp = (struct dirent *)uio_iov_base(uiop); 3175 dp->d_namlen = len; 3176 dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER; 3177 dp->d_type = DT_UNKNOWN; 3178 blksiz += dp->d_reclen; 3179 if (blksiz == DIRBLKSIZ) 3180 blksiz = 0; 3181 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3182 uiop->uio_offset += DIRHDSIZ; 3183 uio_iov_base_add(uiop, DIRHDSIZ); 3184 uio_iov_len_add(uiop, -(DIRHDSIZ)); 3185 cnp->cn_nameptr = uio_iov_base(uiop); 3186 cnp->cn_namelen = len; 3187 NFSCNHASHZERO(cnp); 3188 error = nfsm_mbufuio(nd, uiop, len); 3189 if (error) 3190 goto nfsmout; 3191 cp = uio_iov_base(uiop); 3192 tlen -= len; 3193 *cp = '\0'; 3194 cp += tlen; /* points to cookie storage */ 3195 tl2 = (u_int32_t *)cp; 3196 if (len == 2 && cnp->cn_nameptr[0] == '.' && 3197 cnp->cn_nameptr[1] == '.') 3198 isdotdot = 1; 3199 else 3200 isdotdot = 0; 3201 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3202 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3203 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3204 uiop->uio_offset += (tlen + NFSX_HYPER); 3205 } else { 3206 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3207 if (error) 3208 goto nfsmout; 3209 } 3210 nfhp = NULL; 3211 if (nd->nd_flag & ND_NFSV3) { 3212 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3213 ncookie.lval[0] = *tl++; 3214 ncookie.lval[1] = *tl++; 3215 attrflag = fxdr_unsigned(int, *tl); 3216 if (attrflag) { 3217 error = nfsm_loadattr(nd, &nfsva); 3218 if (error) 3219 goto nfsmout; 3220 } 3221 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3222 if (*tl) { 3223 error = nfsm_getfh(nd, &nfhp); 3224 if (error) 3225 goto nfsmout; 3226 } 3227 if (!attrflag && nfhp != NULL) { 3228 FREE((caddr_t)nfhp, M_NFSFH); 3229 nfhp = NULL; 3230 } 3231 } else { 3232 rderr = 0; 3233 nfsva.na_mntonfileno = 0xffffffff; 3234 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3235 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3236 NULL, NULL, &rderr, p, cred); 3237 if (error) 3238 goto nfsmout; 3239 } 3240 3241 if (bigenough) { 3242 if (nd->nd_flag & ND_NFSV4) { 3243 if (rderr) { 3244 dp->d_fileno = 0; 3245 } else if (gotmnton) { 3246 if (nfsva.na_mntonfileno != 0xffffffff) 3247 dp->d_fileno = nfsva.na_mntonfileno; 3248 else 3249 dp->d_fileno = nfsva.na_fileid; 3250 } else if (nfsva.na_filesid[0] == 3251 dnp->n_vattr.na_filesid[0] && 3252 nfsva.na_filesid[1] == 3253 dnp->n_vattr.na_filesid[1]) { 3254 dp->d_fileno = nfsva.na_fileid; 3255 } else { 3256 do { 3257 fakefileno--; 3258 } while (fakefileno == 3259 nfsva.na_fileid); 3260 dp->d_fileno = fakefileno; 3261 } 3262 } else { 3263 dp->d_fileno = fileno; 3264 } 3265 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3266 ncookie.lval[0]; 3267 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3268 ncookie.lval[1]; 3269 3270 if (nfhp != NULL) { 3271 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3272 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3273 VREF(vp); 3274 newvp = vp; 3275 unlocknewvp = 0; 3276 FREE((caddr_t)nfhp, M_NFSFH); 3277 np = dnp; 3278 } else if (isdotdot != 0) { 3279 /* 3280 * Skip doing a nfscl_nget() call for "..". 3281 * There's a race between acquiring the nfs 3282 * node here and lookups that look for the 3283 * directory being read (in the parent). 3284 * It would try to get a lock on ".." here, 3285 * owning the lock on the directory being 3286 * read. Lookup will hold the lock on ".." 3287 * and try to acquire the lock on the 3288 * directory being read. 3289 * If the directory is unlocked/relocked, 3290 * then there is a LOR with the buflock 3291 * vp is relocked. 3292 */ 3293 free(nfhp, M_NFSFH); 3294 } else { 3295 error = nfscl_nget(vnode_mount(vp), vp, 3296 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 3297 if (!error) { 3298 newvp = NFSTOV(np); 3299 unlocknewvp = 1; 3300 } 3301 } 3302 nfhp = NULL; 3303 if (newvp != NULLVP) { 3304 error = nfscl_loadattrcache(&newvp, 3305 &nfsva, NULL, NULL, 0, 0); 3306 if (error) { 3307 if (unlocknewvp) 3308 vput(newvp); 3309 else 3310 vrele(newvp); 3311 goto nfsmout; 3312 } 3313 dp->d_type = 3314 vtonfs_dtype(np->n_vattr.na_type); 3315 ndp->ni_vp = newvp; 3316 NFSCNHASH(cnp, HASHINIT); 3317 if (cnp->cn_namelen <= NCHNAMLEN) { 3318 np->n_ctime = np->n_vattr.na_ctime; 3319 cache_enter(ndp->ni_dvp,ndp->ni_vp,cnp); 3320 } 3321 if (unlocknewvp) 3322 vput(newvp); 3323 else 3324 vrele(newvp); 3325 newvp = NULLVP; 3326 } 3327 } 3328 } else if (nfhp != NULL) { 3329 FREE((caddr_t)nfhp, M_NFSFH); 3330 } 3331 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3332 more_dirs = fxdr_unsigned(int, *tl); 3333 } 3334 /* 3335 * If at end of rpc data, get the eof boolean 3336 */ 3337 if (!more_dirs) { 3338 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3339 eof = fxdr_unsigned(int, *tl); 3340 if (tryformoredirs) 3341 more_dirs = !eof; 3342 if (nd->nd_flag & ND_NFSV4) { 3343 error = nfscl_postop_attr(nd, nap, attrflagp, 3344 stuff); 3345 if (error) 3346 goto nfsmout; 3347 } 3348 } 3349 mbuf_freem(nd->nd_mrep); 3350 nd->nd_mrep = NULL; 3351 } 3352 /* 3353 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3354 * by increasing d_reclen for the last record. 3355 */ 3356 if (blksiz > 0) { 3357 left = DIRBLKSIZ - blksiz; 3358 dp->d_reclen += left; 3359 uio_iov_base_add(uiop, left); 3360 uio_iov_len_add(uiop, -(left)); 3361 uio_uio_resid_add(uiop, -(left)); 3362 uiop->uio_offset += left; 3363 } 3364 3365 /* 3366 * If returning no data, assume end of file. 3367 * If not bigenough, return not end of file, since you aren't 3368 * returning all the data 3369 * Otherwise, return the eof flag from the server. 3370 */ 3371 if (eofp != NULL) { 3372 if (tresid == uio_uio_resid(uiop)) 3373 *eofp = 1; 3374 else if (!bigenough) 3375 *eofp = 0; 3376 else 3377 *eofp = eof; 3378 } 3379 3380 /* 3381 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3382 */ 3383 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3384 dp = (struct dirent *)uio_iov_base(uiop); 3385 dp->d_type = DT_UNKNOWN; 3386 dp->d_fileno = 0; 3387 dp->d_namlen = 0; 3388 dp->d_name[0] = '\0'; 3389 tl = (u_int32_t *)&dp->d_name[4]; 3390 *tl++ = cookie.lval[0]; 3391 *tl = cookie.lval[1]; 3392 dp->d_reclen = DIRBLKSIZ; 3393 uio_iov_base_add(uiop, DIRBLKSIZ); 3394 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3395 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3396 uiop->uio_offset += DIRBLKSIZ; 3397 } 3398 3399 nfsmout: 3400 if (nd->nd_mrep != NULL) 3401 mbuf_freem(nd->nd_mrep); 3402 return (error); 3403 } 3404 #endif /* !APPLE */ 3405 3406 /* 3407 * Nfs commit rpc 3408 */ 3409 APPLESTATIC int 3410 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 3411 NFSPROC_T *p, u_char *verfp, struct nfsvattr *nap, int *attrflagp, 3412 void *stuff) 3413 { 3414 u_int32_t *tl; 3415 struct nfsrv_descript nfsd, *nd = &nfsd; 3416 nfsattrbit_t attrbits; 3417 int error; 3418 3419 *attrflagp = 0; 3420 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 3421 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3422 txdr_hyper(offset, tl); 3423 tl += 2; 3424 *tl = txdr_unsigned(cnt); 3425 if (nd->nd_flag & ND_NFSV4) { 3426 /* 3427 * And do a Getattr op. 3428 */ 3429 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3430 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3431 NFSGETATTR_ATTRBIT(&attrbits); 3432 (void) nfsrv_putattrbit(nd, &attrbits); 3433 } 3434 error = nfscl_request(nd, vp, p, cred, stuff); 3435 if (error) 3436 return (error); 3437 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 3438 if (!error && !nd->nd_repstat) { 3439 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3440 NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF); 3441 if (nd->nd_flag & ND_NFSV4) 3442 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3443 } 3444 nfsmout: 3445 if (!error && nd->nd_repstat) 3446 error = nd->nd_repstat; 3447 mbuf_freem(nd->nd_mrep); 3448 return (error); 3449 } 3450 3451 /* 3452 * NFS byte range lock rpc. 3453 * (Mostly just calls one of the three lower level RPC routines.) 3454 */ 3455 APPLESTATIC int 3456 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 3457 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3458 { 3459 struct nfscllockowner *lp; 3460 struct nfsclclient *clp; 3461 struct nfsfh *nfhp; 3462 struct nfsrv_descript nfsd, *nd = &nfsd; 3463 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3464 u_int64_t off, len; 3465 off_t start, end; 3466 u_int32_t clidrev = 0; 3467 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 3468 int callcnt, dorpc; 3469 3470 /* 3471 * Convert the flock structure into a start and end and do POSIX 3472 * bounds checking. 3473 */ 3474 switch (fl->l_whence) { 3475 case SEEK_SET: 3476 case SEEK_CUR: 3477 /* 3478 * Caller is responsible for adding any necessary offset 3479 * when SEEK_CUR is used. 3480 */ 3481 start = fl->l_start; 3482 off = fl->l_start; 3483 break; 3484 case SEEK_END: 3485 start = size + fl->l_start; 3486 off = size + fl->l_start; 3487 break; 3488 default: 3489 return (EINVAL); 3490 }; 3491 if (start < 0) 3492 return (EINVAL); 3493 if (fl->l_len != 0) { 3494 end = start + fl->l_len - 1; 3495 if (end < start) 3496 return (EINVAL); 3497 } 3498 3499 len = fl->l_len; 3500 if (len == 0) 3501 len = NFS64BITSSET; 3502 retrycnt = 0; 3503 do { 3504 nd->nd_repstat = 0; 3505 if (op == F_GETLK) { 3506 error = nfscl_getcl(vp, cred, p, &clp); 3507 if (error) 3508 return (error); 3509 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 3510 if (!error) { 3511 clidrev = clp->nfsc_clientidrev; 3512 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 3513 p, id, flags); 3514 } else if (error == -1) { 3515 error = 0; 3516 } 3517 nfscl_clientrelease(clp); 3518 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 3519 /* 3520 * We must loop around for all lockowner cases. 3521 */ 3522 callcnt = 0; 3523 error = nfscl_getcl(vp, cred, p, &clp); 3524 if (error) 3525 return (error); 3526 do { 3527 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 3528 clp, id, flags, &lp, &dorpc); 3529 /* 3530 * If it returns a NULL lp, we're done. 3531 */ 3532 if (lp == NULL) { 3533 if (callcnt == 0) 3534 nfscl_clientrelease(clp); 3535 else 3536 nfscl_releasealllocks(clp, vp, p, id, flags); 3537 return (error); 3538 } 3539 if (nmp->nm_clp != NULL) 3540 clidrev = nmp->nm_clp->nfsc_clientidrev; 3541 else 3542 clidrev = 0; 3543 /* 3544 * If the server doesn't support Posix lock semantics, 3545 * only allow locks on the entire file, since it won't 3546 * handle overlapping byte ranges. 3547 * There might still be a problem when a lock 3548 * upgrade/downgrade (read<->write) occurs, since the 3549 * server "might" expect an unlock first? 3550 */ 3551 if (dorpc && (lp->nfsl_open->nfso_posixlock || 3552 (off == 0 && len == NFS64BITSSET))) { 3553 /* 3554 * Since the lock records will go away, we must 3555 * wait for grace and delay here. 3556 */ 3557 do { 3558 error = nfsrpc_locku(nd, nmp, lp, off, len, 3559 NFSV4LOCKT_READ, cred, p, 0); 3560 if ((nd->nd_repstat == NFSERR_GRACE || 3561 nd->nd_repstat == NFSERR_DELAY) && 3562 error == 0) 3563 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3564 "nfs_advlock"); 3565 } while ((nd->nd_repstat == NFSERR_GRACE || 3566 nd->nd_repstat == NFSERR_DELAY) && error == 0); 3567 } 3568 callcnt++; 3569 } while (error == 0 && nd->nd_repstat == 0); 3570 nfscl_releasealllocks(clp, vp, p, id, flags); 3571 } else if (op == F_SETLK) { 3572 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 3573 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 3574 if (error || donelocally) { 3575 return (error); 3576 } 3577 if (nmp->nm_clp != NULL) 3578 clidrev = nmp->nm_clp->nfsc_clientidrev; 3579 else 3580 clidrev = 0; 3581 nfhp = VTONFS(vp)->n_fhp; 3582 if (!lp->nfsl_open->nfso_posixlock && 3583 (off != 0 || len != NFS64BITSSET)) { 3584 error = EINVAL; 3585 } else { 3586 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 3587 nfhp->nfh_len, lp, newone, reclaim, off, 3588 len, fl->l_type, cred, p, 0); 3589 } 3590 if (!error) 3591 error = nd->nd_repstat; 3592 nfscl_lockrelease(lp, error, newone); 3593 } else { 3594 error = EINVAL; 3595 } 3596 if (!error) 3597 error = nd->nd_repstat; 3598 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 3599 error == NFSERR_STALEDONTRECOVER || 3600 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY) { 3601 (void) nfs_catnap(PZERO, error, "nfs_advlock"); 3602 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 3603 && clidrev != 0) { 3604 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 3605 retrycnt++; 3606 } 3607 } while (error == NFSERR_GRACE || 3608 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3609 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 3610 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 3611 expireret == 0 && clidrev != 0 && retrycnt < 4)); 3612 if (error && retrycnt >= 4) 3613 error = EIO; 3614 return (error); 3615 } 3616 3617 /* 3618 * The lower level routine for the LockT case. 3619 */ 3620 APPLESTATIC int 3621 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 3622 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 3623 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3624 { 3625 u_int32_t *tl; 3626 int error, type, size; 3627 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3628 struct nfsnode *np; 3629 3630 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 3631 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3632 if (fl->l_type == F_RDLCK) 3633 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3634 else 3635 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3636 txdr_hyper(off, tl); 3637 tl += 2; 3638 txdr_hyper(len, tl); 3639 tl += 2; 3640 *tl++ = clp->nfsc_clientid.lval[0]; 3641 *tl = clp->nfsc_clientid.lval[1]; 3642 nfscl_filllockowner(id, own, flags); 3643 np = VTONFS(vp); 3644 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 3645 np->n_fhp->nfh_len); 3646 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 3647 error = nfscl_request(nd, vp, p, cred, NULL); 3648 if (error) 3649 return (error); 3650 if (nd->nd_repstat == 0) { 3651 fl->l_type = F_UNLCK; 3652 } else if (nd->nd_repstat == NFSERR_DENIED) { 3653 nd->nd_repstat = 0; 3654 fl->l_whence = SEEK_SET; 3655 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3656 fl->l_start = fxdr_hyper(tl); 3657 tl += 2; 3658 len = fxdr_hyper(tl); 3659 tl += 2; 3660 if (len == NFS64BITSSET) 3661 fl->l_len = 0; 3662 else 3663 fl->l_len = len; 3664 type = fxdr_unsigned(int, *tl++); 3665 if (type == NFSV4LOCKT_WRITE) 3666 fl->l_type = F_WRLCK; 3667 else 3668 fl->l_type = F_RDLCK; 3669 /* 3670 * XXX For now, I have no idea what to do with the 3671 * conflicting lock_owner, so I'll just set the pid == 0 3672 * and skip over the lock_owner. 3673 */ 3674 fl->l_pid = (pid_t)0; 3675 tl += 2; 3676 size = fxdr_unsigned(int, *tl); 3677 if (size < 0 || size > NFSV4_OPAQUELIMIT) 3678 error = EBADRPC; 3679 if (!error) 3680 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3681 } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 3682 nfscl_initiate_recovery(clp); 3683 nfsmout: 3684 mbuf_freem(nd->nd_mrep); 3685 return (error); 3686 } 3687 3688 /* 3689 * Lower level function that performs the LockU RPC. 3690 */ 3691 static int 3692 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 3693 struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 3694 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 3695 { 3696 u_int32_t *tl; 3697 int error; 3698 3699 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 3700 lp->nfsl_open->nfso_fhlen, NULL); 3701 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 3702 *tl++ = txdr_unsigned(type); 3703 *tl = txdr_unsigned(lp->nfsl_seqid); 3704 if (nfstest_outofseq && 3705 (arc4random() % nfstest_outofseq) == 0) 3706 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 3707 tl++; 3708 *tl++ = lp->nfsl_stateid.seqid; 3709 *tl++ = lp->nfsl_stateid.other[0]; 3710 *tl++ = lp->nfsl_stateid.other[1]; 3711 *tl++ = lp->nfsl_stateid.other[2]; 3712 txdr_hyper(off, tl); 3713 tl += 2; 3714 txdr_hyper(len, tl); 3715 if (syscred) 3716 nd->nd_flag |= ND_USEGSSNAME; 3717 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 3718 NFS_PROG, NFS_VER4, NULL, 1, NULL); 3719 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 3720 if (error) 3721 return (error); 3722 if (nd->nd_repstat == 0) { 3723 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3724 lp->nfsl_stateid.seqid = *tl++; 3725 lp->nfsl_stateid.other[0] = *tl++; 3726 lp->nfsl_stateid.other[1] = *tl++; 3727 lp->nfsl_stateid.other[2] = *tl; 3728 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 3729 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 3730 nfsmout: 3731 mbuf_freem(nd->nd_mrep); 3732 return (error); 3733 } 3734 3735 /* 3736 * The actual Lock RPC. 3737 */ 3738 APPLESTATIC int 3739 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 3740 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 3741 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 3742 NFSPROC_T *p, int syscred) 3743 { 3744 u_int32_t *tl; 3745 int error, size; 3746 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3747 3748 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL); 3749 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3750 if (type == F_RDLCK) 3751 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3752 else 3753 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3754 *tl++ = txdr_unsigned(reclaim); 3755 txdr_hyper(off, tl); 3756 tl += 2; 3757 txdr_hyper(len, tl); 3758 tl += 2; 3759 if (newone) { 3760 *tl = newnfs_true; 3761 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3762 2 * NFSX_UNSIGNED + NFSX_HYPER); 3763 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 3764 *tl++ = lp->nfsl_open->nfso_stateid.seqid; 3765 *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 3766 *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 3767 *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 3768 *tl++ = txdr_unsigned(lp->nfsl_seqid); 3769 *tl++ = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[0]; 3770 *tl = lp->nfsl_open->nfso_own->nfsow_clp->nfsc_clientid.lval[1]; 3771 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 3772 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 3773 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 3774 } else { 3775 *tl = newnfs_false; 3776 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 3777 *tl++ = lp->nfsl_stateid.seqid; 3778 *tl++ = lp->nfsl_stateid.other[0]; 3779 *tl++ = lp->nfsl_stateid.other[1]; 3780 *tl++ = lp->nfsl_stateid.other[2]; 3781 *tl = txdr_unsigned(lp->nfsl_seqid); 3782 if (nfstest_outofseq && 3783 (arc4random() % nfstest_outofseq) == 0) 3784 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 3785 } 3786 if (syscred) 3787 nd->nd_flag |= ND_USEGSSNAME; 3788 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 3789 NFS_PROG, NFS_VER4, NULL, 1, NULL); 3790 if (error) 3791 return (error); 3792 if (newone) 3793 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 3794 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 3795 if (nd->nd_repstat == 0) { 3796 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 3797 lp->nfsl_stateid.seqid = *tl++; 3798 lp->nfsl_stateid.other[0] = *tl++; 3799 lp->nfsl_stateid.other[1] = *tl++; 3800 lp->nfsl_stateid.other[2] = *tl; 3801 } else if (nd->nd_repstat == NFSERR_DENIED) { 3802 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 3803 size = fxdr_unsigned(int, *(tl + 7)); 3804 if (size < 0 || size > NFSV4_OPAQUELIMIT) 3805 error = EBADRPC; 3806 if (!error) 3807 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 3808 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 3809 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 3810 nfsmout: 3811 mbuf_freem(nd->nd_mrep); 3812 return (error); 3813 } 3814 3815 /* 3816 * nfs statfs rpc 3817 * (always called with the vp for the mount point) 3818 */ 3819 APPLESTATIC int 3820 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 3821 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3822 void *stuff) 3823 { 3824 u_int32_t *tl = NULL; 3825 struct nfsrv_descript nfsd, *nd = &nfsd; 3826 struct nfsmount *nmp; 3827 nfsattrbit_t attrbits; 3828 int error; 3829 3830 *attrflagp = 0; 3831 nmp = VFSTONFS(vnode_mount(vp)); 3832 if (NFSHASNFSV4(nmp)) { 3833 /* 3834 * For V4, you actually do a getattr. 3835 */ 3836 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 3837 NFSSTATFS_GETATTRBIT(&attrbits); 3838 (void) nfsrv_putattrbit(nd, &attrbits); 3839 nd->nd_flag |= ND_USEGSSNAME; 3840 error = nfscl_request(nd, vp, p, cred, stuff); 3841 if (error) 3842 return (error); 3843 if (nd->nd_repstat == 0) { 3844 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3845 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 3846 cred); 3847 if (!error) { 3848 nmp->nm_fsid[0] = nap->na_filesid[0]; 3849 nmp->nm_fsid[1] = nap->na_filesid[1]; 3850 NFSSETHASSETFSID(nmp); 3851 *attrflagp = 1; 3852 } 3853 } else { 3854 error = nd->nd_repstat; 3855 } 3856 if (error) 3857 goto nfsmout; 3858 } else { 3859 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 3860 error = nfscl_request(nd, vp, p, cred, stuff); 3861 if (error) 3862 return (error); 3863 if (nd->nd_flag & ND_NFSV3) { 3864 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3865 if (error) 3866 goto nfsmout; 3867 } 3868 if (nd->nd_repstat) { 3869 error = nd->nd_repstat; 3870 goto nfsmout; 3871 } 3872 NFSM_DISSECT(tl, u_int32_t *, 3873 NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 3874 } 3875 if (NFSHASNFSV3(nmp)) { 3876 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 3877 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 3878 sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 3879 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 3880 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 3881 sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 3882 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 3883 } else if (NFSHASNFSV4(nmp) == 0) { 3884 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 3885 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 3886 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 3887 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 3888 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 3889 } 3890 nfsmout: 3891 mbuf_freem(nd->nd_mrep); 3892 return (error); 3893 } 3894 3895 /* 3896 * nfs pathconf rpc 3897 */ 3898 APPLESTATIC int 3899 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 3900 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3901 void *stuff) 3902 { 3903 struct nfsrv_descript nfsd, *nd = &nfsd; 3904 struct nfsmount *nmp; 3905 u_int32_t *tl; 3906 nfsattrbit_t attrbits; 3907 int error; 3908 3909 *attrflagp = 0; 3910 nmp = VFSTONFS(vnode_mount(vp)); 3911 if (NFSHASNFSV4(nmp)) { 3912 /* 3913 * For V4, you actually do a getattr. 3914 */ 3915 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 3916 NFSPATHCONF_GETATTRBIT(&attrbits); 3917 (void) nfsrv_putattrbit(nd, &attrbits); 3918 nd->nd_flag |= ND_USEGSSNAME; 3919 error = nfscl_request(nd, vp, p, cred, stuff); 3920 if (error) 3921 return (error); 3922 if (nd->nd_repstat == 0) { 3923 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 3924 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 3925 cred); 3926 if (!error) 3927 *attrflagp = 1; 3928 } else { 3929 error = nd->nd_repstat; 3930 } 3931 } else { 3932 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 3933 error = nfscl_request(nd, vp, p, cred, stuff); 3934 if (error) 3935 return (error); 3936 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3937 if (nd->nd_repstat && !error) 3938 error = nd->nd_repstat; 3939 if (!error) { 3940 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 3941 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 3942 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 3943 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 3944 pc->pc_chownrestricted = 3945 fxdr_unsigned(u_int32_t, *tl++); 3946 pc->pc_caseinsensitive = 3947 fxdr_unsigned(u_int32_t, *tl++); 3948 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 3949 } 3950 } 3951 nfsmout: 3952 mbuf_freem(nd->nd_mrep); 3953 return (error); 3954 } 3955 3956 /* 3957 * nfs version 3 fsinfo rpc call 3958 */ 3959 APPLESTATIC int 3960 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 3961 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 3962 { 3963 u_int32_t *tl; 3964 struct nfsrv_descript nfsd, *nd = &nfsd; 3965 int error; 3966 3967 *attrflagp = 0; 3968 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 3969 error = nfscl_request(nd, vp, p, cred, stuff); 3970 if (error) 3971 return (error); 3972 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3973 if (nd->nd_repstat && !error) 3974 error = nd->nd_repstat; 3975 if (!error) { 3976 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 3977 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 3978 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 3979 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 3980 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 3981 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 3982 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 3983 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 3984 fsp->fs_maxfilesize = fxdr_hyper(tl); 3985 tl += 2; 3986 fxdr_nfsv3time(tl, &fsp->fs_timedelta); 3987 tl += 2; 3988 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 3989 } 3990 nfsmout: 3991 mbuf_freem(nd->nd_mrep); 3992 return (error); 3993 } 3994 3995 /* 3996 * This function performs the Renew RPC. 3997 */ 3998 APPLESTATIC int 3999 nfsrpc_renew(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p) 4000 { 4001 u_int32_t *tl; 4002 struct nfsrv_descript nfsd; 4003 struct nfsrv_descript *nd = &nfsd; 4004 struct nfsmount *nmp; 4005 int error; 4006 4007 nmp = clp->nfsc_nmp; 4008 if (nmp == NULL) 4009 return (0); 4010 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL); 4011 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4012 *tl++ = clp->nfsc_clientid.lval[0]; 4013 *tl = clp->nfsc_clientid.lval[1]; 4014 nd->nd_flag |= ND_USEGSSNAME; 4015 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4016 NFS_PROG, NFS_VER4, NULL, 1, NULL); 4017 if (error) 4018 return (error); 4019 error = nd->nd_repstat; 4020 mbuf_freem(nd->nd_mrep); 4021 return (error); 4022 } 4023 4024 /* 4025 * This function performs the Releaselockowner RPC. 4026 */ 4027 APPLESTATIC int 4028 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4029 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4030 { 4031 struct nfsrv_descript nfsd, *nd = &nfsd; 4032 u_int32_t *tl; 4033 int error; 4034 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4035 4036 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL); 4037 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4038 *tl++ = nmp->nm_clp->nfsc_clientid.lval[0]; 4039 *tl = nmp->nm_clp->nfsc_clientid.lval[1]; 4040 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4041 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4042 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4043 nd->nd_flag |= ND_USEGSSNAME; 4044 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4045 NFS_PROG, NFS_VER4, NULL, 1, NULL); 4046 if (error) 4047 return (error); 4048 error = nd->nd_repstat; 4049 mbuf_freem(nd->nd_mrep); 4050 return (error); 4051 } 4052 4053 /* 4054 * This function performs the Compound to get the mount pt FH. 4055 */ 4056 APPLESTATIC int 4057 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4058 NFSPROC_T *p) 4059 { 4060 u_int32_t *tl; 4061 struct nfsrv_descript nfsd; 4062 struct nfsrv_descript *nd = &nfsd; 4063 u_char *cp, *cp2; 4064 int error, cnt, len, setnil; 4065 u_int32_t *opcntp; 4066 4067 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp); 4068 cp = dirpath; 4069 cnt = 0; 4070 do { 4071 setnil = 0; 4072 while (*cp == '/') 4073 cp++; 4074 cp2 = cp; 4075 while (*cp2 != '\0' && *cp2 != '/') 4076 cp2++; 4077 if (*cp2 == '/') { 4078 setnil = 1; 4079 *cp2 = '\0'; 4080 } 4081 if (cp2 != cp) { 4082 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4083 *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4084 nfsm_strtom(nd, cp, strlen(cp)); 4085 cnt++; 4086 } 4087 if (setnil) 4088 *cp2++ = '/'; 4089 cp = cp2; 4090 } while (*cp != '\0'); 4091 *opcntp = txdr_unsigned(2 + cnt); 4092 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4093 *tl = txdr_unsigned(NFSV4OP_GETFH); 4094 nd->nd_flag |= ND_USEGSSNAME; 4095 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4096 NFS_PROG, NFS_VER4, NULL, 1, NULL); 4097 if (error) 4098 return (error); 4099 if (nd->nd_repstat == 0) { 4100 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4101 tl += (2 + 2 * cnt); 4102 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4103 len > NFSX_FHMAX) { 4104 nd->nd_repstat = NFSERR_BADXDR; 4105 } else { 4106 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4107 if (nd->nd_repstat == 0) 4108 nmp->nm_fhsize = len; 4109 } 4110 } 4111 error = nd->nd_repstat; 4112 nfsmout: 4113 mbuf_freem(nd->nd_mrep); 4114 return (error); 4115 } 4116 4117 /* 4118 * This function performs the Delegreturn RPC. 4119 */ 4120 APPLESTATIC int 4121 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4122 struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4123 { 4124 u_int32_t *tl; 4125 struct nfsrv_descript nfsd; 4126 struct nfsrv_descript *nd = &nfsd; 4127 int error; 4128 4129 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4130 dp->nfsdl_fhlen, NULL); 4131 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4132 *tl++ = dp->nfsdl_stateid.seqid; 4133 *tl++ = dp->nfsdl_stateid.other[0]; 4134 *tl++ = dp->nfsdl_stateid.other[1]; 4135 *tl = dp->nfsdl_stateid.other[2]; 4136 if (syscred) 4137 nd->nd_flag |= ND_USEGSSNAME; 4138 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4139 NFS_PROG, NFS_VER4, NULL, 1, NULL); 4140 if (error) 4141 return (error); 4142 error = nd->nd_repstat; 4143 mbuf_freem(nd->nd_mrep); 4144 return (error); 4145 } 4146 4147 /* 4148 * nfs getacl call. 4149 */ 4150 APPLESTATIC int 4151 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4152 struct acl *aclp, void *stuff) 4153 { 4154 struct nfsrv_descript nfsd, *nd = &nfsd; 4155 int error; 4156 nfsattrbit_t attrbits; 4157 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4158 4159 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4160 return (EOPNOTSUPP); 4161 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4162 NFSZERO_ATTRBIT(&attrbits); 4163 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4164 (void) nfsrv_putattrbit(nd, &attrbits); 4165 error = nfscl_request(nd, vp, p, cred, stuff); 4166 if (error) 4167 return (error); 4168 if (!nd->nd_repstat) 4169 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4170 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4171 else 4172 error = nd->nd_repstat; 4173 mbuf_freem(nd->nd_mrep); 4174 return (error); 4175 } 4176 4177 /* 4178 * nfs setacl call. 4179 */ 4180 APPLESTATIC int 4181 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4182 struct acl *aclp, void *stuff) 4183 { 4184 int error; 4185 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4186 4187 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4188 return (EOPNOTSUPP); 4189 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4190 return (error); 4191 } 4192 4193 /* 4194 * nfs setacl call. 4195 */ 4196 static int 4197 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4198 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 4199 { 4200 struct nfsrv_descript nfsd, *nd = &nfsd; 4201 int error; 4202 nfsattrbit_t attrbits; 4203 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4204 4205 if (!NFSHASNFSV4(nmp)) 4206 return (EOPNOTSUPP); 4207 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 4208 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 4209 NFSZERO_ATTRBIT(&attrbits); 4210 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4211 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0, 4212 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0); 4213 error = nfscl_request(nd, vp, p, cred, stuff); 4214 if (error) 4215 return (error); 4216 /* Don't care about the pre/postop attributes */ 4217 mbuf_freem(nd->nd_mrep); 4218 return (nd->nd_repstat); 4219 } 4220