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