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