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