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