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