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