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