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