1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 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 #include "opt_inet6.h" 49 50 #include <fs/nfs/nfsport.h> 51 #include <sys/sysctl.h> 52 #include <sys/taskqueue.h> 53 54 SYSCTL_DECL(_vfs_nfs); 55 56 static int nfsignore_eexist = 0; 57 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW, 58 &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink"); 59 60 static int nfscl_dssameconn = 0; 61 SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW, 62 &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs"); 63 64 /* 65 * Global variables 66 */ 67 extern int nfs_numnfscbd; 68 extern struct timeval nfsboottime; 69 extern u_int32_t newnfs_false, newnfs_true; 70 extern nfstype nfsv34_type[9]; 71 extern int nfsrv_useacl; 72 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN]; 73 extern int nfscl_debuglevel; 74 extern int nfs_pnfsiothreads; 75 NFSCLSTATEMUTEX; 76 int nfstest_outofseq = 0; 77 int nfscl_assumeposixlocks = 1; 78 int nfscl_enablecallb = 0; 79 short nfsv4_cbport = NFSV4_CBPORT; 80 int nfstest_openallsetattr = 0; 81 #endif /* !APPLEKEXT */ 82 83 #define DIRHDSIZ offsetof(struct dirent, d_name) 84 85 /* 86 * nfscl_getsameserver() can return one of three values: 87 * NFSDSP_USETHISSESSION - Use this session for the DS. 88 * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new 89 * session. 90 * NFSDSP_NOTFOUND - No matching server was found. 91 */ 92 enum nfsclds_state { 93 NFSDSP_USETHISSESSION = 0, 94 NFSDSP_SEQTHISSESSION = 1, 95 NFSDSP_NOTFOUND = 2, 96 }; 97 98 /* 99 * Do a write RPC on a DS data file, using this structure for the arguments, 100 * so that this function can be executed by a separate kernel process. 101 */ 102 struct nfsclwritedsdorpc { 103 int done; 104 int inprog; 105 struct task tsk; 106 struct vnode *vp; 107 int iomode; 108 int must_commit; 109 nfsv4stateid_t *stateidp; 110 struct nfsclds *dsp; 111 uint64_t off; 112 int len; 113 struct nfsfh *fhp; 114 struct mbuf *m; 115 int vers; 116 int minorvers; 117 struct ucred *cred; 118 NFSPROC_T *p; 119 int err; 120 }; 121 122 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *, 123 struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *); 124 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *, 125 nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *); 126 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *, 127 struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, 128 void *); 129 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *, 130 nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *, 131 struct nfsvattr *, struct nfsfh **, int *, int *, void *); 132 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *, 133 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *, 134 NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *, 135 int *, void *, int *); 136 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *, 137 struct nfscllockowner *, u_int64_t, u_int64_t, 138 u_int32_t, struct ucred *, NFSPROC_T *, int); 139 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *, 140 struct acl *, nfsv4stateid_t *, void *); 141 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int, 142 uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **, 143 struct ucred *, NFSPROC_T *); 144 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *, 145 struct sockaddr_in6 *, sa_family_t, int, struct nfsclds **, NFSPROC_T *); 146 static void nfscl_initsessionslots(struct nfsclsession *); 147 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *, 148 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, 149 struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *, 150 NFSPROC_T *); 151 static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *, 152 nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *, 153 struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *, 154 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); 155 static struct mbuf *nfsm_copym(struct mbuf *, int, int); 156 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *, 157 struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int, 158 struct ucred *, NFSPROC_T *); 159 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *, 160 nfsv4stateid_t *, struct nfsclds *, uint64_t, int, 161 struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *); 162 static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *, 163 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int, 164 struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *); 165 static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *, 166 struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int, 167 struct ucred *, NFSPROC_T *); 168 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *, 169 struct nfsclds *, struct nfsclds **, uint32_t *); 170 static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *, 171 struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *, 172 NFSPROC_T *); 173 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *, 174 struct nfsfh *, int, int, struct ucred *, NFSPROC_T *); 175 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t, 176 uint64_t, uint64_t, nfsv4stateid_t *, int, int, int); 177 static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *, 178 NFSPROC_T *); 179 static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *, 180 int *, struct nfsclflayouthead *); 181 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *, 182 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, 183 struct nfscldeleg **, struct ucred *, NFSPROC_T *); 184 static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *, 185 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, 186 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, 187 struct nfsfh **, int *, int *, void *, int *); 188 static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *, 189 int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int, 190 struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *, 191 struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *); 192 static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *, 193 nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, 194 struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, 195 struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *, 196 int, int, int, int *, struct nfsclflayouthead *, int *); 197 static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t, 198 uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *, 199 struct nfsclflayouthead *, struct ucred *, NFSPROC_T *, void *); 200 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *, 201 int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **, 202 struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *); 203 204 int nfs_pnfsio(task_fn_t *, void *); 205 206 /* 207 * nfs null call from vfs. 208 */ 209 APPLESTATIC int 210 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p) 211 { 212 int error; 213 struct nfsrv_descript nfsd, *nd = &nfsd; 214 215 NFSCL_REQSTART(nd, NFSPROC_NULL, vp); 216 error = nfscl_request(nd, vp, p, cred, NULL); 217 if (nd->nd_repstat && !error) 218 error = nd->nd_repstat; 219 mbuf_freem(nd->nd_mrep); 220 return (error); 221 } 222 223 /* 224 * nfs access rpc op. 225 * For nfs version 3 and 4, use the access rpc to check accessibility. If file 226 * modes are changed on the server, accesses might still fail later. 227 */ 228 APPLESTATIC int 229 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred, 230 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 231 { 232 int error; 233 u_int32_t mode, rmode; 234 235 if (acmode & VREAD) 236 mode = NFSACCESS_READ; 237 else 238 mode = 0; 239 if (vnode_vtype(vp) == VDIR) { 240 if (acmode & VWRITE) 241 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND | 242 NFSACCESS_DELETE); 243 if (acmode & VEXEC) 244 mode |= NFSACCESS_LOOKUP; 245 } else { 246 if (acmode & VWRITE) 247 mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND); 248 if (acmode & VEXEC) 249 mode |= NFSACCESS_EXECUTE; 250 } 251 252 /* 253 * Now, just call nfsrpc_accessrpc() to do the actual RPC. 254 */ 255 error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode, 256 NULL); 257 258 /* 259 * The NFS V3 spec does not clarify whether or not 260 * the returned access bits can be a superset of 261 * the ones requested, so... 262 */ 263 if (!error && (rmode & mode) != mode) 264 error = EACCES; 265 return (error); 266 } 267 268 /* 269 * The actual rpc, separated out for Darwin. 270 */ 271 APPLESTATIC int 272 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred, 273 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep, 274 void *stuff) 275 { 276 u_int32_t *tl; 277 u_int32_t supported, rmode; 278 int error; 279 struct nfsrv_descript nfsd, *nd = &nfsd; 280 nfsattrbit_t attrbits; 281 282 *attrflagp = 0; 283 supported = mode; 284 NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp); 285 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 286 *tl = txdr_unsigned(mode); 287 if (nd->nd_flag & ND_NFSV4) { 288 /* 289 * And do a Getattr op. 290 */ 291 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 292 *tl = txdr_unsigned(NFSV4OP_GETATTR); 293 NFSGETATTR_ATTRBIT(&attrbits); 294 (void) nfsrv_putattrbit(nd, &attrbits); 295 } 296 error = nfscl_request(nd, vp, p, cred, stuff); 297 if (error) 298 return (error); 299 if (nd->nd_flag & ND_NFSV3) { 300 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 301 if (error) 302 goto nfsmout; 303 } 304 if (!nd->nd_repstat) { 305 if (nd->nd_flag & ND_NFSV4) { 306 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 307 supported = fxdr_unsigned(u_int32_t, *tl++); 308 } else { 309 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 310 } 311 rmode = fxdr_unsigned(u_int32_t, *tl); 312 if (nd->nd_flag & ND_NFSV4) 313 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 314 315 /* 316 * It's not obvious what should be done about 317 * unsupported access modes. For now, be paranoid 318 * and clear the unsupported ones. 319 */ 320 rmode &= supported; 321 *rmodep = rmode; 322 } else 323 error = nd->nd_repstat; 324 nfsmout: 325 mbuf_freem(nd->nd_mrep); 326 return (error); 327 } 328 329 /* 330 * nfs open rpc 331 */ 332 APPLESTATIC int 333 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p) 334 { 335 struct nfsclopen *op; 336 struct nfscldeleg *dp; 337 struct nfsfh *nfhp; 338 struct nfsnode *np = VTONFS(vp); 339 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 340 u_int32_t mode, clidrev; 341 int ret, newone, error, expireret = 0, retrycnt; 342 343 /* 344 * For NFSv4, Open Ops are only done on Regular Files. 345 */ 346 if (vnode_vtype(vp) != VREG) 347 return (0); 348 mode = 0; 349 if (amode & FREAD) 350 mode |= NFSV4OPEN_ACCESSREAD; 351 if (amode & FWRITE) 352 mode |= NFSV4OPEN_ACCESSWRITE; 353 nfhp = np->n_fhp; 354 355 retrycnt = 0; 356 #ifdef notdef 357 { char name[100]; int namel; 358 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99; 359 bcopy(NFS4NODENAME(np->n_v4), name, namel); 360 name[namel] = '\0'; 361 printf("rpcopen p=0x%x name=%s",p->p_pid,name); 362 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]); 363 else printf(" fhl=0\n"); 364 } 365 #endif 366 do { 367 dp = NULL; 368 error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1, 369 cred, p, NULL, &op, &newone, &ret, 1); 370 if (error) { 371 return (error); 372 } 373 if (nmp->nm_clp != NULL) 374 clidrev = nmp->nm_clp->nfsc_clientidrev; 375 else 376 clidrev = 0; 377 if (ret == NFSCLOPEN_DOOPEN) { 378 if (np->n_v4 != NULL) { 379 /* 380 * For the first attempt, try and get a layout, if 381 * pNFS is enabled for the mount. 382 */ 383 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || 384 nfs_numnfscbd == 0 || 385 (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0) 386 error = nfsrpc_openrpc(nmp, vp, 387 np->n_v4->n4_data, 388 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 389 np->n_fhp->nfh_len, mode, op, 390 NFS4NODENAME(np->n_v4), 391 np->n_v4->n4_namelen, 392 &dp, 0, 0x0, cred, p, 0, 0); 393 else 394 error = nfsrpc_getopenlayout(nmp, vp, 395 np->n_v4->n4_data, 396 np->n_v4->n4_fhlen, np->n_fhp->nfh_fh, 397 np->n_fhp->nfh_len, mode, op, 398 NFS4NODENAME(np->n_v4), 399 np->n_v4->n4_namelen, &dp, cred, p); 400 if (dp != NULL) { 401 #ifdef APPLE 402 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag); 403 #else 404 NFSLOCKNODE(np); 405 np->n_flag &= ~NDELEGMOD; 406 /* 407 * Invalidate the attribute cache, so that 408 * attributes that pre-date the issue of a 409 * delegation are not cached, since the 410 * cached attributes will remain valid while 411 * the delegation is held. 412 */ 413 NFSINVALATTRCACHE(np); 414 NFSUNLOCKNODE(np); 415 #endif 416 (void) nfscl_deleg(nmp->nm_mountp, 417 op->nfso_own->nfsow_clp, 418 nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp); 419 } 420 } else { 421 error = EIO; 422 } 423 newnfs_copyincred(cred, &op->nfso_cred); 424 } else if (ret == NFSCLOPEN_SETCRED) 425 /* 426 * This is a new local open on a delegation. It needs 427 * to have credentials so that an open can be done 428 * against the server during recovery. 429 */ 430 newnfs_copyincred(cred, &op->nfso_cred); 431 432 /* 433 * nfso_opencnt is the count of how many VOP_OPEN()s have 434 * been done on this Open successfully and a VOP_CLOSE() 435 * is expected for each of these. 436 * If error is non-zero, don't increment it, since the Open 437 * hasn't succeeded yet. 438 */ 439 if (!error) 440 op->nfso_opencnt++; 441 nfscl_openrelease(nmp, op, error, newone); 442 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 443 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 444 error == NFSERR_BADSESSION) { 445 (void) nfs_catnap(PZERO, error, "nfs_open"); 446 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 447 && clidrev != 0) { 448 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 449 retrycnt++; 450 } 451 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 452 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 453 error == NFSERR_BADSESSION || 454 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 455 expireret == 0 && clidrev != 0 && retrycnt < 4)); 456 if (error && retrycnt >= 4) 457 error = EIO; 458 return (error); 459 } 460 461 /* 462 * the actual open rpc 463 */ 464 APPLESTATIC int 465 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen, 466 u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op, 467 u_int8_t *name, int namelen, struct nfscldeleg **dpp, 468 int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p, 469 int syscred, int recursed) 470 { 471 u_int32_t *tl; 472 struct nfsrv_descript nfsd, *nd = &nfsd; 473 struct nfscldeleg *dp, *ndp = NULL; 474 struct nfsvattr nfsva; 475 u_int32_t rflags, deleg; 476 nfsattrbit_t attrbits; 477 int error, ret, acesize, limitby; 478 struct nfsclsession *tsep; 479 480 dp = *dpp; 481 *dpp = NULL; 482 nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0); 483 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 484 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 485 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 486 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 487 tsep = nfsmnt_mdssession(nmp); 488 *tl++ = tsep->nfsess_clientid.lval[0]; 489 *tl = tsep->nfsess_clientid.lval[1]; 490 (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 491 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 492 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 493 if (reclaim) { 494 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS); 495 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 496 *tl = txdr_unsigned(delegtype); 497 } else { 498 if (dp != NULL) { 499 *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR); 500 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 501 if (NFSHASNFSV4N(nmp)) 502 *tl++ = 0; 503 else 504 *tl++ = dp->nfsdl_stateid.seqid; 505 *tl++ = dp->nfsdl_stateid.other[0]; 506 *tl++ = dp->nfsdl_stateid.other[1]; 507 *tl = dp->nfsdl_stateid.other[2]; 508 } else { 509 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 510 } 511 (void) nfsm_strtom(nd, name, namelen); 512 } 513 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 514 *tl = txdr_unsigned(NFSV4OP_GETATTR); 515 NFSZERO_ATTRBIT(&attrbits); 516 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 517 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 518 (void) nfsrv_putattrbit(nd, &attrbits); 519 if (syscred) 520 nd->nd_flag |= ND_USEGSSNAME; 521 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 522 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 523 if (error) 524 return (error); 525 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 526 if (!nd->nd_repstat) { 527 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 528 6 * NFSX_UNSIGNED); 529 op->nfso_stateid.seqid = *tl++; 530 op->nfso_stateid.other[0] = *tl++; 531 op->nfso_stateid.other[1] = *tl++; 532 op->nfso_stateid.other[2] = *tl; 533 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 534 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 535 if (error) 536 goto nfsmout; 537 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 538 deleg = fxdr_unsigned(u_int32_t, *tl); 539 if (deleg == NFSV4OPEN_DELEGATEREAD || 540 deleg == NFSV4OPEN_DELEGATEWRITE) { 541 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 542 NFSCLFLAGS_FIRSTDELEG)) 543 op->nfso_own->nfsow_clp->nfsc_flags |= 544 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 545 ndp = malloc( 546 sizeof (struct nfscldeleg) + newfhlen, 547 M_NFSCLDELEG, M_WAITOK); 548 LIST_INIT(&ndp->nfsdl_owner); 549 LIST_INIT(&ndp->nfsdl_lock); 550 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 551 ndp->nfsdl_fhlen = newfhlen; 552 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 553 newnfs_copyincred(cred, &ndp->nfsdl_cred); 554 nfscl_lockinit(&ndp->nfsdl_rwlock); 555 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 556 NFSX_UNSIGNED); 557 ndp->nfsdl_stateid.seqid = *tl++; 558 ndp->nfsdl_stateid.other[0] = *tl++; 559 ndp->nfsdl_stateid.other[1] = *tl++; 560 ndp->nfsdl_stateid.other[2] = *tl++; 561 ret = fxdr_unsigned(int, *tl); 562 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 563 ndp->nfsdl_flags = NFSCLDL_WRITE; 564 /* 565 * Indicates how much the file can grow. 566 */ 567 NFSM_DISSECT(tl, u_int32_t *, 568 3 * NFSX_UNSIGNED); 569 limitby = fxdr_unsigned(int, *tl++); 570 switch (limitby) { 571 case NFSV4OPEN_LIMITSIZE: 572 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 573 break; 574 case NFSV4OPEN_LIMITBLOCKS: 575 ndp->nfsdl_sizelimit = 576 fxdr_unsigned(u_int64_t, *tl++); 577 ndp->nfsdl_sizelimit *= 578 fxdr_unsigned(u_int64_t, *tl); 579 break; 580 default: 581 error = NFSERR_BADXDR; 582 goto nfsmout; 583 } 584 } else { 585 ndp->nfsdl_flags = NFSCLDL_READ; 586 } 587 if (ret) 588 ndp->nfsdl_flags |= NFSCLDL_RECALL; 589 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 590 &acesize, p); 591 if (error) 592 goto nfsmout; 593 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 594 error = NFSERR_BADXDR; 595 goto nfsmout; 596 } 597 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 598 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 599 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 600 NULL, NULL, NULL, p, cred); 601 if (error) 602 goto nfsmout; 603 if (ndp != NULL) { 604 ndp->nfsdl_change = nfsva.na_filerev; 605 ndp->nfsdl_modtime = nfsva.na_mtime; 606 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 607 } 608 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) { 609 do { 610 ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op, 611 cred, p); 612 if (ret == NFSERR_DELAY) 613 (void) nfs_catnap(PZERO, ret, "nfs_open"); 614 } while (ret == NFSERR_DELAY); 615 error = ret; 616 } 617 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) || 618 nfscl_assumeposixlocks) 619 op->nfso_posixlock = 1; 620 else 621 op->nfso_posixlock = 0; 622 623 /* 624 * If the server is handing out delegations, but we didn't 625 * get one because an OpenConfirm was required, try the 626 * Open again, to get a delegation. This is a harmless no-op, 627 * from a server's point of view. 628 */ 629 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) && 630 (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) 631 && !error && dp == NULL && ndp == NULL && !recursed) { 632 do { 633 ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, 634 newfhlen, mode, op, name, namelen, &ndp, 0, 0x0, 635 cred, p, syscred, 1); 636 if (ret == NFSERR_DELAY) 637 (void) nfs_catnap(PZERO, ret, "nfs_open2"); 638 } while (ret == NFSERR_DELAY); 639 if (ret) { 640 if (ndp != NULL) { 641 free(ndp, M_NFSCLDELEG); 642 ndp = NULL; 643 } 644 if (ret == NFSERR_STALECLIENTID || 645 ret == NFSERR_STALEDONTRECOVER || 646 ret == NFSERR_BADSESSION) 647 error = ret; 648 } 649 } 650 } 651 if (nd->nd_repstat != 0 && error == 0) 652 error = nd->nd_repstat; 653 if (error == NFSERR_STALECLIENTID) 654 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 655 nfsmout: 656 if (!error) 657 *dpp = ndp; 658 else if (ndp != NULL) 659 free(ndp, M_NFSCLDELEG); 660 mbuf_freem(nd->nd_mrep); 661 return (error); 662 } 663 664 /* 665 * open downgrade rpc 666 */ 667 APPLESTATIC int 668 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op, 669 struct ucred *cred, NFSPROC_T *p) 670 { 671 u_int32_t *tl; 672 struct nfsrv_descript nfsd, *nd = &nfsd; 673 int error; 674 675 NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp); 676 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED); 677 if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp)))) 678 *tl++ = 0; 679 else 680 *tl++ = op->nfso_stateid.seqid; 681 *tl++ = op->nfso_stateid.other[0]; 682 *tl++ = op->nfso_stateid.other[1]; 683 *tl++ = op->nfso_stateid.other[2]; 684 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 685 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 686 *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 687 error = nfscl_request(nd, vp, p, cred, NULL); 688 if (error) 689 return (error); 690 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 691 if (!nd->nd_repstat) { 692 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 693 op->nfso_stateid.seqid = *tl++; 694 op->nfso_stateid.other[0] = *tl++; 695 op->nfso_stateid.other[1] = *tl++; 696 op->nfso_stateid.other[2] = *tl; 697 } 698 if (nd->nd_repstat && error == 0) 699 error = nd->nd_repstat; 700 if (error == NFSERR_STALESTATEID) 701 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 702 nfsmout: 703 mbuf_freem(nd->nd_mrep); 704 return (error); 705 } 706 707 /* 708 * V4 Close operation. 709 */ 710 APPLESTATIC int 711 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p) 712 { 713 struct nfsclclient *clp; 714 int error; 715 716 if (vnode_vtype(vp) != VREG) 717 return (0); 718 if (doclose) 719 error = nfscl_doclose(vp, &clp, p); 720 else 721 error = nfscl_getclose(vp, &clp); 722 if (error) 723 return (error); 724 725 nfscl_clientrelease(clp); 726 return (0); 727 } 728 729 /* 730 * Close the open. 731 */ 732 APPLESTATIC void 733 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p) 734 { 735 struct nfsrv_descript nfsd, *nd = &nfsd; 736 struct nfscllockowner *lp, *nlp; 737 struct nfscllock *lop, *nlop; 738 struct ucred *tcred; 739 u_int64_t off = 0, len = 0; 740 u_int32_t type = NFSV4LOCKT_READ; 741 int error, do_unlock, trycnt; 742 743 tcred = newnfs_getcred(); 744 newnfs_copycred(&op->nfso_cred, tcred); 745 /* 746 * (Theoretically this could be done in the same 747 * compound as the close, but having multiple 748 * sequenced Ops in the same compound might be 749 * too scary for some servers.) 750 */ 751 if (op->nfso_posixlock) { 752 off = 0; 753 len = NFS64BITSSET; 754 type = NFSV4LOCKT_READ; 755 } 756 757 /* 758 * Since this function is only called from VOP_INACTIVE(), no 759 * other thread will be manipulating this Open. As such, the 760 * lock lists are not being changed by other threads, so it should 761 * be safe to do this without locking. 762 */ 763 LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) { 764 do_unlock = 1; 765 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) { 766 if (op->nfso_posixlock == 0) { 767 off = lop->nfslo_first; 768 len = lop->nfslo_end - lop->nfslo_first; 769 if (lop->nfslo_type == F_WRLCK) 770 type = NFSV4LOCKT_WRITE; 771 else 772 type = NFSV4LOCKT_READ; 773 } 774 if (do_unlock) { 775 trycnt = 0; 776 do { 777 error = nfsrpc_locku(nd, nmp, lp, off, 778 len, type, tcred, p, 0); 779 if ((nd->nd_repstat == NFSERR_GRACE || 780 nd->nd_repstat == NFSERR_DELAY) && 781 error == 0) 782 (void) nfs_catnap(PZERO, 783 (int)nd->nd_repstat, 784 "nfs_close"); 785 } while ((nd->nd_repstat == NFSERR_GRACE || 786 nd->nd_repstat == NFSERR_DELAY) && 787 error == 0 && trycnt++ < 5); 788 if (op->nfso_posixlock) 789 do_unlock = 0; 790 } 791 nfscl_freelock(lop, 0); 792 } 793 /* 794 * Do a ReleaseLockOwner. 795 * The lock owner name nfsl_owner may be used by other opens for 796 * other files but the lock_owner4 name that nfsrpc_rellockown() 797 * puts on the wire has the file handle for this file appended 798 * to it, so it can be done now. 799 */ 800 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh, 801 lp->nfsl_open->nfso_fhlen, tcred, p); 802 } 803 804 /* 805 * There could be other Opens for different files on the same 806 * OpenOwner, so locking is required. 807 */ 808 NFSLOCKCLSTATE(); 809 nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR); 810 NFSUNLOCKCLSTATE(); 811 do { 812 error = nfscl_tryclose(op, tcred, nmp, p); 813 if (error == NFSERR_GRACE) 814 (void) nfs_catnap(PZERO, error, "nfs_close"); 815 } while (error == NFSERR_GRACE); 816 NFSLOCKCLSTATE(); 817 nfscl_lockunlock(&op->nfso_own->nfsow_rwlock); 818 819 LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) 820 nfscl_freelockowner(lp, 0); 821 nfscl_freeopen(op, 0); 822 NFSUNLOCKCLSTATE(); 823 NFSFREECRED(tcred); 824 } 825 826 /* 827 * The actual Close RPC. 828 */ 829 APPLESTATIC int 830 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp, 831 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p, 832 int syscred) 833 { 834 u_int32_t *tl; 835 int error; 836 837 nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh, 838 op->nfso_fhlen, NULL, NULL, 0, 0); 839 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 840 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 841 if (NFSHASNFSV4N(nmp)) 842 *tl++ = 0; 843 else 844 *tl++ = op->nfso_stateid.seqid; 845 *tl++ = op->nfso_stateid.other[0]; 846 *tl++ = op->nfso_stateid.other[1]; 847 *tl = op->nfso_stateid.other[2]; 848 if (syscred) 849 nd->nd_flag |= ND_USEGSSNAME; 850 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 851 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 852 if (error) 853 return (error); 854 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 855 if (nd->nd_repstat == 0) 856 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 857 error = nd->nd_repstat; 858 if (error == NFSERR_STALESTATEID) 859 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 860 nfsmout: 861 mbuf_freem(nd->nd_mrep); 862 return (error); 863 } 864 865 /* 866 * V4 Open Confirm RPC. 867 */ 868 APPLESTATIC int 869 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen, 870 struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p) 871 { 872 u_int32_t *tl; 873 struct nfsrv_descript nfsd, *nd = &nfsd; 874 struct nfsmount *nmp; 875 int error; 876 877 nmp = VFSTONFS(vnode_mount(vp)); 878 if (NFSHASNFSV4N(nmp)) 879 return (0); /* No confirmation for NFSv4.1. */ 880 nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL, 881 0, 0); 882 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID); 883 *tl++ = op->nfso_stateid.seqid; 884 *tl++ = op->nfso_stateid.other[0]; 885 *tl++ = op->nfso_stateid.other[1]; 886 *tl++ = op->nfso_stateid.other[2]; 887 *tl = txdr_unsigned(op->nfso_own->nfsow_seqid); 888 error = nfscl_request(nd, vp, p, cred, NULL); 889 if (error) 890 return (error); 891 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 892 if (!nd->nd_repstat) { 893 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 894 op->nfso_stateid.seqid = *tl++; 895 op->nfso_stateid.other[0] = *tl++; 896 op->nfso_stateid.other[1] = *tl++; 897 op->nfso_stateid.other[2] = *tl; 898 } 899 error = nd->nd_repstat; 900 if (error == NFSERR_STALESTATEID) 901 nfscl_initiate_recovery(op->nfso_own->nfsow_clp); 902 nfsmout: 903 mbuf_freem(nd->nd_mrep); 904 return (error); 905 } 906 907 /* 908 * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs() 909 * when a mount has just occurred and when the server replies NFSERR_EXPIRED. 910 */ 911 APPLESTATIC int 912 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim, 913 struct ucred *cred, NFSPROC_T *p) 914 { 915 u_int32_t *tl; 916 struct nfsrv_descript nfsd; 917 struct nfsrv_descript *nd = &nfsd; 918 nfsattrbit_t attrbits; 919 u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9]; 920 u_short port; 921 int error, isinet6 = 0, callblen; 922 nfsquad_t confirm; 923 u_int32_t lease; 924 static u_int32_t rev = 0; 925 struct nfsclds *dsp; 926 struct in6_addr a6; 927 struct nfsclsession *tsep; 928 929 if (nfsboottime.tv_sec == 0) 930 NFSSETBOOTTIME(nfsboottime); 931 clp->nfsc_rev = rev++; 932 if (NFSHASNFSV4N(nmp)) { 933 /* 934 * Either there was no previous session or the 935 * previous session has failed, so... 936 * do an ExchangeID followed by the CreateSession. 937 */ 938 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq, 939 NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p); 940 NFSCL_DEBUG(1, "aft exch=%d\n", error); 941 if (error == 0) 942 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 943 &nmp->nm_sockreq, 944 dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p); 945 if (error == 0) { 946 NFSLOCKMNT(nmp); 947 /* 948 * The old sessions cannot be safely free'd 949 * here, since they may still be used by 950 * in-progress RPCs. 951 */ 952 tsep = NULL; 953 if (TAILQ_FIRST(&nmp->nm_sess) != NULL) 954 tsep = NFSMNT_MDSSESSION(nmp); 955 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, 956 nfsclds_list); 957 /* 958 * Wake up RPCs waiting for a slot on the 959 * old session. These will then fail with 960 * NFSERR_BADSESSION and be retried with the 961 * new session by nfsv4_setsequence(). 962 * Also wakeup() processes waiting for the 963 * new session. 964 */ 965 if (tsep != NULL) 966 wakeup(&tsep->nfsess_slots); 967 wakeup(&nmp->nm_sess); 968 NFSUNLOCKMNT(nmp); 969 } else 970 nfscl_freenfsclds(dsp); 971 NFSCL_DEBUG(1, "aft createsess=%d\n", error); 972 if (error == 0 && reclaim == 0) { 973 error = nfsrpc_reclaimcomplete(nmp, cred, p); 974 NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error); 975 if (error == NFSERR_COMPLETEALREADY || 976 error == NFSERR_NOTSUPP) 977 /* Ignore this error. */ 978 error = 0; 979 } 980 return (error); 981 } 982 983 /* 984 * Allocate a single session structure for NFSv4.0, because some of 985 * the fields are used by NFSv4.0 although it doesn't do a session. 986 */ 987 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO); 988 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 989 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF); 990 NFSLOCKMNT(nmp); 991 TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list); 992 tsep = NFSMNT_MDSSESSION(nmp); 993 NFSUNLOCKMNT(nmp); 994 995 nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0); 996 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 997 *tl++ = txdr_unsigned(nfsboottime.tv_sec); 998 *tl = txdr_unsigned(clp->nfsc_rev); 999 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 1000 1001 /* 1002 * set up the callback address 1003 */ 1004 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1005 *tl = txdr_unsigned(NFS_CALLBCKPROG); 1006 callblen = strlen(nfsv4_callbackaddr); 1007 if (callblen == 0) 1008 cp = nfscl_getmyip(nmp, &a6, &isinet6); 1009 if (nfscl_enablecallb && nfs_numnfscbd > 0 && 1010 (callblen > 0 || cp != NULL)) { 1011 port = htons(nfsv4_cbport); 1012 cp2 = (u_int8_t *)&port; 1013 #ifdef INET6 1014 if ((callblen > 0 && 1015 strchr(nfsv4_callbackaddr, ':')) || isinet6) { 1016 char ip6buf[INET6_ADDRSTRLEN], *ip6add; 1017 1018 (void) nfsm_strtom(nd, "tcp6", 4); 1019 if (callblen == 0) { 1020 ip6_sprintf(ip6buf, (struct in6_addr *)cp); 1021 ip6add = ip6buf; 1022 } else { 1023 ip6add = nfsv4_callbackaddr; 1024 } 1025 snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d", 1026 ip6add, cp2[0], cp2[1]); 1027 } else 1028 #endif 1029 { 1030 (void) nfsm_strtom(nd, "tcp", 3); 1031 if (callblen == 0) 1032 snprintf(addr, INET6_ADDRSTRLEN + 9, 1033 "%d.%d.%d.%d.%d.%d", cp[0], cp[1], 1034 cp[2], cp[3], cp2[0], cp2[1]); 1035 else 1036 snprintf(addr, INET6_ADDRSTRLEN + 9, 1037 "%s.%d.%d", nfsv4_callbackaddr, 1038 cp2[0], cp2[1]); 1039 } 1040 (void) nfsm_strtom(nd, addr, strlen(addr)); 1041 } else { 1042 (void) nfsm_strtom(nd, "tcp", 3); 1043 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11); 1044 } 1045 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1046 *tl = txdr_unsigned(clp->nfsc_cbident); 1047 nd->nd_flag |= ND_USEGSSNAME; 1048 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 1049 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1050 if (error) 1051 return (error); 1052 if (nd->nd_repstat == 0) { 1053 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1054 tsep->nfsess_clientid.lval[0] = *tl++; 1055 tsep->nfsess_clientid.lval[1] = *tl++; 1056 confirm.lval[0] = *tl++; 1057 confirm.lval[1] = *tl; 1058 mbuf_freem(nd->nd_mrep); 1059 nd->nd_mrep = NULL; 1060 1061 /* 1062 * and confirm it. 1063 */ 1064 nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL, 1065 NULL, 0, 0); 1066 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1067 *tl++ = tsep->nfsess_clientid.lval[0]; 1068 *tl++ = tsep->nfsess_clientid.lval[1]; 1069 *tl++ = confirm.lval[0]; 1070 *tl = confirm.lval[1]; 1071 nd->nd_flag |= ND_USEGSSNAME; 1072 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 1073 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1074 if (error) 1075 return (error); 1076 mbuf_freem(nd->nd_mrep); 1077 nd->nd_mrep = NULL; 1078 if (nd->nd_repstat == 0) { 1079 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh, 1080 nmp->nm_fhsize, NULL, NULL, 0, 0); 1081 NFSZERO_ATTRBIT(&attrbits); 1082 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 1083 (void) nfsrv_putattrbit(nd, &attrbits); 1084 nd->nd_flag |= ND_USEGSSNAME; 1085 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, 1086 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 1087 if (error) 1088 return (error); 1089 if (nd->nd_repstat == 0) { 1090 error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL, 1091 NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred); 1092 if (error) 1093 goto nfsmout; 1094 clp->nfsc_renew = NFSCL_RENEW(lease); 1095 clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew; 1096 clp->nfsc_clientidrev++; 1097 if (clp->nfsc_clientidrev == 0) 1098 clp->nfsc_clientidrev++; 1099 } 1100 } 1101 } 1102 error = nd->nd_repstat; 1103 nfsmout: 1104 mbuf_freem(nd->nd_mrep); 1105 return (error); 1106 } 1107 1108 /* 1109 * nfs getattr call. 1110 */ 1111 APPLESTATIC int 1112 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 1113 struct nfsvattr *nap, void *stuff) 1114 { 1115 struct nfsrv_descript nfsd, *nd = &nfsd; 1116 int error; 1117 nfsattrbit_t attrbits; 1118 1119 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 1120 if (nd->nd_flag & ND_NFSV4) { 1121 NFSGETATTR_ATTRBIT(&attrbits); 1122 (void) nfsrv_putattrbit(nd, &attrbits); 1123 } 1124 error = nfscl_request(nd, vp, p, cred, stuff); 1125 if (error) 1126 return (error); 1127 if (!nd->nd_repstat) 1128 error = nfsm_loadattr(nd, nap); 1129 else 1130 error = nd->nd_repstat; 1131 mbuf_freem(nd->nd_mrep); 1132 return (error); 1133 } 1134 1135 /* 1136 * nfs getattr call with non-vnode arguemnts. 1137 */ 1138 APPLESTATIC int 1139 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred, 1140 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp, 1141 uint32_t *leasep) 1142 { 1143 struct nfsrv_descript nfsd, *nd = &nfsd; 1144 int error, vers = NFS_VER2; 1145 nfsattrbit_t attrbits; 1146 1147 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0); 1148 if (nd->nd_flag & ND_NFSV4) { 1149 vers = NFS_VER4; 1150 NFSGETATTR_ATTRBIT(&attrbits); 1151 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME); 1152 (void) nfsrv_putattrbit(nd, &attrbits); 1153 } else if (nd->nd_flag & ND_NFSV3) { 1154 vers = NFS_VER3; 1155 } 1156 if (syscred) 1157 nd->nd_flag |= ND_USEGSSNAME; 1158 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 1159 NFS_PROG, vers, NULL, 1, xidp, NULL); 1160 if (error) 1161 return (error); 1162 if (nd->nd_repstat == 0) { 1163 if ((nd->nd_flag & ND_NFSV4) != 0) 1164 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 1165 NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL, 1166 NULL, NULL); 1167 else 1168 error = nfsm_loadattr(nd, nap); 1169 } else 1170 error = nd->nd_repstat; 1171 mbuf_freem(nd->nd_mrep); 1172 return (error); 1173 } 1174 1175 /* 1176 * Do an nfs setattr operation. 1177 */ 1178 APPLESTATIC int 1179 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp, 1180 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp, 1181 void *stuff) 1182 { 1183 int error, expireret = 0, openerr, retrycnt; 1184 u_int32_t clidrev = 0, mode; 1185 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1186 struct nfsfh *nfhp; 1187 nfsv4stateid_t stateid; 1188 void *lckp; 1189 1190 if (nmp->nm_clp != NULL) 1191 clidrev = nmp->nm_clp->nfsc_clientidrev; 1192 if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size)) 1193 mode = NFSV4OPEN_ACCESSWRITE; 1194 else 1195 mode = NFSV4OPEN_ACCESSREAD; 1196 retrycnt = 0; 1197 do { 1198 lckp = NULL; 1199 openerr = 1; 1200 if (NFSHASNFSV4(nmp)) { 1201 nfhp = VTONFS(vp)->n_fhp; 1202 error = nfscl_getstateid(vp, nfhp->nfh_fh, 1203 nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp); 1204 if (error && vnode_vtype(vp) == VREG && 1205 (mode == NFSV4OPEN_ACCESSWRITE || 1206 nfstest_openallsetattr)) { 1207 /* 1208 * No Open stateid, so try and open the file 1209 * now. 1210 */ 1211 if (mode == NFSV4OPEN_ACCESSWRITE) 1212 openerr = nfsrpc_open(vp, FWRITE, cred, 1213 p); 1214 else 1215 openerr = nfsrpc_open(vp, FREAD, cred, 1216 p); 1217 if (!openerr) 1218 (void) nfscl_getstateid(vp, 1219 nfhp->nfh_fh, nfhp->nfh_len, 1220 mode, 0, cred, p, &stateid, &lckp); 1221 } 1222 } 1223 if (vap != NULL) 1224 error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p, 1225 rnap, attrflagp, stuff); 1226 else 1227 error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid, 1228 stuff); 1229 if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) { 1230 NFSLOCKMNT(nmp); 1231 nmp->nm_state |= NFSSTA_OPENMODE; 1232 NFSUNLOCKMNT(nmp); 1233 } 1234 if (error == NFSERR_STALESTATEID) 1235 nfscl_initiate_recovery(nmp->nm_clp); 1236 if (lckp != NULL) 1237 nfscl_lockderef(lckp); 1238 if (!openerr) 1239 (void) nfsrpc_close(vp, 0, p); 1240 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1241 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1242 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1243 (void) nfs_catnap(PZERO, error, "nfs_setattr"); 1244 } else if ((error == NFSERR_EXPIRED || 1245 error == NFSERR_BADSTATEID) && clidrev != 0) { 1246 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1247 } 1248 retrycnt++; 1249 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1250 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1251 error == NFSERR_BADSESSION || 1252 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1253 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1254 expireret == 0 && clidrev != 0 && retrycnt < 4) || 1255 (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD && 1256 retrycnt < 4)); 1257 if (error && retrycnt >= 4) 1258 error = EIO; 1259 return (error); 1260 } 1261 1262 static int 1263 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap, 1264 nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 1265 struct nfsvattr *rnap, int *attrflagp, void *stuff) 1266 { 1267 u_int32_t *tl; 1268 struct nfsrv_descript nfsd, *nd = &nfsd; 1269 int error; 1270 nfsattrbit_t attrbits; 1271 1272 *attrflagp = 0; 1273 NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp); 1274 if (nd->nd_flag & ND_NFSV4) 1275 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1276 vap->va_type = vnode_vtype(vp); 1277 nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0); 1278 if (nd->nd_flag & ND_NFSV3) { 1279 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1280 *tl = newnfs_false; 1281 } else if (nd->nd_flag & ND_NFSV4) { 1282 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1283 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1284 NFSGETATTR_ATTRBIT(&attrbits); 1285 (void) nfsrv_putattrbit(nd, &attrbits); 1286 } 1287 error = nfscl_request(nd, vp, p, cred, stuff); 1288 if (error) 1289 return (error); 1290 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1291 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff); 1292 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error) 1293 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1294 if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error) 1295 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff); 1296 mbuf_freem(nd->nd_mrep); 1297 if (nd->nd_repstat && !error) 1298 error = nd->nd_repstat; 1299 return (error); 1300 } 1301 1302 /* 1303 * nfs lookup rpc 1304 */ 1305 APPLESTATIC int 1306 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred, 1307 NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap, 1308 struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff) 1309 { 1310 u_int32_t *tl; 1311 struct nfsrv_descript nfsd, *nd = &nfsd; 1312 struct nfsmount *nmp; 1313 struct nfsnode *np; 1314 struct nfsfh *nfhp; 1315 nfsattrbit_t attrbits; 1316 int error = 0, lookupp = 0; 1317 1318 *attrflagp = 0; 1319 *dattrflagp = 0; 1320 if (vnode_vtype(dvp) != VDIR) 1321 return (ENOTDIR); 1322 nmp = VFSTONFS(vnode_mount(dvp)); 1323 if (len > NFS_MAXNAMLEN) 1324 return (ENAMETOOLONG); 1325 if (NFSHASNFSV4(nmp) && len == 1 && 1326 name[0] == '.') { 1327 /* 1328 * Just return the current dir's fh. 1329 */ 1330 np = VTONFS(dvp); 1331 nfhp = malloc(sizeof (struct nfsfh) + 1332 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1333 nfhp->nfh_len = np->n_fhp->nfh_len; 1334 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1335 *nfhpp = nfhp; 1336 return (0); 1337 } 1338 if (NFSHASNFSV4(nmp) && len == 2 && 1339 name[0] == '.' && name[1] == '.') { 1340 lookupp = 1; 1341 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp); 1342 } else { 1343 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp); 1344 (void) nfsm_strtom(nd, name, len); 1345 } 1346 if (nd->nd_flag & ND_NFSV4) { 1347 NFSGETATTR_ATTRBIT(&attrbits); 1348 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1349 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1350 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1351 (void) nfsrv_putattrbit(nd, &attrbits); 1352 } 1353 error = nfscl_request(nd, dvp, p, cred, stuff); 1354 if (error) 1355 return (error); 1356 if (nd->nd_repstat) { 1357 /* 1358 * When an NFSv4 Lookupp returns ENOENT, it means that 1359 * the lookup is at the root of an fs, so return this dir. 1360 */ 1361 if (nd->nd_repstat == NFSERR_NOENT && lookupp) { 1362 np = VTONFS(dvp); 1363 nfhp = malloc(sizeof (struct nfsfh) + 1364 np->n_fhp->nfh_len, M_NFSFH, M_WAITOK); 1365 nfhp->nfh_len = np->n_fhp->nfh_len; 1366 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len); 1367 *nfhpp = nfhp; 1368 mbuf_freem(nd->nd_mrep); 1369 return (0); 1370 } 1371 if (nd->nd_flag & ND_NFSV3) 1372 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1373 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 1374 ND_NFSV4) { 1375 /* Load the directory attributes. */ 1376 error = nfsm_loadattr(nd, dnap); 1377 if (error == 0) 1378 *dattrflagp = 1; 1379 } 1380 goto nfsmout; 1381 } 1382 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 1383 /* Load the directory attributes. */ 1384 error = nfsm_loadattr(nd, dnap); 1385 if (error != 0) 1386 goto nfsmout; 1387 *dattrflagp = 1; 1388 /* Skip over the Lookup and GetFH operation status values. */ 1389 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1390 } 1391 error = nfsm_getfh(nd, nfhpp); 1392 if (error) 1393 goto nfsmout; 1394 1395 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1396 if ((nd->nd_flag & ND_NFSV3) && !error) 1397 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff); 1398 nfsmout: 1399 mbuf_freem(nd->nd_mrep); 1400 if (!error && nd->nd_repstat) 1401 error = nd->nd_repstat; 1402 return (error); 1403 } 1404 1405 /* 1406 * Do a readlink rpc. 1407 */ 1408 APPLESTATIC int 1409 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred, 1410 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1411 { 1412 u_int32_t *tl; 1413 struct nfsrv_descript nfsd, *nd = &nfsd; 1414 struct nfsnode *np = VTONFS(vp); 1415 nfsattrbit_t attrbits; 1416 int error, len, cangetattr = 1; 1417 1418 *attrflagp = 0; 1419 NFSCL_REQSTART(nd, NFSPROC_READLINK, vp); 1420 if (nd->nd_flag & ND_NFSV4) { 1421 /* 1422 * And do a Getattr op. 1423 */ 1424 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1425 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1426 NFSGETATTR_ATTRBIT(&attrbits); 1427 (void) nfsrv_putattrbit(nd, &attrbits); 1428 } 1429 error = nfscl_request(nd, vp, p, cred, stuff); 1430 if (error) 1431 return (error); 1432 if (nd->nd_flag & ND_NFSV3) 1433 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1434 if (!nd->nd_repstat && !error) { 1435 NFSM_STRSIZ(len, NFS_MAXPATHLEN); 1436 /* 1437 * This seems weird to me, but must have been added to 1438 * FreeBSD for some reason. The only thing I can think of 1439 * is that there was/is some server that replies with 1440 * more link data than it should? 1441 */ 1442 if (len == NFS_MAXPATHLEN) { 1443 NFSLOCKNODE(np); 1444 if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) { 1445 len = np->n_size; 1446 cangetattr = 0; 1447 } 1448 NFSUNLOCKNODE(np); 1449 } 1450 error = nfsm_mbufuio(nd, uiop, len); 1451 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr) 1452 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1453 } 1454 if (nd->nd_repstat && !error) 1455 error = nd->nd_repstat; 1456 nfsmout: 1457 mbuf_freem(nd->nd_mrep); 1458 return (error); 1459 } 1460 1461 /* 1462 * Read operation. 1463 */ 1464 APPLESTATIC int 1465 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred, 1466 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1467 { 1468 int error, expireret = 0, retrycnt; 1469 u_int32_t clidrev = 0; 1470 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1471 struct nfsnode *np = VTONFS(vp); 1472 struct ucred *newcred; 1473 struct nfsfh *nfhp = NULL; 1474 nfsv4stateid_t stateid; 1475 void *lckp; 1476 1477 if (nmp->nm_clp != NULL) 1478 clidrev = nmp->nm_clp->nfsc_clientidrev; 1479 newcred = cred; 1480 if (NFSHASNFSV4(nmp)) { 1481 nfhp = np->n_fhp; 1482 newcred = NFSNEWCRED(cred); 1483 } 1484 retrycnt = 0; 1485 do { 1486 lckp = NULL; 1487 if (NFSHASNFSV4(nmp)) 1488 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1489 NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid, 1490 &lckp); 1491 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap, 1492 attrflagp, stuff); 1493 if (error == NFSERR_OPENMODE) { 1494 NFSLOCKMNT(nmp); 1495 nmp->nm_state |= NFSSTA_OPENMODE; 1496 NFSUNLOCKMNT(nmp); 1497 } 1498 if (error == NFSERR_STALESTATEID) 1499 nfscl_initiate_recovery(nmp->nm_clp); 1500 if (lckp != NULL) 1501 nfscl_lockderef(lckp); 1502 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1503 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1504 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1505 (void) nfs_catnap(PZERO, error, "nfs_read"); 1506 } else if ((error == NFSERR_EXPIRED || 1507 error == NFSERR_BADSTATEID) && clidrev != 0) { 1508 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1509 } 1510 retrycnt++; 1511 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1512 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1513 error == NFSERR_BADSESSION || 1514 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1515 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1516 expireret == 0 && clidrev != 0 && retrycnt < 4) || 1517 (error == NFSERR_OPENMODE && retrycnt < 4)); 1518 if (error && retrycnt >= 4) 1519 error = EIO; 1520 if (NFSHASNFSV4(nmp)) 1521 NFSFREECRED(newcred); 1522 return (error); 1523 } 1524 1525 /* 1526 * The actual read RPC. 1527 */ 1528 static int 1529 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred, 1530 nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap, 1531 int *attrflagp, void *stuff) 1532 { 1533 u_int32_t *tl; 1534 int error = 0, len, retlen, tsiz, eof = 0; 1535 struct nfsrv_descript nfsd; 1536 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1537 struct nfsrv_descript *nd = &nfsd; 1538 int rsize; 1539 off_t tmp_off; 1540 1541 *attrflagp = 0; 1542 tsiz = uio_uio_resid(uiop); 1543 tmp_off = uiop->uio_offset + tsiz; 1544 NFSLOCKMNT(nmp); 1545 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1546 NFSUNLOCKMNT(nmp); 1547 return (EFBIG); 1548 } 1549 rsize = nmp->nm_rsize; 1550 NFSUNLOCKMNT(nmp); 1551 nd->nd_mrep = NULL; 1552 while (tsiz > 0) { 1553 *attrflagp = 0; 1554 len = (tsiz > rsize) ? rsize : tsiz; 1555 NFSCL_REQSTART(nd, NFSPROC_READ, vp); 1556 if (nd->nd_flag & ND_NFSV4) 1557 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1558 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3); 1559 if (nd->nd_flag & ND_NFSV2) { 1560 *tl++ = txdr_unsigned(uiop->uio_offset); 1561 *tl++ = txdr_unsigned(len); 1562 *tl = 0; 1563 } else { 1564 txdr_hyper(uiop->uio_offset, tl); 1565 *(tl + 2) = txdr_unsigned(len); 1566 } 1567 /* 1568 * Since I can't do a Getattr for NFSv4 for Write, there 1569 * doesn't seem any point in doing one here, either. 1570 * (See the comment in nfsrpc_writerpc() for more info.) 1571 */ 1572 error = nfscl_request(nd, vp, p, cred, stuff); 1573 if (error) 1574 return (error); 1575 if (nd->nd_flag & ND_NFSV3) { 1576 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 1577 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) { 1578 error = nfsm_loadattr(nd, nap); 1579 if (!error) 1580 *attrflagp = 1; 1581 } 1582 if (nd->nd_repstat || error) { 1583 if (!error) 1584 error = nd->nd_repstat; 1585 goto nfsmout; 1586 } 1587 if (nd->nd_flag & ND_NFSV3) { 1588 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1589 eof = fxdr_unsigned(int, *(tl + 1)); 1590 } else if (nd->nd_flag & ND_NFSV4) { 1591 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 1592 eof = fxdr_unsigned(int, *tl); 1593 } 1594 NFSM_STRSIZ(retlen, len); 1595 error = nfsm_mbufuio(nd, uiop, retlen); 1596 if (error) 1597 goto nfsmout; 1598 mbuf_freem(nd->nd_mrep); 1599 nd->nd_mrep = NULL; 1600 tsiz -= retlen; 1601 if (!(nd->nd_flag & ND_NFSV2)) { 1602 if (eof || retlen == 0) 1603 tsiz = 0; 1604 } else if (retlen < len) 1605 tsiz = 0; 1606 } 1607 return (0); 1608 nfsmout: 1609 if (nd->nd_mrep != NULL) 1610 mbuf_freem(nd->nd_mrep); 1611 return (error); 1612 } 1613 1614 /* 1615 * nfs write operation 1616 * When called_from_strategy != 0, it should return EIO for an error that 1617 * indicates recovery is in progress, so that the buffer will be left 1618 * dirty and be written back to the server later. If it loops around, 1619 * the recovery thread could get stuck waiting for the buffer and recovery 1620 * will then deadlock. 1621 */ 1622 APPLESTATIC int 1623 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 1624 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 1625 void *stuff, int called_from_strategy) 1626 { 1627 int error, expireret = 0, retrycnt, nostateid; 1628 u_int32_t clidrev = 0; 1629 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1630 struct nfsnode *np = VTONFS(vp); 1631 struct ucred *newcred; 1632 struct nfsfh *nfhp = NULL; 1633 nfsv4stateid_t stateid; 1634 void *lckp; 1635 1636 *must_commit = 0; 1637 if (nmp->nm_clp != NULL) 1638 clidrev = nmp->nm_clp->nfsc_clientidrev; 1639 newcred = cred; 1640 if (NFSHASNFSV4(nmp)) { 1641 newcred = NFSNEWCRED(cred); 1642 nfhp = np->n_fhp; 1643 } 1644 retrycnt = 0; 1645 do { 1646 lckp = NULL; 1647 nostateid = 0; 1648 if (NFSHASNFSV4(nmp)) { 1649 (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 1650 NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid, 1651 &lckp); 1652 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 1653 stateid.other[2] == 0) { 1654 nostateid = 1; 1655 NFSCL_DEBUG(1, "stateid0 in write\n"); 1656 } 1657 } 1658 1659 /* 1660 * If there is no stateid for NFSv4, it means this is an 1661 * extraneous write after close. Basically a poorly 1662 * implemented buffer cache. Just don't do the write. 1663 */ 1664 if (nostateid) 1665 error = 0; 1666 else 1667 error = nfsrpc_writerpc(vp, uiop, iomode, must_commit, 1668 newcred, &stateid, p, nap, attrflagp, stuff); 1669 if (error == NFSERR_STALESTATEID) 1670 nfscl_initiate_recovery(nmp->nm_clp); 1671 if (lckp != NULL) 1672 nfscl_lockderef(lckp); 1673 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 1674 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 1675 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 1676 (void) nfs_catnap(PZERO, error, "nfs_write"); 1677 } else if ((error == NFSERR_EXPIRED || 1678 error == NFSERR_BADSTATEID) && clidrev != 0) { 1679 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 1680 } 1681 retrycnt++; 1682 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 1683 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1684 error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) || 1685 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 1686 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 1687 expireret == 0 && clidrev != 0 && retrycnt < 4)); 1688 if (error != 0 && (retrycnt >= 4 || 1689 ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 1690 error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0))) 1691 error = EIO; 1692 if (NFSHASNFSV4(nmp)) 1693 NFSFREECRED(newcred); 1694 return (error); 1695 } 1696 1697 /* 1698 * The actual write RPC. 1699 */ 1700 static int 1701 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode, 1702 int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp, 1703 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 1704 { 1705 u_int32_t *tl; 1706 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 1707 struct nfsnode *np = VTONFS(vp); 1708 int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC; 1709 int wccflag = 0, wsize; 1710 int32_t backup; 1711 struct nfsrv_descript nfsd; 1712 struct nfsrv_descript *nd = &nfsd; 1713 nfsattrbit_t attrbits; 1714 off_t tmp_off; 1715 1716 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 1717 *attrflagp = 0; 1718 tsiz = uio_uio_resid(uiop); 1719 tmp_off = uiop->uio_offset + tsiz; 1720 NFSLOCKMNT(nmp); 1721 if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) { 1722 NFSUNLOCKMNT(nmp); 1723 return (EFBIG); 1724 } 1725 wsize = nmp->nm_wsize; 1726 NFSUNLOCKMNT(nmp); 1727 nd->nd_mrep = NULL; /* NFSv2 sometimes does a write with */ 1728 nd->nd_repstat = 0; /* uio_resid == 0, so the while is not done */ 1729 while (tsiz > 0) { 1730 *attrflagp = 0; 1731 len = (tsiz > wsize) ? wsize : tsiz; 1732 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp); 1733 if (nd->nd_flag & ND_NFSV4) { 1734 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 1735 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED); 1736 txdr_hyper(uiop->uio_offset, tl); 1737 tl += 2; 1738 *tl++ = txdr_unsigned(*iomode); 1739 *tl = txdr_unsigned(len); 1740 } else if (nd->nd_flag & ND_NFSV3) { 1741 NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED); 1742 txdr_hyper(uiop->uio_offset, tl); 1743 tl += 2; 1744 *tl++ = txdr_unsigned(len); 1745 *tl++ = txdr_unsigned(*iomode); 1746 *tl = txdr_unsigned(len); 1747 } else { 1748 u_int32_t x; 1749 1750 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 1751 /* 1752 * Not sure why someone changed this, since the 1753 * RFC clearly states that "beginoffset" and 1754 * "totalcount" are ignored, but it wouldn't 1755 * surprise me if there's a busted server out there. 1756 */ 1757 /* Set both "begin" and "current" to non-garbage. */ 1758 x = txdr_unsigned((u_int32_t)uiop->uio_offset); 1759 *tl++ = x; /* "begin offset" */ 1760 *tl++ = x; /* "current offset" */ 1761 x = txdr_unsigned(len); 1762 *tl++ = x; /* total to this offset */ 1763 *tl = x; /* size of this write */ 1764 1765 } 1766 nfsm_uiombuf(nd, uiop, len); 1767 /* 1768 * Although it is tempting to do a normal Getattr Op in the 1769 * NFSv4 compound, the result can be a nearly hung client 1770 * system if the Getattr asks for Owner and/or OwnerGroup. 1771 * It occurs when the client can't map either the Owner or 1772 * Owner_group name in the Getattr reply to a uid/gid. When 1773 * there is a cache miss, the kernel does an upcall to the 1774 * nfsuserd. Then, it can try and read the local /etc/passwd 1775 * or /etc/group file. It can then block in getnewbuf(), 1776 * waiting for dirty writes to be pushed to the NFS server. 1777 * The only reason this doesn't result in a complete 1778 * deadlock, is that the upcall times out and allows 1779 * the write to complete. However, progress is so slow 1780 * that it might just as well be deadlocked. 1781 * As such, we get the rest of the attributes, but not 1782 * Owner or Owner_group. 1783 * nb: nfscl_loadattrcache() needs to be told that these 1784 * partial attributes from a write rpc are being 1785 * passed in, via a argument flag. 1786 */ 1787 if (nd->nd_flag & ND_NFSV4) { 1788 NFSWRITEGETATTR_ATTRBIT(&attrbits); 1789 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1790 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1791 (void) nfsrv_putattrbit(nd, &attrbits); 1792 } 1793 error = nfscl_request(nd, vp, p, cred, stuff); 1794 if (error) 1795 return (error); 1796 if (nd->nd_repstat) { 1797 /* 1798 * In case the rpc gets retried, roll 1799 * the uio fileds changed by nfsm_uiombuf() 1800 * back. 1801 */ 1802 uiop->uio_offset -= len; 1803 uio_uio_resid_add(uiop, len); 1804 uio_iov_base_add(uiop, -len); 1805 uio_iov_len_add(uiop, len); 1806 } 1807 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1808 error = nfscl_wcc_data(nd, vp, nap, attrflagp, 1809 &wccflag, stuff); 1810 if (error) 1811 goto nfsmout; 1812 } 1813 if (!nd->nd_repstat) { 1814 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 1815 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 1816 + NFSX_VERF); 1817 rlen = fxdr_unsigned(int, *tl++); 1818 if (rlen == 0) { 1819 error = NFSERR_IO; 1820 goto nfsmout; 1821 } else if (rlen < len) { 1822 backup = len - rlen; 1823 uio_iov_base_add(uiop, -(backup)); 1824 uio_iov_len_add(uiop, backup); 1825 uiop->uio_offset -= backup; 1826 uio_uio_resid_add(uiop, backup); 1827 len = rlen; 1828 } 1829 commit = fxdr_unsigned(int, *tl++); 1830 1831 /* 1832 * Return the lowest commitment level 1833 * obtained by any of the RPCs. 1834 */ 1835 if (committed == NFSWRITE_FILESYNC) 1836 committed = commit; 1837 else if (committed == NFSWRITE_DATASYNC && 1838 commit == NFSWRITE_UNSTABLE) 1839 committed = commit; 1840 NFSLOCKMNT(nmp); 1841 if (!NFSHASWRITEVERF(nmp)) { 1842 NFSBCOPY((caddr_t)tl, 1843 (caddr_t)&nmp->nm_verf[0], 1844 NFSX_VERF); 1845 NFSSETWRITEVERF(nmp); 1846 } else if (NFSBCMP(tl, nmp->nm_verf, 1847 NFSX_VERF)) { 1848 *must_commit = 1; 1849 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 1850 } 1851 NFSUNLOCKMNT(nmp); 1852 } 1853 if (nd->nd_flag & ND_NFSV4) 1854 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1855 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 1856 error = nfsm_loadattr(nd, nap); 1857 if (!error) 1858 *attrflagp = NFS_LATTR_NOSHRINK; 1859 } 1860 } else { 1861 error = nd->nd_repstat; 1862 } 1863 if (error) 1864 goto nfsmout; 1865 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4)); 1866 mbuf_freem(nd->nd_mrep); 1867 nd->nd_mrep = NULL; 1868 tsiz -= len; 1869 } 1870 nfsmout: 1871 if (nd->nd_mrep != NULL) 1872 mbuf_freem(nd->nd_mrep); 1873 *iomode = committed; 1874 if (nd->nd_repstat && !error) 1875 error = nd->nd_repstat; 1876 return (error); 1877 } 1878 1879 /* 1880 * nfs mknod rpc 1881 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 1882 * mode set to specify the file type and the size field for rdev. 1883 */ 1884 APPLESTATIC int 1885 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1886 u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p, 1887 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1888 int *attrflagp, int *dattrflagp, void *dstuff) 1889 { 1890 u_int32_t *tl; 1891 int error = 0; 1892 struct nfsrv_descript nfsd, *nd = &nfsd; 1893 nfsattrbit_t attrbits; 1894 1895 *nfhpp = NULL; 1896 *attrflagp = 0; 1897 *dattrflagp = 0; 1898 if (namelen > NFS_MAXNAMLEN) 1899 return (ENAMETOOLONG); 1900 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp); 1901 if (nd->nd_flag & ND_NFSV4) { 1902 if (vtyp == VBLK || vtyp == VCHR) { 1903 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 1904 *tl++ = vtonfsv34_type(vtyp); 1905 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1906 *tl = txdr_unsigned(NFSMINOR(rdev)); 1907 } else { 1908 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1909 *tl = vtonfsv34_type(vtyp); 1910 } 1911 } 1912 (void) nfsm_strtom(nd, name, namelen); 1913 if (nd->nd_flag & ND_NFSV3) { 1914 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 1915 *tl = vtonfsv34_type(vtyp); 1916 } 1917 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 1918 nfscl_fillsattr(nd, vap, dvp, 0, 0); 1919 if ((nd->nd_flag & ND_NFSV3) && 1920 (vtyp == VCHR || vtyp == VBLK)) { 1921 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1922 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 1923 *tl = txdr_unsigned(NFSMINOR(rdev)); 1924 } 1925 if (nd->nd_flag & ND_NFSV4) { 1926 NFSGETATTR_ATTRBIT(&attrbits); 1927 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1928 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 1929 *tl = txdr_unsigned(NFSV4OP_GETATTR); 1930 (void) nfsrv_putattrbit(nd, &attrbits); 1931 } 1932 if (nd->nd_flag & ND_NFSV2) 1933 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 1934 error = nfscl_request(nd, dvp, p, cred, dstuff); 1935 if (error) 1936 return (error); 1937 if (nd->nd_flag & ND_NFSV4) 1938 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1939 if (!nd->nd_repstat) { 1940 if (nd->nd_flag & ND_NFSV4) { 1941 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 1942 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 1943 if (error) 1944 goto nfsmout; 1945 } 1946 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 1947 if (error) 1948 goto nfsmout; 1949 } 1950 if (nd->nd_flag & ND_NFSV3) 1951 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 1952 if (!error && nd->nd_repstat) 1953 error = nd->nd_repstat; 1954 nfsmout: 1955 mbuf_freem(nd->nd_mrep); 1956 return (error); 1957 } 1958 1959 /* 1960 * nfs file create call 1961 * Mostly just call the approriate routine. (I separated out v4, so that 1962 * error recovery wouldn't be as difficult.) 1963 */ 1964 APPLESTATIC int 1965 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 1966 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 1967 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 1968 int *attrflagp, int *dattrflagp, void *dstuff) 1969 { 1970 int error = 0, newone, expireret = 0, retrycnt, unlocked; 1971 struct nfsclowner *owp; 1972 struct nfscldeleg *dp; 1973 struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp)); 1974 u_int32_t clidrev; 1975 1976 if (NFSHASNFSV4(nmp)) { 1977 retrycnt = 0; 1978 do { 1979 dp = NULL; 1980 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 1981 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 1982 NULL, 1); 1983 if (error) 1984 return (error); 1985 if (nmp->nm_clp != NULL) 1986 clidrev = nmp->nm_clp->nfsc_clientidrev; 1987 else 1988 clidrev = 0; 1989 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || 1990 nfs_numnfscbd == 0 || retrycnt > 0) 1991 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, 1992 fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 1993 attrflagp, dattrflagp, dstuff, &unlocked); 1994 else 1995 error = nfsrpc_getcreatelayout(dvp, name, namelen, vap, 1996 cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 1997 attrflagp, dattrflagp, dstuff, &unlocked); 1998 /* 1999 * There is no need to invalidate cached attributes here, 2000 * since new post-delegation issue attributes are always 2001 * returned by nfsrpc_createv4() and these will update the 2002 * attribute cache. 2003 */ 2004 if (dp != NULL) 2005 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 2006 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 2007 nfscl_ownerrelease(nmp, owp, error, newone, unlocked); 2008 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 2009 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2010 error == NFSERR_BADSESSION) { 2011 (void) nfs_catnap(PZERO, error, "nfs_open"); 2012 } else if ((error == NFSERR_EXPIRED || 2013 error == NFSERR_BADSTATEID) && clidrev != 0) { 2014 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 2015 retrycnt++; 2016 } 2017 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 2018 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2019 error == NFSERR_BADSESSION || 2020 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 2021 expireret == 0 && clidrev != 0 && retrycnt < 4)); 2022 if (error && retrycnt >= 4) 2023 error = EIO; 2024 } else { 2025 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 2026 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 2027 dstuff); 2028 } 2029 return (error); 2030 } 2031 2032 /* 2033 * The create rpc for v2 and 3. 2034 */ 2035 static int 2036 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2037 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 2038 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 2039 int *attrflagp, int *dattrflagp, void *dstuff) 2040 { 2041 u_int32_t *tl; 2042 int error = 0; 2043 struct nfsrv_descript nfsd, *nd = &nfsd; 2044 2045 *nfhpp = NULL; 2046 *attrflagp = 0; 2047 *dattrflagp = 0; 2048 if (namelen > NFS_MAXNAMLEN) 2049 return (ENAMETOOLONG); 2050 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 2051 (void) nfsm_strtom(nd, name, namelen); 2052 if (nd->nd_flag & ND_NFSV3) { 2053 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2054 if (fmode & O_EXCL) { 2055 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2056 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2057 *tl++ = cverf.lval[0]; 2058 *tl = cverf.lval[1]; 2059 } else { 2060 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2061 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2062 } 2063 } else { 2064 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 2065 } 2066 error = nfscl_request(nd, dvp, p, cred, dstuff); 2067 if (error) 2068 return (error); 2069 if (nd->nd_repstat == 0) { 2070 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2071 if (error) 2072 goto nfsmout; 2073 } 2074 if (nd->nd_flag & ND_NFSV3) 2075 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2076 if (nd->nd_repstat != 0 && error == 0) 2077 error = nd->nd_repstat; 2078 nfsmout: 2079 mbuf_freem(nd->nd_mrep); 2080 return (error); 2081 } 2082 2083 static int 2084 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2085 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 2086 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2087 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2088 int *dattrflagp, void *dstuff, int *unlockedp) 2089 { 2090 u_int32_t *tl; 2091 int error = 0, deleg, newone, ret, acesize, limitby; 2092 struct nfsrv_descript nfsd, *nd = &nfsd; 2093 struct nfsclopen *op; 2094 struct nfscldeleg *dp = NULL; 2095 struct nfsnode *np; 2096 struct nfsfh *nfhp; 2097 nfsattrbit_t attrbits; 2098 nfsv4stateid_t stateid; 2099 u_int32_t rflags; 2100 struct nfsmount *nmp; 2101 struct nfsclsession *tsep; 2102 2103 nmp = VFSTONFS(dvp->v_mount); 2104 np = VTONFS(dvp); 2105 *unlockedp = 0; 2106 *nfhpp = NULL; 2107 *dpp = NULL; 2108 *attrflagp = 0; 2109 *dattrflagp = 0; 2110 if (namelen > NFS_MAXNAMLEN) 2111 return (ENAMETOOLONG); 2112 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp); 2113 /* 2114 * For V4, this is actually an Open op. 2115 */ 2116 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2117 *tl++ = txdr_unsigned(owp->nfsow_seqid); 2118 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 2119 NFSV4OPEN_ACCESSREAD); 2120 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 2121 tsep = nfsmnt_mdssession(nmp); 2122 *tl++ = tsep->nfsess_clientid.lval[0]; 2123 *tl = tsep->nfsess_clientid.lval[1]; 2124 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 2125 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2126 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 2127 if (fmode & O_EXCL) { 2128 if (NFSHASNFSV4N(nmp)) { 2129 if (NFSHASSESSPERSIST(nmp)) { 2130 /* Use GUARDED for persistent sessions. */ 2131 *tl = txdr_unsigned(NFSCREATE_GUARDED); 2132 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2133 } else { 2134 /* Otherwise, use EXCLUSIVE4_1. */ 2135 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 2136 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2137 *tl++ = cverf.lval[0]; 2138 *tl = cverf.lval[1]; 2139 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2140 } 2141 } else { 2142 /* NFSv4.0 */ 2143 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2144 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2145 *tl++ = cverf.lval[0]; 2146 *tl = cverf.lval[1]; 2147 } 2148 } else { 2149 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2150 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2151 } 2152 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2153 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 2154 (void) nfsm_strtom(nd, name, namelen); 2155 /* Get the new file's handle and attributes. */ 2156 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2157 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2158 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2159 NFSGETATTR_ATTRBIT(&attrbits); 2160 (void) nfsrv_putattrbit(nd, &attrbits); 2161 /* Get the directory's post-op attributes. */ 2162 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2163 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2164 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 2165 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2166 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2167 (void) nfsrv_putattrbit(nd, &attrbits); 2168 error = nfscl_request(nd, dvp, p, cred, dstuff); 2169 if (error) 2170 return (error); 2171 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 2172 if (nd->nd_repstat == 0) { 2173 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2174 6 * NFSX_UNSIGNED); 2175 stateid.seqid = *tl++; 2176 stateid.other[0] = *tl++; 2177 stateid.other[1] = *tl++; 2178 stateid.other[2] = *tl; 2179 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 2180 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2181 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2182 deleg = fxdr_unsigned(int, *tl); 2183 if (deleg == NFSV4OPEN_DELEGATEREAD || 2184 deleg == NFSV4OPEN_DELEGATEWRITE) { 2185 if (!(owp->nfsow_clp->nfsc_flags & 2186 NFSCLFLAGS_FIRSTDELEG)) 2187 owp->nfsow_clp->nfsc_flags |= 2188 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 2189 dp = malloc( 2190 sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 2191 M_NFSCLDELEG, M_WAITOK); 2192 LIST_INIT(&dp->nfsdl_owner); 2193 LIST_INIT(&dp->nfsdl_lock); 2194 dp->nfsdl_clp = owp->nfsow_clp; 2195 newnfs_copyincred(cred, &dp->nfsdl_cred); 2196 nfscl_lockinit(&dp->nfsdl_rwlock); 2197 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2198 NFSX_UNSIGNED); 2199 dp->nfsdl_stateid.seqid = *tl++; 2200 dp->nfsdl_stateid.other[0] = *tl++; 2201 dp->nfsdl_stateid.other[1] = *tl++; 2202 dp->nfsdl_stateid.other[2] = *tl++; 2203 ret = fxdr_unsigned(int, *tl); 2204 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 2205 dp->nfsdl_flags = NFSCLDL_WRITE; 2206 /* 2207 * Indicates how much the file can grow. 2208 */ 2209 NFSM_DISSECT(tl, u_int32_t *, 2210 3 * NFSX_UNSIGNED); 2211 limitby = fxdr_unsigned(int, *tl++); 2212 switch (limitby) { 2213 case NFSV4OPEN_LIMITSIZE: 2214 dp->nfsdl_sizelimit = fxdr_hyper(tl); 2215 break; 2216 case NFSV4OPEN_LIMITBLOCKS: 2217 dp->nfsdl_sizelimit = 2218 fxdr_unsigned(u_int64_t, *tl++); 2219 dp->nfsdl_sizelimit *= 2220 fxdr_unsigned(u_int64_t, *tl); 2221 break; 2222 default: 2223 error = NFSERR_BADXDR; 2224 goto nfsmout; 2225 } 2226 } else { 2227 dp->nfsdl_flags = NFSCLDL_READ; 2228 } 2229 if (ret) 2230 dp->nfsdl_flags |= NFSCLDL_RECALL; 2231 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 2232 &acesize, p); 2233 if (error) 2234 goto nfsmout; 2235 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 2236 error = NFSERR_BADXDR; 2237 goto nfsmout; 2238 } 2239 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2240 if (error) 2241 goto nfsmout; 2242 /* Get rid of the PutFH and Getattr status values. */ 2243 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2244 /* Load the directory attributes. */ 2245 error = nfsm_loadattr(nd, dnap); 2246 if (error) 2247 goto nfsmout; 2248 *dattrflagp = 1; 2249 if (dp != NULL && *attrflagp) { 2250 dp->nfsdl_change = nnap->na_filerev; 2251 dp->nfsdl_modtime = nnap->na_mtime; 2252 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 2253 } 2254 /* 2255 * We can now complete the Open state. 2256 */ 2257 nfhp = *nfhpp; 2258 if (dp != NULL) { 2259 dp->nfsdl_fhlen = nfhp->nfh_len; 2260 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 2261 } 2262 /* 2263 * Get an Open structure that will be 2264 * attached to the OpenOwner, acquired already. 2265 */ 2266 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 2267 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 2268 cred, p, NULL, &op, &newone, NULL, 0); 2269 if (error) 2270 goto nfsmout; 2271 op->nfso_stateid = stateid; 2272 newnfs_copyincred(cred, &op->nfso_cred); 2273 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 2274 do { 2275 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 2276 nfhp->nfh_len, op, cred, p); 2277 if (ret == NFSERR_DELAY) 2278 (void) nfs_catnap(PZERO, ret, "nfs_create"); 2279 } while (ret == NFSERR_DELAY); 2280 error = ret; 2281 } 2282 2283 /* 2284 * If the server is handing out delegations, but we didn't 2285 * get one because an OpenConfirm was required, try the 2286 * Open again, to get a delegation. This is a harmless no-op, 2287 * from a server's point of view. 2288 */ 2289 if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 2290 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 2291 !error && dp == NULL) { 2292 do { 2293 ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp, 2294 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 2295 nfhp->nfh_fh, nfhp->nfh_len, 2296 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2297 name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2298 if (ret == NFSERR_DELAY) 2299 (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2300 } while (ret == NFSERR_DELAY); 2301 if (ret) { 2302 if (dp != NULL) { 2303 free(dp, M_NFSCLDELEG); 2304 dp = NULL; 2305 } 2306 if (ret == NFSERR_STALECLIENTID || 2307 ret == NFSERR_STALEDONTRECOVER || 2308 ret == NFSERR_BADSESSION) 2309 error = ret; 2310 } 2311 } 2312 nfscl_openrelease(nmp, op, error, newone); 2313 *unlockedp = 1; 2314 } 2315 if (nd->nd_repstat != 0 && error == 0) 2316 error = nd->nd_repstat; 2317 if (error == NFSERR_STALECLIENTID) 2318 nfscl_initiate_recovery(owp->nfsow_clp); 2319 nfsmout: 2320 if (!error) 2321 *dpp = dp; 2322 else if (dp != NULL) 2323 free(dp, M_NFSCLDELEG); 2324 mbuf_freem(nd->nd_mrep); 2325 return (error); 2326 } 2327 2328 /* 2329 * Nfs remove rpc 2330 */ 2331 APPLESTATIC int 2332 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2333 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, 2334 void *dstuff) 2335 { 2336 u_int32_t *tl; 2337 struct nfsrv_descript nfsd, *nd = &nfsd; 2338 struct nfsnode *np; 2339 struct nfsmount *nmp; 2340 nfsv4stateid_t dstateid; 2341 int error, ret = 0, i; 2342 2343 *dattrflagp = 0; 2344 if (namelen > NFS_MAXNAMLEN) 2345 return (ENAMETOOLONG); 2346 nmp = VFSTONFS(vnode_mount(dvp)); 2347 tryagain: 2348 if (NFSHASNFSV4(nmp) && ret == 0) { 2349 ret = nfscl_removedeleg(vp, p, &dstateid); 2350 if (ret == 1) { 2351 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp); 2352 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2353 NFSX_UNSIGNED); 2354 if (NFSHASNFSV4N(nmp)) 2355 *tl++ = 0; 2356 else 2357 *tl++ = dstateid.seqid; 2358 *tl++ = dstateid.other[0]; 2359 *tl++ = dstateid.other[1]; 2360 *tl++ = dstateid.other[2]; 2361 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2362 np = VTONFS(dvp); 2363 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2364 np->n_fhp->nfh_len, 0); 2365 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2366 *tl = txdr_unsigned(NFSV4OP_REMOVE); 2367 } 2368 } else { 2369 ret = 0; 2370 } 2371 if (ret == 0) 2372 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp); 2373 (void) nfsm_strtom(nd, name, namelen); 2374 error = nfscl_request(nd, dvp, p, cred, dstuff); 2375 if (error) 2376 return (error); 2377 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2378 /* For NFSv4, parse out any Delereturn replies. */ 2379 if (ret > 0 && nd->nd_repstat != 0 && 2380 (nd->nd_flag & ND_NOMOREDATA)) { 2381 /* 2382 * If the Delegreturn failed, try again without 2383 * it. The server will Recall, as required. 2384 */ 2385 mbuf_freem(nd->nd_mrep); 2386 goto tryagain; 2387 } 2388 for (i = 0; i < (ret * 2); i++) { 2389 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2390 ND_NFSV4) { 2391 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2392 if (*(tl + 1)) 2393 nd->nd_flag |= ND_NOMOREDATA; 2394 } 2395 } 2396 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2397 } 2398 if (nd->nd_repstat && !error) 2399 error = nd->nd_repstat; 2400 nfsmout: 2401 mbuf_freem(nd->nd_mrep); 2402 return (error); 2403 } 2404 2405 /* 2406 * Do an nfs rename rpc. 2407 */ 2408 APPLESTATIC int 2409 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2410 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2411 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2412 int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff) 2413 { 2414 u_int32_t *tl; 2415 struct nfsrv_descript nfsd, *nd = &nfsd; 2416 struct nfsmount *nmp; 2417 struct nfsnode *np; 2418 nfsattrbit_t attrbits; 2419 nfsv4stateid_t fdstateid, tdstateid; 2420 int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2421 2422 *fattrflagp = 0; 2423 *tattrflagp = 0; 2424 nmp = VFSTONFS(vnode_mount(fdvp)); 2425 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2426 return (ENAMETOOLONG); 2427 tryagain: 2428 if (NFSHASNFSV4(nmp) && ret == 0) { 2429 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2430 &tdstateid, &gottd, p); 2431 if (gotfd && gottd) { 2432 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp); 2433 } else if (gotfd) { 2434 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp); 2435 } else if (gottd) { 2436 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp); 2437 } 2438 if (gotfd) { 2439 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2440 if (NFSHASNFSV4N(nmp)) 2441 *tl++ = 0; 2442 else 2443 *tl++ = fdstateid.seqid; 2444 *tl++ = fdstateid.other[0]; 2445 *tl++ = fdstateid.other[1]; 2446 *tl = fdstateid.other[2]; 2447 if (gottd) { 2448 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2449 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2450 np = VTONFS(tvp); 2451 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2452 np->n_fhp->nfh_len, 0); 2453 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2454 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2455 } 2456 } 2457 if (gottd) { 2458 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2459 if (NFSHASNFSV4N(nmp)) 2460 *tl++ = 0; 2461 else 2462 *tl++ = tdstateid.seqid; 2463 *tl++ = tdstateid.other[0]; 2464 *tl++ = tdstateid.other[1]; 2465 *tl = tdstateid.other[2]; 2466 } 2467 if (ret > 0) { 2468 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2469 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2470 np = VTONFS(fdvp); 2471 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, 2472 np->n_fhp->nfh_len, 0); 2473 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2474 *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2475 } 2476 } else { 2477 ret = 0; 2478 } 2479 if (ret == 0) 2480 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp); 2481 if (nd->nd_flag & ND_NFSV4) { 2482 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2483 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2484 NFSWCCATTR_ATTRBIT(&attrbits); 2485 (void) nfsrv_putattrbit(nd, &attrbits); 2486 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2487 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2488 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2489 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2490 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2491 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2492 (void) nfsrv_putattrbit(nd, &attrbits); 2493 nd->nd_flag |= ND_V4WCCATTR; 2494 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2495 *tl = txdr_unsigned(NFSV4OP_RENAME); 2496 } 2497 (void) nfsm_strtom(nd, fnameptr, fnamelen); 2498 if (!(nd->nd_flag & ND_NFSV4)) 2499 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2500 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2501 (void) nfsm_strtom(nd, tnameptr, tnamelen); 2502 error = nfscl_request(nd, fdvp, p, cred, fstuff); 2503 if (error) 2504 return (error); 2505 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2506 /* For NFSv4, parse out any Delereturn replies. */ 2507 if (ret > 0 && nd->nd_repstat != 0 && 2508 (nd->nd_flag & ND_NOMOREDATA)) { 2509 /* 2510 * If the Delegreturn failed, try again without 2511 * it. The server will Recall, as required. 2512 */ 2513 mbuf_freem(nd->nd_mrep); 2514 goto tryagain; 2515 } 2516 for (i = 0; i < (ret * 2); i++) { 2517 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2518 ND_NFSV4) { 2519 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2520 if (*(tl + 1)) { 2521 if (i == 0 && ret > 1) { 2522 /* 2523 * If the Delegreturn failed, try again 2524 * without it. The server will Recall, as 2525 * required. 2526 * If ret > 1, the first iteration of this 2527 * loop is the second DelegReturn result. 2528 */ 2529 mbuf_freem(nd->nd_mrep); 2530 goto tryagain; 2531 } else { 2532 nd->nd_flag |= ND_NOMOREDATA; 2533 } 2534 } 2535 } 2536 } 2537 /* Now, the first wcc attribute reply. */ 2538 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2539 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2540 if (*(tl + 1)) 2541 nd->nd_flag |= ND_NOMOREDATA; 2542 } 2543 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, 2544 fstuff); 2545 /* and the second wcc attribute reply. */ 2546 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2547 !error) { 2548 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2549 if (*(tl + 1)) 2550 nd->nd_flag |= ND_NOMOREDATA; 2551 } 2552 if (!error) 2553 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2554 NULL, tstuff); 2555 } 2556 if (nd->nd_repstat && !error) 2557 error = nd->nd_repstat; 2558 nfsmout: 2559 mbuf_freem(nd->nd_mrep); 2560 return (error); 2561 } 2562 2563 /* 2564 * nfs hard link create rpc 2565 */ 2566 APPLESTATIC int 2567 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2568 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2569 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2570 { 2571 u_int32_t *tl; 2572 struct nfsrv_descript nfsd, *nd = &nfsd; 2573 nfsattrbit_t attrbits; 2574 int error = 0; 2575 2576 *attrflagp = 0; 2577 *dattrflagp = 0; 2578 if (namelen > NFS_MAXNAMLEN) 2579 return (ENAMETOOLONG); 2580 NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2581 if (nd->nd_flag & ND_NFSV4) { 2582 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2583 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2584 } 2585 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2586 VTONFS(dvp)->n_fhp->nfh_len, 0); 2587 if (nd->nd_flag & ND_NFSV4) { 2588 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2589 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2590 NFSWCCATTR_ATTRBIT(&attrbits); 2591 (void) nfsrv_putattrbit(nd, &attrbits); 2592 nd->nd_flag |= ND_V4WCCATTR; 2593 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2594 *tl = txdr_unsigned(NFSV4OP_LINK); 2595 } 2596 (void) nfsm_strtom(nd, name, namelen); 2597 error = nfscl_request(nd, vp, p, cred, dstuff); 2598 if (error) 2599 return (error); 2600 if (nd->nd_flag & ND_NFSV3) { 2601 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2602 if (!error) 2603 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2604 NULL, dstuff); 2605 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2606 /* 2607 * First, parse out the PutFH and Getattr result. 2608 */ 2609 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2610 if (!(*(tl + 1))) 2611 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2612 if (*(tl + 1)) 2613 nd->nd_flag |= ND_NOMOREDATA; 2614 /* 2615 * Get the pre-op attributes. 2616 */ 2617 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2618 } 2619 if (nd->nd_repstat && !error) 2620 error = nd->nd_repstat; 2621 nfsmout: 2622 mbuf_freem(nd->nd_mrep); 2623 return (error); 2624 } 2625 2626 /* 2627 * nfs symbolic link create rpc 2628 */ 2629 APPLESTATIC int 2630 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target, 2631 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2632 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2633 int *dattrflagp, void *dstuff) 2634 { 2635 u_int32_t *tl; 2636 struct nfsrv_descript nfsd, *nd = &nfsd; 2637 struct nfsmount *nmp; 2638 int slen, error = 0; 2639 2640 *nfhpp = NULL; 2641 *attrflagp = 0; 2642 *dattrflagp = 0; 2643 nmp = VFSTONFS(vnode_mount(dvp)); 2644 slen = strlen(target); 2645 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2646 return (ENAMETOOLONG); 2647 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2648 if (nd->nd_flag & ND_NFSV4) { 2649 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2650 *tl = txdr_unsigned(NFLNK); 2651 (void) nfsm_strtom(nd, target, slen); 2652 } 2653 (void) nfsm_strtom(nd, name, namelen); 2654 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2655 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2656 if (!(nd->nd_flag & ND_NFSV4)) 2657 (void) nfsm_strtom(nd, target, slen); 2658 if (nd->nd_flag & ND_NFSV2) 2659 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2660 error = nfscl_request(nd, dvp, p, cred, dstuff); 2661 if (error) 2662 return (error); 2663 if (nd->nd_flag & ND_NFSV4) 2664 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2665 if ((nd->nd_flag & ND_NFSV3) && !error) { 2666 if (!nd->nd_repstat) 2667 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2668 if (!error) 2669 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2670 NULL, dstuff); 2671 } 2672 if (nd->nd_repstat && !error) 2673 error = nd->nd_repstat; 2674 mbuf_freem(nd->nd_mrep); 2675 /* 2676 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2677 * Only do this if vfs.nfs.ignore_eexist is set. 2678 * Never do this for NFSv4.1 or later minor versions, since sessions 2679 * should guarantee "exactly once" RPC semantics. 2680 */ 2681 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2682 nmp->nm_minorvers == 0)) 2683 error = 0; 2684 return (error); 2685 } 2686 2687 /* 2688 * nfs make dir rpc 2689 */ 2690 APPLESTATIC int 2691 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2692 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2693 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2694 int *dattrflagp, void *dstuff) 2695 { 2696 u_int32_t *tl; 2697 struct nfsrv_descript nfsd, *nd = &nfsd; 2698 nfsattrbit_t attrbits; 2699 int error = 0; 2700 struct nfsfh *fhp; 2701 struct nfsmount *nmp; 2702 2703 *nfhpp = NULL; 2704 *attrflagp = 0; 2705 *dattrflagp = 0; 2706 nmp = VFSTONFS(vnode_mount(dvp)); 2707 fhp = VTONFS(dvp)->n_fhp; 2708 if (namelen > NFS_MAXNAMLEN) 2709 return (ENAMETOOLONG); 2710 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 2711 if (nd->nd_flag & ND_NFSV4) { 2712 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2713 *tl = txdr_unsigned(NFDIR); 2714 } 2715 (void) nfsm_strtom(nd, name, namelen); 2716 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 2717 if (nd->nd_flag & ND_NFSV4) { 2718 NFSGETATTR_ATTRBIT(&attrbits); 2719 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2720 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2721 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2722 (void) nfsrv_putattrbit(nd, &attrbits); 2723 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2724 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2725 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0); 2726 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2727 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2728 (void) nfsrv_putattrbit(nd, &attrbits); 2729 } 2730 error = nfscl_request(nd, dvp, p, cred, dstuff); 2731 if (error) 2732 return (error); 2733 if (nd->nd_flag & ND_NFSV4) 2734 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2735 if (!nd->nd_repstat && !error) { 2736 if (nd->nd_flag & ND_NFSV4) { 2737 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2738 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2739 } 2740 if (!error) 2741 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2742 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 2743 /* Get rid of the PutFH and Getattr status values. */ 2744 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2745 /* Load the directory attributes. */ 2746 error = nfsm_loadattr(nd, dnap); 2747 if (error == 0) 2748 *dattrflagp = 1; 2749 } 2750 } 2751 if ((nd->nd_flag & ND_NFSV3) && !error) 2752 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2753 if (nd->nd_repstat && !error) 2754 error = nd->nd_repstat; 2755 nfsmout: 2756 mbuf_freem(nd->nd_mrep); 2757 /* 2758 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 2759 * Only do this if vfs.nfs.ignore_eexist is set. 2760 * Never do this for NFSv4.1 or later minor versions, since sessions 2761 * should guarantee "exactly once" RPC semantics. 2762 */ 2763 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 2764 nmp->nm_minorvers == 0)) 2765 error = 0; 2766 return (error); 2767 } 2768 2769 /* 2770 * nfs remove directory call 2771 */ 2772 APPLESTATIC int 2773 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 2774 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 2775 { 2776 struct nfsrv_descript nfsd, *nd = &nfsd; 2777 int error = 0; 2778 2779 *dattrflagp = 0; 2780 if (namelen > NFS_MAXNAMLEN) 2781 return (ENAMETOOLONG); 2782 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 2783 (void) nfsm_strtom(nd, name, namelen); 2784 error = nfscl_request(nd, dvp, p, cred, dstuff); 2785 if (error) 2786 return (error); 2787 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2788 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2789 if (nd->nd_repstat && !error) 2790 error = nd->nd_repstat; 2791 mbuf_freem(nd->nd_mrep); 2792 /* 2793 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 2794 */ 2795 if (error == ENOENT) 2796 error = 0; 2797 return (error); 2798 } 2799 2800 /* 2801 * Readdir rpc. 2802 * Always returns with either uio_resid unchanged, if you are at the 2803 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 2804 * filled in. 2805 * I felt this would allow caching of directory blocks more easily 2806 * than returning a pertially filled block. 2807 * Directory offset cookies: 2808 * Oh my, what to do with them... 2809 * I can think of three ways to deal with them: 2810 * 1 - have the layer above these RPCs maintain a map between logical 2811 * directory byte offsets and the NFS directory offset cookies 2812 * 2 - pass the opaque directory offset cookies up into userland 2813 * and let the libc functions deal with them, via the system call 2814 * 3 - return them to userland in the "struct dirent", so future versions 2815 * of libc can use them and do whatever is necessary to make things work 2816 * above these rpc calls, in the meantime 2817 * For now, I do #3 by "hiding" the directory offset cookies after the 2818 * d_name field in struct dirent. This is space inside d_reclen that 2819 * will be ignored by anything that doesn't know about them. 2820 * The directory offset cookies are filled in as the last 8 bytes of 2821 * each directory entry, after d_name. Someday, the userland libc 2822 * functions may be able to use these. In the meantime, it satisfies 2823 * OpenBSD's requirements for cookies being returned. 2824 * If expects the directory offset cookie for the read to be in uio_offset 2825 * and returns the one for the next entry after this directory block in 2826 * there, as well. 2827 */ 2828 APPLESTATIC int 2829 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 2830 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 2831 int *eofp, void *stuff) 2832 { 2833 int len, left; 2834 struct dirent *dp = NULL; 2835 u_int32_t *tl; 2836 nfsquad_t cookie, ncookie; 2837 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 2838 struct nfsnode *dnp = VTONFS(vp); 2839 struct nfsvattr nfsva; 2840 struct nfsrv_descript nfsd, *nd = &nfsd; 2841 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 2842 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 2843 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 2844 char *cp; 2845 nfsattrbit_t attrbits, dattrbits; 2846 u_int32_t rderr, *tl2 = NULL; 2847 size_t tresid; 2848 2849 KASSERT(uiop->uio_iovcnt == 1 && 2850 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 2851 ("nfs readdirrpc bad uio")); 2852 ncookie.lval[0] = ncookie.lval[1] = 0; 2853 /* 2854 * There is no point in reading a lot more than uio_resid, however 2855 * adding one additional DIRBLKSIZ makes sense. Since uio_resid 2856 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 2857 * will never make readsize > nm_readdirsize. 2858 */ 2859 readsize = nmp->nm_readdirsize; 2860 if (readsize > uio_uio_resid(uiop)) 2861 readsize = uio_uio_resid(uiop) + DIRBLKSIZ; 2862 2863 *attrflagp = 0; 2864 if (eofp) 2865 *eofp = 0; 2866 tresid = uio_uio_resid(uiop); 2867 cookie.lval[0] = cookiep->nfsuquad[0]; 2868 cookie.lval[1] = cookiep->nfsuquad[1]; 2869 nd->nd_mrep = NULL; 2870 2871 /* 2872 * For NFSv4, first create the "." and ".." entries. 2873 */ 2874 if (NFSHASNFSV4(nmp)) { 2875 reqsize = 6 * NFSX_UNSIGNED; 2876 NFSGETATTR_ATTRBIT(&dattrbits); 2877 NFSZERO_ATTRBIT(&attrbits); 2878 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 2879 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 2880 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 2881 NFSATTRBIT_MOUNTEDONFILEID)) { 2882 NFSSETBIT_ATTRBIT(&attrbits, 2883 NFSATTRBIT_MOUNTEDONFILEID); 2884 gotmnton = 1; 2885 } else { 2886 /* 2887 * Must fake it. Use the fileno, except when the 2888 * fsid is != to that of the directory. For that 2889 * case, generate a fake fileno that is not the same. 2890 */ 2891 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 2892 gotmnton = 0; 2893 } 2894 2895 /* 2896 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 2897 */ 2898 if (uiop->uio_offset == 0) { 2899 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 2900 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2901 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2902 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2903 (void) nfsrv_putattrbit(nd, &attrbits); 2904 error = nfscl_request(nd, vp, p, cred, stuff); 2905 if (error) 2906 return (error); 2907 dotfileid = 0; /* Fake out the compiler. */ 2908 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 2909 error = nfsm_loadattr(nd, &nfsva); 2910 if (error != 0) 2911 goto nfsmout; 2912 dotfileid = nfsva.na_fileid; 2913 } 2914 if (nd->nd_repstat == 0) { 2915 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2916 len = fxdr_unsigned(int, *(tl + 4)); 2917 if (len > 0 && len <= NFSX_V4FHMAX) 2918 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 2919 else 2920 error = EPERM; 2921 if (!error) { 2922 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 2923 nfsva.na_mntonfileno = UINT64_MAX; 2924 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 2925 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 2926 NULL, NULL, NULL, p, cred); 2927 if (error) { 2928 dotdotfileid = dotfileid; 2929 } else if (gotmnton) { 2930 if (nfsva.na_mntonfileno != UINT64_MAX) 2931 dotdotfileid = nfsva.na_mntonfileno; 2932 else 2933 dotdotfileid = nfsva.na_fileid; 2934 } else if (nfsva.na_filesid[0] == 2935 dnp->n_vattr.na_filesid[0] && 2936 nfsva.na_filesid[1] == 2937 dnp->n_vattr.na_filesid[1]) { 2938 dotdotfileid = nfsva.na_fileid; 2939 } else { 2940 do { 2941 fakefileno--; 2942 } while (fakefileno == 2943 nfsva.na_fileid); 2944 dotdotfileid = fakefileno; 2945 } 2946 } 2947 } else if (nd->nd_repstat == NFSERR_NOENT) { 2948 /* 2949 * Lookupp returns NFSERR_NOENT when we are 2950 * at the root, so just use the current dir. 2951 */ 2952 nd->nd_repstat = 0; 2953 dotdotfileid = dotfileid; 2954 } else { 2955 error = nd->nd_repstat; 2956 } 2957 mbuf_freem(nd->nd_mrep); 2958 if (error) 2959 return (error); 2960 nd->nd_mrep = NULL; 2961 dp = (struct dirent *)uio_iov_base(uiop); 2962 dp->d_off = 0; 2963 dp->d_type = DT_DIR; 2964 dp->d_fileno = dotfileid; 2965 dp->d_namlen = 1; 2966 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 2967 dp->d_name[0] = '.'; 2968 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 2969 /* 2970 * Just make these offset cookie 0. 2971 */ 2972 tl = (u_int32_t *)&dp->d_name[8]; 2973 *tl++ = 0; 2974 *tl = 0; 2975 blksiz += dp->d_reclen; 2976 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2977 uiop->uio_offset += dp->d_reclen; 2978 uio_iov_base_add(uiop, dp->d_reclen); 2979 uio_iov_len_add(uiop, -(dp->d_reclen)); 2980 dp = (struct dirent *)uio_iov_base(uiop); 2981 dp->d_off = 0; 2982 dp->d_type = DT_DIR; 2983 dp->d_fileno = dotdotfileid; 2984 dp->d_namlen = 2; 2985 *((uint64_t *)dp->d_name) = 0; 2986 dp->d_name[0] = '.'; 2987 dp->d_name[1] = '.'; 2988 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 2989 /* 2990 * Just make these offset cookie 0. 2991 */ 2992 tl = (u_int32_t *)&dp->d_name[8]; 2993 *tl++ = 0; 2994 *tl = 0; 2995 blksiz += dp->d_reclen; 2996 uio_uio_resid_add(uiop, -(dp->d_reclen)); 2997 uiop->uio_offset += dp->d_reclen; 2998 uio_iov_base_add(uiop, dp->d_reclen); 2999 uio_iov_len_add(uiop, -(dp->d_reclen)); 3000 } 3001 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 3002 } else { 3003 reqsize = 5 * NFSX_UNSIGNED; 3004 } 3005 3006 3007 /* 3008 * Loop around doing readdir rpc's of size readsize. 3009 * The stopping criteria is EOF or buffer full. 3010 */ 3011 while (more_dirs && bigenough) { 3012 *attrflagp = 0; 3013 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 3014 if (nd->nd_flag & ND_NFSV2) { 3015 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3016 *tl++ = cookie.lval[1]; 3017 *tl = txdr_unsigned(readsize); 3018 } else { 3019 NFSM_BUILD(tl, u_int32_t *, reqsize); 3020 *tl++ = cookie.lval[0]; 3021 *tl++ = cookie.lval[1]; 3022 if (cookie.qval == 0) { 3023 *tl++ = 0; 3024 *tl++ = 0; 3025 } else { 3026 NFSLOCKNODE(dnp); 3027 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3028 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3029 NFSUNLOCKNODE(dnp); 3030 } 3031 if (nd->nd_flag & ND_NFSV4) { 3032 *tl++ = txdr_unsigned(readsize); 3033 *tl = txdr_unsigned(readsize); 3034 (void) nfsrv_putattrbit(nd, &attrbits); 3035 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3036 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3037 (void) nfsrv_putattrbit(nd, &dattrbits); 3038 } else { 3039 *tl = txdr_unsigned(readsize); 3040 } 3041 } 3042 error = nfscl_request(nd, vp, p, cred, stuff); 3043 if (error) 3044 return (error); 3045 if (!(nd->nd_flag & ND_NFSV2)) { 3046 if (nd->nd_flag & ND_NFSV3) 3047 error = nfscl_postop_attr(nd, nap, attrflagp, 3048 stuff); 3049 if (!nd->nd_repstat && !error) { 3050 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3051 NFSLOCKNODE(dnp); 3052 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3053 dnp->n_cookieverf.nfsuquad[1] = *tl; 3054 NFSUNLOCKNODE(dnp); 3055 } 3056 } 3057 if (nd->nd_repstat || error) { 3058 if (!error) 3059 error = nd->nd_repstat; 3060 goto nfsmout; 3061 } 3062 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3063 more_dirs = fxdr_unsigned(int, *tl); 3064 if (!more_dirs) 3065 tryformoredirs = 0; 3066 3067 /* loop through the dir entries, doctoring them to 4bsd form */ 3068 while (more_dirs && bigenough) { 3069 if (nd->nd_flag & ND_NFSV4) { 3070 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3071 ncookie.lval[0] = *tl++; 3072 ncookie.lval[1] = *tl++; 3073 len = fxdr_unsigned(int, *tl); 3074 } else if (nd->nd_flag & ND_NFSV3) { 3075 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3076 nfsva.na_fileid = fxdr_hyper(tl); 3077 tl += 2; 3078 len = fxdr_unsigned(int, *tl); 3079 } else { 3080 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3081 nfsva.na_fileid = fxdr_unsigned(uint64_t, 3082 *tl++); 3083 len = fxdr_unsigned(int, *tl); 3084 } 3085 if (len <= 0 || len > NFS_MAXNAMLEN) { 3086 error = EBADRPC; 3087 goto nfsmout; 3088 } 3089 tlen = roundup2(len, 8); 3090 if (tlen == len) 3091 tlen += 8; /* To ensure null termination. */ 3092 left = DIRBLKSIZ - blksiz; 3093 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3094 dp->d_reclen += left; 3095 uio_iov_base_add(uiop, left); 3096 uio_iov_len_add(uiop, -(left)); 3097 uio_uio_resid_add(uiop, -(left)); 3098 uiop->uio_offset += left; 3099 blksiz = 0; 3100 } 3101 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3102 uio_uio_resid(uiop)) 3103 bigenough = 0; 3104 if (bigenough) { 3105 dp = (struct dirent *)uio_iov_base(uiop); 3106 dp->d_off = 0; 3107 dp->d_namlen = len; 3108 dp->d_reclen = _GENERIC_DIRLEN(len) + 3109 NFSX_HYPER; 3110 dp->d_type = DT_UNKNOWN; 3111 blksiz += dp->d_reclen; 3112 if (blksiz == DIRBLKSIZ) 3113 blksiz = 0; 3114 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3115 uiop->uio_offset += DIRHDSIZ; 3116 uio_iov_base_add(uiop, DIRHDSIZ); 3117 uio_iov_len_add(uiop, -(DIRHDSIZ)); 3118 error = nfsm_mbufuio(nd, uiop, len); 3119 if (error) 3120 goto nfsmout; 3121 cp = uio_iov_base(uiop); 3122 tlen -= len; 3123 *cp = '\0'; /* null terminate */ 3124 cp += tlen; /* points to cookie storage */ 3125 tl2 = (u_int32_t *)cp; 3126 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3127 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3128 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3129 uiop->uio_offset += (tlen + NFSX_HYPER); 3130 } else { 3131 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3132 if (error) 3133 goto nfsmout; 3134 } 3135 if (nd->nd_flag & ND_NFSV4) { 3136 rderr = 0; 3137 nfsva.na_mntonfileno = UINT64_MAX; 3138 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3139 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3140 NULL, NULL, &rderr, p, cred); 3141 if (error) 3142 goto nfsmout; 3143 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3144 } else if (nd->nd_flag & ND_NFSV3) { 3145 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3146 ncookie.lval[0] = *tl++; 3147 ncookie.lval[1] = *tl++; 3148 } else { 3149 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3150 ncookie.lval[0] = 0; 3151 ncookie.lval[1] = *tl++; 3152 } 3153 if (bigenough) { 3154 if (nd->nd_flag & ND_NFSV4) { 3155 if (rderr) { 3156 dp->d_fileno = 0; 3157 } else { 3158 if (gotmnton) { 3159 if (nfsva.na_mntonfileno != UINT64_MAX) 3160 dp->d_fileno = nfsva.na_mntonfileno; 3161 else 3162 dp->d_fileno = nfsva.na_fileid; 3163 } else if (nfsva.na_filesid[0] == 3164 dnp->n_vattr.na_filesid[0] && 3165 nfsva.na_filesid[1] == 3166 dnp->n_vattr.na_filesid[1]) { 3167 dp->d_fileno = nfsva.na_fileid; 3168 } else { 3169 do { 3170 fakefileno--; 3171 } while (fakefileno == 3172 nfsva.na_fileid); 3173 dp->d_fileno = fakefileno; 3174 } 3175 dp->d_type = vtonfs_dtype(nfsva.na_type); 3176 } 3177 } else { 3178 dp->d_fileno = nfsva.na_fileid; 3179 } 3180 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3181 ncookie.lval[0]; 3182 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3183 ncookie.lval[1]; 3184 } 3185 more_dirs = fxdr_unsigned(int, *tl); 3186 } 3187 /* 3188 * If at end of rpc data, get the eof boolean 3189 */ 3190 if (!more_dirs) { 3191 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3192 eof = fxdr_unsigned(int, *tl); 3193 if (tryformoredirs) 3194 more_dirs = !eof; 3195 if (nd->nd_flag & ND_NFSV4) { 3196 error = nfscl_postop_attr(nd, nap, attrflagp, 3197 stuff); 3198 if (error) 3199 goto nfsmout; 3200 } 3201 } 3202 mbuf_freem(nd->nd_mrep); 3203 nd->nd_mrep = NULL; 3204 } 3205 /* 3206 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3207 * by increasing d_reclen for the last record. 3208 */ 3209 if (blksiz > 0) { 3210 left = DIRBLKSIZ - blksiz; 3211 dp->d_reclen += left; 3212 uio_iov_base_add(uiop, left); 3213 uio_iov_len_add(uiop, -(left)); 3214 uio_uio_resid_add(uiop, -(left)); 3215 uiop->uio_offset += left; 3216 } 3217 3218 /* 3219 * If returning no data, assume end of file. 3220 * If not bigenough, return not end of file, since you aren't 3221 * returning all the data 3222 * Otherwise, return the eof flag from the server. 3223 */ 3224 if (eofp) { 3225 if (tresid == ((size_t)(uio_uio_resid(uiop)))) 3226 *eofp = 1; 3227 else if (!bigenough) 3228 *eofp = 0; 3229 else 3230 *eofp = eof; 3231 } 3232 3233 /* 3234 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3235 */ 3236 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3237 dp = (struct dirent *)uio_iov_base(uiop); 3238 dp->d_type = DT_UNKNOWN; 3239 dp->d_fileno = 0; 3240 dp->d_namlen = 0; 3241 dp->d_name[0] = '\0'; 3242 tl = (u_int32_t *)&dp->d_name[4]; 3243 *tl++ = cookie.lval[0]; 3244 *tl = cookie.lval[1]; 3245 dp->d_reclen = DIRBLKSIZ; 3246 uio_iov_base_add(uiop, DIRBLKSIZ); 3247 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3248 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3249 uiop->uio_offset += DIRBLKSIZ; 3250 } 3251 3252 nfsmout: 3253 if (nd->nd_mrep != NULL) 3254 mbuf_freem(nd->nd_mrep); 3255 return (error); 3256 } 3257 3258 #ifndef APPLE 3259 /* 3260 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 3261 * (Also used for NFS V4 when mount flag set.) 3262 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 3263 */ 3264 APPLESTATIC int 3265 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3266 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3267 int *eofp, void *stuff) 3268 { 3269 int len, left; 3270 struct dirent *dp = NULL; 3271 u_int32_t *tl; 3272 vnode_t newvp = NULLVP; 3273 struct nfsrv_descript nfsd, *nd = &nfsd; 3274 struct nameidata nami, *ndp = &nami; 3275 struct componentname *cnp = &ndp->ni_cnd; 3276 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3277 struct nfsnode *dnp = VTONFS(vp), *np; 3278 struct nfsvattr nfsva; 3279 struct nfsfh *nfhp; 3280 nfsquad_t cookie, ncookie; 3281 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3282 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 3283 int isdotdot = 0, unlocknewvp = 0; 3284 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3285 u_int64_t fileno = 0; 3286 char *cp; 3287 nfsattrbit_t attrbits, dattrbits; 3288 size_t tresid; 3289 u_int32_t *tl2 = NULL, rderr; 3290 struct timespec dctime; 3291 3292 KASSERT(uiop->uio_iovcnt == 1 && 3293 (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0, 3294 ("nfs readdirplusrpc bad uio")); 3295 ncookie.lval[0] = ncookie.lval[1] = 0; 3296 timespecclear(&dctime); 3297 *attrflagp = 0; 3298 if (eofp != NULL) 3299 *eofp = 0; 3300 ndp->ni_dvp = vp; 3301 nd->nd_mrep = NULL; 3302 cookie.lval[0] = cookiep->nfsuquad[0]; 3303 cookie.lval[1] = cookiep->nfsuquad[1]; 3304 tresid = uio_uio_resid(uiop); 3305 3306 /* 3307 * For NFSv4, first create the "." and ".." entries. 3308 */ 3309 if (NFSHASNFSV4(nmp)) { 3310 NFSGETATTR_ATTRBIT(&dattrbits); 3311 NFSZERO_ATTRBIT(&attrbits); 3312 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3313 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3314 NFSATTRBIT_MOUNTEDONFILEID)) { 3315 NFSSETBIT_ATTRBIT(&attrbits, 3316 NFSATTRBIT_MOUNTEDONFILEID); 3317 gotmnton = 1; 3318 } else { 3319 /* 3320 * Must fake it. Use the fileno, except when the 3321 * fsid is != to that of the directory. For that 3322 * case, generate a fake fileno that is not the same. 3323 */ 3324 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3325 gotmnton = 0; 3326 } 3327 3328 /* 3329 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3330 */ 3331 if (uiop->uio_offset == 0) { 3332 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3333 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3334 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3335 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3336 (void) nfsrv_putattrbit(nd, &attrbits); 3337 error = nfscl_request(nd, vp, p, cred, stuff); 3338 if (error) 3339 return (error); 3340 dotfileid = 0; /* Fake out the compiler. */ 3341 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3342 error = nfsm_loadattr(nd, &nfsva); 3343 if (error != 0) 3344 goto nfsmout; 3345 dctime = nfsva.na_ctime; 3346 dotfileid = nfsva.na_fileid; 3347 } 3348 if (nd->nd_repstat == 0) { 3349 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3350 len = fxdr_unsigned(int, *(tl + 4)); 3351 if (len > 0 && len <= NFSX_V4FHMAX) 3352 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3353 else 3354 error = EPERM; 3355 if (!error) { 3356 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3357 nfsva.na_mntonfileno = UINT64_MAX; 3358 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3359 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3360 NULL, NULL, NULL, p, cred); 3361 if (error) { 3362 dotdotfileid = dotfileid; 3363 } else if (gotmnton) { 3364 if (nfsva.na_mntonfileno != UINT64_MAX) 3365 dotdotfileid = nfsva.na_mntonfileno; 3366 else 3367 dotdotfileid = nfsva.na_fileid; 3368 } else if (nfsva.na_filesid[0] == 3369 dnp->n_vattr.na_filesid[0] && 3370 nfsva.na_filesid[1] == 3371 dnp->n_vattr.na_filesid[1]) { 3372 dotdotfileid = nfsva.na_fileid; 3373 } else { 3374 do { 3375 fakefileno--; 3376 } while (fakefileno == 3377 nfsva.na_fileid); 3378 dotdotfileid = fakefileno; 3379 } 3380 } 3381 } else if (nd->nd_repstat == NFSERR_NOENT) { 3382 /* 3383 * Lookupp returns NFSERR_NOENT when we are 3384 * at the root, so just use the current dir. 3385 */ 3386 nd->nd_repstat = 0; 3387 dotdotfileid = dotfileid; 3388 } else { 3389 error = nd->nd_repstat; 3390 } 3391 mbuf_freem(nd->nd_mrep); 3392 if (error) 3393 return (error); 3394 nd->nd_mrep = NULL; 3395 dp = (struct dirent *)uio_iov_base(uiop); 3396 dp->d_off = 0; 3397 dp->d_type = DT_DIR; 3398 dp->d_fileno = dotfileid; 3399 dp->d_namlen = 1; 3400 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3401 dp->d_name[0] = '.'; 3402 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3403 /* 3404 * Just make these offset cookie 0. 3405 */ 3406 tl = (u_int32_t *)&dp->d_name[8]; 3407 *tl++ = 0; 3408 *tl = 0; 3409 blksiz += dp->d_reclen; 3410 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3411 uiop->uio_offset += dp->d_reclen; 3412 uio_iov_base_add(uiop, dp->d_reclen); 3413 uio_iov_len_add(uiop, -(dp->d_reclen)); 3414 dp = (struct dirent *)uio_iov_base(uiop); 3415 dp->d_off = 0; 3416 dp->d_type = DT_DIR; 3417 dp->d_fileno = dotdotfileid; 3418 dp->d_namlen = 2; 3419 *((uint64_t *)dp->d_name) = 0; 3420 dp->d_name[0] = '.'; 3421 dp->d_name[1] = '.'; 3422 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3423 /* 3424 * Just make these offset cookie 0. 3425 */ 3426 tl = (u_int32_t *)&dp->d_name[8]; 3427 *tl++ = 0; 3428 *tl = 0; 3429 blksiz += dp->d_reclen; 3430 uio_uio_resid_add(uiop, -(dp->d_reclen)); 3431 uiop->uio_offset += dp->d_reclen; 3432 uio_iov_base_add(uiop, dp->d_reclen); 3433 uio_iov_len_add(uiop, -(dp->d_reclen)); 3434 } 3435 NFSREADDIRPLUS_ATTRBIT(&attrbits); 3436 if (gotmnton) 3437 NFSSETBIT_ATTRBIT(&attrbits, 3438 NFSATTRBIT_MOUNTEDONFILEID); 3439 } 3440 3441 /* 3442 * Loop around doing readdir rpc's of size nm_readdirsize. 3443 * The stopping criteria is EOF or buffer full. 3444 */ 3445 while (more_dirs && bigenough) { 3446 *attrflagp = 0; 3447 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3448 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3449 *tl++ = cookie.lval[0]; 3450 *tl++ = cookie.lval[1]; 3451 if (cookie.qval == 0) { 3452 *tl++ = 0; 3453 *tl++ = 0; 3454 } else { 3455 NFSLOCKNODE(dnp); 3456 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3457 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3458 NFSUNLOCKNODE(dnp); 3459 } 3460 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3461 *tl = txdr_unsigned(nmp->nm_readdirsize); 3462 if (nd->nd_flag & ND_NFSV4) { 3463 (void) nfsrv_putattrbit(nd, &attrbits); 3464 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3465 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3466 (void) nfsrv_putattrbit(nd, &dattrbits); 3467 } 3468 error = nfscl_request(nd, vp, p, cred, stuff); 3469 if (error) 3470 return (error); 3471 if (nd->nd_flag & ND_NFSV3) 3472 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3473 if (nd->nd_repstat || error) { 3474 if (!error) 3475 error = nd->nd_repstat; 3476 goto nfsmout; 3477 } 3478 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 3479 dctime = nap->na_ctime; 3480 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3481 NFSLOCKNODE(dnp); 3482 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3483 dnp->n_cookieverf.nfsuquad[1] = *tl++; 3484 NFSUNLOCKNODE(dnp); 3485 more_dirs = fxdr_unsigned(int, *tl); 3486 if (!more_dirs) 3487 tryformoredirs = 0; 3488 3489 /* loop through the dir entries, doctoring them to 4bsd form */ 3490 while (more_dirs && bigenough) { 3491 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3492 if (nd->nd_flag & ND_NFSV4) { 3493 ncookie.lval[0] = *tl++; 3494 ncookie.lval[1] = *tl++; 3495 } else { 3496 fileno = fxdr_hyper(tl); 3497 tl += 2; 3498 } 3499 len = fxdr_unsigned(int, *tl); 3500 if (len <= 0 || len > NFS_MAXNAMLEN) { 3501 error = EBADRPC; 3502 goto nfsmout; 3503 } 3504 tlen = roundup2(len, 8); 3505 if (tlen == len) 3506 tlen += 8; /* To ensure null termination. */ 3507 left = DIRBLKSIZ - blksiz; 3508 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3509 dp->d_reclen += left; 3510 uio_iov_base_add(uiop, left); 3511 uio_iov_len_add(uiop, -(left)); 3512 uio_uio_resid_add(uiop, -(left)); 3513 uiop->uio_offset += left; 3514 blksiz = 0; 3515 } 3516 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3517 uio_uio_resid(uiop)) 3518 bigenough = 0; 3519 if (bigenough) { 3520 dp = (struct dirent *)uio_iov_base(uiop); 3521 dp->d_off = 0; 3522 dp->d_namlen = len; 3523 dp->d_reclen = _GENERIC_DIRLEN(len) + 3524 NFSX_HYPER; 3525 dp->d_type = DT_UNKNOWN; 3526 blksiz += dp->d_reclen; 3527 if (blksiz == DIRBLKSIZ) 3528 blksiz = 0; 3529 uio_uio_resid_add(uiop, -(DIRHDSIZ)); 3530 uiop->uio_offset += DIRHDSIZ; 3531 uio_iov_base_add(uiop, DIRHDSIZ); 3532 uio_iov_len_add(uiop, -(DIRHDSIZ)); 3533 cnp->cn_nameptr = uio_iov_base(uiop); 3534 cnp->cn_namelen = len; 3535 NFSCNHASHZERO(cnp); 3536 error = nfsm_mbufuio(nd, uiop, len); 3537 if (error) 3538 goto nfsmout; 3539 cp = uio_iov_base(uiop); 3540 tlen -= len; 3541 *cp = '\0'; 3542 cp += tlen; /* points to cookie storage */ 3543 tl2 = (u_int32_t *)cp; 3544 if (len == 2 && cnp->cn_nameptr[0] == '.' && 3545 cnp->cn_nameptr[1] == '.') 3546 isdotdot = 1; 3547 else 3548 isdotdot = 0; 3549 uio_iov_base_add(uiop, (tlen + NFSX_HYPER)); 3550 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER)); 3551 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER)); 3552 uiop->uio_offset += (tlen + NFSX_HYPER); 3553 } else { 3554 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3555 if (error) 3556 goto nfsmout; 3557 } 3558 nfhp = NULL; 3559 if (nd->nd_flag & ND_NFSV3) { 3560 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3561 ncookie.lval[0] = *tl++; 3562 ncookie.lval[1] = *tl++; 3563 attrflag = fxdr_unsigned(int, *tl); 3564 if (attrflag) { 3565 error = nfsm_loadattr(nd, &nfsva); 3566 if (error) 3567 goto nfsmout; 3568 } 3569 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3570 if (*tl) { 3571 error = nfsm_getfh(nd, &nfhp); 3572 if (error) 3573 goto nfsmout; 3574 } 3575 if (!attrflag && nfhp != NULL) { 3576 free(nfhp, M_NFSFH); 3577 nfhp = NULL; 3578 } 3579 } else { 3580 rderr = 0; 3581 nfsva.na_mntonfileno = 0xffffffff; 3582 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3583 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3584 NULL, NULL, &rderr, p, cred); 3585 if (error) 3586 goto nfsmout; 3587 } 3588 3589 if (bigenough) { 3590 if (nd->nd_flag & ND_NFSV4) { 3591 if (rderr) { 3592 dp->d_fileno = 0; 3593 } else if (gotmnton) { 3594 if (nfsva.na_mntonfileno != 0xffffffff) 3595 dp->d_fileno = nfsva.na_mntonfileno; 3596 else 3597 dp->d_fileno = nfsva.na_fileid; 3598 } else if (nfsva.na_filesid[0] == 3599 dnp->n_vattr.na_filesid[0] && 3600 nfsva.na_filesid[1] == 3601 dnp->n_vattr.na_filesid[1]) { 3602 dp->d_fileno = nfsva.na_fileid; 3603 } else { 3604 do { 3605 fakefileno--; 3606 } while (fakefileno == 3607 nfsva.na_fileid); 3608 dp->d_fileno = fakefileno; 3609 } 3610 } else { 3611 dp->d_fileno = fileno; 3612 } 3613 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3614 ncookie.lval[0]; 3615 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3616 ncookie.lval[1]; 3617 3618 if (nfhp != NULL) { 3619 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3620 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3621 VREF(vp); 3622 newvp = vp; 3623 unlocknewvp = 0; 3624 free(nfhp, M_NFSFH); 3625 np = dnp; 3626 } else if (isdotdot != 0) { 3627 /* 3628 * Skip doing a nfscl_nget() call for "..". 3629 * There's a race between acquiring the nfs 3630 * node here and lookups that look for the 3631 * directory being read (in the parent). 3632 * It would try to get a lock on ".." here, 3633 * owning the lock on the directory being 3634 * read. Lookup will hold the lock on ".." 3635 * and try to acquire the lock on the 3636 * directory being read. 3637 * If the directory is unlocked/relocked, 3638 * then there is a LOR with the buflock 3639 * vp is relocked. 3640 */ 3641 free(nfhp, M_NFSFH); 3642 } else { 3643 error = nfscl_nget(vnode_mount(vp), vp, 3644 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 3645 if (!error) { 3646 newvp = NFSTOV(np); 3647 unlocknewvp = 1; 3648 } 3649 } 3650 nfhp = NULL; 3651 if (newvp != NULLVP) { 3652 error = nfscl_loadattrcache(&newvp, 3653 &nfsva, NULL, NULL, 0, 0); 3654 if (error) { 3655 if (unlocknewvp) 3656 vput(newvp); 3657 else 3658 vrele(newvp); 3659 goto nfsmout; 3660 } 3661 dp->d_type = 3662 vtonfs_dtype(np->n_vattr.na_type); 3663 ndp->ni_vp = newvp; 3664 NFSCNHASH(cnp, HASHINIT); 3665 if (cnp->cn_namelen <= NCHNAMLEN && 3666 (newvp->v_type != VDIR || 3667 dctime.tv_sec != 0)) { 3668 cache_enter_time(ndp->ni_dvp, 3669 ndp->ni_vp, cnp, 3670 &nfsva.na_ctime, 3671 newvp->v_type != VDIR ? NULL : 3672 &dctime); 3673 } 3674 if (unlocknewvp) 3675 vput(newvp); 3676 else 3677 vrele(newvp); 3678 newvp = NULLVP; 3679 } 3680 } 3681 } else if (nfhp != NULL) { 3682 free(nfhp, M_NFSFH); 3683 } 3684 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3685 more_dirs = fxdr_unsigned(int, *tl); 3686 } 3687 /* 3688 * If at end of rpc data, get the eof boolean 3689 */ 3690 if (!more_dirs) { 3691 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3692 eof = fxdr_unsigned(int, *tl); 3693 if (tryformoredirs) 3694 more_dirs = !eof; 3695 if (nd->nd_flag & ND_NFSV4) { 3696 error = nfscl_postop_attr(nd, nap, attrflagp, 3697 stuff); 3698 if (error) 3699 goto nfsmout; 3700 } 3701 } 3702 mbuf_freem(nd->nd_mrep); 3703 nd->nd_mrep = NULL; 3704 } 3705 /* 3706 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3707 * by increasing d_reclen for the last record. 3708 */ 3709 if (blksiz > 0) { 3710 left = DIRBLKSIZ - blksiz; 3711 dp->d_reclen += left; 3712 uio_iov_base_add(uiop, left); 3713 uio_iov_len_add(uiop, -(left)); 3714 uio_uio_resid_add(uiop, -(left)); 3715 uiop->uio_offset += left; 3716 } 3717 3718 /* 3719 * If returning no data, assume end of file. 3720 * If not bigenough, return not end of file, since you aren't 3721 * returning all the data 3722 * Otherwise, return the eof flag from the server. 3723 */ 3724 if (eofp != NULL) { 3725 if (tresid == uio_uio_resid(uiop)) 3726 *eofp = 1; 3727 else if (!bigenough) 3728 *eofp = 0; 3729 else 3730 *eofp = eof; 3731 } 3732 3733 /* 3734 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3735 */ 3736 while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) { 3737 dp = (struct dirent *)uio_iov_base(uiop); 3738 dp->d_type = DT_UNKNOWN; 3739 dp->d_fileno = 0; 3740 dp->d_namlen = 0; 3741 dp->d_name[0] = '\0'; 3742 tl = (u_int32_t *)&dp->d_name[4]; 3743 *tl++ = cookie.lval[0]; 3744 *tl = cookie.lval[1]; 3745 dp->d_reclen = DIRBLKSIZ; 3746 uio_iov_base_add(uiop, DIRBLKSIZ); 3747 uio_iov_len_add(uiop, -(DIRBLKSIZ)); 3748 uio_uio_resid_add(uiop, -(DIRBLKSIZ)); 3749 uiop->uio_offset += DIRBLKSIZ; 3750 } 3751 3752 nfsmout: 3753 if (nd->nd_mrep != NULL) 3754 mbuf_freem(nd->nd_mrep); 3755 return (error); 3756 } 3757 #endif /* !APPLE */ 3758 3759 /* 3760 * Nfs commit rpc 3761 */ 3762 APPLESTATIC int 3763 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 3764 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 3765 { 3766 u_int32_t *tl; 3767 struct nfsrv_descript nfsd, *nd = &nfsd; 3768 nfsattrbit_t attrbits; 3769 int error; 3770 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3771 3772 *attrflagp = 0; 3773 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 3774 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3775 txdr_hyper(offset, tl); 3776 tl += 2; 3777 *tl = txdr_unsigned(cnt); 3778 if (nd->nd_flag & ND_NFSV4) { 3779 /* 3780 * And do a Getattr op. 3781 */ 3782 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3783 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3784 NFSGETATTR_ATTRBIT(&attrbits); 3785 (void) nfsrv_putattrbit(nd, &attrbits); 3786 } 3787 error = nfscl_request(nd, vp, p, cred, stuff); 3788 if (error) 3789 return (error); 3790 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 3791 if (!error && !nd->nd_repstat) { 3792 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 3793 NFSLOCKMNT(nmp); 3794 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { 3795 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 3796 nd->nd_repstat = NFSERR_STALEWRITEVERF; 3797 } 3798 NFSUNLOCKMNT(nmp); 3799 if (nd->nd_flag & ND_NFSV4) 3800 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3801 } 3802 nfsmout: 3803 if (!error && nd->nd_repstat) 3804 error = nd->nd_repstat; 3805 mbuf_freem(nd->nd_mrep); 3806 return (error); 3807 } 3808 3809 /* 3810 * NFS byte range lock rpc. 3811 * (Mostly just calls one of the three lower level RPC routines.) 3812 */ 3813 APPLESTATIC int 3814 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 3815 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3816 { 3817 struct nfscllockowner *lp; 3818 struct nfsclclient *clp; 3819 struct nfsfh *nfhp; 3820 struct nfsrv_descript nfsd, *nd = &nfsd; 3821 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 3822 u_int64_t off, len; 3823 off_t start, end; 3824 u_int32_t clidrev = 0; 3825 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 3826 int callcnt, dorpc; 3827 3828 /* 3829 * Convert the flock structure into a start and end and do POSIX 3830 * bounds checking. 3831 */ 3832 switch (fl->l_whence) { 3833 case SEEK_SET: 3834 case SEEK_CUR: 3835 /* 3836 * Caller is responsible for adding any necessary offset 3837 * when SEEK_CUR is used. 3838 */ 3839 start = fl->l_start; 3840 off = fl->l_start; 3841 break; 3842 case SEEK_END: 3843 start = size + fl->l_start; 3844 off = size + fl->l_start; 3845 break; 3846 default: 3847 return (EINVAL); 3848 } 3849 if (start < 0) 3850 return (EINVAL); 3851 if (fl->l_len != 0) { 3852 end = start + fl->l_len - 1; 3853 if (end < start) 3854 return (EINVAL); 3855 } 3856 3857 len = fl->l_len; 3858 if (len == 0) 3859 len = NFS64BITSSET; 3860 retrycnt = 0; 3861 do { 3862 nd->nd_repstat = 0; 3863 if (op == F_GETLK) { 3864 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3865 if (error) 3866 return (error); 3867 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 3868 if (!error) { 3869 clidrev = clp->nfsc_clientidrev; 3870 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 3871 p, id, flags); 3872 } else if (error == -1) { 3873 error = 0; 3874 } 3875 nfscl_clientrelease(clp); 3876 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 3877 /* 3878 * We must loop around for all lockowner cases. 3879 */ 3880 callcnt = 0; 3881 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, &clp); 3882 if (error) 3883 return (error); 3884 do { 3885 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 3886 clp, id, flags, &lp, &dorpc); 3887 /* 3888 * If it returns a NULL lp, we're done. 3889 */ 3890 if (lp == NULL) { 3891 if (callcnt == 0) 3892 nfscl_clientrelease(clp); 3893 else 3894 nfscl_releasealllocks(clp, vp, p, id, flags); 3895 return (error); 3896 } 3897 if (nmp->nm_clp != NULL) 3898 clidrev = nmp->nm_clp->nfsc_clientidrev; 3899 else 3900 clidrev = 0; 3901 /* 3902 * If the server doesn't support Posix lock semantics, 3903 * only allow locks on the entire file, since it won't 3904 * handle overlapping byte ranges. 3905 * There might still be a problem when a lock 3906 * upgrade/downgrade (read<->write) occurs, since the 3907 * server "might" expect an unlock first? 3908 */ 3909 if (dorpc && (lp->nfsl_open->nfso_posixlock || 3910 (off == 0 && len == NFS64BITSSET))) { 3911 /* 3912 * Since the lock records will go away, we must 3913 * wait for grace and delay here. 3914 */ 3915 do { 3916 error = nfsrpc_locku(nd, nmp, lp, off, len, 3917 NFSV4LOCKT_READ, cred, p, 0); 3918 if ((nd->nd_repstat == NFSERR_GRACE || 3919 nd->nd_repstat == NFSERR_DELAY) && 3920 error == 0) 3921 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 3922 "nfs_advlock"); 3923 } while ((nd->nd_repstat == NFSERR_GRACE || 3924 nd->nd_repstat == NFSERR_DELAY) && error == 0); 3925 } 3926 callcnt++; 3927 } while (error == 0 && nd->nd_repstat == 0); 3928 nfscl_releasealllocks(clp, vp, p, id, flags); 3929 } else if (op == F_SETLK) { 3930 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 3931 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 3932 if (error || donelocally) { 3933 return (error); 3934 } 3935 if (nmp->nm_clp != NULL) 3936 clidrev = nmp->nm_clp->nfsc_clientidrev; 3937 else 3938 clidrev = 0; 3939 nfhp = VTONFS(vp)->n_fhp; 3940 if (!lp->nfsl_open->nfso_posixlock && 3941 (off != 0 || len != NFS64BITSSET)) { 3942 error = EINVAL; 3943 } else { 3944 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 3945 nfhp->nfh_len, lp, newone, reclaim, off, 3946 len, fl->l_type, cred, p, 0); 3947 } 3948 if (!error) 3949 error = nd->nd_repstat; 3950 nfscl_lockrelease(lp, error, newone); 3951 } else { 3952 error = EINVAL; 3953 } 3954 if (!error) 3955 error = nd->nd_repstat; 3956 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 3957 error == NFSERR_STALEDONTRECOVER || 3958 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3959 error == NFSERR_BADSESSION) { 3960 (void) nfs_catnap(PZERO, error, "nfs_advlock"); 3961 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 3962 && clidrev != 0) { 3963 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 3964 retrycnt++; 3965 } 3966 } while (error == NFSERR_GRACE || 3967 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 3968 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 3969 error == NFSERR_BADSESSION || 3970 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 3971 expireret == 0 && clidrev != 0 && retrycnt < 4)); 3972 if (error && retrycnt >= 4) 3973 error = EIO; 3974 return (error); 3975 } 3976 3977 /* 3978 * The lower level routine for the LockT case. 3979 */ 3980 APPLESTATIC int 3981 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 3982 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 3983 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 3984 { 3985 u_int32_t *tl; 3986 int error, type, size; 3987 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 3988 struct nfsnode *np; 3989 struct nfsmount *nmp; 3990 struct nfsclsession *tsep; 3991 3992 nmp = VFSTONFS(vp->v_mount); 3993 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 3994 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 3995 if (fl->l_type == F_RDLCK) 3996 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 3997 else 3998 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 3999 txdr_hyper(off, tl); 4000 tl += 2; 4001 txdr_hyper(len, tl); 4002 tl += 2; 4003 tsep = nfsmnt_mdssession(nmp); 4004 *tl++ = tsep->nfsess_clientid.lval[0]; 4005 *tl = tsep->nfsess_clientid.lval[1]; 4006 nfscl_filllockowner(id, own, flags); 4007 np = VTONFS(vp); 4008 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 4009 np->n_fhp->nfh_len); 4010 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 4011 error = nfscl_request(nd, vp, p, cred, NULL); 4012 if (error) 4013 return (error); 4014 if (nd->nd_repstat == 0) { 4015 fl->l_type = F_UNLCK; 4016 } else if (nd->nd_repstat == NFSERR_DENIED) { 4017 nd->nd_repstat = 0; 4018 fl->l_whence = SEEK_SET; 4019 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4020 fl->l_start = fxdr_hyper(tl); 4021 tl += 2; 4022 len = fxdr_hyper(tl); 4023 tl += 2; 4024 if (len == NFS64BITSSET) 4025 fl->l_len = 0; 4026 else 4027 fl->l_len = len; 4028 type = fxdr_unsigned(int, *tl++); 4029 if (type == NFSV4LOCKT_WRITE) 4030 fl->l_type = F_WRLCK; 4031 else 4032 fl->l_type = F_RDLCK; 4033 /* 4034 * XXX For now, I have no idea what to do with the 4035 * conflicting lock_owner, so I'll just set the pid == 0 4036 * and skip over the lock_owner. 4037 */ 4038 fl->l_pid = (pid_t)0; 4039 tl += 2; 4040 size = fxdr_unsigned(int, *tl); 4041 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4042 error = EBADRPC; 4043 if (!error) 4044 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4045 } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 4046 nfscl_initiate_recovery(clp); 4047 nfsmout: 4048 mbuf_freem(nd->nd_mrep); 4049 return (error); 4050 } 4051 4052 /* 4053 * Lower level function that performs the LockU RPC. 4054 */ 4055 static int 4056 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 4057 struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 4058 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 4059 { 4060 u_int32_t *tl; 4061 int error; 4062 4063 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 4064 lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0); 4065 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 4066 *tl++ = txdr_unsigned(type); 4067 *tl = txdr_unsigned(lp->nfsl_seqid); 4068 if (nfstest_outofseq && 4069 (arc4random() % nfstest_outofseq) == 0) 4070 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4071 tl++; 4072 if (NFSHASNFSV4N(nmp)) 4073 *tl++ = 0; 4074 else 4075 *tl++ = lp->nfsl_stateid.seqid; 4076 *tl++ = lp->nfsl_stateid.other[0]; 4077 *tl++ = lp->nfsl_stateid.other[1]; 4078 *tl++ = lp->nfsl_stateid.other[2]; 4079 txdr_hyper(off, tl); 4080 tl += 2; 4081 txdr_hyper(len, tl); 4082 if (syscred) 4083 nd->nd_flag |= ND_USEGSSNAME; 4084 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4085 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4086 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4087 if (error) 4088 return (error); 4089 if (nd->nd_repstat == 0) { 4090 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4091 lp->nfsl_stateid.seqid = *tl++; 4092 lp->nfsl_stateid.other[0] = *tl++; 4093 lp->nfsl_stateid.other[1] = *tl++; 4094 lp->nfsl_stateid.other[2] = *tl; 4095 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4096 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4097 nfsmout: 4098 mbuf_freem(nd->nd_mrep); 4099 return (error); 4100 } 4101 4102 /* 4103 * The actual Lock RPC. 4104 */ 4105 APPLESTATIC int 4106 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 4107 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 4108 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 4109 NFSPROC_T *p, int syscred) 4110 { 4111 u_int32_t *tl; 4112 int error, size; 4113 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4114 struct nfsclsession *tsep; 4115 4116 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0); 4117 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4118 if (type == F_RDLCK) 4119 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4120 else 4121 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4122 *tl++ = txdr_unsigned(reclaim); 4123 txdr_hyper(off, tl); 4124 tl += 2; 4125 txdr_hyper(len, tl); 4126 tl += 2; 4127 if (newone) { 4128 *tl = newnfs_true; 4129 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 4130 2 * NFSX_UNSIGNED + NFSX_HYPER); 4131 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 4132 if (NFSHASNFSV4N(nmp)) 4133 *tl++ = 0; 4134 else 4135 *tl++ = lp->nfsl_open->nfso_stateid.seqid; 4136 *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 4137 *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 4138 *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 4139 *tl++ = txdr_unsigned(lp->nfsl_seqid); 4140 tsep = nfsmnt_mdssession(nmp); 4141 *tl++ = tsep->nfsess_clientid.lval[0]; 4142 *tl = tsep->nfsess_clientid.lval[1]; 4143 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4144 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4145 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4146 } else { 4147 *tl = newnfs_false; 4148 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 4149 if (NFSHASNFSV4N(nmp)) 4150 *tl++ = 0; 4151 else 4152 *tl++ = lp->nfsl_stateid.seqid; 4153 *tl++ = lp->nfsl_stateid.other[0]; 4154 *tl++ = lp->nfsl_stateid.other[1]; 4155 *tl++ = lp->nfsl_stateid.other[2]; 4156 *tl = txdr_unsigned(lp->nfsl_seqid); 4157 if (nfstest_outofseq && 4158 (arc4random() % nfstest_outofseq) == 0) 4159 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4160 } 4161 if (syscred) 4162 nd->nd_flag |= ND_USEGSSNAME; 4163 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 4164 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4165 if (error) 4166 return (error); 4167 if (newone) 4168 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 4169 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4170 if (nd->nd_repstat == 0) { 4171 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4172 lp->nfsl_stateid.seqid = *tl++; 4173 lp->nfsl_stateid.other[0] = *tl++; 4174 lp->nfsl_stateid.other[1] = *tl++; 4175 lp->nfsl_stateid.other[2] = *tl; 4176 } else if (nd->nd_repstat == NFSERR_DENIED) { 4177 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4178 size = fxdr_unsigned(int, *(tl + 7)); 4179 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4180 error = EBADRPC; 4181 if (!error) 4182 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4183 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4184 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4185 nfsmout: 4186 mbuf_freem(nd->nd_mrep); 4187 return (error); 4188 } 4189 4190 /* 4191 * nfs statfs rpc 4192 * (always called with the vp for the mount point) 4193 */ 4194 APPLESTATIC int 4195 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 4196 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4197 void *stuff) 4198 { 4199 u_int32_t *tl = NULL; 4200 struct nfsrv_descript nfsd, *nd = &nfsd; 4201 struct nfsmount *nmp; 4202 nfsattrbit_t attrbits; 4203 int error; 4204 4205 *attrflagp = 0; 4206 nmp = VFSTONFS(vnode_mount(vp)); 4207 if (NFSHASNFSV4(nmp)) { 4208 /* 4209 * For V4, you actually do a getattr. 4210 */ 4211 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4212 NFSSTATFS_GETATTRBIT(&attrbits); 4213 (void) nfsrv_putattrbit(nd, &attrbits); 4214 nd->nd_flag |= ND_USEGSSNAME; 4215 error = nfscl_request(nd, vp, p, cred, stuff); 4216 if (error) 4217 return (error); 4218 if (nd->nd_repstat == 0) { 4219 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4220 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 4221 cred); 4222 if (!error) { 4223 nmp->nm_fsid[0] = nap->na_filesid[0]; 4224 nmp->nm_fsid[1] = nap->na_filesid[1]; 4225 NFSSETHASSETFSID(nmp); 4226 *attrflagp = 1; 4227 } 4228 } else { 4229 error = nd->nd_repstat; 4230 } 4231 if (error) 4232 goto nfsmout; 4233 } else { 4234 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 4235 error = nfscl_request(nd, vp, p, cred, stuff); 4236 if (error) 4237 return (error); 4238 if (nd->nd_flag & ND_NFSV3) { 4239 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4240 if (error) 4241 goto nfsmout; 4242 } 4243 if (nd->nd_repstat) { 4244 error = nd->nd_repstat; 4245 goto nfsmout; 4246 } 4247 NFSM_DISSECT(tl, u_int32_t *, 4248 NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 4249 } 4250 if (NFSHASNFSV3(nmp)) { 4251 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 4252 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 4253 sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 4254 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 4255 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 4256 sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 4257 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 4258 } else if (NFSHASNFSV4(nmp) == 0) { 4259 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 4260 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 4261 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 4262 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 4263 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 4264 } 4265 nfsmout: 4266 mbuf_freem(nd->nd_mrep); 4267 return (error); 4268 } 4269 4270 /* 4271 * nfs pathconf rpc 4272 */ 4273 APPLESTATIC int 4274 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 4275 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4276 void *stuff) 4277 { 4278 struct nfsrv_descript nfsd, *nd = &nfsd; 4279 struct nfsmount *nmp; 4280 u_int32_t *tl; 4281 nfsattrbit_t attrbits; 4282 int error; 4283 4284 *attrflagp = 0; 4285 nmp = VFSTONFS(vnode_mount(vp)); 4286 if (NFSHASNFSV4(nmp)) { 4287 /* 4288 * For V4, you actually do a getattr. 4289 */ 4290 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4291 NFSPATHCONF_GETATTRBIT(&attrbits); 4292 (void) nfsrv_putattrbit(nd, &attrbits); 4293 nd->nd_flag |= ND_USEGSSNAME; 4294 error = nfscl_request(nd, vp, p, cred, stuff); 4295 if (error) 4296 return (error); 4297 if (nd->nd_repstat == 0) { 4298 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4299 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 4300 cred); 4301 if (!error) 4302 *attrflagp = 1; 4303 } else { 4304 error = nd->nd_repstat; 4305 } 4306 } else { 4307 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 4308 error = nfscl_request(nd, vp, p, cred, stuff); 4309 if (error) 4310 return (error); 4311 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4312 if (nd->nd_repstat && !error) 4313 error = nd->nd_repstat; 4314 if (!error) { 4315 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 4316 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 4317 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 4318 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 4319 pc->pc_chownrestricted = 4320 fxdr_unsigned(u_int32_t, *tl++); 4321 pc->pc_caseinsensitive = 4322 fxdr_unsigned(u_int32_t, *tl++); 4323 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 4324 } 4325 } 4326 nfsmout: 4327 mbuf_freem(nd->nd_mrep); 4328 return (error); 4329 } 4330 4331 /* 4332 * nfs version 3 fsinfo rpc call 4333 */ 4334 APPLESTATIC int 4335 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 4336 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 4337 { 4338 u_int32_t *tl; 4339 struct nfsrv_descript nfsd, *nd = &nfsd; 4340 int error; 4341 4342 *attrflagp = 0; 4343 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 4344 error = nfscl_request(nd, vp, p, cred, stuff); 4345 if (error) 4346 return (error); 4347 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4348 if (nd->nd_repstat && !error) 4349 error = nd->nd_repstat; 4350 if (!error) { 4351 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 4352 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 4353 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 4354 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 4355 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 4356 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 4357 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 4358 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 4359 fsp->fs_maxfilesize = fxdr_hyper(tl); 4360 tl += 2; 4361 fxdr_nfsv3time(tl, &fsp->fs_timedelta); 4362 tl += 2; 4363 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 4364 } 4365 nfsmout: 4366 mbuf_freem(nd->nd_mrep); 4367 return (error); 4368 } 4369 4370 /* 4371 * This function performs the Renew RPC. 4372 */ 4373 APPLESTATIC int 4374 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, 4375 NFSPROC_T *p) 4376 { 4377 u_int32_t *tl; 4378 struct nfsrv_descript nfsd; 4379 struct nfsrv_descript *nd = &nfsd; 4380 struct nfsmount *nmp; 4381 int error; 4382 struct nfssockreq *nrp; 4383 struct nfsclsession *tsep; 4384 4385 nmp = clp->nfsc_nmp; 4386 if (nmp == NULL) 4387 return (0); 4388 if (dsp == NULL) 4389 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0, 4390 0); 4391 else 4392 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, 4393 &dsp->nfsclds_sess, 0, 0); 4394 if (!NFSHASNFSV4N(nmp)) { 4395 /* NFSv4.1 just uses a Sequence Op and not a Renew. */ 4396 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4397 tsep = nfsmnt_mdssession(nmp); 4398 *tl++ = tsep->nfsess_clientid.lval[0]; 4399 *tl = tsep->nfsess_clientid.lval[1]; 4400 } 4401 nrp = NULL; 4402 if (dsp != NULL) 4403 nrp = dsp->nfsclds_sockp; 4404 if (nrp == NULL) 4405 /* If NULL, use the MDS socket. */ 4406 nrp = &nmp->nm_sockreq; 4407 nd->nd_flag |= ND_USEGSSNAME; 4408 if (dsp == NULL) 4409 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4410 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4411 else { 4412 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4413 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 4414 if (error == ENXIO) 4415 nfscl_cancelreqs(dsp); 4416 } 4417 if (error) 4418 return (error); 4419 error = nd->nd_repstat; 4420 mbuf_freem(nd->nd_mrep); 4421 return (error); 4422 } 4423 4424 /* 4425 * This function performs the Releaselockowner RPC. 4426 */ 4427 APPLESTATIC int 4428 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4429 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4430 { 4431 struct nfsrv_descript nfsd, *nd = &nfsd; 4432 u_int32_t *tl; 4433 int error; 4434 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4435 struct nfsclsession *tsep; 4436 4437 if (NFSHASNFSV4N(nmp)) { 4438 /* For NFSv4.1, do a FreeStateID. */ 4439 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, 4440 NULL, 0, 0); 4441 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); 4442 } else { 4443 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, 4444 NULL, 0, 0); 4445 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4446 tsep = nfsmnt_mdssession(nmp); 4447 *tl++ = tsep->nfsess_clientid.lval[0]; 4448 *tl = tsep->nfsess_clientid.lval[1]; 4449 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4450 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4451 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4452 } 4453 nd->nd_flag |= ND_USEGSSNAME; 4454 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4455 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4456 if (error) 4457 return (error); 4458 error = nd->nd_repstat; 4459 mbuf_freem(nd->nd_mrep); 4460 return (error); 4461 } 4462 4463 /* 4464 * This function performs the Compound to get the mount pt FH. 4465 */ 4466 APPLESTATIC int 4467 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4468 NFSPROC_T *p) 4469 { 4470 u_int32_t *tl; 4471 struct nfsrv_descript nfsd; 4472 struct nfsrv_descript *nd = &nfsd; 4473 u_char *cp, *cp2; 4474 int error, cnt, len, setnil; 4475 u_int32_t *opcntp; 4476 4477 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0, 4478 0); 4479 cp = dirpath; 4480 cnt = 0; 4481 do { 4482 setnil = 0; 4483 while (*cp == '/') 4484 cp++; 4485 cp2 = cp; 4486 while (*cp2 != '\0' && *cp2 != '/') 4487 cp2++; 4488 if (*cp2 == '/') { 4489 setnil = 1; 4490 *cp2 = '\0'; 4491 } 4492 if (cp2 != cp) { 4493 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4494 *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4495 nfsm_strtom(nd, cp, strlen(cp)); 4496 cnt++; 4497 } 4498 if (setnil) 4499 *cp2++ = '/'; 4500 cp = cp2; 4501 } while (*cp != '\0'); 4502 if (NFSHASNFSV4N(nmp)) 4503 /* Has a Sequence Op done by nfscl_reqstart(). */ 4504 *opcntp = txdr_unsigned(3 + cnt); 4505 else 4506 *opcntp = txdr_unsigned(2 + cnt); 4507 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4508 *tl = txdr_unsigned(NFSV4OP_GETFH); 4509 nd->nd_flag |= ND_USEGSSNAME; 4510 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4511 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4512 if (error) 4513 return (error); 4514 if (nd->nd_repstat == 0) { 4515 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4516 tl += (2 + 2 * cnt); 4517 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4518 len > NFSX_FHMAX) { 4519 nd->nd_repstat = NFSERR_BADXDR; 4520 } else { 4521 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4522 if (nd->nd_repstat == 0) 4523 nmp->nm_fhsize = len; 4524 } 4525 } 4526 error = nd->nd_repstat; 4527 nfsmout: 4528 mbuf_freem(nd->nd_mrep); 4529 return (error); 4530 } 4531 4532 /* 4533 * This function performs the Delegreturn RPC. 4534 */ 4535 APPLESTATIC int 4536 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4537 struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4538 { 4539 u_int32_t *tl; 4540 struct nfsrv_descript nfsd; 4541 struct nfsrv_descript *nd = &nfsd; 4542 int error; 4543 4544 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4545 dp->nfsdl_fhlen, NULL, NULL, 0, 0); 4546 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4547 if (NFSHASNFSV4N(nmp)) 4548 *tl++ = 0; 4549 else 4550 *tl++ = dp->nfsdl_stateid.seqid; 4551 *tl++ = dp->nfsdl_stateid.other[0]; 4552 *tl++ = dp->nfsdl_stateid.other[1]; 4553 *tl = dp->nfsdl_stateid.other[2]; 4554 if (syscred) 4555 nd->nd_flag |= ND_USEGSSNAME; 4556 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4557 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4558 if (error) 4559 return (error); 4560 error = nd->nd_repstat; 4561 mbuf_freem(nd->nd_mrep); 4562 return (error); 4563 } 4564 4565 /* 4566 * nfs getacl call. 4567 */ 4568 APPLESTATIC int 4569 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4570 struct acl *aclp, void *stuff) 4571 { 4572 struct nfsrv_descript nfsd, *nd = &nfsd; 4573 int error; 4574 nfsattrbit_t attrbits; 4575 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4576 4577 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4578 return (EOPNOTSUPP); 4579 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4580 NFSZERO_ATTRBIT(&attrbits); 4581 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4582 (void) nfsrv_putattrbit(nd, &attrbits); 4583 error = nfscl_request(nd, vp, p, cred, stuff); 4584 if (error) 4585 return (error); 4586 if (!nd->nd_repstat) 4587 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4588 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4589 else 4590 error = nd->nd_repstat; 4591 mbuf_freem(nd->nd_mrep); 4592 return (error); 4593 } 4594 4595 /* 4596 * nfs setacl call. 4597 */ 4598 APPLESTATIC int 4599 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4600 struct acl *aclp, void *stuff) 4601 { 4602 int error; 4603 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4604 4605 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4606 return (EOPNOTSUPP); 4607 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4608 return (error); 4609 } 4610 4611 /* 4612 * nfs setacl call. 4613 */ 4614 static int 4615 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4616 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 4617 { 4618 struct nfsrv_descript nfsd, *nd = &nfsd; 4619 int error; 4620 nfsattrbit_t attrbits; 4621 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 4622 4623 if (!NFSHASNFSV4(nmp)) 4624 return (EOPNOTSUPP); 4625 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 4626 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 4627 NFSZERO_ATTRBIT(&attrbits); 4628 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4629 (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0, 4630 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); 4631 error = nfscl_request(nd, vp, p, cred, stuff); 4632 if (error) 4633 return (error); 4634 /* Don't care about the pre/postop attributes */ 4635 mbuf_freem(nd->nd_mrep); 4636 return (nd->nd_repstat); 4637 } 4638 4639 /* 4640 * Do the NFSv4.1 Exchange ID. 4641 */ 4642 int 4643 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, 4644 struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp, 4645 struct ucred *cred, NFSPROC_T *p) 4646 { 4647 uint32_t *tl, v41flags; 4648 struct nfsrv_descript nfsd; 4649 struct nfsrv_descript *nd = &nfsd; 4650 struct nfsclds *dsp; 4651 struct timespec verstime; 4652 int error, len; 4653 4654 *dspp = NULL; 4655 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, 0, 0); 4656 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4657 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ 4658 *tl = txdr_unsigned(clp->nfsc_rev); 4659 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 4660 4661 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 4662 *tl++ = txdr_unsigned(exchflags); 4663 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); 4664 4665 /* Set the implementation id4 */ 4666 *tl = txdr_unsigned(1); 4667 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 4668 (void) nfsm_strtom(nd, version, strlen(version)); 4669 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 4670 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 4671 verstime.tv_nsec = 0; 4672 txdr_nfsv4time(&verstime, tl); 4673 nd->nd_flag |= ND_USEGSSNAME; 4674 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4675 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4676 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, 4677 (int)nd->nd_repstat); 4678 if (error != 0) 4679 return (error); 4680 if (nd->nd_repstat == 0) { 4681 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); 4682 len = fxdr_unsigned(int, *(tl + 7)); 4683 if (len < 0 || len > NFSV4_OPAQUELIMIT) { 4684 error = NFSERR_BADXDR; 4685 goto nfsmout; 4686 } 4687 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, 4688 M_WAITOK | M_ZERO); 4689 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; 4690 dsp->nfsclds_servownlen = len; 4691 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; 4692 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; 4693 dsp->nfsclds_sess.nfsess_sequenceid = 4694 fxdr_unsigned(uint32_t, *tl++); 4695 v41flags = fxdr_unsigned(uint32_t, *tl); 4696 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && 4697 NFSHASPNFSOPT(nmp)) { 4698 NFSCL_DEBUG(1, "set PNFS\n"); 4699 NFSLOCKMNT(nmp); 4700 nmp->nm_state |= NFSSTA_PNFS; 4701 NFSUNLOCKMNT(nmp); 4702 dsp->nfsclds_flags |= NFSCLDS_MDS; 4703 } 4704 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) 4705 dsp->nfsclds_flags |= NFSCLDS_DS; 4706 if (len > 0) 4707 nd->nd_repstat = nfsrv_mtostr(nd, 4708 dsp->nfsclds_serverown, len); 4709 if (nd->nd_repstat == 0) { 4710 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 4711 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 4712 NULL, MTX_DEF); 4713 nfscl_initsessionslots(&dsp->nfsclds_sess); 4714 *dspp = dsp; 4715 } else 4716 free(dsp, M_NFSCLDS); 4717 } 4718 error = nd->nd_repstat; 4719 nfsmout: 4720 mbuf_freem(nd->nd_mrep); 4721 return (error); 4722 } 4723 4724 /* 4725 * Do the NFSv4.1 Create Session. 4726 */ 4727 int 4728 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, 4729 struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred, 4730 NFSPROC_T *p) 4731 { 4732 uint32_t crflags, maxval, *tl; 4733 struct nfsrv_descript nfsd; 4734 struct nfsrv_descript *nd = &nfsd; 4735 int error, irdcnt; 4736 4737 /* Make sure nm_rsize, nm_wsize is set. */ 4738 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0) 4739 nmp->nm_rsize = NFS_MAXBSIZE; 4740 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0) 4741 nmp->nm_wsize = NFS_MAXBSIZE; 4742 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, 0, 4743 0); 4744 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 4745 *tl++ = sep->nfsess_clientid.lval[0]; 4746 *tl++ = sep->nfsess_clientid.lval[1]; 4747 *tl++ = txdr_unsigned(sequenceid); 4748 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); 4749 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0) 4750 crflags |= NFSV4CRSESS_CONNBACKCHAN; 4751 *tl = txdr_unsigned(crflags); 4752 4753 /* Fill in fore channel attributes. */ 4754 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4755 *tl++ = 0; /* Header pad size */ 4756 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);/* Max request size */ 4757 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);/* Max reply size */ 4758 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4759 *tl++ = txdr_unsigned(20); /* Max operations */ 4760 *tl++ = txdr_unsigned(64); /* Max slots */ 4761 *tl = 0; /* No rdma ird */ 4762 4763 /* Fill in back channel attributes. */ 4764 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4765 *tl++ = 0; /* Header pad size */ 4766 *tl++ = txdr_unsigned(10000); /* Max request size */ 4767 *tl++ = txdr_unsigned(10000); /* Max response size */ 4768 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 4769 *tl++ = txdr_unsigned(4); /* Max operations */ 4770 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ 4771 *tl = 0; /* No rdma ird */ 4772 4773 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); 4774 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ 4775 4776 /* Allow AUTH_SYS callbacks as uid, gid == 0. */ 4777 *tl++ = txdr_unsigned(1); /* Auth_sys only */ 4778 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ 4779 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ 4780 *tl++ = 0; /* Null machine name */ 4781 *tl++ = 0; /* Uid == 0 */ 4782 *tl++ = 0; /* Gid == 0 */ 4783 *tl = 0; /* No additional gids */ 4784 nd->nd_flag |= ND_USEGSSNAME; 4785 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, 4786 NFS_VER4, NULL, 1, NULL, NULL); 4787 if (error != 0) 4788 return (error); 4789 if (nd->nd_repstat == 0) { 4790 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 4791 2 * NFSX_UNSIGNED); 4792 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); 4793 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 4794 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); 4795 crflags = fxdr_unsigned(uint32_t, *tl); 4796 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { 4797 NFSLOCKMNT(nmp); 4798 nmp->nm_state |= NFSSTA_SESSPERSIST; 4799 NFSUNLOCKMNT(nmp); 4800 } 4801 4802 /* Get the fore channel slot count. */ 4803 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4804 tl++; /* Skip the header pad size. */ 4805 4806 /* Make sure nm_wsize is small enough. */ 4807 maxval = fxdr_unsigned(uint32_t, *tl++); 4808 while (maxval < nmp->nm_wsize + NFS_MAXXDR) { 4809 if (nmp->nm_wsize > 8096) 4810 nmp->nm_wsize /= 2; 4811 else 4812 break; 4813 } 4814 4815 /* Make sure nm_rsize is small enough. */ 4816 maxval = fxdr_unsigned(uint32_t, *tl++); 4817 while (maxval < nmp->nm_rsize + NFS_MAXXDR) { 4818 if (nmp->nm_rsize > 8096) 4819 nmp->nm_rsize /= 2; 4820 else 4821 break; 4822 } 4823 4824 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); 4825 tl++; 4826 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); 4827 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); 4828 irdcnt = fxdr_unsigned(int, *tl); 4829 if (irdcnt > 0) 4830 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 4831 4832 /* and the back channel slot count. */ 4833 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 4834 tl += 5; 4835 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 4836 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 4837 } 4838 error = nd->nd_repstat; 4839 nfsmout: 4840 mbuf_freem(nd->nd_mrep); 4841 return (error); 4842 } 4843 4844 /* 4845 * Do the NFSv4.1 Destroy Session. 4846 */ 4847 int 4848 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp, 4849 struct ucred *cred, NFSPROC_T *p) 4850 { 4851 uint32_t *tl; 4852 struct nfsrv_descript nfsd; 4853 struct nfsrv_descript *nd = &nfsd; 4854 int error; 4855 struct nfsclsession *tsep; 4856 4857 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0, 4858 0); 4859 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 4860 tsep = nfsmnt_mdssession(nmp); 4861 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID); 4862 nd->nd_flag |= ND_USEGSSNAME; 4863 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4864 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4865 if (error != 0) 4866 return (error); 4867 error = nd->nd_repstat; 4868 mbuf_freem(nd->nd_mrep); 4869 return (error); 4870 } 4871 4872 /* 4873 * Do the NFSv4.1 Destroy Client. 4874 */ 4875 int 4876 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 4877 struct ucred *cred, NFSPROC_T *p) 4878 { 4879 uint32_t *tl; 4880 struct nfsrv_descript nfsd; 4881 struct nfsrv_descript *nd = &nfsd; 4882 int error; 4883 struct nfsclsession *tsep; 4884 4885 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0, 4886 0); 4887 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4888 tsep = nfsmnt_mdssession(nmp); 4889 *tl++ = tsep->nfsess_clientid.lval[0]; 4890 *tl = tsep->nfsess_clientid.lval[1]; 4891 nd->nd_flag |= ND_USEGSSNAME; 4892 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4893 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4894 if (error != 0) 4895 return (error); 4896 error = nd->nd_repstat; 4897 mbuf_freem(nd->nd_mrep); 4898 return (error); 4899 } 4900 4901 /* 4902 * Do the NFSv4.1 LayoutGet. 4903 */ 4904 static int 4905 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 4906 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype, 4907 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep, 4908 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p, 4909 void *stuff) 4910 { 4911 struct nfsrv_descript nfsd, *nd = &nfsd; 4912 int error; 4913 4914 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0, 4915 0); 4916 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, 4917 layouttype, layoutlen, 0); 4918 nd->nd_flag |= ND_USEGSSNAME; 4919 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4920 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4921 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); 4922 if (error != 0) 4923 return (error); 4924 if (nd->nd_repstat == 0) 4925 error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp); 4926 if (error == 0 && nd->nd_repstat != 0) 4927 error = nd->nd_repstat; 4928 mbuf_freem(nd->nd_mrep); 4929 return (error); 4930 } 4931 4932 /* 4933 * Do the NFSv4.1 Get Device Info. 4934 */ 4935 int 4936 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 4937 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 4938 NFSPROC_T *p) 4939 { 4940 uint32_t cnt, *tl, vers, minorvers; 4941 struct nfsrv_descript nfsd; 4942 struct nfsrv_descript *nd = &nfsd; 4943 struct sockaddr_in sin, ssin; 4944 struct sockaddr_in6 sin6, ssin6; 4945 struct nfsclds *dsp = NULL, **dspp, **gotdspp; 4946 struct nfscldevinfo *ndi; 4947 int addrcnt = 0, bitcnt, error, gotvers, i, isudp, j, stripecnt; 4948 uint8_t stripeindex; 4949 sa_family_t af, safilled; 4950 4951 *ndip = NULL; 4952 ndi = NULL; 4953 gotdspp = NULL; 4954 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0, 4955 0); 4956 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 4957 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 4958 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 4959 *tl++ = txdr_unsigned(layouttype); 4960 *tl++ = txdr_unsigned(100000); 4961 if (notifybitsp != NULL && *notifybitsp != 0) { 4962 *tl = txdr_unsigned(1); /* One word of bits. */ 4963 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 4964 *tl = txdr_unsigned(*notifybitsp); 4965 } else 4966 *tl = txdr_unsigned(0); 4967 nd->nd_flag |= ND_USEGSSNAME; 4968 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4969 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4970 if (error != 0) 4971 return (error); 4972 if (nd->nd_repstat == 0) { 4973 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 4974 if (layouttype != fxdr_unsigned(int, *tl)) 4975 printf("EEK! devinfo layout type not same!\n"); 4976 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) { 4977 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 4978 stripecnt = fxdr_unsigned(int, *tl); 4979 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 4980 if (stripecnt < 1 || stripecnt > 4096) { 4981 printf("pNFS File layout devinfo stripecnt %d:" 4982 " out of range\n", stripecnt); 4983 error = NFSERR_BADXDR; 4984 goto nfsmout; 4985 } 4986 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * 4987 NFSX_UNSIGNED); 4988 addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 4989 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 4990 if (addrcnt < 1 || addrcnt > 128) { 4991 printf("NFS devinfo addrcnt %d: out of range\n", 4992 addrcnt); 4993 error = NFSERR_BADXDR; 4994 goto nfsmout; 4995 } 4996 4997 /* 4998 * Now we know how many stripe indices and addresses, so 4999 * we can allocate the structure the correct size. 5000 */ 5001 i = (stripecnt * sizeof(uint8_t)) / 5002 sizeof(struct nfsclds *) + 1; 5003 NFSCL_DEBUG(4, "stripeindices=%d\n", i); 5004 ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 5005 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | 5006 M_ZERO); 5007 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5008 NFSX_V4DEVICEID); 5009 ndi->nfsdi_refcnt = 0; 5010 ndi->nfsdi_flags = NFSDI_FILELAYOUT; 5011 ndi->nfsdi_stripecnt = stripecnt; 5012 ndi->nfsdi_addrcnt = addrcnt; 5013 /* Fill in the stripe indices. */ 5014 for (i = 0; i < stripecnt; i++) { 5015 stripeindex = fxdr_unsigned(uint8_t, *tl++); 5016 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 5017 if (stripeindex >= addrcnt) { 5018 printf("pNFS File Layout devinfo" 5019 " stripeindex %d: too big\n", 5020 (int)stripeindex); 5021 error = NFSERR_BADXDR; 5022 goto nfsmout; 5023 } 5024 nfsfldi_setstripeindex(ndi, i, stripeindex); 5025 } 5026 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 5027 /* For Flex File, we only get one address list. */ 5028 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *), 5029 M_NFSDEVINFO, M_WAITOK | M_ZERO); 5030 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5031 NFSX_V4DEVICEID); 5032 ndi->nfsdi_refcnt = 0; 5033 ndi->nfsdi_flags = NFSDI_FLEXFILE; 5034 addrcnt = ndi->nfsdi_addrcnt = 1; 5035 } 5036 5037 /* Now, dissect the server address(es). */ 5038 safilled = AF_UNSPEC; 5039 for (i = 0; i < addrcnt; i++) { 5040 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5041 cnt = fxdr_unsigned(uint32_t, *tl); 5042 if (cnt == 0) { 5043 printf("NFS devinfo 0 len addrlist\n"); 5044 error = NFSERR_BADXDR; 5045 goto nfsmout; 5046 } 5047 dspp = nfsfldi_addr(ndi, i); 5048 safilled = AF_UNSPEC; 5049 for (j = 0; j < cnt; j++) { 5050 error = nfsv4_getipaddr(nd, &sin, &sin6, &af, 5051 &isudp); 5052 if (error != 0 && error != EPERM) { 5053 error = NFSERR_BADXDR; 5054 goto nfsmout; 5055 } 5056 if (error == 0 && isudp == 0) { 5057 /* 5058 * The priority is: 5059 * - Same address family. 5060 * Save the address and dspp, so that 5061 * the connection can be done after 5062 * parsing is complete. 5063 */ 5064 if (safilled == AF_UNSPEC || 5065 (af == nmp->nm_nam->sa_family && 5066 safilled != nmp->nm_nam->sa_family) 5067 ) { 5068 if (af == AF_INET) 5069 ssin = sin; 5070 else 5071 ssin6 = sin6; 5072 safilled = af; 5073 gotdspp = dspp; 5074 } 5075 } 5076 } 5077 } 5078 5079 gotvers = NFS_VER4; /* Always NFSv4 for File Layout. */ 5080 /* For Flex File, we will take one of the versions to use. */ 5081 if (layouttype == NFSLAYOUT_FLEXFILE) { 5082 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5083 j = fxdr_unsigned(int, *tl); 5084 if (j < 1 || j > NFSDEV_MAXVERS) { 5085 printf("pNFS: too many versions\n"); 5086 error = NFSERR_BADXDR; 5087 goto nfsmout; 5088 } 5089 gotvers = 0; 5090 for (i = 0; i < j; i++) { 5091 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED); 5092 vers = fxdr_unsigned(uint32_t, *tl++); 5093 minorvers = fxdr_unsigned(uint32_t, *tl++); 5094 if ((vers == NFS_VER4 && minorvers == 5095 NFSV41_MINORVERSION) || (vers == NFS_VER3 && 5096 gotvers == 0)) { 5097 gotvers = vers; 5098 /* We'll take this one. */ 5099 ndi->nfsdi_versindex = i; 5100 ndi->nfsdi_vers = vers; 5101 ndi->nfsdi_minorvers = minorvers; 5102 ndi->nfsdi_rsize = fxdr_unsigned( 5103 uint32_t, *tl++); 5104 ndi->nfsdi_wsize = fxdr_unsigned( 5105 uint32_t, *tl++); 5106 if (*tl == newnfs_true) 5107 ndi->nfsdi_flags |= 5108 NFSDI_TIGHTCOUPLED; 5109 else 5110 ndi->nfsdi_flags &= 5111 ~NFSDI_TIGHTCOUPLED; 5112 } 5113 } 5114 if (gotvers == 0) { 5115 printf("pNFS: no NFSv3 or NFSv4.1\n"); 5116 error = NFSERR_BADXDR; 5117 goto nfsmout; 5118 } 5119 } 5120 5121 /* And the notify bits. */ 5122 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5123 bitcnt = fxdr_unsigned(int, *tl); 5124 if (bitcnt > 0) { 5125 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5126 if (notifybitsp != NULL) 5127 *notifybitsp = 5128 fxdr_unsigned(uint32_t, *tl); 5129 } 5130 if (safilled != AF_UNSPEC) { 5131 KASSERT(ndi != NULL, ("ndi is NULL")); 5132 *ndip = ndi; 5133 } else 5134 error = EPERM; 5135 if (error == 0) { 5136 /* 5137 * Now we can do a TCP connection for the correct 5138 * NFS version and IP address. 5139 */ 5140 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled, 5141 gotvers, &dsp, p); 5142 } 5143 if (error == 0) { 5144 KASSERT(gotdspp != NULL, ("gotdspp is NULL")); 5145 *gotdspp = dsp; 5146 } 5147 } 5148 if (nd->nd_repstat != 0 && error == 0) 5149 error = nd->nd_repstat; 5150 nfsmout: 5151 if (error != 0 && ndi != NULL) 5152 nfscl_freedevinfo(ndi); 5153 mbuf_freem(nd->nd_mrep); 5154 return (error); 5155 } 5156 5157 /* 5158 * Do the NFSv4.1 LayoutCommit. 5159 */ 5160 int 5161 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5162 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5163 int layouttype, struct ucred *cred, NFSPROC_T *p, void *stuff) 5164 { 5165 uint32_t *tl; 5166 struct nfsrv_descript nfsd, *nd = &nfsd; 5167 int error; 5168 5169 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL, 5170 0, 0); 5171 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5172 NFSX_STATEID); 5173 txdr_hyper(off, tl); 5174 tl += 2; 5175 txdr_hyper(len, tl); 5176 tl += 2; 5177 if (reclaim != 0) 5178 *tl++ = newnfs_true; 5179 else 5180 *tl++ = newnfs_false; 5181 *tl++ = txdr_unsigned(stateidp->seqid); 5182 *tl++ = stateidp->other[0]; 5183 *tl++ = stateidp->other[1]; 5184 *tl++ = stateidp->other[2]; 5185 *tl++ = newnfs_true; 5186 if (lastbyte < off) 5187 lastbyte = off; 5188 else if (lastbyte >= (off + len)) 5189 lastbyte = off + len - 1; 5190 txdr_hyper(lastbyte, tl); 5191 tl += 2; 5192 *tl++ = newnfs_false; 5193 *tl++ = txdr_unsigned(layouttype); 5194 /* All supported layouts are 0 length. */ 5195 *tl = txdr_unsigned(0); 5196 nd->nd_flag |= ND_USEGSSNAME; 5197 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5198 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5199 if (error != 0) 5200 return (error); 5201 error = nd->nd_repstat; 5202 mbuf_freem(nd->nd_mrep); 5203 return (error); 5204 } 5205 5206 /* 5207 * Do the NFSv4.1 LayoutReturn. 5208 */ 5209 int 5210 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5211 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5212 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5213 uint32_t stat, uint32_t op, char *devid) 5214 { 5215 uint32_t *tl; 5216 struct nfsrv_descript nfsd, *nd = &nfsd; 5217 uint64_t tu64; 5218 int error; 5219 5220 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL, 5221 0, 0); 5222 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5223 if (reclaim != 0) 5224 *tl++ = newnfs_true; 5225 else 5226 *tl++ = newnfs_false; 5227 *tl++ = txdr_unsigned(layouttype); 5228 *tl++ = txdr_unsigned(iomode); 5229 *tl = txdr_unsigned(layoutreturn); 5230 if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5231 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5232 NFSX_UNSIGNED); 5233 txdr_hyper(offset, tl); 5234 tl += 2; 5235 txdr_hyper(len, tl); 5236 tl += 2; 5237 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5238 *tl++ = txdr_unsigned(stateidp->seqid); 5239 *tl++ = stateidp->other[0]; 5240 *tl++ = stateidp->other[1]; 5241 *tl++ = stateidp->other[2]; 5242 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) 5243 *tl = txdr_unsigned(0); 5244 else if (layouttype == NFSLAYOUT_FLEXFILE) { 5245 if (stat != 0) { 5246 *tl = txdr_unsigned(2 * NFSX_HYPER + 5247 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5248 NFSX_UNSIGNED); 5249 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 5250 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5251 NFSX_UNSIGNED); 5252 *tl++ = txdr_unsigned(1); /* One error. */ 5253 tu64 = 0; /* Offset. */ 5254 txdr_hyper(tu64, tl); tl += 2; 5255 tu64 = UINT64_MAX; /* Length. */ 5256 txdr_hyper(tu64, tl); tl += 2; 5257 NFSBCOPY(stateidp, tl, NFSX_STATEID); 5258 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5259 *tl++ = txdr_unsigned(1); /* One error. */ 5260 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5261 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5262 *tl++ = txdr_unsigned(stat); 5263 *tl++ = txdr_unsigned(op); 5264 } else { 5265 *tl = txdr_unsigned(2 * NFSX_UNSIGNED); 5266 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5267 /* No ioerrs. */ 5268 *tl++ = 0; 5269 } 5270 *tl = 0; /* No stats yet. */ 5271 } 5272 } 5273 nd->nd_flag |= ND_USEGSSNAME; 5274 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5275 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5276 if (error != 0) 5277 return (error); 5278 if (nd->nd_repstat == 0) { 5279 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5280 if (*tl != 0) { 5281 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5282 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5283 stateidp->other[0] = *tl++; 5284 stateidp->other[1] = *tl++; 5285 stateidp->other[2] = *tl; 5286 } 5287 } else 5288 error = nd->nd_repstat; 5289 nfsmout: 5290 mbuf_freem(nd->nd_mrep); 5291 return (error); 5292 } 5293 5294 /* 5295 * Acquire a layout and devinfo, if possible. The caller must have acquired 5296 * a reference count on the nfsclclient structure before calling this. 5297 * Return the layout in lypp with a reference count on it, if successful. 5298 */ 5299 static int 5300 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 5301 int iomode, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, uint64_t off, 5302 struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 5303 { 5304 struct nfscllayout *lyp; 5305 struct nfsclflayout *flp; 5306 struct nfsclflayouthead flh; 5307 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose; 5308 nfsv4stateid_t stateid; 5309 struct nfsclsession *tsep; 5310 5311 *lypp = NULL; 5312 if (NFSHASFLEXFILE(nmp)) 5313 layouttype = NFSLAYOUT_FLEXFILE; 5314 else 5315 layouttype = NFSLAYOUT_NFSV4_1_FILES; 5316 /* 5317 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 5318 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 5319 * flp == NULL. 5320 */ 5321 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 5322 off, &flp, &recalled); 5323 islocked = 0; 5324 if (lyp == NULL || flp == NULL) { 5325 if (recalled != 0) 5326 return (EIO); 5327 LIST_INIT(&flh); 5328 tsep = nfsmnt_mdssession(nmp); 5329 layoutlen = tsep->nfsess_maxcache - 5330 (NFSX_STATEID + 3 * NFSX_UNSIGNED); 5331 if (lyp == NULL) { 5332 stateid.seqid = 0; 5333 stateid.other[0] = stateidp->other[0]; 5334 stateid.other[1] = stateidp->other[1]; 5335 stateid.other[2] = stateidp->other[2]; 5336 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5337 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, 5338 (uint64_t)0, layouttype, layoutlen, &stateid, 5339 &retonclose, &flh, cred, p, NULL); 5340 } else { 5341 islocked = 1; 5342 stateid.seqid = lyp->nfsly_stateid.seqid; 5343 stateid.other[0] = lyp->nfsly_stateid.other[0]; 5344 stateid.other[1] = lyp->nfsly_stateid.other[1]; 5345 stateid.other[2] = lyp->nfsly_stateid.other[2]; 5346 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5347 nfhp->nfh_len, iomode, off, UINT64_MAX, 5348 (uint64_t)0, layouttype, layoutlen, &stateid, 5349 &retonclose, &flh, cred, p, NULL); 5350 } 5351 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, 5352 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, 5353 &flh, layouttype, error, NULL, cred, p); 5354 if (error == 0) 5355 *lypp = lyp; 5356 else if (islocked != 0) 5357 nfscl_rellayout(lyp, 1); 5358 } else 5359 *lypp = lyp; 5360 return (error); 5361 } 5362 5363 /* 5364 * Do a TCP connection plus exchange id and create session. 5365 * If successful, a "struct nfsclds" is linked into the list for the 5366 * mount point and a pointer to it is returned. 5367 */ 5368 static int 5369 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin, 5370 struct sockaddr_in6 *sin6, sa_family_t af, int vers, struct nfsclds **dspp, 5371 NFSPROC_T *p) 5372 { 5373 struct sockaddr_in *msad, *sad; 5374 struct sockaddr_in6 *msad6, *sad6; 5375 struct nfsclclient *clp; 5376 struct nfssockreq *nrp; 5377 struct nfsclds *dsp, *tdsp; 5378 int error; 5379 enum nfsclds_state retv; 5380 uint32_t sequenceid; 5381 5382 KASSERT(nmp->nm_sockreq.nr_cred != NULL, 5383 ("nfsrpc_fillsa: NULL nr_cred")); 5384 NFSLOCKCLSTATE(); 5385 clp = nmp->nm_clp; 5386 NFSUNLOCKCLSTATE(); 5387 if (clp == NULL) 5388 return (EPERM); 5389 if (af == AF_INET) { 5390 NFSLOCKMNT(nmp); 5391 /* 5392 * Check to see if we already have a session for this 5393 * address that is usable for a DS. 5394 * Note that the MDS's address is in a different place 5395 * than the sessions already acquired for DS's. 5396 */ 5397 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 5398 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5399 while (tdsp != NULL) { 5400 if (msad != NULL && msad->sin_family == AF_INET && 5401 sin->sin_addr.s_addr == msad->sin_addr.s_addr && 5402 sin->sin_port == msad->sin_port && 5403 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5404 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5405 *dspp = tdsp; 5406 NFSUNLOCKMNT(nmp); 5407 NFSCL_DEBUG(4, "fnd same addr\n"); 5408 return (0); 5409 } 5410 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5411 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5412 msad = (struct sockaddr_in *) 5413 tdsp->nfsclds_sockp->nr_nam; 5414 else 5415 msad = NULL; 5416 } 5417 NFSUNLOCKMNT(nmp); 5418 5419 /* No IP address match, so look for new/trunked one. */ 5420 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 5421 sad->sin_len = sizeof(*sad); 5422 sad->sin_family = AF_INET; 5423 sad->sin_port = sin->sin_port; 5424 sad->sin_addr.s_addr = sin->sin_addr.s_addr; 5425 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5426 nrp->nr_nam = (struct sockaddr *)sad; 5427 } else if (af == AF_INET6) { 5428 NFSLOCKMNT(nmp); 5429 /* 5430 * Check to see if we already have a session for this 5431 * address that is usable for a DS. 5432 * Note that the MDS's address is in a different place 5433 * than the sessions already acquired for DS's. 5434 */ 5435 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 5436 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5437 while (tdsp != NULL) { 5438 if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 5439 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 5440 &msad6->sin6_addr) && 5441 sin6->sin6_port == msad6->sin6_port && 5442 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5443 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5444 *dspp = tdsp; 5445 NFSUNLOCKMNT(nmp); 5446 return (0); 5447 } 5448 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5449 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5450 msad6 = (struct sockaddr_in6 *) 5451 tdsp->nfsclds_sockp->nr_nam; 5452 else 5453 msad6 = NULL; 5454 } 5455 NFSUNLOCKMNT(nmp); 5456 5457 /* No IP address match, so look for new/trunked one. */ 5458 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 5459 sad6->sin6_len = sizeof(*sad6); 5460 sad6->sin6_family = AF_INET6; 5461 sad6->sin6_port = sin6->sin6_port; 5462 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr, 5463 sizeof(struct in6_addr)); 5464 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5465 nrp->nr_nam = (struct sockaddr *)sad6; 5466 } else 5467 return (EPERM); 5468 5469 nrp->nr_sotype = SOCK_STREAM; 5470 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 5471 nrp->nr_prog = NFS_PROG; 5472 nrp->nr_vers = vers; 5473 5474 /* 5475 * Use the credentials that were used for the mount, which are 5476 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 5477 * Ref. counting the credentials with crhold() is probably not 5478 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 5479 * unmount, but I did it anyhow. 5480 */ 5481 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 5482 error = newnfs_connect(nmp, nrp, NULL, p, 0); 5483 NFSCL_DEBUG(3, "DS connect=%d\n", error); 5484 5485 dsp = NULL; 5486 /* Now, do the exchangeid and create session. */ 5487 if (error == 0) { 5488 if (vers == NFS_VER4) { 5489 error = nfsrpc_exchangeid(nmp, clp, nrp, 5490 NFSV4EXCH_USEPNFSDS, &dsp, nrp->nr_cred, p); 5491 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 5492 if (error != 0) 5493 newnfs_disconnect(nrp); 5494 } else { 5495 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, 5496 M_WAITOK | M_ZERO); 5497 dsp->nfsclds_flags |= NFSCLDS_DS; 5498 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */ 5499 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 5500 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 5501 NULL, MTX_DEF); 5502 } 5503 } 5504 if (error == 0) { 5505 dsp->nfsclds_sockp = nrp; 5506 if (vers == NFS_VER4) { 5507 NFSLOCKMNT(nmp); 5508 retv = nfscl_getsameserver(nmp, dsp, &tdsp, 5509 &sequenceid); 5510 NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 5511 if (retv == NFSDSP_USETHISSESSION && 5512 nfscl_dssameconn != 0) { 5513 NFSLOCKDS(tdsp); 5514 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN; 5515 NFSUNLOCKDS(tdsp); 5516 NFSUNLOCKMNT(nmp); 5517 /* 5518 * If there is already a session for this 5519 * server, use it. 5520 */ 5521 (void)newnfs_disconnect(nrp); 5522 nfscl_freenfsclds(dsp); 5523 *dspp = tdsp; 5524 return (0); 5525 } 5526 if (retv == NFSDSP_NOTFOUND) 5527 sequenceid = 5528 dsp->nfsclds_sess.nfsess_sequenceid; 5529 NFSUNLOCKMNT(nmp); 5530 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 5531 nrp, sequenceid, 0, nrp->nr_cred, p); 5532 NFSCL_DEBUG(3, "DS createsess=%d\n", error); 5533 } 5534 } else { 5535 NFSFREECRED(nrp->nr_cred); 5536 NFSFREEMUTEX(&nrp->nr_mtx); 5537 free(nrp->nr_nam, M_SONAME); 5538 free(nrp, M_NFSSOCKREQ); 5539 } 5540 if (error == 0) { 5541 NFSCL_DEBUG(3, "add DS session\n"); 5542 /* 5543 * Put it at the end of the list. That way the list 5544 * is ordered by when the entry was added. This matters 5545 * since the one done first is the one that should be 5546 * used for sequencid'ing any subsequent create sessions. 5547 */ 5548 NFSLOCKMNT(nmp); 5549 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 5550 NFSUNLOCKMNT(nmp); 5551 *dspp = dsp; 5552 } else if (dsp != NULL) { 5553 newnfs_disconnect(nrp); 5554 nfscl_freenfsclds(dsp); 5555 } 5556 return (error); 5557 } 5558 5559 /* 5560 * Do the NFSv4.1 Reclaim Complete. 5561 */ 5562 int 5563 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 5564 { 5565 uint32_t *tl; 5566 struct nfsrv_descript nfsd; 5567 struct nfsrv_descript *nd = &nfsd; 5568 int error; 5569 5570 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0, 5571 0); 5572 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5573 *tl = newnfs_false; 5574 nd->nd_flag |= ND_USEGSSNAME; 5575 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5576 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5577 if (error != 0) 5578 return (error); 5579 error = nd->nd_repstat; 5580 mbuf_freem(nd->nd_mrep); 5581 return (error); 5582 } 5583 5584 /* 5585 * Initialize the slot tables for a session. 5586 */ 5587 static void 5588 nfscl_initsessionslots(struct nfsclsession *sep) 5589 { 5590 int i; 5591 5592 for (i = 0; i < NFSV4_CBSLOTS; i++) { 5593 if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 5594 m_freem(sep->nfsess_cbslots[i].nfssl_reply); 5595 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 5596 } 5597 for (i = 0; i < 64; i++) 5598 sep->nfsess_slotseq[i] = 0; 5599 sep->nfsess_slots = 0; 5600 } 5601 5602 /* 5603 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 5604 */ 5605 int 5606 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5607 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) 5608 { 5609 struct nfsnode *np = VTONFS(vp); 5610 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 5611 struct nfscllayout *layp; 5612 struct nfscldevinfo *dip; 5613 struct nfsclflayout *rflp; 5614 struct mbuf *m; 5615 struct nfsclwritedsdorpc *drpc, *tdrpc; 5616 nfsv4stateid_t stateid; 5617 struct ucred *newcred; 5618 uint64_t lastbyte, len, off, oresid, xfer; 5619 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo; 5620 void *lckp; 5621 uint8_t *dev; 5622 void *iovbase = NULL; 5623 size_t iovlen = 0; 5624 off_t offs = 0; 5625 ssize_t resid = 0; 5626 5627 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 5628 (np->n_flag & NNOLAYOUT) != 0) 5629 return (EIO); 5630 /* Now, get a reference cnt on the clientid for this mount. */ 5631 if (nfscl_getref(nmp) == 0) 5632 return (EIO); 5633 5634 /* Find an appropriate stateid. */ 5635 newcred = NFSNEWCRED(cred); 5636 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 5637 rwaccess, 1, newcred, p, &stateid, &lckp); 5638 if (error != 0) { 5639 NFSFREECRED(newcred); 5640 nfscl_relref(nmp); 5641 return (error); 5642 } 5643 /* Search for a layout for this file. */ 5644 off = uiop->uio_offset; 5645 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 5646 np->n_fhp->nfh_len, off, &rflp, &recalled); 5647 if (layp == NULL || rflp == NULL) { 5648 if (recalled != 0) { 5649 NFSFREECRED(newcred); 5650 nfscl_relref(nmp); 5651 return (EIO); 5652 } 5653 if (layp != NULL) { 5654 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 5655 layp = NULL; 5656 } 5657 /* Try and get a Layout, if it is supported. */ 5658 if (rwaccess == NFSV4OPEN_ACCESSWRITE || 5659 (np->n_flag & NWRITEOPENED) != 0) 5660 iolaymode = NFSLAYOUTIOMODE_RW; 5661 else 5662 iolaymode = NFSLAYOUTIOMODE_READ; 5663 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 5664 NULL, &stateid, off, &layp, newcred, p); 5665 if (error != 0) { 5666 NFSLOCKNODE(np); 5667 np->n_flag |= NNOLAYOUT; 5668 NFSUNLOCKNODE(np); 5669 if (lckp != NULL) 5670 nfscl_lockderef(lckp); 5671 NFSFREECRED(newcred); 5672 if (layp != NULL) 5673 nfscl_rellayout(layp, 0); 5674 nfscl_relref(nmp); 5675 return (error); 5676 } 5677 } 5678 5679 /* 5680 * Loop around finding a layout that works for the first part of 5681 * this I/O operation, and then call the function that actually 5682 * does the RPC. 5683 */ 5684 eof = 0; 5685 len = (uint64_t)uiop->uio_resid; 5686 while (len > 0 && error == 0 && eof == 0) { 5687 off = uiop->uio_offset; 5688 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 5689 if (error == 0) { 5690 oresid = xfer = (uint64_t)uiop->uio_resid; 5691 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 5692 xfer = rflp->nfsfl_end - rflp->nfsfl_off; 5693 /* 5694 * For Flex File layout with mirrored DSs, select one 5695 * of them at random for reads. For writes and commits, 5696 * do all mirrors. 5697 */ 5698 m = NULL; 5699 tdrpc = drpc = NULL; 5700 firstmirror = 0; 5701 mirrorcnt = 1; 5702 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 && 5703 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) { 5704 if (rwaccess == NFSV4OPEN_ACCESSREAD) { 5705 firstmirror = arc4random() % mirrorcnt; 5706 mirrorcnt = firstmirror + 1; 5707 } else { 5708 if (docommit == 0) { 5709 /* 5710 * Save values, so uiop can be 5711 * rolled back upon a write 5712 * error. 5713 */ 5714 offs = uiop->uio_offset; 5715 resid = uiop->uio_resid; 5716 iovbase = 5717 uiop->uio_iov->iov_base; 5718 iovlen = uiop->uio_iov->iov_len; 5719 m = nfsm_uiombuflist(uiop, len, 5720 NULL, NULL); 5721 } 5722 tdrpc = drpc = malloc(sizeof(*drpc) * 5723 (mirrorcnt - 1), M_TEMP, M_WAITOK | 5724 M_ZERO); 5725 } 5726 } 5727 for (i = firstmirror; i < mirrorcnt && error == 0; i++){ 5728 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { 5729 dev = rflp->nfsfl_ffm[i].dev; 5730 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 5731 rflp->nfsfl_ffm[i].devp); 5732 } else { 5733 dev = rflp->nfsfl_dev; 5734 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 5735 rflp->nfsfl_devp); 5736 } 5737 if (dip != NULL) { 5738 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE) 5739 != 0) 5740 error = nfscl_dofflayoutio(vp, 5741 uiop, iomode, must_commit, 5742 &eof, &stateid, rwaccess, 5743 dip, layp, rflp, off, xfer, 5744 i, docommit, m, tdrpc, 5745 newcred, p); 5746 else 5747 error = nfscl_doflayoutio(vp, 5748 uiop, iomode, must_commit, 5749 &eof, &stateid, rwaccess, 5750 dip, layp, rflp, off, xfer, 5751 docommit, newcred, p); 5752 nfscl_reldevinfo(dip); 5753 } else 5754 error = EIO; 5755 tdrpc++; 5756 } 5757 if (m != NULL) 5758 m_freem(m); 5759 tdrpc = drpc; 5760 timo = hz / 50; /* Wait for 20msec. */ 5761 if (timo < 1) 5762 timo = 1; 5763 for (i = firstmirror; i < mirrorcnt - 1 && 5764 tdrpc != NULL; i++, tdrpc++) { 5765 /* 5766 * For the unused drpc entries, both inprog and 5767 * err == 0, so this loop won't break. 5768 */ 5769 while (tdrpc->inprog != 0 && tdrpc->done == 0) 5770 tsleep(&tdrpc->tsk, PVFS, "clrpcio", 5771 timo); 5772 if (error == 0 && tdrpc->err != 0) 5773 error = tdrpc->err; 5774 } 5775 free(drpc, M_TEMP); 5776 if (error == 0) { 5777 if (mirrorcnt > 1 && rwaccess == 5778 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 5779 NFSLOCKCLSTATE(); 5780 layp->nfsly_flags |= NFSLY_WRITTEN; 5781 NFSUNLOCKCLSTATE(); 5782 } 5783 lastbyte = off + xfer - 1; 5784 NFSLOCKCLSTATE(); 5785 if (lastbyte > layp->nfsly_lastbyte) 5786 layp->nfsly_lastbyte = lastbyte; 5787 NFSUNLOCKCLSTATE(); 5788 } else if (error == NFSERR_OPENMODE && 5789 rwaccess == NFSV4OPEN_ACCESSREAD) { 5790 NFSLOCKMNT(nmp); 5791 nmp->nm_state |= NFSSTA_OPENMODE; 5792 NFSUNLOCKMNT(nmp); 5793 } else 5794 error = EIO; 5795 if (error == 0) 5796 len -= (oresid - (uint64_t)uiop->uio_resid); 5797 else if (mirrorcnt > 1 && rwaccess == 5798 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 5799 /* 5800 * In case the rpc gets retried, roll the 5801 * uio fields changed by nfsm_uiombuflist() 5802 * back. 5803 */ 5804 uiop->uio_offset = offs; 5805 uiop->uio_resid = resid; 5806 uiop->uio_iov->iov_base = iovbase; 5807 uiop->uio_iov->iov_len = iovlen; 5808 } 5809 } 5810 } 5811 if (lckp != NULL) 5812 nfscl_lockderef(lckp); 5813 NFSFREECRED(newcred); 5814 nfscl_rellayout(layp, 0); 5815 nfscl_relref(nmp); 5816 return (error); 5817 } 5818 5819 /* 5820 * Make a copy of the mbuf chain and add an mbuf for null padding, as required. 5821 */ 5822 static struct mbuf * 5823 nfsm_copym(struct mbuf *m, int off, int xfer) 5824 { 5825 struct mbuf *m2, *m3, *m4; 5826 uint32_t *tl; 5827 int rem; 5828 5829 m2 = m_copym(m, off, xfer, M_WAITOK); 5830 rem = NFSM_RNDUP(xfer) - xfer; 5831 if (rem > 0) { 5832 /* 5833 * The zero padding to a multiple of 4 bytes is required by 5834 * the XDR. So that the mbufs copied by reference aren't 5835 * modified, add an mbuf with the zero'd bytes to the list. 5836 * rem will be a maximum of 3, so one zero'd uint32_t is 5837 * sufficient. 5838 */ 5839 m3 = m2; 5840 while (m3->m_next != NULL) 5841 m3 = m3->m_next; 5842 NFSMGET(m4); 5843 tl = NFSMTOD(m4, uint32_t *); 5844 *tl = 0; 5845 mbuf_setlen(m4, rem); 5846 mbuf_setnext(m3, m4); 5847 } 5848 return (m2); 5849 } 5850 5851 /* 5852 * Find a file layout that will handle the first bytes of the requested 5853 * range and return the information from it needed to the I/O operation. 5854 */ 5855 int 5856 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 5857 struct nfsclflayout **retflpp) 5858 { 5859 struct nfsclflayout *flp, *nflp, *rflp; 5860 uint32_t rw; 5861 5862 rflp = NULL; 5863 rw = rwaccess; 5864 /* For reading, do the Read list first and then the Write list. */ 5865 do { 5866 if (rw == NFSV4OPEN_ACCESSREAD) 5867 flp = LIST_FIRST(&lyp->nfsly_flayread); 5868 else 5869 flp = LIST_FIRST(&lyp->nfsly_flayrw); 5870 while (flp != NULL) { 5871 nflp = LIST_NEXT(flp, nfsfl_list); 5872 if (flp->nfsfl_off > off) 5873 break; 5874 if (flp->nfsfl_end > off && 5875 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 5876 rflp = flp; 5877 flp = nflp; 5878 } 5879 if (rw == NFSV4OPEN_ACCESSREAD) 5880 rw = NFSV4OPEN_ACCESSWRITE; 5881 else 5882 rw = 0; 5883 } while (rw != 0); 5884 if (rflp != NULL) { 5885 /* This one covers the most bytes starting at off. */ 5886 *retflpp = rflp; 5887 return (0); 5888 } 5889 return (EIO); 5890 } 5891 5892 /* 5893 * Do I/O using an NFSv4.1 file layout. 5894 */ 5895 static int 5896 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5897 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 5898 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 5899 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) 5900 { 5901 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 5902 int commit_thru_mds, error, stripe_index, stripe_pos; 5903 struct nfsnode *np; 5904 struct nfsfh *fhp; 5905 struct nfsclds **dspp; 5906 5907 np = VTONFS(vp); 5908 rel_off = off - flp->nfsfl_patoff; 5909 stripe_unit_size = (flp->nfsfl_util >> 6) & 0x3ffffff; 5910 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 5911 dp->nfsdi_stripecnt; 5912 transfer = stripe_unit_size - (rel_off % stripe_unit_size); 5913 error = 0; 5914 5915 /* Loop around, doing I/O for each stripe unit. */ 5916 while (len > 0 && error == 0) { 5917 stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 5918 dspp = nfsfldi_addr(dp, stripe_index); 5919 if (len > transfer && docommit == 0) 5920 xfer = transfer; 5921 else 5922 xfer = len; 5923 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 5924 /* Dense layout. */ 5925 if (stripe_pos >= flp->nfsfl_fhcnt) 5926 return (EIO); 5927 fhp = flp->nfsfl_fh[stripe_pos]; 5928 io_off = (rel_off / (stripe_unit_size * 5929 dp->nfsdi_stripecnt)) * stripe_unit_size + 5930 rel_off % stripe_unit_size; 5931 } else { 5932 /* Sparse layout. */ 5933 if (flp->nfsfl_fhcnt > 1) { 5934 if (stripe_index >= flp->nfsfl_fhcnt) 5935 return (EIO); 5936 fhp = flp->nfsfl_fh[stripe_index]; 5937 } else if (flp->nfsfl_fhcnt == 1) 5938 fhp = flp->nfsfl_fh[0]; 5939 else 5940 fhp = np->n_fhp; 5941 io_off = off; 5942 } 5943 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { 5944 commit_thru_mds = 1; 5945 if (docommit != 0) 5946 error = EIO; 5947 } else { 5948 commit_thru_mds = 0; 5949 mtx_lock(&np->n_mtx); 5950 np->n_flag |= NDSCOMMIT; 5951 mtx_unlock(&np->n_mtx); 5952 } 5953 if (docommit != 0) { 5954 if (error == 0) 5955 error = nfsrpc_commitds(vp, io_off, xfer, 5956 *dspp, fhp, 0, 0, cred, p); 5957 if (error == 0) { 5958 /* 5959 * Set both eof and uio_resid = 0 to end any 5960 * loops. 5961 */ 5962 *eofp = 1; 5963 uiop->uio_resid = 0; 5964 } else { 5965 mtx_lock(&np->n_mtx); 5966 np->n_flag &= ~NDSCOMMIT; 5967 mtx_unlock(&np->n_mtx); 5968 } 5969 } else if (rwflag == NFSV4OPEN_ACCESSREAD) 5970 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 5971 io_off, xfer, fhp, 0, 0, 0, cred, p); 5972 else { 5973 error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 5974 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 5975 0, 0, 0, cred, p); 5976 if (error == 0) { 5977 NFSLOCKCLSTATE(); 5978 lyp->nfsly_flags |= NFSLY_WRITTEN; 5979 NFSUNLOCKCLSTATE(); 5980 } 5981 } 5982 if (error == 0) { 5983 transfer = stripe_unit_size; 5984 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 5985 len -= xfer; 5986 off += xfer; 5987 } 5988 } 5989 return (error); 5990 } 5991 5992 /* 5993 * Do I/O using an NFSv4.1 flex file layout. 5994 */ 5995 static int 5996 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 5997 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 5998 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 5999 uint64_t len, int mirror, int docommit, struct mbuf *mp, 6000 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6001 { 6002 uint64_t transfer, xfer; 6003 int error, rel_off; 6004 struct nfsnode *np; 6005 struct nfsfh *fhp; 6006 struct nfsclds **dspp; 6007 struct ucred *tcred; 6008 struct mbuf *m; 6009 6010 np = VTONFS(vp); 6011 error = 0; 6012 rel_off = 0; 6013 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, 6014 (uintmax_t)len); 6015 /* Loop around, doing I/O for each stripe unit. */ 6016 while (len > 0 && error == 0) { 6017 dspp = nfsfldi_addr(dp, 0); 6018 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex]; 6019 stateidp = &flp->nfsfl_ffm[mirror].st; 6020 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n", 6021 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid); 6022 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) { 6023 tcred = NFSNEWCRED(cred); 6024 tcred->cr_uid = flp->nfsfl_ffm[mirror].user; 6025 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group; 6026 tcred->cr_ngroups = 1; 6027 } else 6028 tcred = cred; 6029 if (rwflag == NFSV4OPEN_ACCESSREAD) 6030 transfer = dp->nfsdi_rsize; 6031 else 6032 transfer = dp->nfsdi_wsize; 6033 mtx_lock(&np->n_mtx); 6034 np->n_flag |= NDSCOMMIT; 6035 mtx_unlock(&np->n_mtx); 6036 if (len > transfer && docommit == 0) 6037 xfer = transfer; 6038 else 6039 xfer = len; 6040 if (docommit != 0) { 6041 if (error == 0) { 6042 /* 6043 * Do last mirrored DS commit with this thread. 6044 */ 6045 if (mirror < flp->nfsfl_mirrorcnt - 1) 6046 error = nfsio_commitds(vp, off, xfer, 6047 *dspp, fhp, dp->nfsdi_vers, 6048 dp->nfsdi_minorvers, drpc, tcred, 6049 p); 6050 else 6051 error = nfsrpc_commitds(vp, off, xfer, 6052 *dspp, fhp, dp->nfsdi_vers, 6053 dp->nfsdi_minorvers, tcred, p); 6054 NFSCL_DEBUG(4, "commitds=%d\n", error); 6055 if (error != 0 && error != EACCES && error != 6056 ESTALE) { 6057 NFSCL_DEBUG(4, 6058 "DS layreterr for commit\n"); 6059 nfscl_dserr(NFSV4OP_COMMIT, error, dp, 6060 lyp, *dspp); 6061 } 6062 } 6063 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error); 6064 if (error == 0) { 6065 /* 6066 * Set both eof and uio_resid = 0 to end any 6067 * loops. 6068 */ 6069 *eofp = 1; 6070 uiop->uio_resid = 0; 6071 } else { 6072 mtx_lock(&np->n_mtx); 6073 np->n_flag &= ~NDSCOMMIT; 6074 mtx_unlock(&np->n_mtx); 6075 } 6076 } else if (rwflag == NFSV4OPEN_ACCESSREAD) { 6077 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6078 off, xfer, fhp, 1, dp->nfsdi_vers, 6079 dp->nfsdi_minorvers, tcred, p); 6080 NFSCL_DEBUG(4, "readds=%d\n", error); 6081 if (error != 0 && error != EACCES && error != ESTALE) { 6082 NFSCL_DEBUG(4, "DS layreterr for read\n"); 6083 nfscl_dserr(NFSV4OP_READ, error, dp, lyp, 6084 *dspp); 6085 } 6086 } else { 6087 if (flp->nfsfl_mirrorcnt == 1) { 6088 error = nfsrpc_writeds(vp, uiop, iomode, 6089 must_commit, stateidp, *dspp, off, xfer, 6090 fhp, 0, 1, dp->nfsdi_vers, 6091 dp->nfsdi_minorvers, tcred, p); 6092 if (error == 0) { 6093 NFSLOCKCLSTATE(); 6094 lyp->nfsly_flags |= NFSLY_WRITTEN; 6095 NFSUNLOCKCLSTATE(); 6096 } 6097 } else { 6098 m = nfsm_copym(mp, rel_off, xfer); 6099 NFSCL_DEBUG(4, "mcopy reloff=%d xfer=%jd\n", 6100 rel_off, (uintmax_t)xfer); 6101 /* 6102 * Do last write to a mirrored DS with this 6103 * thread. 6104 */ 6105 if (mirror < flp->nfsfl_mirrorcnt - 1) 6106 error = nfsio_writedsmir(vp, iomode, 6107 must_commit, stateidp, *dspp, off, 6108 xfer, fhp, m, dp->nfsdi_vers, 6109 dp->nfsdi_minorvers, drpc, tcred, 6110 p); 6111 else 6112 error = nfsrpc_writedsmir(vp, iomode, 6113 must_commit, stateidp, *dspp, off, 6114 xfer, fhp, m, dp->nfsdi_vers, 6115 dp->nfsdi_minorvers, tcred, p); 6116 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); 6117 if (error != 0 && error != EACCES && error != 6118 ESTALE) { 6119 NFSCL_DEBUG(4, 6120 "DS layreterr for write\n"); 6121 nfscl_dserr(NFSV4OP_WRITE, error, dp, 6122 lyp, *dspp); 6123 } 6124 } 6125 } 6126 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error); 6127 if (error == 0) { 6128 len -= xfer; 6129 off += xfer; 6130 rel_off += xfer; 6131 } 6132 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) 6133 NFSFREECRED(tcred); 6134 } 6135 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error); 6136 return (error); 6137 } 6138 6139 /* 6140 * The actual read RPC done to a DS. 6141 */ 6142 static int 6143 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 6144 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex, 6145 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) 6146 { 6147 uint32_t *tl; 6148 int attrflag, error, retlen; 6149 struct nfsrv_descript nfsd; 6150 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6151 struct nfsrv_descript *nd = &nfsd; 6152 struct nfssockreq *nrp; 6153 struct nfsvattr na; 6154 6155 nd->nd_mrep = NULL; 6156 if (vers == 0 || vers == NFS_VER4) { 6157 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, 6158 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6159 vers = NFS_VER4; 6160 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers); 6161 if (flex != 0) 6162 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6163 else 6164 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6165 } else { 6166 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh, 6167 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6168 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n"); 6169 } 6170 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 6171 txdr_hyper(io_off, tl); 6172 *(tl + 2) = txdr_unsigned(len); 6173 nrp = dsp->nfsclds_sockp; 6174 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp); 6175 if (nrp == NULL) 6176 /* If NULL, use the MDS socket. */ 6177 nrp = &nmp->nm_sockreq; 6178 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6179 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6180 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat, 6181 error); 6182 if (error != 0) 6183 return (error); 6184 if (vers == NFS_VER3) { 6185 error = nfscl_postop_attr(nd, &na, &attrflag, NULL); 6186 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error); 6187 if (error != 0) 6188 goto nfsmout; 6189 } 6190 if (nd->nd_repstat != 0) { 6191 error = nd->nd_repstat; 6192 goto nfsmout; 6193 } 6194 if (vers == NFS_VER3) { 6195 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6196 *eofp = fxdr_unsigned(int, *(tl + 1)); 6197 } else { 6198 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6199 *eofp = fxdr_unsigned(int, *tl); 6200 } 6201 NFSM_STRSIZ(retlen, len); 6202 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp); 6203 error = nfsm_mbufuio(nd, uiop, retlen); 6204 nfsmout: 6205 if (nd->nd_mrep != NULL) 6206 mbuf_freem(nd->nd_mrep); 6207 return (error); 6208 } 6209 6210 /* 6211 * The actual write RPC done to a DS. 6212 */ 6213 static int 6214 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6215 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6216 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers, 6217 struct ucred *cred, NFSPROC_T *p) 6218 { 6219 uint32_t *tl; 6220 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6221 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC; 6222 int32_t backup; 6223 struct nfsrv_descript nfsd; 6224 struct nfsrv_descript *nd = &nfsd; 6225 struct nfssockreq *nrp; 6226 struct nfsvattr na; 6227 6228 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 6229 nd->nd_mrep = NULL; 6230 if (vers == 0 || vers == NFS_VER4) { 6231 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6232 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6233 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers); 6234 vers = NFS_VER4; 6235 if (flex != 0) 6236 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6237 else 6238 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6239 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6240 } else { 6241 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6242 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6243 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n"); 6244 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6245 } 6246 txdr_hyper(io_off, tl); 6247 tl += 2; 6248 if (vers == NFS_VER3) 6249 *tl++ = txdr_unsigned(len); 6250 *tl++ = txdr_unsigned(*iomode); 6251 *tl = txdr_unsigned(len); 6252 nfsm_uiombuf(nd, uiop, len); 6253 nrp = dsp->nfsclds_sockp; 6254 if (nrp == NULL) 6255 /* If NULL, use the MDS socket. */ 6256 nrp = &nmp->nm_sockreq; 6257 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6258 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6259 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error, 6260 nd->nd_repstat); 6261 if (error != 0) 6262 return (error); 6263 if (nd->nd_repstat != 0) { 6264 /* 6265 * In case the rpc gets retried, roll 6266 * the uio fileds changed by nfsm_uiombuf() 6267 * back. 6268 */ 6269 uiop->uio_offset -= len; 6270 uio_uio_resid_add(uiop, len); 6271 uio_iov_base_add(uiop, -len); 6272 uio_iov_len_add(uiop, len); 6273 error = nd->nd_repstat; 6274 } else { 6275 if (vers == NFS_VER3) { 6276 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6277 NULL); 6278 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error); 6279 if (error != 0) 6280 goto nfsmout; 6281 } 6282 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6283 rlen = fxdr_unsigned(int, *tl++); 6284 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen); 6285 if (rlen == 0) { 6286 error = NFSERR_IO; 6287 goto nfsmout; 6288 } else if (rlen < len) { 6289 backup = len - rlen; 6290 uio_iov_base_add(uiop, -(backup)); 6291 uio_iov_len_add(uiop, backup); 6292 uiop->uio_offset -= backup; 6293 uio_uio_resid_add(uiop, backup); 6294 len = rlen; 6295 } 6296 commit = fxdr_unsigned(int, *tl++); 6297 6298 /* 6299 * Return the lowest commitment level 6300 * obtained by any of the RPCs. 6301 */ 6302 if (committed == NFSWRITE_FILESYNC) 6303 committed = commit; 6304 else if (committed == NFSWRITE_DATASYNC && 6305 commit == NFSWRITE_UNSTABLE) 6306 committed = commit; 6307 if (commit_thru_mds != 0) { 6308 NFSLOCKMNT(nmp); 6309 if (!NFSHASWRITEVERF(nmp)) { 6310 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6311 NFSSETWRITEVERF(nmp); 6312 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 6313 *must_commit = 1; 6314 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6315 } 6316 NFSUNLOCKMNT(nmp); 6317 } else { 6318 NFSLOCKDS(dsp); 6319 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6320 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6321 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6322 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6323 *must_commit = 1; 6324 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6325 } 6326 NFSUNLOCKDS(dsp); 6327 } 6328 } 6329 nfsmout: 6330 if (nd->nd_mrep != NULL) 6331 mbuf_freem(nd->nd_mrep); 6332 *iomode = committed; 6333 if (nd->nd_repstat != 0 && error == 0) 6334 error = nd->nd_repstat; 6335 return (error); 6336 } 6337 6338 /* 6339 * The actual write RPC done to a DS. 6340 * This variant is called from a separate kernel process for mirrors. 6341 * Any short write is considered an IO error. 6342 */ 6343 static int 6344 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6345 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6346 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6347 struct ucred *cred, NFSPROC_T *p) 6348 { 6349 uint32_t *tl; 6350 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6351 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen; 6352 struct nfsrv_descript nfsd; 6353 struct nfsrv_descript *nd = &nfsd; 6354 struct nfssockreq *nrp; 6355 struct nfsvattr na; 6356 6357 nd->nd_mrep = NULL; 6358 if (vers == 0 || vers == NFS_VER4) { 6359 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6360 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6361 vers = NFS_VER4; 6362 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n", 6363 minorvers); 6364 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6365 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6366 } else { 6367 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6368 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6369 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n"); 6370 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6371 } 6372 txdr_hyper(io_off, tl); 6373 tl += 2; 6374 if (vers == NFS_VER3) 6375 *tl++ = txdr_unsigned(len); 6376 *tl++ = txdr_unsigned(*iomode); 6377 *tl = txdr_unsigned(len); 6378 if (len > 0) { 6379 /* Put data in mbuf chain. */ 6380 nd->nd_mb->m_next = m; 6381 /* Set nd_mb and nd_bpos to end of data. */ 6382 while (m->m_next != NULL) 6383 m = m->m_next; 6384 nd->nd_mb = m; 6385 nd->nd_bpos = mtod(m, char *) + m->m_len; 6386 NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len); 6387 } 6388 nrp = dsp->nfsclds_sockp; 6389 if (nrp == NULL) 6390 /* If NULL, use the MDS socket. */ 6391 nrp = &nmp->nm_sockreq; 6392 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6393 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6394 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error, 6395 nd->nd_repstat); 6396 if (error != 0) 6397 return (error); 6398 if (nd->nd_repstat != 0) 6399 error = nd->nd_repstat; 6400 else { 6401 if (vers == NFS_VER3) { 6402 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6403 NULL); 6404 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n", 6405 error); 6406 if (error != 0) 6407 goto nfsmout; 6408 } 6409 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6410 rlen = fxdr_unsigned(int, *tl++); 6411 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, 6412 rlen); 6413 if (rlen != len) { 6414 error = NFSERR_IO; 6415 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", 6416 len, rlen); 6417 goto nfsmout; 6418 } 6419 commit = fxdr_unsigned(int, *tl++); 6420 6421 /* 6422 * Return the lowest commitment level 6423 * obtained by any of the RPCs. 6424 */ 6425 if (committed == NFSWRITE_FILESYNC) 6426 committed = commit; 6427 else if (committed == NFSWRITE_DATASYNC && 6428 commit == NFSWRITE_UNSTABLE) 6429 committed = commit; 6430 NFSLOCKDS(dsp); 6431 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6432 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6433 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6434 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6435 *must_commit = 1; 6436 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6437 } 6438 NFSUNLOCKDS(dsp); 6439 } 6440 nfsmout: 6441 if (nd->nd_mrep != NULL) 6442 mbuf_freem(nd->nd_mrep); 6443 *iomode = committed; 6444 if (nd->nd_repstat != 0 && error == 0) 6445 error = nd->nd_repstat; 6446 return (error); 6447 } 6448 6449 /* 6450 * Start up the thread that will execute nfsrpc_writedsmir(). 6451 */ 6452 static void 6453 start_writedsmir(void *arg, int pending) 6454 { 6455 struct nfsclwritedsdorpc *drpc; 6456 6457 drpc = (struct nfsclwritedsdorpc *)arg; 6458 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode, 6459 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len, 6460 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred, 6461 drpc->p); 6462 drpc->done = 1; 6463 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err); 6464 } 6465 6466 /* 6467 * Set up the write DS mirror call for the pNFS I/O thread. 6468 */ 6469 static int 6470 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6471 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len, 6472 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6473 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6474 { 6475 int error, ret; 6476 6477 error = 0; 6478 drpc->done = 0; 6479 drpc->vp = vp; 6480 drpc->iomode = *iomode; 6481 drpc->must_commit = *must_commit; 6482 drpc->stateidp = stateidp; 6483 drpc->dsp = dsp; 6484 drpc->off = off; 6485 drpc->len = len; 6486 drpc->fhp = fhp; 6487 drpc->m = m; 6488 drpc->vers = vers; 6489 drpc->minorvers = minorvers; 6490 drpc->cred = cred; 6491 drpc->p = p; 6492 drpc->inprog = 0; 6493 ret = EIO; 6494 if (nfs_pnfsiothreads != 0) { 6495 ret = nfs_pnfsio(start_writedsmir, drpc); 6496 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret); 6497 } 6498 if (ret != 0) 6499 error = nfsrpc_writedsmir(vp, iomode, must_commit, stateidp, 6500 dsp, off, len, fhp, m, vers, minorvers, cred, p); 6501 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error); 6502 return (error); 6503 } 6504 6505 /* 6506 * Free up the nfsclds structure. 6507 */ 6508 void 6509 nfscl_freenfsclds(struct nfsclds *dsp) 6510 { 6511 int i; 6512 6513 if (dsp == NULL) 6514 return; 6515 if (dsp->nfsclds_sockp != NULL) { 6516 NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 6517 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 6518 free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 6519 free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 6520 } 6521 NFSFREEMUTEX(&dsp->nfsclds_mtx); 6522 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 6523 for (i = 0; i < NFSV4_CBSLOTS; i++) { 6524 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 6525 m_freem( 6526 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 6527 } 6528 free(dsp, M_NFSCLDS); 6529 } 6530 6531 static enum nfsclds_state 6532 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 6533 struct nfsclds **retdspp, uint32_t *sequencep) 6534 { 6535 struct nfsclds *dsp; 6536 int fndseq; 6537 6538 /* 6539 * Search the list of nfsclds structures for one with the same 6540 * server. 6541 */ 6542 fndseq = 0; 6543 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 6544 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 6545 dsp->nfsclds_servownlen != 0 && 6546 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 6547 dsp->nfsclds_servownlen) && 6548 dsp->nfsclds_sess.nfsess_defunct == 0) { 6549 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 6550 TAILQ_FIRST(&nmp->nm_sess), dsp, 6551 dsp->nfsclds_flags); 6552 if (fndseq == 0) { 6553 /* Get sequenceid# from first entry. */ 6554 *sequencep = 6555 dsp->nfsclds_sess.nfsess_sequenceid; 6556 fndseq = 1; 6557 } 6558 /* Server major id matches. */ 6559 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 6560 *retdspp = dsp; 6561 return (NFSDSP_USETHISSESSION); 6562 } 6563 6564 } 6565 } 6566 if (fndseq != 0) 6567 return (NFSDSP_SEQTHISSESSION); 6568 return (NFSDSP_NOTFOUND); 6569 } 6570 6571 /* 6572 * NFS commit rpc to a NFSv4.1 DS. 6573 */ 6574 static int 6575 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 6576 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, 6577 NFSPROC_T *p) 6578 { 6579 uint32_t *tl; 6580 struct nfsrv_descript nfsd, *nd = &nfsd; 6581 struct nfsmount *nmp = VFSTONFS(vnode_mount(vp)); 6582 struct nfssockreq *nrp; 6583 struct nfsvattr na; 6584 int attrflag, error; 6585 6586 nd->nd_mrep = NULL; 6587 if (vers == 0 || vers == NFS_VER4) { 6588 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, 6589 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6590 vers = NFS_VER4; 6591 } else 6592 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh, 6593 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6594 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers, 6595 minorvers); 6596 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 6597 txdr_hyper(offset, tl); 6598 tl += 2; 6599 *tl = txdr_unsigned(cnt); 6600 nrp = dsp->nfsclds_sockp; 6601 if (nrp == NULL) 6602 /* If NULL, use the MDS socket. */ 6603 nrp = &nmp->nm_sockreq; 6604 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6605 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6606 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error, 6607 nd->nd_repstat); 6608 if (error != 0) 6609 return (error); 6610 if (nd->nd_repstat == 0) { 6611 if (vers == NFS_VER3) { 6612 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6613 NULL); 6614 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error); 6615 if (error != 0) 6616 goto nfsmout; 6617 } 6618 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 6619 NFSLOCKDS(dsp); 6620 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6621 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6622 error = NFSERR_STALEWRITEVERF; 6623 } 6624 NFSUNLOCKDS(dsp); 6625 } 6626 nfsmout: 6627 if (error == 0 && nd->nd_repstat != 0) 6628 error = nd->nd_repstat; 6629 mbuf_freem(nd->nd_mrep); 6630 return (error); 6631 } 6632 6633 /* 6634 * Start up the thread that will execute nfsrpc_commitds(). 6635 */ 6636 static void 6637 start_commitds(void *arg, int pending) 6638 { 6639 struct nfsclwritedsdorpc *drpc; 6640 6641 drpc = (struct nfsclwritedsdorpc *)arg; 6642 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len, 6643 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, 6644 drpc->p); 6645 drpc->done = 1; 6646 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err); 6647 } 6648 6649 /* 6650 * Set up the commit DS mirror call for the pNFS I/O thread. 6651 */ 6652 static int 6653 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 6654 struct nfsfh *fhp, int vers, int minorvers, 6655 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6656 { 6657 int error, ret; 6658 6659 error = 0; 6660 drpc->done = 0; 6661 drpc->vp = vp; 6662 drpc->off = offset; 6663 drpc->len = cnt; 6664 drpc->dsp = dsp; 6665 drpc->fhp = fhp; 6666 drpc->vers = vers; 6667 drpc->minorvers = minorvers; 6668 drpc->cred = cred; 6669 drpc->p = p; 6670 drpc->inprog = 0; 6671 ret = EIO; 6672 if (nfs_pnfsiothreads != 0) { 6673 ret = nfs_pnfsio(start_commitds, drpc); 6674 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret); 6675 } 6676 if (ret != 0) 6677 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers, 6678 minorvers, cred, p); 6679 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error); 6680 return (error); 6681 } 6682 6683 /* 6684 * Set up the XDR arguments for the LayoutGet operation. 6685 */ 6686 static void 6687 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, 6688 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype, 6689 int layoutlen, int usecurstateid) 6690 { 6691 uint32_t *tl; 6692 6693 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 6694 NFSX_STATEID); 6695 *tl++ = newnfs_false; /* Don't signal availability. */ 6696 *tl++ = txdr_unsigned(layouttype); 6697 *tl++ = txdr_unsigned(iomode); 6698 txdr_hyper(offset, tl); 6699 tl += 2; 6700 txdr_hyper(len, tl); 6701 tl += 2; 6702 txdr_hyper(minlen, tl); 6703 tl += 2; 6704 if (usecurstateid != 0) { 6705 /* Special stateid for Current stateid. */ 6706 *tl++ = txdr_unsigned(1); 6707 *tl++ = 0; 6708 *tl++ = 0; 6709 *tl++ = 0; 6710 } else { 6711 *tl++ = txdr_unsigned(stateidp->seqid); 6712 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 6713 *tl++ = stateidp->other[0]; 6714 *tl++ = stateidp->other[1]; 6715 *tl++ = stateidp->other[2]; 6716 } 6717 *tl = txdr_unsigned(layoutlen); 6718 } 6719 6720 /* 6721 * Parse the reply for a successful LayoutGet operation. 6722 */ 6723 static int 6724 nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp, 6725 int *retonclosep, struct nfsclflayouthead *flhp) 6726 { 6727 uint32_t *tl; 6728 struct nfsclflayout *flp, *prevflp, *tflp; 6729 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen; 6730 int m, mirrorcnt; 6731 uint64_t retlen, off; 6732 struct nfsfh *nfhp; 6733 uint8_t *cp; 6734 uid_t user; 6735 gid_t grp; 6736 6737 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n"); 6738 error = 0; 6739 flp = NULL; 6740 gotiomode = -1; 6741 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 6742 if (*tl++ != 0) 6743 *retonclosep = 1; 6744 else 6745 *retonclosep = 0; 6746 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 6747 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 6748 (int)stateidp->seqid); 6749 stateidp->other[0] = *tl++; 6750 stateidp->other[1] = *tl++; 6751 stateidp->other[2] = *tl++; 6752 cnt = fxdr_unsigned(int, *tl); 6753 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 6754 if (cnt <= 0 || cnt > 10000) { 6755 /* Don't accept more than 10000 layouts in reply. */ 6756 error = NFSERR_BADXDR; 6757 goto nfsmout; 6758 } 6759 for (i = 0; i < cnt; i++) { 6760 /* Dissect to the layout type. */ 6761 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 6762 3 * NFSX_UNSIGNED); 6763 off = fxdr_hyper(tl); tl += 2; 6764 retlen = fxdr_hyper(tl); tl += 2; 6765 iomode = fxdr_unsigned(int, *tl++); 6766 laytype = fxdr_unsigned(int, *tl); 6767 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype, 6768 (uintmax_t)off, (uintmax_t)retlen, iomode); 6769 /* Ignore length of layout body for now. */ 6770 if (laytype == NFSLAYOUT_NFSV4_1_FILES) { 6771 /* Parse the File layout up to fhcnt. */ 6772 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + 6773 NFSX_HYPER + NFSX_V4DEVICEID); 6774 fhcnt = fxdr_unsigned(int, *(tl + 4 + 6775 NFSX_V4DEVICEID / NFSX_UNSIGNED)); 6776 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 6777 if (fhcnt < 0 || fhcnt > 100) { 6778 /* Don't accept more than 100 file handles. */ 6779 error = NFSERR_BADXDR; 6780 goto nfsmout; 6781 } 6782 if (fhcnt > 0) 6783 flp = malloc(sizeof(*flp) + fhcnt * 6784 sizeof(struct nfsfh *), M_NFSFLAYOUT, 6785 M_WAITOK); 6786 else 6787 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, 6788 M_WAITOK); 6789 flp->nfsfl_flags = NFSFL_FILE; 6790 flp->nfsfl_fhcnt = 0; 6791 flp->nfsfl_devp = NULL; 6792 flp->nfsfl_off = off; 6793 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 6794 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 6795 else 6796 flp->nfsfl_end = flp->nfsfl_off + retlen; 6797 flp->nfsfl_iomode = iomode; 6798 if (gotiomode == -1) 6799 gotiomode = flp->nfsfl_iomode; 6800 /* Ignore layout body length for now. */ 6801 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 6802 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 6803 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 6804 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 6805 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 6806 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 6807 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n", 6808 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff); 6809 for (j = 0; j < fhcnt; j++) { 6810 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6811 nfhlen = fxdr_unsigned(int, *tl); 6812 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 6813 error = NFSERR_BADXDR; 6814 goto nfsmout; 6815 } 6816 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, 6817 M_NFSFH, M_WAITOK); 6818 flp->nfsfl_fh[j] = nfhp; 6819 flp->nfsfl_fhcnt++; 6820 nfhp->nfh_len = nfhlen; 6821 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 6822 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 6823 } 6824 } else if (laytype == NFSLAYOUT_FLEXFILE) { 6825 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 6826 NFSX_HYPER); 6827 mirrorcnt = fxdr_unsigned(int, *(tl + 2)); 6828 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt); 6829 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) { 6830 error = NFSERR_BADXDR; 6831 goto nfsmout; 6832 } 6833 flp = malloc(sizeof(*flp) + mirrorcnt * 6834 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK); 6835 flp->nfsfl_flags = NFSFL_FLEXFILE; 6836 flp->nfsfl_mirrorcnt = mirrorcnt; 6837 for (j = 0; j < mirrorcnt; j++) 6838 flp->nfsfl_ffm[j].devp = NULL; 6839 flp->nfsfl_off = off; 6840 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 6841 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 6842 else 6843 flp->nfsfl_end = flp->nfsfl_off + retlen; 6844 flp->nfsfl_iomode = iomode; 6845 if (gotiomode == -1) 6846 gotiomode = flp->nfsfl_iomode; 6847 flp->nfsfl_stripeunit = fxdr_hyper(tl); 6848 NFSCL_DEBUG(4, "stripeunit=%ju\n", 6849 (uintmax_t)flp->nfsfl_stripeunit); 6850 for (j = 0; j < mirrorcnt; j++) { 6851 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6852 k = fxdr_unsigned(int, *tl); 6853 if (k < 1 || k > 128) { 6854 error = NFSERR_BADXDR; 6855 goto nfsmout; 6856 } 6857 NFSCL_DEBUG(4, "servercnt=%d\n", k); 6858 for (l = 0; l < k; l++) { 6859 NFSM_DISSECT(tl, uint32_t *, 6860 NFSX_V4DEVICEID + NFSX_STATEID + 6861 2 * NFSX_UNSIGNED); 6862 if (l == 0) { 6863 /* Just use the first server. */ 6864 NFSBCOPY(tl, 6865 flp->nfsfl_ffm[j].dev, 6866 NFSX_V4DEVICEID); 6867 tl += (NFSX_V4DEVICEID / 6868 NFSX_UNSIGNED); 6869 tl++; 6870 flp->nfsfl_ffm[j].st.seqid = 6871 *tl++; 6872 flp->nfsfl_ffm[j].st.other[0] = 6873 *tl++; 6874 flp->nfsfl_ffm[j].st.other[1] = 6875 *tl++; 6876 flp->nfsfl_ffm[j].st.other[2] = 6877 *tl++; 6878 NFSCL_DEBUG(4, "st.seqid=%u " 6879 "st.o0=0x%x st.o1=0x%x " 6880 "st.o2=0x%x\n", 6881 flp->nfsfl_ffm[j].st.seqid, 6882 flp->nfsfl_ffm[j].st.other[0], 6883 flp->nfsfl_ffm[j].st.other[1], 6884 flp->nfsfl_ffm[j].st.other[2]); 6885 } else 6886 tl += ((NFSX_V4DEVICEID + 6887 NFSX_STATEID + 6888 NFSX_UNSIGNED) / 6889 NFSX_UNSIGNED); 6890 fhcnt = fxdr_unsigned(int, *tl); 6891 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 6892 if (fhcnt < 1 || 6893 fhcnt > NFSDEV_MAXVERS) { 6894 error = NFSERR_BADXDR; 6895 goto nfsmout; 6896 } 6897 for (m = 0; m < fhcnt; m++) { 6898 NFSM_DISSECT(tl, uint32_t *, 6899 NFSX_UNSIGNED); 6900 nfhlen = fxdr_unsigned(int, 6901 *tl); 6902 NFSCL_DEBUG(4, "nfhlen=%d\n", 6903 nfhlen); 6904 if (nfhlen <= 0 || nfhlen > 6905 NFSX_V4FHMAX) { 6906 error = NFSERR_BADXDR; 6907 goto nfsmout; 6908 } 6909 NFSM_DISSECT(cp, uint8_t *, 6910 NFSM_RNDUP(nfhlen)); 6911 if (l == 0) { 6912 flp->nfsfl_ffm[j].fhcnt 6913 = fhcnt; 6914 nfhp = malloc( 6915 sizeof(*nfhp) + 6916 nfhlen - 1, M_NFSFH, 6917 M_WAITOK); 6918 flp->nfsfl_ffm[j].fh[m] 6919 = nfhp; 6920 nfhp->nfh_len = nfhlen; 6921 NFSBCOPY(cp, 6922 nfhp->nfh_fh, 6923 nfhlen); 6924 NFSCL_DEBUG(4, 6925 "got fh\n"); 6926 } 6927 } 6928 /* Now, get the ffsd_user/ffds_group. */ 6929 error = nfsrv_parseug(nd, 0, &user, 6930 &grp, curthread); 6931 NFSCL_DEBUG(4, "after parseu=%d\n", 6932 error); 6933 if (error == 0) 6934 error = nfsrv_parseug(nd, 1, 6935 &user, &grp, curthread); 6936 NFSCL_DEBUG(4, "aft parseg=%d\n", 6937 grp); 6938 if (error != 0) 6939 goto nfsmout; 6940 NFSCL_DEBUG(4, "user=%d group=%d\n", 6941 user, grp); 6942 if (l == 0) { 6943 flp->nfsfl_ffm[j].user = user; 6944 flp->nfsfl_ffm[j].group = grp; 6945 NFSCL_DEBUG(4, 6946 "usr=%d grp=%d\n", user, 6947 grp); 6948 } 6949 } 6950 } 6951 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6952 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++); 6953 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl); 6954 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n", 6955 flp->nfsfl_fflags, flp->nfsfl_statshint); 6956 } else { 6957 error = NFSERR_BADXDR; 6958 goto nfsmout; 6959 } 6960 if (flp->nfsfl_iomode == gotiomode) { 6961 /* Keep the list in increasing offset order. */ 6962 tflp = LIST_FIRST(flhp); 6963 prevflp = NULL; 6964 while (tflp != NULL && 6965 tflp->nfsfl_off < flp->nfsfl_off) { 6966 prevflp = tflp; 6967 tflp = LIST_NEXT(tflp, nfsfl_list); 6968 } 6969 if (prevflp == NULL) 6970 LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 6971 else 6972 LIST_INSERT_AFTER(prevflp, flp, 6973 nfsfl_list); 6974 NFSCL_DEBUG(4, "flp inserted\n"); 6975 } else { 6976 printf("nfscl_layoutget(): got wrong iomode\n"); 6977 nfscl_freeflayout(flp); 6978 } 6979 flp = NULL; 6980 } 6981 nfsmout: 6982 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error); 6983 if (error != 0 && flp != NULL) 6984 nfscl_freeflayout(flp); 6985 return (error); 6986 } 6987 6988 /* 6989 * Parse a user/group digit string. 6990 */ 6991 static int 6992 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp, 6993 NFSPROC_T *p) 6994 { 6995 uint32_t *tl; 6996 char *cp, *str, str0[NFSV4_SMALLSTR + 1]; 6997 uint32_t len = 0; 6998 int error = 0; 6999 7000 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7001 len = fxdr_unsigned(uint32_t, *tl); 7002 str = NULL; 7003 if (len > NFSV4_OPAQUELIMIT) { 7004 error = NFSERR_BADXDR; 7005 goto nfsmout; 7006 } 7007 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len); 7008 if (len == 0) { 7009 if (dogrp != 0) 7010 *gidp = GID_NOGROUP; 7011 else 7012 *uidp = UID_NOBODY; 7013 return (0); 7014 } 7015 if (len > NFSV4_SMALLSTR) 7016 str = malloc(len + 1, M_TEMP, M_WAITOK); 7017 else 7018 str = str0; 7019 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len)); 7020 NFSBCOPY(cp, str, len); 7021 str[len] = '\0'; 7022 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str); 7023 if (dogrp != 0) 7024 error = nfsv4_strtogid(nd, str, len, gidp, p); 7025 else 7026 error = nfsv4_strtouid(nd, str, len, uidp, p); 7027 nfsmout: 7028 if (len > NFSV4_SMALLSTR) 7029 free(str, M_TEMP); 7030 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error); 7031 return (error); 7032 } 7033 7034 /* 7035 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), 7036 * so that it does both an Open and a Layoutget. 7037 */ 7038 static int 7039 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7040 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7041 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7042 struct ucred *cred, NFSPROC_T *p) 7043 { 7044 struct nfscllayout *lyp; 7045 struct nfsclflayout *flp; 7046 struct nfsclflayouthead flh; 7047 int error, islocked, layoutlen, recalled, retonclose, usecurstateid; 7048 int layouttype, laystat; 7049 nfsv4stateid_t stateid; 7050 struct nfsclsession *tsep; 7051 7052 error = 0; 7053 if (NFSHASFLEXFILE(nmp)) 7054 layouttype = NFSLAYOUT_FLEXFILE; 7055 else 7056 layouttype = NFSLAYOUT_NFSV4_1_FILES; 7057 /* 7058 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 7059 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 7060 * flp == NULL. 7061 */ 7062 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, &flp, 7063 &recalled); 7064 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); 7065 if (lyp == NULL) 7066 islocked = 0; 7067 else if (flp != NULL) 7068 islocked = 1; 7069 else 7070 islocked = 2; 7071 if ((lyp == NULL || flp == NULL) && recalled == 0) { 7072 LIST_INIT(&flh); 7073 tsep = nfsmnt_mdssession(nmp); 7074 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 7075 3 * NFSX_UNSIGNED); 7076 if (lyp == NULL) 7077 usecurstateid = 1; 7078 else { 7079 usecurstateid = 0; 7080 stateid.seqid = lyp->nfsly_stateid.seqid; 7081 stateid.other[0] = lyp->nfsly_stateid.other[0]; 7082 stateid.other[1] = lyp->nfsly_stateid.other[1]; 7083 stateid.other[2] = lyp->nfsly_stateid.other[2]; 7084 } 7085 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, 7086 newfhp, newfhlen, mode, op, name, namelen, 7087 dpp, &stateid, usecurstateid, layouttype, layoutlen, 7088 &retonclose, &flh, &laystat, cred, p); 7089 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", 7090 laystat, error); 7091 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, 7092 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, 7093 &islocked, cred, p); 7094 } else 7095 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, 7096 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); 7097 if (islocked == 2) 7098 nfscl_rellayout(lyp, 1); 7099 else if (islocked == 1) 7100 nfscl_rellayout(lyp, 0); 7101 return (error); 7102 } 7103 7104 /* 7105 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS 7106 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are 7107 * handled by nfsrpc_openrpc(). 7108 * For the case where op == NULL, dvp is the directory. When op != NULL, it 7109 * can be NULL. 7110 */ 7111 static int 7112 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7113 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7114 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7115 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, 7116 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, 7117 int *laystatp, struct ucred *cred, NFSPROC_T *p) 7118 { 7119 uint32_t *tl; 7120 struct nfsrv_descript nfsd, *nd = &nfsd; 7121 struct nfscldeleg *ndp = NULL; 7122 struct nfsvattr nfsva; 7123 struct nfsclsession *tsep; 7124 uint32_t rflags, deleg; 7125 nfsattrbit_t attrbits; 7126 int error, ret, acesize, limitby, iomode; 7127 7128 *dpp = NULL; 7129 *laystatp = ENXIO; 7130 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL, 7131 0, 0); 7132 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 7133 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 7134 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 7135 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 7136 tsep = nfsmnt_mdssession(nmp); 7137 *tl++ = tsep->nfsess_clientid.lval[0]; 7138 *tl = tsep->nfsess_clientid.lval[1]; 7139 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 7140 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7141 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 7142 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 7143 nfsm_strtom(nd, name, namelen); 7144 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7145 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7146 NFSZERO_ATTRBIT(&attrbits); 7147 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 7148 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 7149 nfsrv_putattrbit(nd, &attrbits); 7150 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7151 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 7152 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) 7153 iomode = NFSLAYOUTIOMODE_RW; 7154 else 7155 iomode = NFSLAYOUTIOMODE_READ; 7156 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, 7157 layouttype, layoutlen, usecurstateid); 7158 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 7159 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 7160 if (error != 0) 7161 return (error); 7162 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 7163 if (nd->nd_repstat != 0) 7164 *laystatp = nd->nd_repstat; 7165 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7166 /* ND_NOMOREDATA will be set if the Open operation failed. */ 7167 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7168 6 * NFSX_UNSIGNED); 7169 op->nfso_stateid.seqid = *tl++; 7170 op->nfso_stateid.other[0] = *tl++; 7171 op->nfso_stateid.other[1] = *tl++; 7172 op->nfso_stateid.other[2] = *tl; 7173 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 7174 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 7175 if (error != 0) 7176 goto nfsmout; 7177 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 7178 deleg = fxdr_unsigned(u_int32_t, *tl); 7179 if (deleg == NFSV4OPEN_DELEGATEREAD || 7180 deleg == NFSV4OPEN_DELEGATEWRITE) { 7181 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 7182 NFSCLFLAGS_FIRSTDELEG)) 7183 op->nfso_own->nfsow_clp->nfsc_flags |= 7184 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 7185 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, 7186 M_NFSCLDELEG, M_WAITOK); 7187 LIST_INIT(&ndp->nfsdl_owner); 7188 LIST_INIT(&ndp->nfsdl_lock); 7189 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 7190 ndp->nfsdl_fhlen = newfhlen; 7191 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 7192 newnfs_copyincred(cred, &ndp->nfsdl_cred); 7193 nfscl_lockinit(&ndp->nfsdl_rwlock); 7194 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7195 NFSX_UNSIGNED); 7196 ndp->nfsdl_stateid.seqid = *tl++; 7197 ndp->nfsdl_stateid.other[0] = *tl++; 7198 ndp->nfsdl_stateid.other[1] = *tl++; 7199 ndp->nfsdl_stateid.other[2] = *tl++; 7200 ret = fxdr_unsigned(int, *tl); 7201 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 7202 ndp->nfsdl_flags = NFSCLDL_WRITE; 7203 /* 7204 * Indicates how much the file can grow. 7205 */ 7206 NFSM_DISSECT(tl, u_int32_t *, 7207 3 * NFSX_UNSIGNED); 7208 limitby = fxdr_unsigned(int, *tl++); 7209 switch (limitby) { 7210 case NFSV4OPEN_LIMITSIZE: 7211 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 7212 break; 7213 case NFSV4OPEN_LIMITBLOCKS: 7214 ndp->nfsdl_sizelimit = 7215 fxdr_unsigned(u_int64_t, *tl++); 7216 ndp->nfsdl_sizelimit *= 7217 fxdr_unsigned(u_int64_t, *tl); 7218 break; 7219 default: 7220 error = NFSERR_BADXDR; 7221 goto nfsmout; 7222 }; 7223 } else 7224 ndp->nfsdl_flags = NFSCLDL_READ; 7225 if (ret != 0) 7226 ndp->nfsdl_flags |= NFSCLDL_RECALL; 7227 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 7228 &acesize, p); 7229 if (error != 0) 7230 goto nfsmout; 7231 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 7232 error = NFSERR_BADXDR; 7233 goto nfsmout; 7234 } 7235 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || 7236 nfscl_assumeposixlocks) 7237 op->nfso_posixlock = 1; 7238 else 7239 op->nfso_posixlock = 0; 7240 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7241 /* If the 2nd element == NFS_OK, the Getattr succeeded. */ 7242 if (*++tl == 0) { 7243 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 7244 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 7245 NULL, NULL, NULL, p, cred); 7246 if (error != 0) 7247 goto nfsmout; 7248 if (ndp != NULL) { 7249 ndp->nfsdl_change = nfsva.na_filerev; 7250 ndp->nfsdl_modtime = nfsva.na_mtime; 7251 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 7252 *dpp = ndp; 7253 ndp = NULL; 7254 } 7255 /* 7256 * At this point, the Open has succeeded, so set 7257 * nd_repstat = NFS_OK. If the Layoutget failed, 7258 * this function just won't return a layout. 7259 */ 7260 if (nd->nd_repstat == 0) { 7261 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7262 *laystatp = fxdr_unsigned(int, *++tl); 7263 if (*laystatp == 0) { 7264 error = nfsrv_parselayoutget(nd, 7265 stateidp, retonclosep, flhp); 7266 if (error != 0) 7267 *laystatp = error; 7268 } 7269 } else 7270 nd->nd_repstat = 0; /* Return 0 for Open. */ 7271 } 7272 } 7273 if (nd->nd_repstat != 0 && error == 0) 7274 error = nd->nd_repstat; 7275 nfsmout: 7276 free(ndp, M_NFSCLDELEG); 7277 mbuf_freem(nd->nd_mrep); 7278 return (error); 7279 } 7280 7281 /* 7282 * Similar nfsrpc_createv4(), but also does the LayoutGet operation. 7283 * Used only for mounts with pNFS enabled. 7284 */ 7285 static int 7286 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 7287 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 7288 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 7289 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 7290 int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp, 7291 int usecurstateid, int layouttype, int layoutlen, int *retonclosep, 7292 struct nfsclflayouthead *flhp, int *laystatp) 7293 { 7294 uint32_t *tl; 7295 int error = 0, deleg, newone, ret, acesize, limitby; 7296 struct nfsrv_descript nfsd, *nd = &nfsd; 7297 struct nfsclopen *op; 7298 struct nfscldeleg *dp = NULL; 7299 struct nfsnode *np; 7300 struct nfsfh *nfhp; 7301 struct nfsclsession *tsep; 7302 nfsattrbit_t attrbits; 7303 nfsv4stateid_t stateid; 7304 struct nfsmount *nmp; 7305 7306 nmp = VFSTONFS(dvp->v_mount); 7307 np = VTONFS(dvp); 7308 *laystatp = ENXIO; 7309 *unlockedp = 0; 7310 *nfhpp = NULL; 7311 *dpp = NULL; 7312 *attrflagp = 0; 7313 *dattrflagp = 0; 7314 if (namelen > NFS_MAXNAMLEN) 7315 return (ENAMETOOLONG); 7316 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp); 7317 /* 7318 * For V4, this is actually an Open op. 7319 */ 7320 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 7321 *tl++ = txdr_unsigned(owp->nfsow_seqid); 7322 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 7323 NFSV4OPEN_ACCESSREAD); 7324 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 7325 tsep = nfsmnt_mdssession(nmp); 7326 *tl++ = tsep->nfsess_clientid.lval[0]; 7327 *tl = tsep->nfsess_clientid.lval[1]; 7328 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 7329 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7330 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 7331 if ((fmode & O_EXCL) != 0) { 7332 if (NFSHASSESSPERSIST(nmp)) { 7333 /* Use GUARDED for persistent sessions. */ 7334 *tl = txdr_unsigned(NFSCREATE_GUARDED); 7335 nfscl_fillsattr(nd, vap, dvp, 0, 0); 7336 } else { 7337 /* Otherwise, use EXCLUSIVE4_1. */ 7338 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 7339 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 7340 *tl++ = cverf.lval[0]; 7341 *tl = cverf.lval[1]; 7342 nfscl_fillsattr(nd, vap, dvp, 0, 0); 7343 } 7344 } else { 7345 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 7346 nfscl_fillsattr(nd, vap, dvp, 0, 0); 7347 } 7348 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7349 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 7350 nfsm_strtom(nd, name, namelen); 7351 /* Get the new file's handle and attributes, plus save the FH. */ 7352 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 7353 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); 7354 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 7355 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7356 NFSGETATTR_ATTRBIT(&attrbits); 7357 nfsrv_putattrbit(nd, &attrbits); 7358 /* Get the directory's post-op attributes. */ 7359 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7360 *tl = txdr_unsigned(NFSV4OP_PUTFH); 7361 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 7362 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 7363 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7364 nfsrv_putattrbit(nd, &attrbits); 7365 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7366 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); 7367 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 7368 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, 7369 layouttype, layoutlen, usecurstateid); 7370 error = nfscl_request(nd, dvp, p, cred, dstuff); 7371 if (error != 0) 7372 return (error); 7373 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, 7374 error); 7375 if (nd->nd_repstat != 0) 7376 *laystatp = nd->nd_repstat; 7377 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 7378 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7379 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); 7380 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7381 6 * NFSX_UNSIGNED); 7382 stateid.seqid = *tl++; 7383 stateid.other[0] = *tl++; 7384 stateid.other[1] = *tl++; 7385 stateid.other[2] = *tl; 7386 nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 7387 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 7388 deleg = fxdr_unsigned(int, *tl); 7389 if (deleg == NFSV4OPEN_DELEGATEREAD || 7390 deleg == NFSV4OPEN_DELEGATEWRITE) { 7391 if (!(owp->nfsow_clp->nfsc_flags & 7392 NFSCLFLAGS_FIRSTDELEG)) 7393 owp->nfsow_clp->nfsc_flags |= 7394 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 7395 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, 7396 M_NFSCLDELEG, M_WAITOK); 7397 LIST_INIT(&dp->nfsdl_owner); 7398 LIST_INIT(&dp->nfsdl_lock); 7399 dp->nfsdl_clp = owp->nfsow_clp; 7400 newnfs_copyincred(cred, &dp->nfsdl_cred); 7401 nfscl_lockinit(&dp->nfsdl_rwlock); 7402 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7403 NFSX_UNSIGNED); 7404 dp->nfsdl_stateid.seqid = *tl++; 7405 dp->nfsdl_stateid.other[0] = *tl++; 7406 dp->nfsdl_stateid.other[1] = *tl++; 7407 dp->nfsdl_stateid.other[2] = *tl++; 7408 ret = fxdr_unsigned(int, *tl); 7409 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 7410 dp->nfsdl_flags = NFSCLDL_WRITE; 7411 /* 7412 * Indicates how much the file can grow. 7413 */ 7414 NFSM_DISSECT(tl, u_int32_t *, 7415 3 * NFSX_UNSIGNED); 7416 limitby = fxdr_unsigned(int, *tl++); 7417 switch (limitby) { 7418 case NFSV4OPEN_LIMITSIZE: 7419 dp->nfsdl_sizelimit = fxdr_hyper(tl); 7420 break; 7421 case NFSV4OPEN_LIMITBLOCKS: 7422 dp->nfsdl_sizelimit = 7423 fxdr_unsigned(u_int64_t, *tl++); 7424 dp->nfsdl_sizelimit *= 7425 fxdr_unsigned(u_int64_t, *tl); 7426 break; 7427 default: 7428 error = NFSERR_BADXDR; 7429 goto nfsmout; 7430 }; 7431 } else { 7432 dp->nfsdl_flags = NFSCLDL_READ; 7433 } 7434 if (ret != 0) 7435 dp->nfsdl_flags |= NFSCLDL_RECALL; 7436 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 7437 &acesize, p); 7438 if (error != 0) 7439 goto nfsmout; 7440 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 7441 error = NFSERR_BADXDR; 7442 goto nfsmout; 7443 } 7444 7445 /* Now, we should have the status for the SaveFH. */ 7446 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7447 if (*++tl == 0) { 7448 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); 7449 /* 7450 * Now, process the GetFH and Getattr for the newly 7451 * created file. nfscl_mtofh() will set 7452 * ND_NOMOREDATA if these weren't successful. 7453 */ 7454 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 7455 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); 7456 if (error != 0) 7457 goto nfsmout; 7458 } else 7459 nd->nd_flag |= ND_NOMOREDATA; 7460 /* Now we have the PutFH and Getattr for the directory. */ 7461 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7462 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7463 if (*++tl != 0) 7464 nd->nd_flag |= ND_NOMOREDATA; 7465 else { 7466 NFSM_DISSECT(tl, uint32_t *, 2 * 7467 NFSX_UNSIGNED); 7468 if (*++tl != 0) 7469 nd->nd_flag |= ND_NOMOREDATA; 7470 } 7471 } 7472 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7473 /* Load the directory attributes. */ 7474 error = nfsm_loadattr(nd, dnap); 7475 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); 7476 if (error != 0) 7477 goto nfsmout; 7478 *dattrflagp = 1; 7479 if (dp != NULL && *attrflagp != 0) { 7480 dp->nfsdl_change = nnap->na_filerev; 7481 dp->nfsdl_modtime = nnap->na_mtime; 7482 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 7483 } 7484 /* 7485 * We can now complete the Open state. 7486 */ 7487 nfhp = *nfhpp; 7488 if (dp != NULL) { 7489 dp->nfsdl_fhlen = nfhp->nfh_len; 7490 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, 7491 nfhp->nfh_len); 7492 } 7493 /* 7494 * Get an Open structure that will be 7495 * attached to the OpenOwner, acquired already. 7496 */ 7497 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 7498 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 7499 cred, p, NULL, &op, &newone, NULL, 0); 7500 if (error != 0) 7501 goto nfsmout; 7502 op->nfso_stateid = stateid; 7503 newnfs_copyincred(cred, &op->nfso_cred); 7504 7505 nfscl_openrelease(nmp, op, error, newone); 7506 *unlockedp = 1; 7507 7508 /* Now, handle the RestoreFH and LayoutGet. */ 7509 if (nd->nd_repstat == 0) { 7510 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 7511 *laystatp = fxdr_unsigned(int, *(tl + 3)); 7512 if (*laystatp == 0) { 7513 error = nfsrv_parselayoutget(nd, 7514 stateidp, retonclosep, flhp); 7515 if (error != 0) 7516 *laystatp = error; 7517 } 7518 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", 7519 error); 7520 } else 7521 nd->nd_repstat = 0; 7522 } 7523 } 7524 if (nd->nd_repstat != 0 && error == 0) 7525 error = nd->nd_repstat; 7526 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) 7527 nfscl_initiate_recovery(owp->nfsow_clp); 7528 nfsmout: 7529 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); 7530 if (error == 0) 7531 *dpp = dp; 7532 else 7533 free(dp, M_NFSCLDELEG); 7534 mbuf_freem(nd->nd_mrep); 7535 return (error); 7536 } 7537 7538 /* 7539 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. 7540 */ 7541 static int 7542 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 7543 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 7544 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 7545 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 7546 int *dattrflagp, void *dstuff, int *unlockedp) 7547 { 7548 struct nfscllayout *lyp; 7549 struct nfsclflayouthead flh; 7550 struct nfsfh *nfhp; 7551 struct nfsclsession *tsep; 7552 struct nfsmount *nmp; 7553 nfsv4stateid_t stateid; 7554 int error, layoutlen, layouttype, retonclose, laystat; 7555 7556 error = 0; 7557 nmp = VFSTONFS(dvp->v_mount); 7558 if (NFSHASFLEXFILE(nmp)) 7559 layouttype = NFSLAYOUT_FLEXFILE; 7560 else 7561 layouttype = NFSLAYOUT_NFSV4_1_FILES; 7562 LIST_INIT(&flh); 7563 tsep = nfsmnt_mdssession(nmp); 7564 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); 7565 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, 7566 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 7567 dstuff, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose, 7568 &flh, &laystat); 7569 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", 7570 laystat, error); 7571 lyp = NULL; 7572 if (laystat == 0) { 7573 nfhp = *nfhpp; 7574 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, 7575 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, 7576 layouttype, laystat, NULL, cred, p); 7577 } else 7578 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, 7579 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, 7580 cred, p); 7581 if (laystat == 0) 7582 nfscl_rellayout(lyp, 0); 7583 return (error); 7584 } 7585 7586 /* 7587 * Process the results of a layoutget() operation. 7588 */ 7589 static int 7590 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, 7591 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, 7592 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype, 7593 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) 7594 { 7595 struct nfsclflayout *tflp; 7596 struct nfscldevinfo *dip; 7597 uint8_t *dev; 7598 int i, mirrorcnt; 7599 7600 if (laystat == NFSERR_UNKNLAYOUTTYPE) { 7601 NFSLOCKMNT(nmp); 7602 if (!NFSHASFLEXFILE(nmp)) { 7603 /* Switch to using Flex File Layout. */ 7604 nmp->nm_state |= NFSSTA_FLEXFILE; 7605 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 7606 /* Disable pNFS. */ 7607 NFSCL_DEBUG(1, "disable PNFS\n"); 7608 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE); 7609 } 7610 NFSUNLOCKMNT(nmp); 7611 } 7612 if (laystat == 0) { 7613 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); 7614 LIST_FOREACH(tflp, flhp, nfsfl_list) { 7615 if (layouttype == NFSLAYOUT_FLEXFILE) 7616 mirrorcnt = tflp->nfsfl_mirrorcnt; 7617 else 7618 mirrorcnt = 1; 7619 for (i = 0; i < mirrorcnt; i++) { 7620 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp); 7621 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); 7622 if (laystat != 0) { 7623 if (layouttype == NFSLAYOUT_FLEXFILE) 7624 dev = tflp->nfsfl_ffm[i].dev; 7625 else 7626 dev = tflp->nfsfl_dev; 7627 laystat = nfsrpc_getdeviceinfo(nmp, dev, 7628 layouttype, notifybit, &dip, cred, 7629 p); 7630 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", 7631 laystat); 7632 if (laystat != 0) 7633 goto out; 7634 laystat = nfscl_adddevinfo(nmp, dip, i, 7635 tflp); 7636 if (laystat != 0) 7637 printf("nfsrpc_layoutgetresout" 7638 ": cannot add\n"); 7639 } 7640 } 7641 } 7642 } 7643 out: 7644 if (laystat == 0) { 7645 /* 7646 * nfscl_layout() always returns with the nfsly_lock 7647 * set to a refcnt (shared lock). 7648 * Passing in dvp is sufficient, since it is only used to 7649 * get the fsid for the file system. 7650 */ 7651 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, 7652 layouttype, retonclose, flhp, lypp, cred, p); 7653 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", 7654 laystat); 7655 if (laystat == 0 && islockedp != NULL) 7656 *islockedp = 1; 7657 } 7658 return (laystat); 7659 } 7660 7661