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