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