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