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