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