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, stuff); 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, stuff); 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, stuff); 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, dstuff); 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, dstuff); 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, dstuff); 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, dstuff); 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, 2887 fstuff); 2888 /* and the second wcc attribute reply. */ 2889 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 2890 !error) { 2891 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2892 if (*(tl + 1)) 2893 nd->nd_flag |= ND_NOMOREDATA; 2894 } 2895 if (!error) 2896 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 2897 NULL, tstuff); 2898 } 2899 if (nd->nd_repstat && !error) 2900 error = nd->nd_repstat; 2901 nfsmout: 2902 m_freem(nd->nd_mrep); 2903 return (error); 2904 } 2905 2906 /* 2907 * nfs hard link create rpc 2908 */ 2909 int 2910 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 2911 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2912 struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff) 2913 { 2914 u_int32_t *tl; 2915 struct nfsrv_descript nfsd, *nd = &nfsd; 2916 nfsattrbit_t attrbits; 2917 int error = 0; 2918 2919 *attrflagp = 0; 2920 *dattrflagp = 0; 2921 if (namelen > NFS_MAXNAMLEN) 2922 return (ENAMETOOLONG); 2923 NFSCL_REQSTART(nd, NFSPROC_LINK, vp); 2924 if (nd->nd_flag & ND_NFSV4) { 2925 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2926 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2927 } 2928 (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh, 2929 VTONFS(dvp)->n_fhp->nfh_len, 0); 2930 if (nd->nd_flag & ND_NFSV4) { 2931 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2932 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2933 NFSWCCATTR_ATTRBIT(&attrbits); 2934 (void) nfsrv_putattrbit(nd, &attrbits); 2935 nd->nd_flag |= ND_V4WCCATTR; 2936 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2937 *tl = txdr_unsigned(NFSV4OP_LINK); 2938 } 2939 (void) nfsm_strtom(nd, name, namelen); 2940 error = nfscl_request(nd, vp, p, cred, dstuff); 2941 if (error) 2942 return (error); 2943 if (nd->nd_flag & ND_NFSV3) { 2944 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff); 2945 if (!error) 2946 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 2947 NULL, dstuff); 2948 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 2949 /* 2950 * First, parse out the PutFH and Getattr result. 2951 */ 2952 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2953 if (!(*(tl + 1))) 2954 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2955 if (*(tl + 1)) 2956 nd->nd_flag |= ND_NOMOREDATA; 2957 /* 2958 * Get the pre-op attributes. 2959 */ 2960 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 2961 } 2962 if (nd->nd_repstat && !error) 2963 error = nd->nd_repstat; 2964 nfsmout: 2965 m_freem(nd->nd_mrep); 2966 return (error); 2967 } 2968 2969 /* 2970 * nfs symbolic link create rpc 2971 */ 2972 int 2973 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target, 2974 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2975 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2976 int *dattrflagp, void *dstuff) 2977 { 2978 u_int32_t *tl; 2979 struct nfsrv_descript nfsd, *nd = &nfsd; 2980 struct nfsmount *nmp; 2981 int slen, error = 0; 2982 2983 *nfhpp = NULL; 2984 *attrflagp = 0; 2985 *dattrflagp = 0; 2986 nmp = VFSTONFS(dvp->v_mount); 2987 slen = strlen(target); 2988 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 2989 return (ENAMETOOLONG); 2990 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp); 2991 if (nd->nd_flag & ND_NFSV4) { 2992 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2993 *tl = txdr_unsigned(NFLNK); 2994 (void) nfsm_strtom(nd, target, slen); 2995 } 2996 (void) nfsm_strtom(nd, name, namelen); 2997 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2998 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2999 if (!(nd->nd_flag & ND_NFSV4)) 3000 (void) nfsm_strtom(nd, target, slen); 3001 if (nd->nd_flag & ND_NFSV2) 3002 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 3003 error = nfscl_request(nd, dvp, p, cred, dstuff); 3004 if (error) 3005 return (error); 3006 if (nd->nd_flag & ND_NFSV4) 3007 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 3008 if ((nd->nd_flag & ND_NFSV3) && !error) { 3009 if (!nd->nd_repstat) 3010 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 3011 if (!error) 3012 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 3013 NULL, dstuff); 3014 } 3015 if (nd->nd_repstat && !error) 3016 error = nd->nd_repstat; 3017 m_freem(nd->nd_mrep); 3018 /* 3019 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 3020 * Only do this if vfs.nfs.ignore_eexist is set. 3021 * Never do this for NFSv4.1 or later minor versions, since sessions 3022 * should guarantee "exactly once" RPC semantics. 3023 */ 3024 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 3025 nmp->nm_minorvers == 0)) 3026 error = 0; 3027 return (error); 3028 } 3029 3030 /* 3031 * nfs make dir rpc 3032 */ 3033 int 3034 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 3035 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 3036 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 3037 int *dattrflagp, void *dstuff) 3038 { 3039 u_int32_t *tl; 3040 struct nfsrv_descript nfsd, *nd = &nfsd; 3041 nfsattrbit_t attrbits; 3042 int error = 0; 3043 struct nfsfh *fhp; 3044 struct nfsmount *nmp; 3045 3046 *nfhpp = NULL; 3047 *attrflagp = 0; 3048 *dattrflagp = 0; 3049 nmp = VFSTONFS(dvp->v_mount); 3050 fhp = VTONFS(dvp)->n_fhp; 3051 if (namelen > NFS_MAXNAMLEN) 3052 return (ENAMETOOLONG); 3053 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp); 3054 if (nd->nd_flag & ND_NFSV4) { 3055 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3056 *tl = txdr_unsigned(NFDIR); 3057 } 3058 (void) nfsm_strtom(nd, name, namelen); 3059 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 3060 if (nd->nd_flag & ND_NFSV4) { 3061 NFSGETATTR_ATTRBIT(&attrbits); 3062 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3063 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3064 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3065 (void) nfsrv_putattrbit(nd, &attrbits); 3066 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3067 *tl = txdr_unsigned(NFSV4OP_PUTFH); 3068 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0); 3069 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3070 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3071 (void) nfsrv_putattrbit(nd, &attrbits); 3072 } 3073 error = nfscl_request(nd, dvp, p, cred, dstuff); 3074 if (error) 3075 return (error); 3076 if (nd->nd_flag & ND_NFSV4) 3077 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 3078 if (!nd->nd_repstat && !error) { 3079 if (nd->nd_flag & ND_NFSV4) { 3080 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3081 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 3082 } 3083 if (!error) 3084 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 3085 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 3086 /* Get rid of the PutFH and Getattr status values. */ 3087 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 3088 /* Load the directory attributes. */ 3089 error = nfsm_loadattr(nd, dnap); 3090 if (error == 0) 3091 *dattrflagp = 1; 3092 } 3093 } 3094 if ((nd->nd_flag & ND_NFSV3) && !error) 3095 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 3096 if (nd->nd_repstat && !error) 3097 error = nd->nd_repstat; 3098 nfsmout: 3099 m_freem(nd->nd_mrep); 3100 /* 3101 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 3102 * Only do this if vfs.nfs.ignore_eexist is set. 3103 * Never do this for NFSv4.1 or later minor versions, since sessions 3104 * should guarantee "exactly once" RPC semantics. 3105 */ 3106 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 3107 nmp->nm_minorvers == 0)) 3108 error = 0; 3109 return (error); 3110 } 3111 3112 /* 3113 * nfs remove directory call 3114 */ 3115 int 3116 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 3117 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff) 3118 { 3119 struct nfsrv_descript nfsd, *nd = &nfsd; 3120 int error = 0; 3121 3122 *dattrflagp = 0; 3123 if (namelen > NFS_MAXNAMLEN) 3124 return (ENAMETOOLONG); 3125 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp); 3126 (void) nfsm_strtom(nd, name, namelen); 3127 error = nfscl_request(nd, dvp, p, cred, dstuff); 3128 if (error) 3129 return (error); 3130 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 3131 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff); 3132 if (nd->nd_repstat && !error) 3133 error = nd->nd_repstat; 3134 m_freem(nd->nd_mrep); 3135 /* 3136 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 3137 */ 3138 if (error == ENOENT) 3139 error = 0; 3140 return (error); 3141 } 3142 3143 /* 3144 * Readdir rpc. 3145 * Always returns with either uio_resid unchanged, if you are at the 3146 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 3147 * filled in. 3148 * I felt this would allow caching of directory blocks more easily 3149 * than returning a pertially filled block. 3150 * Directory offset cookies: 3151 * Oh my, what to do with them... 3152 * I can think of three ways to deal with them: 3153 * 1 - have the layer above these RPCs maintain a map between logical 3154 * directory byte offsets and the NFS directory offset cookies 3155 * 2 - pass the opaque directory offset cookies up into userland 3156 * and let the libc functions deal with them, via the system call 3157 * 3 - return them to userland in the "struct dirent", so future versions 3158 * of libc can use them and do whatever is necessary to make things work 3159 * above these rpc calls, in the meantime 3160 * For now, I do #3 by "hiding" the directory offset cookies after the 3161 * d_name field in struct dirent. This is space inside d_reclen that 3162 * will be ignored by anything that doesn't know about them. 3163 * The directory offset cookies are filled in as the last 8 bytes of 3164 * each directory entry, after d_name. Someday, the userland libc 3165 * functions may be able to use these. In the meantime, it satisfies 3166 * OpenBSD's requirements for cookies being returned. 3167 * If expects the directory offset cookie for the read to be in uio_offset 3168 * and returns the one for the next entry after this directory block in 3169 * there, as well. 3170 */ 3171 int 3172 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3173 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3174 int *eofp, void *stuff) 3175 { 3176 int len, left; 3177 struct dirent *dp = NULL; 3178 u_int32_t *tl; 3179 nfsquad_t cookie, ncookie; 3180 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 3181 struct nfsnode *dnp = VTONFS(vp); 3182 struct nfsvattr nfsva; 3183 struct nfsrv_descript nfsd, *nd = &nfsd; 3184 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3185 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 3186 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3187 char *cp; 3188 nfsattrbit_t attrbits, dattrbits; 3189 u_int32_t rderr, *tl2 = NULL; 3190 size_t tresid; 3191 3192 KASSERT(uiop->uio_iovcnt == 1 && 3193 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 3194 ("nfs readdirrpc bad uio")); 3195 ncookie.lval[0] = ncookie.lval[1] = 0; 3196 /* 3197 * There is no point in reading a lot more than uio_resid, however 3198 * adding one additional DIRBLKSIZ makes sense. Since uio_resid 3199 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 3200 * will never make readsize > nm_readdirsize. 3201 */ 3202 readsize = nmp->nm_readdirsize; 3203 if (readsize > uiop->uio_resid) 3204 readsize = uiop->uio_resid + DIRBLKSIZ; 3205 3206 *attrflagp = 0; 3207 if (eofp) 3208 *eofp = 0; 3209 tresid = uiop->uio_resid; 3210 cookie.lval[0] = cookiep->nfsuquad[0]; 3211 cookie.lval[1] = cookiep->nfsuquad[1]; 3212 nd->nd_mrep = NULL; 3213 3214 /* 3215 * For NFSv4, first create the "." and ".." entries. 3216 */ 3217 if (NFSHASNFSV4(nmp)) { 3218 reqsize = 6 * NFSX_UNSIGNED; 3219 NFSGETATTR_ATTRBIT(&dattrbits); 3220 NFSZERO_ATTRBIT(&attrbits); 3221 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3222 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 3223 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3224 NFSATTRBIT_MOUNTEDONFILEID)) { 3225 NFSSETBIT_ATTRBIT(&attrbits, 3226 NFSATTRBIT_MOUNTEDONFILEID); 3227 gotmnton = 1; 3228 } else { 3229 /* 3230 * Must fake it. Use the fileno, except when the 3231 * fsid is != to that of the directory. For that 3232 * case, generate a fake fileno that is not the same. 3233 */ 3234 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3235 gotmnton = 0; 3236 } 3237 3238 /* 3239 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3240 */ 3241 if (uiop->uio_offset == 0) { 3242 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3243 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3244 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3245 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3246 (void) nfsrv_putattrbit(nd, &attrbits); 3247 error = nfscl_request(nd, vp, p, cred, stuff); 3248 if (error) 3249 return (error); 3250 dotfileid = 0; /* Fake out the compiler. */ 3251 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3252 error = nfsm_loadattr(nd, &nfsva); 3253 if (error != 0) 3254 goto nfsmout; 3255 dotfileid = nfsva.na_fileid; 3256 } 3257 if (nd->nd_repstat == 0) { 3258 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3259 len = fxdr_unsigned(int, *(tl + 4)); 3260 if (len > 0 && len <= NFSX_V4FHMAX) 3261 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3262 else 3263 error = EPERM; 3264 if (!error) { 3265 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3266 nfsva.na_mntonfileno = UINT64_MAX; 3267 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3268 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3269 NULL, NULL, NULL, p, cred); 3270 if (error) { 3271 dotdotfileid = dotfileid; 3272 } else if (gotmnton) { 3273 if (nfsva.na_mntonfileno != UINT64_MAX) 3274 dotdotfileid = nfsva.na_mntonfileno; 3275 else 3276 dotdotfileid = nfsva.na_fileid; 3277 } else if (nfsva.na_filesid[0] == 3278 dnp->n_vattr.na_filesid[0] && 3279 nfsva.na_filesid[1] == 3280 dnp->n_vattr.na_filesid[1]) { 3281 dotdotfileid = nfsva.na_fileid; 3282 } else { 3283 do { 3284 fakefileno--; 3285 } while (fakefileno == 3286 nfsva.na_fileid); 3287 dotdotfileid = fakefileno; 3288 } 3289 } 3290 } else if (nd->nd_repstat == NFSERR_NOENT) { 3291 /* 3292 * Lookupp returns NFSERR_NOENT when we are 3293 * at the root, so just use the current dir. 3294 */ 3295 nd->nd_repstat = 0; 3296 dotdotfileid = dotfileid; 3297 } else { 3298 error = nd->nd_repstat; 3299 } 3300 m_freem(nd->nd_mrep); 3301 if (error) 3302 return (error); 3303 nd->nd_mrep = NULL; 3304 dp = (struct dirent *)uiop->uio_iov->iov_base; 3305 dp->d_pad0 = dp->d_pad1 = 0; 3306 dp->d_off = 0; 3307 dp->d_type = DT_DIR; 3308 dp->d_fileno = dotfileid; 3309 dp->d_namlen = 1; 3310 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3311 dp->d_name[0] = '.'; 3312 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3313 /* 3314 * Just make these offset cookie 0. 3315 */ 3316 tl = (u_int32_t *)&dp->d_name[8]; 3317 *tl++ = 0; 3318 *tl = 0; 3319 blksiz += dp->d_reclen; 3320 uiop->uio_resid -= dp->d_reclen; 3321 uiop->uio_offset += dp->d_reclen; 3322 uiop->uio_iov->iov_base = 3323 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3324 uiop->uio_iov->iov_len -= dp->d_reclen; 3325 dp = (struct dirent *)uiop->uio_iov->iov_base; 3326 dp->d_pad0 = dp->d_pad1 = 0; 3327 dp->d_off = 0; 3328 dp->d_type = DT_DIR; 3329 dp->d_fileno = dotdotfileid; 3330 dp->d_namlen = 2; 3331 *((uint64_t *)dp->d_name) = 0; 3332 dp->d_name[0] = '.'; 3333 dp->d_name[1] = '.'; 3334 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3335 /* 3336 * Just make these offset cookie 0. 3337 */ 3338 tl = (u_int32_t *)&dp->d_name[8]; 3339 *tl++ = 0; 3340 *tl = 0; 3341 blksiz += dp->d_reclen; 3342 uiop->uio_resid -= dp->d_reclen; 3343 uiop->uio_offset += dp->d_reclen; 3344 uiop->uio_iov->iov_base = 3345 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3346 uiop->uio_iov->iov_len -= dp->d_reclen; 3347 } 3348 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 3349 } else { 3350 reqsize = 5 * NFSX_UNSIGNED; 3351 } 3352 3353 /* 3354 * Loop around doing readdir rpc's of size readsize. 3355 * The stopping criteria is EOF or buffer full. 3356 */ 3357 while (more_dirs && bigenough) { 3358 *attrflagp = 0; 3359 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp); 3360 if (nd->nd_flag & ND_NFSV2) { 3361 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3362 *tl++ = cookie.lval[1]; 3363 *tl = txdr_unsigned(readsize); 3364 } else { 3365 NFSM_BUILD(tl, u_int32_t *, reqsize); 3366 *tl++ = cookie.lval[0]; 3367 *tl++ = cookie.lval[1]; 3368 if (cookie.qval == 0) { 3369 *tl++ = 0; 3370 *tl++ = 0; 3371 } else { 3372 NFSLOCKNODE(dnp); 3373 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3374 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3375 NFSUNLOCKNODE(dnp); 3376 } 3377 if (nd->nd_flag & ND_NFSV4) { 3378 *tl++ = txdr_unsigned(readsize); 3379 *tl = txdr_unsigned(readsize); 3380 (void) nfsrv_putattrbit(nd, &attrbits); 3381 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3382 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3383 (void) nfsrv_putattrbit(nd, &dattrbits); 3384 } else { 3385 *tl = txdr_unsigned(readsize); 3386 } 3387 } 3388 error = nfscl_request(nd, vp, p, cred, stuff); 3389 if (error) 3390 return (error); 3391 if (!(nd->nd_flag & ND_NFSV2)) { 3392 if (nd->nd_flag & ND_NFSV3) 3393 error = nfscl_postop_attr(nd, nap, attrflagp, 3394 stuff); 3395 if (!nd->nd_repstat && !error) { 3396 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3397 NFSLOCKNODE(dnp); 3398 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3399 dnp->n_cookieverf.nfsuquad[1] = *tl; 3400 NFSUNLOCKNODE(dnp); 3401 } 3402 } 3403 if (nd->nd_repstat || error) { 3404 if (!error) 3405 error = nd->nd_repstat; 3406 goto nfsmout; 3407 } 3408 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3409 more_dirs = fxdr_unsigned(int, *tl); 3410 if (!more_dirs) 3411 tryformoredirs = 0; 3412 3413 /* loop through the dir entries, doctoring them to 4bsd form */ 3414 while (more_dirs && bigenough) { 3415 if (nd->nd_flag & ND_NFSV4) { 3416 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3417 ncookie.lval[0] = *tl++; 3418 ncookie.lval[1] = *tl++; 3419 len = fxdr_unsigned(int, *tl); 3420 } else if (nd->nd_flag & ND_NFSV3) { 3421 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3422 nfsva.na_fileid = fxdr_hyper(tl); 3423 tl += 2; 3424 len = fxdr_unsigned(int, *tl); 3425 } else { 3426 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3427 nfsva.na_fileid = fxdr_unsigned(uint64_t, 3428 *tl++); 3429 len = fxdr_unsigned(int, *tl); 3430 } 3431 if (len <= 0 || len > NFS_MAXNAMLEN) { 3432 error = EBADRPC; 3433 goto nfsmout; 3434 } 3435 tlen = roundup2(len, 8); 3436 if (tlen == len) 3437 tlen += 8; /* To ensure null termination. */ 3438 left = DIRBLKSIZ - blksiz; 3439 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3440 NFSBZERO(uiop->uio_iov->iov_base, left); 3441 dp->d_reclen += left; 3442 uiop->uio_iov->iov_base = 3443 (char *)uiop->uio_iov->iov_base + left; 3444 uiop->uio_iov->iov_len -= left; 3445 uiop->uio_resid -= left; 3446 uiop->uio_offset += left; 3447 blksiz = 0; 3448 } 3449 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3450 uiop->uio_resid) 3451 bigenough = 0; 3452 if (bigenough) { 3453 dp = (struct dirent *)uiop->uio_iov->iov_base; 3454 dp->d_pad0 = dp->d_pad1 = 0; 3455 dp->d_off = 0; 3456 dp->d_namlen = len; 3457 dp->d_reclen = _GENERIC_DIRLEN(len) + 3458 NFSX_HYPER; 3459 dp->d_type = DT_UNKNOWN; 3460 blksiz += dp->d_reclen; 3461 if (blksiz == DIRBLKSIZ) 3462 blksiz = 0; 3463 uiop->uio_resid -= DIRHDSIZ; 3464 uiop->uio_offset += DIRHDSIZ; 3465 uiop->uio_iov->iov_base = 3466 (char *)uiop->uio_iov->iov_base + DIRHDSIZ; 3467 uiop->uio_iov->iov_len -= DIRHDSIZ; 3468 error = nfsm_mbufuio(nd, uiop, len); 3469 if (error) 3470 goto nfsmout; 3471 cp = uiop->uio_iov->iov_base; 3472 tlen -= len; 3473 NFSBZERO(cp, tlen); 3474 cp += tlen; /* points to cookie storage */ 3475 tl2 = (u_int32_t *)cp; 3476 uiop->uio_iov->iov_base = 3477 (char *)uiop->uio_iov->iov_base + tlen + 3478 NFSX_HYPER; 3479 uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; 3480 uiop->uio_resid -= tlen + NFSX_HYPER; 3481 uiop->uio_offset += (tlen + NFSX_HYPER); 3482 } else { 3483 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3484 if (error) 3485 goto nfsmout; 3486 } 3487 if (nd->nd_flag & ND_NFSV4) { 3488 rderr = 0; 3489 nfsva.na_mntonfileno = UINT64_MAX; 3490 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3491 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3492 NULL, NULL, &rderr, p, cred); 3493 if (error) 3494 goto nfsmout; 3495 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3496 } else if (nd->nd_flag & ND_NFSV3) { 3497 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3498 ncookie.lval[0] = *tl++; 3499 ncookie.lval[1] = *tl++; 3500 } else { 3501 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3502 ncookie.lval[0] = 0; 3503 ncookie.lval[1] = *tl++; 3504 } 3505 if (bigenough) { 3506 if (nd->nd_flag & ND_NFSV4) { 3507 if (rderr) { 3508 dp->d_fileno = 0; 3509 } else { 3510 if (gotmnton) { 3511 if (nfsva.na_mntonfileno != UINT64_MAX) 3512 dp->d_fileno = nfsva.na_mntonfileno; 3513 else 3514 dp->d_fileno = nfsva.na_fileid; 3515 } else if (nfsva.na_filesid[0] == 3516 dnp->n_vattr.na_filesid[0] && 3517 nfsva.na_filesid[1] == 3518 dnp->n_vattr.na_filesid[1]) { 3519 dp->d_fileno = nfsva.na_fileid; 3520 } else { 3521 do { 3522 fakefileno--; 3523 } while (fakefileno == 3524 nfsva.na_fileid); 3525 dp->d_fileno = fakefileno; 3526 } 3527 dp->d_type = vtonfs_dtype(nfsva.na_type); 3528 } 3529 } else { 3530 dp->d_fileno = nfsva.na_fileid; 3531 } 3532 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3533 ncookie.lval[0]; 3534 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3535 ncookie.lval[1]; 3536 } 3537 more_dirs = fxdr_unsigned(int, *tl); 3538 } 3539 /* 3540 * If at end of rpc data, get the eof boolean 3541 */ 3542 if (!more_dirs) { 3543 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3544 eof = fxdr_unsigned(int, *tl); 3545 if (tryformoredirs) 3546 more_dirs = !eof; 3547 if (nd->nd_flag & ND_NFSV4) { 3548 error = nfscl_postop_attr(nd, nap, attrflagp, 3549 stuff); 3550 if (error) 3551 goto nfsmout; 3552 } 3553 } 3554 m_freem(nd->nd_mrep); 3555 nd->nd_mrep = NULL; 3556 } 3557 /* 3558 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3559 * by increasing d_reclen for the last record. 3560 */ 3561 if (blksiz > 0) { 3562 left = DIRBLKSIZ - blksiz; 3563 NFSBZERO(uiop->uio_iov->iov_base, left); 3564 dp->d_reclen += left; 3565 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 3566 left; 3567 uiop->uio_iov->iov_len -= left; 3568 uiop->uio_resid -= left; 3569 uiop->uio_offset += left; 3570 } 3571 3572 /* 3573 * If returning no data, assume end of file. 3574 * If not bigenough, return not end of file, since you aren't 3575 * returning all the data 3576 * Otherwise, return the eof flag from the server. 3577 */ 3578 if (eofp) { 3579 if (tresid == ((size_t)(uiop->uio_resid))) 3580 *eofp = 1; 3581 else if (!bigenough) 3582 *eofp = 0; 3583 else 3584 *eofp = eof; 3585 } 3586 3587 /* 3588 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3589 */ 3590 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { 3591 dp = (struct dirent *)uiop->uio_iov->iov_base; 3592 NFSBZERO(dp, DIRBLKSIZ); 3593 dp->d_type = DT_UNKNOWN; 3594 tl = (u_int32_t *)&dp->d_name[4]; 3595 *tl++ = cookie.lval[0]; 3596 *tl = cookie.lval[1]; 3597 dp->d_reclen = DIRBLKSIZ; 3598 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 3599 DIRBLKSIZ; 3600 uiop->uio_iov->iov_len -= DIRBLKSIZ; 3601 uiop->uio_resid -= DIRBLKSIZ; 3602 uiop->uio_offset += DIRBLKSIZ; 3603 } 3604 3605 nfsmout: 3606 if (nd->nd_mrep != NULL) 3607 m_freem(nd->nd_mrep); 3608 return (error); 3609 } 3610 3611 #ifndef APPLE 3612 /* 3613 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 3614 * (Also used for NFS V4 when mount flag set.) 3615 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 3616 */ 3617 int 3618 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3619 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3620 int *eofp, void *stuff) 3621 { 3622 int len, left; 3623 struct dirent *dp = NULL; 3624 u_int32_t *tl; 3625 vnode_t newvp = NULLVP; 3626 struct nfsrv_descript nfsd, *nd = &nfsd; 3627 struct nameidata nami, *ndp = &nami; 3628 struct componentname *cnp = &ndp->ni_cnd; 3629 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 3630 struct nfsnode *dnp = VTONFS(vp), *np; 3631 struct nfsvattr nfsva; 3632 struct nfsfh *nfhp; 3633 nfsquad_t cookie, ncookie; 3634 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3635 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 3636 int isdotdot = 0, unlocknewvp = 0; 3637 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3638 u_int64_t fileno = 0; 3639 char *cp; 3640 nfsattrbit_t attrbits, dattrbits; 3641 size_t tresid; 3642 u_int32_t *tl2 = NULL, rderr; 3643 struct timespec dctime, ts; 3644 bool attr_ok; 3645 3646 KASSERT(uiop->uio_iovcnt == 1 && 3647 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 3648 ("nfs readdirplusrpc bad uio")); 3649 ncookie.lval[0] = ncookie.lval[1] = 0; 3650 timespecclear(&dctime); 3651 *attrflagp = 0; 3652 if (eofp != NULL) 3653 *eofp = 0; 3654 ndp->ni_dvp = vp; 3655 nd->nd_mrep = NULL; 3656 cookie.lval[0] = cookiep->nfsuquad[0]; 3657 cookie.lval[1] = cookiep->nfsuquad[1]; 3658 tresid = uiop->uio_resid; 3659 3660 /* 3661 * For NFSv4, first create the "." and ".." entries. 3662 */ 3663 if (NFSHASNFSV4(nmp)) { 3664 NFSGETATTR_ATTRBIT(&dattrbits); 3665 NFSZERO_ATTRBIT(&attrbits); 3666 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3667 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3668 NFSATTRBIT_MOUNTEDONFILEID)) { 3669 NFSSETBIT_ATTRBIT(&attrbits, 3670 NFSATTRBIT_MOUNTEDONFILEID); 3671 gotmnton = 1; 3672 } else { 3673 /* 3674 * Must fake it. Use the fileno, except when the 3675 * fsid is != to that of the directory. For that 3676 * case, generate a fake fileno that is not the same. 3677 */ 3678 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3679 gotmnton = 0; 3680 } 3681 3682 /* 3683 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3684 */ 3685 if (uiop->uio_offset == 0) { 3686 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp); 3687 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3688 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3689 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3690 (void) nfsrv_putattrbit(nd, &attrbits); 3691 error = nfscl_request(nd, vp, p, cred, stuff); 3692 if (error) 3693 return (error); 3694 dotfileid = 0; /* Fake out the compiler. */ 3695 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3696 error = nfsm_loadattr(nd, &nfsva); 3697 if (error != 0) 3698 goto nfsmout; 3699 dctime = nfsva.na_ctime; 3700 dotfileid = nfsva.na_fileid; 3701 } 3702 if (nd->nd_repstat == 0) { 3703 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3704 len = fxdr_unsigned(int, *(tl + 4)); 3705 if (len > 0 && len <= NFSX_V4FHMAX) 3706 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3707 else 3708 error = EPERM; 3709 if (!error) { 3710 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3711 nfsva.na_mntonfileno = UINT64_MAX; 3712 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3713 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3714 NULL, NULL, NULL, p, cred); 3715 if (error) { 3716 dotdotfileid = dotfileid; 3717 } else if (gotmnton) { 3718 if (nfsva.na_mntonfileno != UINT64_MAX) 3719 dotdotfileid = nfsva.na_mntonfileno; 3720 else 3721 dotdotfileid = nfsva.na_fileid; 3722 } else if (nfsva.na_filesid[0] == 3723 dnp->n_vattr.na_filesid[0] && 3724 nfsva.na_filesid[1] == 3725 dnp->n_vattr.na_filesid[1]) { 3726 dotdotfileid = nfsva.na_fileid; 3727 } else { 3728 do { 3729 fakefileno--; 3730 } while (fakefileno == 3731 nfsva.na_fileid); 3732 dotdotfileid = fakefileno; 3733 } 3734 } 3735 } else if (nd->nd_repstat == NFSERR_NOENT) { 3736 /* 3737 * Lookupp returns NFSERR_NOENT when we are 3738 * at the root, so just use the current dir. 3739 */ 3740 nd->nd_repstat = 0; 3741 dotdotfileid = dotfileid; 3742 } else { 3743 error = nd->nd_repstat; 3744 } 3745 m_freem(nd->nd_mrep); 3746 if (error) 3747 return (error); 3748 nd->nd_mrep = NULL; 3749 dp = (struct dirent *)uiop->uio_iov->iov_base; 3750 dp->d_pad0 = dp->d_pad1 = 0; 3751 dp->d_off = 0; 3752 dp->d_type = DT_DIR; 3753 dp->d_fileno = dotfileid; 3754 dp->d_namlen = 1; 3755 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3756 dp->d_name[0] = '.'; 3757 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3758 /* 3759 * Just make these offset cookie 0. 3760 */ 3761 tl = (u_int32_t *)&dp->d_name[8]; 3762 *tl++ = 0; 3763 *tl = 0; 3764 blksiz += dp->d_reclen; 3765 uiop->uio_resid -= dp->d_reclen; 3766 uiop->uio_offset += dp->d_reclen; 3767 uiop->uio_iov->iov_base = 3768 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3769 uiop->uio_iov->iov_len -= dp->d_reclen; 3770 dp = (struct dirent *)uiop->uio_iov->iov_base; 3771 dp->d_pad0 = dp->d_pad1 = 0; 3772 dp->d_off = 0; 3773 dp->d_type = DT_DIR; 3774 dp->d_fileno = dotdotfileid; 3775 dp->d_namlen = 2; 3776 *((uint64_t *)dp->d_name) = 0; 3777 dp->d_name[0] = '.'; 3778 dp->d_name[1] = '.'; 3779 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3780 /* 3781 * Just make these offset cookie 0. 3782 */ 3783 tl = (u_int32_t *)&dp->d_name[8]; 3784 *tl++ = 0; 3785 *tl = 0; 3786 blksiz += dp->d_reclen; 3787 uiop->uio_resid -= dp->d_reclen; 3788 uiop->uio_offset += dp->d_reclen; 3789 uiop->uio_iov->iov_base = 3790 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3791 uiop->uio_iov->iov_len -= dp->d_reclen; 3792 } 3793 NFSREADDIRPLUS_ATTRBIT(&attrbits); 3794 if (gotmnton) 3795 NFSSETBIT_ATTRBIT(&attrbits, 3796 NFSATTRBIT_MOUNTEDONFILEID); 3797 if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3798 NFSATTRBIT_TIMECREATE)) 3799 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); 3800 } 3801 3802 /* 3803 * Loop around doing readdir rpc's of size nm_readdirsize. 3804 * The stopping criteria is EOF or buffer full. 3805 */ 3806 while (more_dirs && bigenough) { 3807 *attrflagp = 0; 3808 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp); 3809 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3810 *tl++ = cookie.lval[0]; 3811 *tl++ = cookie.lval[1]; 3812 if (cookie.qval == 0) { 3813 *tl++ = 0; 3814 *tl++ = 0; 3815 } else { 3816 NFSLOCKNODE(dnp); 3817 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3818 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3819 NFSUNLOCKNODE(dnp); 3820 } 3821 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3822 *tl = txdr_unsigned(nmp->nm_readdirsize); 3823 if (nd->nd_flag & ND_NFSV4) { 3824 (void) nfsrv_putattrbit(nd, &attrbits); 3825 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3826 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3827 (void) nfsrv_putattrbit(nd, &dattrbits); 3828 } 3829 nanouptime(&ts); 3830 error = nfscl_request(nd, vp, p, cred, stuff); 3831 if (error) 3832 return (error); 3833 if (nd->nd_flag & ND_NFSV3) 3834 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 3835 if (nd->nd_repstat || error) { 3836 if (!error) 3837 error = nd->nd_repstat; 3838 goto nfsmout; 3839 } 3840 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 3841 dctime = nap->na_ctime; 3842 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3843 NFSLOCKNODE(dnp); 3844 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3845 dnp->n_cookieverf.nfsuquad[1] = *tl++; 3846 NFSUNLOCKNODE(dnp); 3847 more_dirs = fxdr_unsigned(int, *tl); 3848 if (!more_dirs) 3849 tryformoredirs = 0; 3850 3851 /* loop through the dir entries, doctoring them to 4bsd form */ 3852 while (more_dirs && bigenough) { 3853 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3854 if (nd->nd_flag & ND_NFSV4) { 3855 ncookie.lval[0] = *tl++; 3856 ncookie.lval[1] = *tl++; 3857 } else { 3858 fileno = fxdr_hyper(tl); 3859 tl += 2; 3860 } 3861 len = fxdr_unsigned(int, *tl); 3862 if (len <= 0 || len > NFS_MAXNAMLEN) { 3863 error = EBADRPC; 3864 goto nfsmout; 3865 } 3866 tlen = roundup2(len, 8); 3867 if (tlen == len) 3868 tlen += 8; /* To ensure null termination. */ 3869 left = DIRBLKSIZ - blksiz; 3870 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3871 NFSBZERO(uiop->uio_iov->iov_base, left); 3872 dp->d_reclen += left; 3873 uiop->uio_iov->iov_base = 3874 (char *)uiop->uio_iov->iov_base + left; 3875 uiop->uio_iov->iov_len -= left; 3876 uiop->uio_resid -= left; 3877 uiop->uio_offset += left; 3878 blksiz = 0; 3879 } 3880 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3881 uiop->uio_resid) 3882 bigenough = 0; 3883 if (bigenough) { 3884 dp = (struct dirent *)uiop->uio_iov->iov_base; 3885 dp->d_pad0 = dp->d_pad1 = 0; 3886 dp->d_off = 0; 3887 dp->d_namlen = len; 3888 dp->d_reclen = _GENERIC_DIRLEN(len) + 3889 NFSX_HYPER; 3890 dp->d_type = DT_UNKNOWN; 3891 blksiz += dp->d_reclen; 3892 if (blksiz == DIRBLKSIZ) 3893 blksiz = 0; 3894 uiop->uio_resid -= DIRHDSIZ; 3895 uiop->uio_offset += DIRHDSIZ; 3896 uiop->uio_iov->iov_base = 3897 (char *)uiop->uio_iov->iov_base + DIRHDSIZ; 3898 uiop->uio_iov->iov_len -= DIRHDSIZ; 3899 cnp->cn_nameptr = uiop->uio_iov->iov_base; 3900 cnp->cn_namelen = len; 3901 NFSCNHASHZERO(cnp); 3902 error = nfsm_mbufuio(nd, uiop, len); 3903 if (error) 3904 goto nfsmout; 3905 cp = uiop->uio_iov->iov_base; 3906 tlen -= len; 3907 NFSBZERO(cp, tlen); 3908 cp += tlen; /* points to cookie storage */ 3909 tl2 = (u_int32_t *)cp; 3910 if (len == 2 && cnp->cn_nameptr[0] == '.' && 3911 cnp->cn_nameptr[1] == '.') 3912 isdotdot = 1; 3913 else 3914 isdotdot = 0; 3915 uiop->uio_iov->iov_base = 3916 (char *)uiop->uio_iov->iov_base + tlen + 3917 NFSX_HYPER; 3918 uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; 3919 uiop->uio_resid -= tlen + NFSX_HYPER; 3920 uiop->uio_offset += (tlen + NFSX_HYPER); 3921 } else { 3922 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3923 if (error) 3924 goto nfsmout; 3925 } 3926 nfhp = NULL; 3927 if (nd->nd_flag & ND_NFSV3) { 3928 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3929 ncookie.lval[0] = *tl++; 3930 ncookie.lval[1] = *tl++; 3931 attrflag = fxdr_unsigned(int, *tl); 3932 if (attrflag) { 3933 error = nfsm_loadattr(nd, &nfsva); 3934 if (error) 3935 goto nfsmout; 3936 } 3937 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 3938 if (*tl) { 3939 error = nfsm_getfh(nd, &nfhp); 3940 if (error) 3941 goto nfsmout; 3942 } 3943 if (!attrflag && nfhp != NULL) { 3944 free(nfhp, M_NFSFH); 3945 nfhp = NULL; 3946 } 3947 } else { 3948 rderr = 0; 3949 nfsva.na_mntonfileno = 0xffffffff; 3950 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 3951 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3952 NULL, NULL, &rderr, p, cred); 3953 if (error) 3954 goto nfsmout; 3955 } 3956 3957 if (bigenough) { 3958 if (nd->nd_flag & ND_NFSV4) { 3959 if (rderr) { 3960 dp->d_fileno = 0; 3961 } else if (gotmnton) { 3962 if (nfsva.na_mntonfileno != 0xffffffff) 3963 dp->d_fileno = nfsva.na_mntonfileno; 3964 else 3965 dp->d_fileno = nfsva.na_fileid; 3966 } else if (nfsva.na_filesid[0] == 3967 dnp->n_vattr.na_filesid[0] && 3968 nfsva.na_filesid[1] == 3969 dnp->n_vattr.na_filesid[1]) { 3970 dp->d_fileno = nfsva.na_fileid; 3971 } else { 3972 do { 3973 fakefileno--; 3974 } while (fakefileno == 3975 nfsva.na_fileid); 3976 dp->d_fileno = fakefileno; 3977 } 3978 } else { 3979 dp->d_fileno = fileno; 3980 } 3981 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3982 ncookie.lval[0]; 3983 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3984 ncookie.lval[1]; 3985 3986 if (nfhp != NULL) { 3987 attr_ok = true; 3988 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 3989 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 3990 VREF(vp); 3991 newvp = vp; 3992 unlocknewvp = 0; 3993 free(nfhp, M_NFSFH); 3994 np = dnp; 3995 } else if (isdotdot != 0) { 3996 /* 3997 * Skip doing a nfscl_nget() call for "..". 3998 * There's a race between acquiring the nfs 3999 * node here and lookups that look for the 4000 * directory being read (in the parent). 4001 * It would try to get a lock on ".." here, 4002 * owning the lock on the directory being 4003 * read. Lookup will hold the lock on ".." 4004 * and try to acquire the lock on the 4005 * directory being read. 4006 * If the directory is unlocked/relocked, 4007 * then there is a LOR with the buflock 4008 * vp is relocked. 4009 */ 4010 free(nfhp, M_NFSFH); 4011 } else { 4012 error = nfscl_nget(vp->v_mount, vp, 4013 nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE); 4014 if (!error) { 4015 newvp = NFSTOV(np); 4016 unlocknewvp = 1; 4017 /* 4018 * If n_localmodtime >= time before RPC, 4019 * then a file modification operation, 4020 * such as VOP_SETATTR() of size, has 4021 * occurred while the Lookup RPC and 4022 * acquisition of the vnode happened. As 4023 * such, the attributes might be stale, 4024 * with possibly an incorrect size. 4025 */ 4026 NFSLOCKNODE(np); 4027 if (timespecisset( 4028 &np->n_localmodtime) && 4029 timespeccmp(&np->n_localmodtime, 4030 &ts, >=)) { 4031 NFSCL_DEBUG(4, "nfsrpc_readdirplus:" 4032 " localmod stale attributes\n"); 4033 attr_ok = false; 4034 } 4035 NFSUNLOCKNODE(np); 4036 } 4037 } 4038 nfhp = NULL; 4039 if (newvp != NULLVP) { 4040 if (attr_ok) 4041 error = nfscl_loadattrcache(&newvp, 4042 &nfsva, NULL, NULL, 0, 0); 4043 if (error) { 4044 if (unlocknewvp) 4045 vput(newvp); 4046 else 4047 vrele(newvp); 4048 goto nfsmout; 4049 } 4050 dp->d_type = 4051 vtonfs_dtype(np->n_vattr.na_type); 4052 ndp->ni_vp = newvp; 4053 NFSCNHASH(cnp, HASHINIT); 4054 if (cnp->cn_namelen <= NCHNAMLEN && 4055 ndp->ni_dvp != ndp->ni_vp && 4056 (newvp->v_type != VDIR || 4057 dctime.tv_sec != 0)) { 4058 cache_enter_time_flags(ndp->ni_dvp, 4059 ndp->ni_vp, cnp, 4060 &nfsva.na_ctime, 4061 newvp->v_type != VDIR ? NULL : 4062 &dctime, VFS_CACHE_DROPOLD); 4063 } 4064 if (unlocknewvp) 4065 vput(newvp); 4066 else 4067 vrele(newvp); 4068 newvp = NULLVP; 4069 } 4070 } 4071 } else if (nfhp != NULL) { 4072 free(nfhp, M_NFSFH); 4073 } 4074 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4075 more_dirs = fxdr_unsigned(int, *tl); 4076 } 4077 /* 4078 * If at end of rpc data, get the eof boolean 4079 */ 4080 if (!more_dirs) { 4081 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4082 eof = fxdr_unsigned(int, *tl); 4083 if (tryformoredirs) 4084 more_dirs = !eof; 4085 if (nd->nd_flag & ND_NFSV4) { 4086 error = nfscl_postop_attr(nd, nap, attrflagp, 4087 stuff); 4088 if (error) 4089 goto nfsmout; 4090 } 4091 } 4092 m_freem(nd->nd_mrep); 4093 nd->nd_mrep = NULL; 4094 } 4095 /* 4096 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 4097 * by increasing d_reclen for the last record. 4098 */ 4099 if (blksiz > 0) { 4100 left = DIRBLKSIZ - blksiz; 4101 NFSBZERO(uiop->uio_iov->iov_base, left); 4102 dp->d_reclen += left; 4103 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 4104 left; 4105 uiop->uio_iov->iov_len -= left; 4106 uiop->uio_resid -= left; 4107 uiop->uio_offset += left; 4108 } 4109 4110 /* 4111 * If returning no data, assume end of file. 4112 * If not bigenough, return not end of file, since you aren't 4113 * returning all the data 4114 * Otherwise, return the eof flag from the server. 4115 */ 4116 if (eofp != NULL) { 4117 if (tresid == uiop->uio_resid) 4118 *eofp = 1; 4119 else if (!bigenough) 4120 *eofp = 0; 4121 else 4122 *eofp = eof; 4123 } 4124 4125 /* 4126 * Add extra empty records to any remaining DIRBLKSIZ chunks. 4127 */ 4128 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { 4129 dp = (struct dirent *)uiop->uio_iov->iov_base; 4130 NFSBZERO(dp, DIRBLKSIZ); 4131 dp->d_type = DT_UNKNOWN; 4132 tl = (u_int32_t *)&dp->d_name[4]; 4133 *tl++ = cookie.lval[0]; 4134 *tl = cookie.lval[1]; 4135 dp->d_reclen = DIRBLKSIZ; 4136 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 4137 DIRBLKSIZ; 4138 uiop->uio_iov->iov_len -= DIRBLKSIZ; 4139 uiop->uio_resid -= DIRBLKSIZ; 4140 uiop->uio_offset += DIRBLKSIZ; 4141 } 4142 4143 nfsmout: 4144 if (nd->nd_mrep != NULL) 4145 m_freem(nd->nd_mrep); 4146 return (error); 4147 } 4148 #endif /* !APPLE */ 4149 4150 /* 4151 * Nfs commit rpc 4152 */ 4153 int 4154 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 4155 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 4156 { 4157 u_int32_t *tl; 4158 struct nfsrv_descript nfsd, *nd = &nfsd; 4159 nfsattrbit_t attrbits; 4160 int error; 4161 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4162 4163 *attrflagp = 0; 4164 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp); 4165 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4166 txdr_hyper(offset, tl); 4167 tl += 2; 4168 *tl = txdr_unsigned(cnt); 4169 if (nd->nd_flag & ND_NFSV4) { 4170 /* 4171 * And do a Getattr op. 4172 */ 4173 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4174 *tl = txdr_unsigned(NFSV4OP_GETATTR); 4175 NFSGETATTR_ATTRBIT(&attrbits); 4176 (void) nfsrv_putattrbit(nd, &attrbits); 4177 } 4178 error = nfscl_request(nd, vp, p, cred, stuff); 4179 if (error) 4180 return (error); 4181 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff); 4182 if (!error && !nd->nd_repstat) { 4183 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 4184 NFSLOCKMNT(nmp); 4185 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { 4186 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 4187 nd->nd_repstat = NFSERR_STALEWRITEVERF; 4188 } 4189 NFSUNLOCKMNT(nmp); 4190 if (nd->nd_flag & ND_NFSV4) 4191 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4192 } 4193 nfsmout: 4194 if (!error && nd->nd_repstat) 4195 error = nd->nd_repstat; 4196 m_freem(nd->nd_mrep); 4197 return (error); 4198 } 4199 4200 /* 4201 * NFS byte range lock rpc. 4202 * (Mostly just calls one of the three lower level RPC routines.) 4203 */ 4204 int 4205 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 4206 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 4207 { 4208 struct nfscllockowner *lp; 4209 struct nfsclclient *clp; 4210 struct nfsfh *nfhp; 4211 struct nfsrv_descript nfsd, *nd = &nfsd; 4212 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4213 u_int64_t off, len; 4214 off_t start, end; 4215 u_int32_t clidrev = 0; 4216 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 4217 int callcnt, dorpc; 4218 4219 /* 4220 * Convert the flock structure into a start and end and do POSIX 4221 * bounds checking. 4222 */ 4223 switch (fl->l_whence) { 4224 case SEEK_SET: 4225 case SEEK_CUR: 4226 /* 4227 * Caller is responsible for adding any necessary offset 4228 * when SEEK_CUR is used. 4229 */ 4230 start = fl->l_start; 4231 off = fl->l_start; 4232 break; 4233 case SEEK_END: 4234 start = size + fl->l_start; 4235 off = size + fl->l_start; 4236 break; 4237 default: 4238 return (EINVAL); 4239 } 4240 if (start < 0) 4241 return (EINVAL); 4242 if (fl->l_len != 0) { 4243 end = start + fl->l_len - 1; 4244 if (end < start) 4245 return (EINVAL); 4246 } 4247 4248 len = fl->l_len; 4249 if (len == 0) 4250 len = NFS64BITSSET; 4251 retrycnt = 0; 4252 do { 4253 nd->nd_repstat = 0; 4254 if (op == F_GETLK) { 4255 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); 4256 if (error) 4257 return (error); 4258 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 4259 if (!error) { 4260 clidrev = clp->nfsc_clientidrev; 4261 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 4262 p, id, flags); 4263 } else if (error == -1) { 4264 error = 0; 4265 } 4266 nfscl_clientrelease(clp); 4267 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 4268 /* 4269 * We must loop around for all lockowner cases. 4270 */ 4271 callcnt = 0; 4272 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); 4273 if (error) 4274 return (error); 4275 do { 4276 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 4277 clp, id, flags, &lp, &dorpc); 4278 /* 4279 * If it returns a NULL lp, we're done. 4280 */ 4281 if (lp == NULL) { 4282 if (callcnt == 0) 4283 nfscl_clientrelease(clp); 4284 else 4285 nfscl_releasealllocks(clp, vp, p, id, flags); 4286 return (error); 4287 } 4288 if (nmp->nm_clp != NULL) 4289 clidrev = nmp->nm_clp->nfsc_clientidrev; 4290 else 4291 clidrev = 0; 4292 /* 4293 * If the server doesn't support Posix lock semantics, 4294 * only allow locks on the entire file, since it won't 4295 * handle overlapping byte ranges. 4296 * There might still be a problem when a lock 4297 * upgrade/downgrade (read<->write) occurs, since the 4298 * server "might" expect an unlock first? 4299 */ 4300 if (dorpc && (lp->nfsl_open->nfso_posixlock || 4301 (off == 0 && len == NFS64BITSSET))) { 4302 /* 4303 * Since the lock records will go away, we must 4304 * wait for grace and delay here. 4305 */ 4306 do { 4307 error = nfsrpc_locku(nd, nmp, lp, off, len, 4308 NFSV4LOCKT_READ, cred, p, 0); 4309 if ((nd->nd_repstat == NFSERR_GRACE || 4310 nd->nd_repstat == NFSERR_DELAY) && 4311 error == 0) 4312 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 4313 "nfs_advlock"); 4314 } while ((nd->nd_repstat == NFSERR_GRACE || 4315 nd->nd_repstat == NFSERR_DELAY) && error == 0); 4316 } 4317 callcnt++; 4318 } while (error == 0 && nd->nd_repstat == 0); 4319 nfscl_releasealllocks(clp, vp, p, id, flags); 4320 } else if (op == F_SETLK) { 4321 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 4322 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 4323 if (error || donelocally) { 4324 return (error); 4325 } 4326 if (nmp->nm_clp != NULL) 4327 clidrev = nmp->nm_clp->nfsc_clientidrev; 4328 else 4329 clidrev = 0; 4330 nfhp = VTONFS(vp)->n_fhp; 4331 if (!lp->nfsl_open->nfso_posixlock && 4332 (off != 0 || len != NFS64BITSSET)) { 4333 error = EINVAL; 4334 } else { 4335 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 4336 nfhp->nfh_len, lp, newone, reclaim, off, 4337 len, fl->l_type, cred, p, 0); 4338 } 4339 if (!error) 4340 error = nd->nd_repstat; 4341 nfscl_lockrelease(lp, error, newone); 4342 } else { 4343 error = EINVAL; 4344 } 4345 if (!error) 4346 error = nd->nd_repstat; 4347 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 4348 error == NFSERR_STALEDONTRECOVER || 4349 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 4350 error == NFSERR_BADSESSION) { 4351 (void) nfs_catnap(PZERO, error, "nfs_advlock"); 4352 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 4353 && clidrev != 0) { 4354 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 4355 retrycnt++; 4356 } 4357 } while (error == NFSERR_GRACE || 4358 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 4359 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 4360 error == NFSERR_BADSESSION || 4361 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 4362 expireret == 0 && clidrev != 0 && retrycnt < 4)); 4363 if (error && retrycnt >= 4) 4364 error = EIO; 4365 return (error); 4366 } 4367 4368 /* 4369 * The lower level routine for the LockT case. 4370 */ 4371 int 4372 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 4373 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 4374 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 4375 { 4376 u_int32_t *tl; 4377 int error, type, size; 4378 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4379 struct nfsnode *np; 4380 struct nfsmount *nmp; 4381 struct nfsclsession *tsep; 4382 4383 nmp = VFSTONFS(vp->v_mount); 4384 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp); 4385 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4386 if (fl->l_type == F_RDLCK) 4387 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4388 else 4389 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4390 txdr_hyper(off, tl); 4391 tl += 2; 4392 txdr_hyper(len, tl); 4393 tl += 2; 4394 tsep = nfsmnt_mdssession(nmp); 4395 *tl++ = tsep->nfsess_clientid.lval[0]; 4396 *tl = tsep->nfsess_clientid.lval[1]; 4397 nfscl_filllockowner(id, own, flags); 4398 np = VTONFS(vp); 4399 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 4400 np->n_fhp->nfh_len); 4401 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 4402 error = nfscl_request(nd, vp, p, cred, NULL); 4403 if (error) 4404 return (error); 4405 if (nd->nd_repstat == 0) { 4406 fl->l_type = F_UNLCK; 4407 } else if (nd->nd_repstat == NFSERR_DENIED) { 4408 nd->nd_repstat = 0; 4409 fl->l_whence = SEEK_SET; 4410 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4411 fl->l_start = fxdr_hyper(tl); 4412 tl += 2; 4413 len = fxdr_hyper(tl); 4414 tl += 2; 4415 if (len == NFS64BITSSET) 4416 fl->l_len = 0; 4417 else 4418 fl->l_len = len; 4419 type = fxdr_unsigned(int, *tl++); 4420 if (type == NFSV4LOCKT_WRITE) 4421 fl->l_type = F_WRLCK; 4422 else 4423 fl->l_type = F_RDLCK; 4424 /* 4425 * XXX For now, I have no idea what to do with the 4426 * conflicting lock_owner, so I'll just set the pid == 0 4427 * and skip over the lock_owner. 4428 */ 4429 fl->l_pid = (pid_t)0; 4430 tl += 2; 4431 size = fxdr_unsigned(int, *tl); 4432 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4433 error = EBADRPC; 4434 if (!error) 4435 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4436 } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 4437 nfscl_initiate_recovery(clp); 4438 nfsmout: 4439 m_freem(nd->nd_mrep); 4440 return (error); 4441 } 4442 4443 /* 4444 * Lower level function that performs the LockU RPC. 4445 */ 4446 static int 4447 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 4448 struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 4449 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 4450 { 4451 u_int32_t *tl; 4452 int error; 4453 4454 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 4455 lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0); 4456 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 4457 *tl++ = txdr_unsigned(type); 4458 *tl = txdr_unsigned(lp->nfsl_seqid); 4459 if (nfstest_outofseq && 4460 (arc4random() % nfstest_outofseq) == 0) 4461 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4462 tl++; 4463 if (NFSHASNFSV4N(nmp)) 4464 *tl++ = 0; 4465 else 4466 *tl++ = lp->nfsl_stateid.seqid; 4467 *tl++ = lp->nfsl_stateid.other[0]; 4468 *tl++ = lp->nfsl_stateid.other[1]; 4469 *tl++ = lp->nfsl_stateid.other[2]; 4470 txdr_hyper(off, tl); 4471 tl += 2; 4472 txdr_hyper(len, tl); 4473 if (syscred) 4474 nd->nd_flag |= ND_USEGSSNAME; 4475 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4476 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4477 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4478 if (error) 4479 return (error); 4480 if (nd->nd_repstat == 0) { 4481 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4482 lp->nfsl_stateid.seqid = *tl++; 4483 lp->nfsl_stateid.other[0] = *tl++; 4484 lp->nfsl_stateid.other[1] = *tl++; 4485 lp->nfsl_stateid.other[2] = *tl; 4486 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4487 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4488 nfsmout: 4489 m_freem(nd->nd_mrep); 4490 return (error); 4491 } 4492 4493 /* 4494 * The actual Lock RPC. 4495 */ 4496 int 4497 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 4498 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 4499 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 4500 NFSPROC_T *p, int syscred) 4501 { 4502 u_int32_t *tl; 4503 int error, size; 4504 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4505 struct nfsclsession *tsep; 4506 4507 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0); 4508 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4509 if (type == F_RDLCK) 4510 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4511 else 4512 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4513 *tl++ = txdr_unsigned(reclaim); 4514 txdr_hyper(off, tl); 4515 tl += 2; 4516 txdr_hyper(len, tl); 4517 tl += 2; 4518 if (newone) { 4519 *tl = newnfs_true; 4520 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 4521 2 * NFSX_UNSIGNED + NFSX_HYPER); 4522 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 4523 if (NFSHASNFSV4N(nmp)) 4524 *tl++ = 0; 4525 else 4526 *tl++ = lp->nfsl_open->nfso_stateid.seqid; 4527 *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 4528 *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 4529 *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 4530 *tl++ = txdr_unsigned(lp->nfsl_seqid); 4531 tsep = nfsmnt_mdssession(nmp); 4532 *tl++ = tsep->nfsess_clientid.lval[0]; 4533 *tl = tsep->nfsess_clientid.lval[1]; 4534 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4535 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4536 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4537 } else { 4538 *tl = newnfs_false; 4539 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 4540 if (NFSHASNFSV4N(nmp)) 4541 *tl++ = 0; 4542 else 4543 *tl++ = lp->nfsl_stateid.seqid; 4544 *tl++ = lp->nfsl_stateid.other[0]; 4545 *tl++ = lp->nfsl_stateid.other[1]; 4546 *tl++ = lp->nfsl_stateid.other[2]; 4547 *tl = txdr_unsigned(lp->nfsl_seqid); 4548 if (nfstest_outofseq && 4549 (arc4random() % nfstest_outofseq) == 0) 4550 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4551 } 4552 if (syscred) 4553 nd->nd_flag |= ND_USEGSSNAME; 4554 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 4555 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4556 if (error) 4557 return (error); 4558 if (newone) 4559 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 4560 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4561 if (nd->nd_repstat == 0) { 4562 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4563 lp->nfsl_stateid.seqid = *tl++; 4564 lp->nfsl_stateid.other[0] = *tl++; 4565 lp->nfsl_stateid.other[1] = *tl++; 4566 lp->nfsl_stateid.other[2] = *tl; 4567 } else if (nd->nd_repstat == NFSERR_DENIED) { 4568 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4569 size = fxdr_unsigned(int, *(tl + 7)); 4570 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4571 error = EBADRPC; 4572 if (!error) 4573 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4574 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4575 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4576 nfsmout: 4577 m_freem(nd->nd_mrep); 4578 return (error); 4579 } 4580 4581 /* 4582 * nfs statfs rpc 4583 * (always called with the vp for the mount point) 4584 */ 4585 int 4586 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 4587 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4588 void *stuff) 4589 { 4590 u_int32_t *tl = NULL; 4591 struct nfsrv_descript nfsd, *nd = &nfsd; 4592 struct nfsmount *nmp; 4593 nfsattrbit_t attrbits; 4594 int error; 4595 4596 *attrflagp = 0; 4597 nmp = VFSTONFS(vp->v_mount); 4598 if (NFSHASNFSV4(nmp)) { 4599 /* 4600 * For V4, you actually do a getattr. 4601 */ 4602 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4603 NFSSTATFS_GETATTRBIT(&attrbits); 4604 (void) nfsrv_putattrbit(nd, &attrbits); 4605 nd->nd_flag |= ND_USEGSSNAME; 4606 error = nfscl_request(nd, vp, p, cred, stuff); 4607 if (error) 4608 return (error); 4609 if (nd->nd_repstat == 0) { 4610 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4611 NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p, 4612 cred); 4613 if (!error) { 4614 nmp->nm_fsid[0] = nap->na_filesid[0]; 4615 nmp->nm_fsid[1] = nap->na_filesid[1]; 4616 NFSSETHASSETFSID(nmp); 4617 *attrflagp = 1; 4618 } 4619 } else { 4620 error = nd->nd_repstat; 4621 } 4622 if (error) 4623 goto nfsmout; 4624 } else { 4625 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp); 4626 error = nfscl_request(nd, vp, p, cred, stuff); 4627 if (error) 4628 return (error); 4629 if (nd->nd_flag & ND_NFSV3) { 4630 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4631 if (error) 4632 goto nfsmout; 4633 } 4634 if (nd->nd_repstat) { 4635 error = nd->nd_repstat; 4636 goto nfsmout; 4637 } 4638 NFSM_DISSECT(tl, u_int32_t *, 4639 NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 4640 } 4641 if (NFSHASNFSV3(nmp)) { 4642 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 4643 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 4644 sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 4645 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 4646 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 4647 sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 4648 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 4649 } else if (NFSHASNFSV4(nmp) == 0) { 4650 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 4651 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 4652 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 4653 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 4654 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 4655 } 4656 nfsmout: 4657 m_freem(nd->nd_mrep); 4658 return (error); 4659 } 4660 4661 /* 4662 * nfs pathconf rpc 4663 */ 4664 int 4665 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 4666 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 4667 void *stuff) 4668 { 4669 struct nfsrv_descript nfsd, *nd = &nfsd; 4670 struct nfsmount *nmp; 4671 u_int32_t *tl; 4672 nfsattrbit_t attrbits; 4673 int error; 4674 4675 *attrflagp = 0; 4676 nmp = VFSTONFS(vp->v_mount); 4677 if (NFSHASNFSV4(nmp)) { 4678 /* 4679 * For V4, you actually do a getattr. 4680 */ 4681 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp); 4682 NFSPATHCONF_GETATTRBIT(&attrbits); 4683 (void) nfsrv_putattrbit(nd, &attrbits); 4684 nd->nd_flag |= ND_USEGSSNAME; 4685 error = nfscl_request(nd, vp, p, cred, stuff); 4686 if (error) 4687 return (error); 4688 if (nd->nd_repstat == 0) { 4689 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4690 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 4691 cred); 4692 if (!error) 4693 *attrflagp = 1; 4694 } else { 4695 error = nd->nd_repstat; 4696 } 4697 } else { 4698 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp); 4699 error = nfscl_request(nd, vp, p, cred, stuff); 4700 if (error) 4701 return (error); 4702 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4703 if (nd->nd_repstat && !error) 4704 error = nd->nd_repstat; 4705 if (!error) { 4706 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 4707 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 4708 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 4709 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 4710 pc->pc_chownrestricted = 4711 fxdr_unsigned(u_int32_t, *tl++); 4712 pc->pc_caseinsensitive = 4713 fxdr_unsigned(u_int32_t, *tl++); 4714 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 4715 } 4716 } 4717 nfsmout: 4718 m_freem(nd->nd_mrep); 4719 return (error); 4720 } 4721 4722 /* 4723 * nfs version 3 fsinfo rpc call 4724 */ 4725 int 4726 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 4727 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff) 4728 { 4729 u_int32_t *tl; 4730 struct nfsrv_descript nfsd, *nd = &nfsd; 4731 int error; 4732 4733 *attrflagp = 0; 4734 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp); 4735 error = nfscl_request(nd, vp, p, cred, stuff); 4736 if (error) 4737 return (error); 4738 error = nfscl_postop_attr(nd, nap, attrflagp, stuff); 4739 if (nd->nd_repstat && !error) 4740 error = nd->nd_repstat; 4741 if (!error) { 4742 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 4743 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 4744 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 4745 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 4746 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 4747 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 4748 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 4749 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 4750 fsp->fs_maxfilesize = fxdr_hyper(tl); 4751 tl += 2; 4752 fxdr_nfsv3time(tl, &fsp->fs_timedelta); 4753 tl += 2; 4754 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 4755 } 4756 nfsmout: 4757 m_freem(nd->nd_mrep); 4758 return (error); 4759 } 4760 4761 /* 4762 * This function performs the Renew RPC. 4763 */ 4764 int 4765 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, 4766 NFSPROC_T *p) 4767 { 4768 u_int32_t *tl; 4769 struct nfsrv_descript nfsd; 4770 struct nfsrv_descript *nd = &nfsd; 4771 struct nfsmount *nmp; 4772 int error; 4773 struct nfssockreq *nrp; 4774 struct nfsclsession *tsep; 4775 4776 nmp = clp->nfsc_nmp; 4777 if (nmp == NULL) 4778 return (0); 4779 if (dsp == NULL) 4780 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0, 4781 0); 4782 else 4783 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, 4784 &dsp->nfsclds_sess, 0, 0); 4785 if (!NFSHASNFSV4N(nmp)) { 4786 /* NFSv4.1 just uses a Sequence Op and not a Renew. */ 4787 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4788 tsep = nfsmnt_mdssession(nmp); 4789 *tl++ = tsep->nfsess_clientid.lval[0]; 4790 *tl = tsep->nfsess_clientid.lval[1]; 4791 } 4792 nrp = NULL; 4793 if (dsp != NULL) 4794 nrp = dsp->nfsclds_sockp; 4795 if (nrp == NULL) 4796 /* If NULL, use the MDS socket. */ 4797 nrp = &nmp->nm_sockreq; 4798 nd->nd_flag |= ND_USEGSSNAME; 4799 if (dsp == NULL) 4800 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4801 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4802 else { 4803 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4804 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 4805 if (error == ENXIO) 4806 nfscl_cancelreqs(dsp); 4807 } 4808 if (error) 4809 return (error); 4810 error = nd->nd_repstat; 4811 m_freem(nd->nd_mrep); 4812 return (error); 4813 } 4814 4815 /* 4816 * This function performs the Releaselockowner RPC. 4817 */ 4818 int 4819 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4820 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4821 { 4822 struct nfsrv_descript nfsd, *nd = &nfsd; 4823 u_int32_t *tl; 4824 int error; 4825 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4826 struct nfsclsession *tsep; 4827 4828 if (NFSHASNFSV4N(nmp)) { 4829 /* For NFSv4.1, do a FreeStateID. */ 4830 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, 4831 NULL, 0, 0); 4832 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); 4833 } else { 4834 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, 4835 NULL, 0, 0); 4836 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4837 tsep = nfsmnt_mdssession(nmp); 4838 *tl++ = tsep->nfsess_clientid.lval[0]; 4839 *tl = tsep->nfsess_clientid.lval[1]; 4840 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4841 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4842 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4843 } 4844 nd->nd_flag |= ND_USEGSSNAME; 4845 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4846 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4847 if (error) 4848 return (error); 4849 error = nd->nd_repstat; 4850 m_freem(nd->nd_mrep); 4851 return (error); 4852 } 4853 4854 /* 4855 * This function performs the Compound to get the mount pt FH. 4856 */ 4857 int 4858 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 4859 NFSPROC_T *p) 4860 { 4861 u_int32_t *tl; 4862 struct nfsrv_descript nfsd; 4863 struct nfsrv_descript *nd = &nfsd; 4864 u_char *cp, *cp2; 4865 int error, cnt, len, setnil; 4866 u_int32_t *opcntp; 4867 4868 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0, 4869 0); 4870 cp = dirpath; 4871 cnt = 0; 4872 do { 4873 setnil = 0; 4874 while (*cp == '/') 4875 cp++; 4876 cp2 = cp; 4877 while (*cp2 != '\0' && *cp2 != '/') 4878 cp2++; 4879 if (*cp2 == '/') { 4880 setnil = 1; 4881 *cp2 = '\0'; 4882 } 4883 if (cp2 != cp) { 4884 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4885 *tl = txdr_unsigned(NFSV4OP_LOOKUP); 4886 nfsm_strtom(nd, cp, strlen(cp)); 4887 cnt++; 4888 } 4889 if (setnil) 4890 *cp2++ = '/'; 4891 cp = cp2; 4892 } while (*cp != '\0'); 4893 if (NFSHASNFSV4N(nmp)) 4894 /* Has a Sequence Op done by nfscl_reqstart(). */ 4895 *opcntp = txdr_unsigned(3 + cnt); 4896 else 4897 *opcntp = txdr_unsigned(2 + cnt); 4898 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4899 *tl = txdr_unsigned(NFSV4OP_GETFH); 4900 nd->nd_flag |= ND_USEGSSNAME; 4901 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4902 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4903 if (error) 4904 return (error); 4905 if (nd->nd_repstat == 0) { 4906 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 4907 tl += (2 + 2 * cnt); 4908 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 4909 len > NFSX_FHMAX) { 4910 nd->nd_repstat = NFSERR_BADXDR; 4911 } else { 4912 nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len); 4913 if (nd->nd_repstat == 0) 4914 nmp->nm_fhsize = len; 4915 } 4916 } 4917 error = nd->nd_repstat; 4918 nfsmout: 4919 m_freem(nd->nd_mrep); 4920 return (error); 4921 } 4922 4923 /* 4924 * This function performs the Delegreturn RPC. 4925 */ 4926 int 4927 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 4928 struct nfsmount *nmp, NFSPROC_T *p, int syscred) 4929 { 4930 u_int32_t *tl; 4931 struct nfsrv_descript nfsd; 4932 struct nfsrv_descript *nd = &nfsd; 4933 int error; 4934 4935 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 4936 dp->nfsdl_fhlen, NULL, NULL, 0, 0); 4937 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 4938 if (NFSHASNFSV4N(nmp)) 4939 *tl++ = 0; 4940 else 4941 *tl++ = dp->nfsdl_stateid.seqid; 4942 *tl++ = dp->nfsdl_stateid.other[0]; 4943 *tl++ = dp->nfsdl_stateid.other[1]; 4944 *tl = dp->nfsdl_stateid.other[2]; 4945 if (syscred) 4946 nd->nd_flag |= ND_USEGSSNAME; 4947 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4948 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4949 if (error) 4950 return (error); 4951 error = nd->nd_repstat; 4952 m_freem(nd->nd_mrep); 4953 return (error); 4954 } 4955 4956 /* 4957 * nfs getacl call. 4958 */ 4959 int 4960 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4961 struct acl *aclp, void *stuff) 4962 { 4963 struct nfsrv_descript nfsd, *nd = &nfsd; 4964 int error; 4965 nfsattrbit_t attrbits; 4966 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4967 4968 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4969 return (EOPNOTSUPP); 4970 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp); 4971 NFSZERO_ATTRBIT(&attrbits); 4972 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 4973 (void) nfsrv_putattrbit(nd, &attrbits); 4974 error = nfscl_request(nd, vp, p, cred, stuff); 4975 if (error) 4976 return (error); 4977 if (!nd->nd_repstat) 4978 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 4979 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 4980 else 4981 error = nd->nd_repstat; 4982 m_freem(nd->nd_mrep); 4983 return (error); 4984 } 4985 4986 /* 4987 * nfs setacl call. 4988 */ 4989 int 4990 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 4991 struct acl *aclp, void *stuff) 4992 { 4993 int error; 4994 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4995 4996 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 4997 return (EOPNOTSUPP); 4998 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff); 4999 return (error); 5000 } 5001 5002 /* 5003 * nfs setacl call. 5004 */ 5005 static int 5006 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 5007 struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff) 5008 { 5009 struct nfsrv_descript nfsd, *nd = &nfsd; 5010 int error; 5011 nfsattrbit_t attrbits; 5012 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 5013 5014 if (!NFSHASNFSV4(nmp)) 5015 return (EOPNOTSUPP); 5016 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp); 5017 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 5018 NFSZERO_ATTRBIT(&attrbits); 5019 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 5020 (void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0, 5021 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); 5022 error = nfscl_request(nd, vp, p, cred, stuff); 5023 if (error) 5024 return (error); 5025 /* Don't care about the pre/postop attributes */ 5026 m_freem(nd->nd_mrep); 5027 return (nd->nd_repstat); 5028 } 5029 5030 /* 5031 * Do the NFSv4.1 Exchange ID. 5032 */ 5033 int 5034 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, 5035 struct nfssockreq *nrp, int minorvers, uint32_t exchflags, 5036 struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p) 5037 { 5038 uint32_t *tl, v41flags; 5039 struct nfsrv_descript nfsd; 5040 struct nfsrv_descript *nd = &nfsd; 5041 struct nfsclds *dsp; 5042 struct timespec verstime; 5043 int error, len; 5044 5045 *dspp = NULL; 5046 if (minorvers == 0) 5047 minorvers = nmp->nm_minorvers; 5048 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, 5049 NFS_VER4, minorvers); 5050 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5051 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ 5052 *tl = txdr_unsigned(clp->nfsc_rev); 5053 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 5054 5055 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 5056 *tl++ = txdr_unsigned(exchflags); 5057 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); 5058 5059 /* Set the implementation id4 */ 5060 *tl = txdr_unsigned(1); 5061 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 5062 (void) nfsm_strtom(nd, version, strlen(version)); 5063 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 5064 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 5065 verstime.tv_nsec = 0; 5066 txdr_nfsv4time(&verstime, tl); 5067 nd->nd_flag |= ND_USEGSSNAME; 5068 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 5069 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5070 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, 5071 (int)nd->nd_repstat); 5072 if (error != 0) 5073 return (error); 5074 if (nd->nd_repstat == 0) { 5075 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); 5076 len = fxdr_unsigned(int, *(tl + 7)); 5077 if (len < 0 || len > NFSV4_OPAQUELIMIT) { 5078 error = NFSERR_BADXDR; 5079 goto nfsmout; 5080 } 5081 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, 5082 M_WAITOK | M_ZERO); 5083 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; 5084 dsp->nfsclds_servownlen = len; 5085 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; 5086 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; 5087 dsp->nfsclds_sess.nfsess_sequenceid = 5088 fxdr_unsigned(uint32_t, *tl++); 5089 v41flags = fxdr_unsigned(uint32_t, *tl); 5090 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && 5091 NFSHASPNFSOPT(nmp)) { 5092 NFSCL_DEBUG(1, "set PNFS\n"); 5093 NFSLOCKMNT(nmp); 5094 nmp->nm_state |= NFSSTA_PNFS; 5095 NFSUNLOCKMNT(nmp); 5096 dsp->nfsclds_flags |= NFSCLDS_MDS; 5097 } 5098 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) 5099 dsp->nfsclds_flags |= NFSCLDS_DS; 5100 if (minorvers == NFSV42_MINORVERSION) 5101 dsp->nfsclds_flags |= NFSCLDS_MINORV2; 5102 if (len > 0) 5103 nd->nd_repstat = nfsrv_mtostr(nd, 5104 dsp->nfsclds_serverown, len); 5105 if (nd->nd_repstat == 0) { 5106 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 5107 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 5108 NULL, MTX_DEF); 5109 nfscl_initsessionslots(&dsp->nfsclds_sess); 5110 *dspp = dsp; 5111 } else 5112 free(dsp, M_NFSCLDS); 5113 } 5114 error = nd->nd_repstat; 5115 nfsmout: 5116 m_freem(nd->nd_mrep); 5117 return (error); 5118 } 5119 5120 /* 5121 * Do the NFSv4.1 Create Session. 5122 */ 5123 int 5124 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, 5125 struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds, 5126 struct ucred *cred, NFSPROC_T *p) 5127 { 5128 uint32_t crflags, maxval, *tl; 5129 struct nfsrv_descript nfsd; 5130 struct nfsrv_descript *nd = &nfsd; 5131 int error, irdcnt, minorvers; 5132 5133 /* Make sure nm_rsize, nm_wsize is set. */ 5134 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0) 5135 nmp->nm_rsize = NFS_MAXBSIZE; 5136 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0) 5137 nmp->nm_wsize = NFS_MAXBSIZE; 5138 if (dsp == NULL) 5139 minorvers = nmp->nm_minorvers; 5140 else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0) 5141 minorvers = NFSV42_MINORVERSION; 5142 else 5143 minorvers = NFSV41_MINORVERSION; 5144 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, 5145 NFS_VER4, minorvers); 5146 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5147 *tl++ = sep->nfsess_clientid.lval[0]; 5148 *tl++ = sep->nfsess_clientid.lval[1]; 5149 *tl++ = txdr_unsigned(sequenceid); 5150 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); 5151 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0) 5152 crflags |= NFSV4CRSESS_CONNBACKCHAN; 5153 *tl = txdr_unsigned(crflags); 5154 5155 /* Fill in fore channel attributes. */ 5156 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5157 *tl++ = 0; /* Header pad size */ 5158 if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >= 5159 nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) { 5160 /* 5161 * NFSv4.2 Extended Attribute operations may want to do 5162 * requests/replies that are larger than nm_rsize/nm_wsize. 5163 */ 5164 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); 5165 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); 5166 } else { 5167 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR); 5168 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR); 5169 } 5170 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 5171 *tl++ = txdr_unsigned(20); /* Max operations */ 5172 *tl++ = txdr_unsigned(64); /* Max slots */ 5173 *tl = 0; /* No rdma ird */ 5174 5175 /* Fill in back channel attributes. */ 5176 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5177 *tl++ = 0; /* Header pad size */ 5178 *tl++ = txdr_unsigned(10000); /* Max request size */ 5179 *tl++ = txdr_unsigned(10000); /* Max response size */ 5180 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 5181 *tl++ = txdr_unsigned(4); /* Max operations */ 5182 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ 5183 *tl = 0; /* No rdma ird */ 5184 5185 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); 5186 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ 5187 5188 /* Allow AUTH_SYS callbacks as uid, gid == 0. */ 5189 *tl++ = txdr_unsigned(1); /* Auth_sys only */ 5190 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ 5191 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ 5192 *tl++ = 0; /* Null machine name */ 5193 *tl++ = 0; /* Uid == 0 */ 5194 *tl++ = 0; /* Gid == 0 */ 5195 *tl = 0; /* No additional gids */ 5196 nd->nd_flag |= ND_USEGSSNAME; 5197 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, 5198 NFS_VER4, NULL, 1, NULL, NULL); 5199 if (error != 0) 5200 return (error); 5201 if (nd->nd_repstat == 0) { 5202 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 5203 2 * NFSX_UNSIGNED); 5204 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); 5205 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 5206 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); 5207 crflags = fxdr_unsigned(uint32_t, *tl); 5208 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { 5209 NFSLOCKMNT(nmp); 5210 nmp->nm_state |= NFSSTA_SESSPERSIST; 5211 NFSUNLOCKMNT(nmp); 5212 } 5213 5214 /* Get the fore channel slot count. */ 5215 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5216 tl++; /* Skip the header pad size. */ 5217 5218 /* Make sure nm_wsize is small enough. */ 5219 maxval = fxdr_unsigned(uint32_t, *tl++); 5220 while (maxval < nmp->nm_wsize + NFS_MAXXDR) { 5221 if (nmp->nm_wsize > 8096) 5222 nmp->nm_wsize /= 2; 5223 else 5224 break; 5225 } 5226 sep->nfsess_maxreq = maxval; 5227 5228 /* Make sure nm_rsize is small enough. */ 5229 maxval = fxdr_unsigned(uint32_t, *tl++); 5230 while (maxval < nmp->nm_rsize + NFS_MAXXDR) { 5231 if (nmp->nm_rsize > 8096) 5232 nmp->nm_rsize /= 2; 5233 else 5234 break; 5235 } 5236 sep->nfsess_maxresp = maxval; 5237 5238 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); 5239 tl++; 5240 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); 5241 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); 5242 irdcnt = fxdr_unsigned(int, *tl); 5243 if (irdcnt < 0 || irdcnt > 1) { 5244 error = NFSERR_BADXDR; 5245 goto nfsmout; 5246 } 5247 if (irdcnt > 0) 5248 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 5249 5250 /* and the back channel slot count. */ 5251 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5252 tl += 5; 5253 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 5254 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 5255 } 5256 error = nd->nd_repstat; 5257 nfsmout: 5258 m_freem(nd->nd_mrep); 5259 return (error); 5260 } 5261 5262 /* 5263 * Do the NFSv4.1 Destroy Session. 5264 */ 5265 int 5266 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp, 5267 struct ucred *cred, NFSPROC_T *p) 5268 { 5269 uint32_t *tl; 5270 struct nfsrv_descript nfsd; 5271 struct nfsrv_descript *nd = &nfsd; 5272 int error; 5273 struct nfsclsession *tsep; 5274 5275 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0, 5276 0); 5277 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 5278 tsep = nfsmnt_mdssession(nmp); 5279 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID); 5280 nd->nd_flag |= ND_USEGSSNAME; 5281 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5282 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5283 if (error != 0) 5284 return (error); 5285 error = nd->nd_repstat; 5286 m_freem(nd->nd_mrep); 5287 return (error); 5288 } 5289 5290 /* 5291 * Do the NFSv4.1 Destroy Client. 5292 */ 5293 int 5294 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 5295 struct ucred *cred, NFSPROC_T *p) 5296 { 5297 uint32_t *tl; 5298 struct nfsrv_descript nfsd; 5299 struct nfsrv_descript *nd = &nfsd; 5300 int error; 5301 struct nfsclsession *tsep; 5302 5303 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0, 5304 0); 5305 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5306 tsep = nfsmnt_mdssession(nmp); 5307 *tl++ = tsep->nfsess_clientid.lval[0]; 5308 *tl = tsep->nfsess_clientid.lval[1]; 5309 nd->nd_flag |= ND_USEGSSNAME; 5310 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5311 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5312 if (error != 0) 5313 return (error); 5314 error = nd->nd_repstat; 5315 m_freem(nd->nd_mrep); 5316 return (error); 5317 } 5318 5319 /* 5320 * Do the NFSv4.1 LayoutGet. 5321 */ 5322 static int 5323 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 5324 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype, 5325 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep, 5326 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p, 5327 void *stuff) 5328 { 5329 struct nfsrv_descript nfsd, *nd = &nfsd; 5330 int error; 5331 5332 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0, 5333 0); 5334 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, 5335 layouttype, layoutlen, 0); 5336 nd->nd_flag |= ND_USEGSSNAME; 5337 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5338 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5339 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); 5340 if (error != 0) 5341 return (error); 5342 if (nd->nd_repstat == 0) 5343 error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep, 5344 flhp); 5345 if (error == 0 && nd->nd_repstat != 0) 5346 error = nd->nd_repstat; 5347 m_freem(nd->nd_mrep); 5348 return (error); 5349 } 5350 5351 /* 5352 * Do the NFSv4.1 Get Device Info. 5353 */ 5354 int 5355 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 5356 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 5357 NFSPROC_T *p) 5358 { 5359 uint32_t cnt, *tl, vers, minorvers; 5360 struct nfsrv_descript nfsd; 5361 struct nfsrv_descript *nd = &nfsd; 5362 struct sockaddr_in sin, ssin; 5363 struct sockaddr_in6 sin6, ssin6; 5364 struct nfsclds *dsp = NULL, **dspp, **gotdspp; 5365 struct nfscldevinfo *ndi; 5366 int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j; 5367 int stripecnt; 5368 uint8_t stripeindex; 5369 sa_family_t af, safilled; 5370 5371 ssin.sin_port = 0; /* To shut up compiler. */ 5372 ssin.sin_addr.s_addr = 0; /* ditto */ 5373 *ndip = NULL; 5374 ndi = NULL; 5375 gotdspp = NULL; 5376 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0, 5377 0); 5378 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5379 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 5380 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5381 *tl++ = txdr_unsigned(layouttype); 5382 *tl++ = txdr_unsigned(100000); 5383 if (notifybitsp != NULL && *notifybitsp != 0) { 5384 *tl = txdr_unsigned(1); /* One word of bits. */ 5385 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5386 *tl = txdr_unsigned(*notifybitsp); 5387 } else 5388 *tl = txdr_unsigned(0); 5389 nd->nd_flag |= ND_USEGSSNAME; 5390 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5391 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5392 if (error != 0) 5393 return (error); 5394 if (nd->nd_repstat == 0) { 5395 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5396 if (layouttype != fxdr_unsigned(int, *tl)) 5397 printf("EEK! devinfo layout type not same!\n"); 5398 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) { 5399 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5400 stripecnt = fxdr_unsigned(int, *tl); 5401 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 5402 if (stripecnt < 1 || stripecnt > 4096) { 5403 printf("pNFS File layout devinfo stripecnt %d:" 5404 " out of range\n", stripecnt); 5405 error = NFSERR_BADXDR; 5406 goto nfsmout; 5407 } 5408 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * 5409 NFSX_UNSIGNED); 5410 addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 5411 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 5412 if (addrcnt < 1 || addrcnt > 128) { 5413 printf("NFS devinfo addrcnt %d: out of range\n", 5414 addrcnt); 5415 error = NFSERR_BADXDR; 5416 goto nfsmout; 5417 } 5418 5419 /* 5420 * Now we know how many stripe indices and addresses, so 5421 * we can allocate the structure the correct size. 5422 */ 5423 i = (stripecnt * sizeof(uint8_t)) / 5424 sizeof(struct nfsclds *) + 1; 5425 NFSCL_DEBUG(4, "stripeindices=%d\n", i); 5426 ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 5427 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | 5428 M_ZERO); 5429 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5430 NFSX_V4DEVICEID); 5431 ndi->nfsdi_refcnt = 0; 5432 ndi->nfsdi_flags = NFSDI_FILELAYOUT; 5433 ndi->nfsdi_stripecnt = stripecnt; 5434 ndi->nfsdi_addrcnt = addrcnt; 5435 /* Fill in the stripe indices. */ 5436 for (i = 0; i < stripecnt; i++) { 5437 stripeindex = fxdr_unsigned(uint8_t, *tl++); 5438 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 5439 if (stripeindex >= addrcnt) { 5440 printf("pNFS File Layout devinfo" 5441 " stripeindex %d: too big\n", 5442 (int)stripeindex); 5443 error = NFSERR_BADXDR; 5444 goto nfsmout; 5445 } 5446 nfsfldi_setstripeindex(ndi, i, stripeindex); 5447 } 5448 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 5449 /* For Flex File, we only get one address list. */ 5450 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *), 5451 M_NFSDEVINFO, M_WAITOK | M_ZERO); 5452 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5453 NFSX_V4DEVICEID); 5454 ndi->nfsdi_refcnt = 0; 5455 ndi->nfsdi_flags = NFSDI_FLEXFILE; 5456 addrcnt = ndi->nfsdi_addrcnt = 1; 5457 } 5458 5459 /* Now, dissect the server address(es). */ 5460 safilled = AF_UNSPEC; 5461 for (i = 0; i < addrcnt; i++) { 5462 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5463 cnt = fxdr_unsigned(uint32_t, *tl); 5464 if (cnt == 0) { 5465 printf("NFS devinfo 0 len addrlist\n"); 5466 error = NFSERR_BADXDR; 5467 goto nfsmout; 5468 } 5469 dspp = nfsfldi_addr(ndi, i); 5470 safilled = AF_UNSPEC; 5471 for (j = 0; j < cnt; j++) { 5472 error = nfsv4_getipaddr(nd, &sin, &sin6, &af, 5473 &isudp); 5474 if (error != 0 && error != EPERM) { 5475 error = NFSERR_BADXDR; 5476 goto nfsmout; 5477 } 5478 if (error == 0 && isudp == 0) { 5479 /* 5480 * The priority is: 5481 * - Same address family. 5482 * Save the address and dspp, so that 5483 * the connection can be done after 5484 * parsing is complete. 5485 */ 5486 if (safilled == AF_UNSPEC || 5487 (af == nmp->nm_nam->sa_family && 5488 safilled != nmp->nm_nam->sa_family) 5489 ) { 5490 if (af == AF_INET) 5491 ssin = sin; 5492 else 5493 ssin6 = sin6; 5494 safilled = af; 5495 gotdspp = dspp; 5496 } 5497 } 5498 } 5499 } 5500 5501 gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */ 5502 gotminor = NFSV41_MINORVERSION; 5503 /* For Flex File, we will take one of the versions to use. */ 5504 if (layouttype == NFSLAYOUT_FLEXFILE) { 5505 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5506 j = fxdr_unsigned(int, *tl); 5507 if (j < 1 || j > NFSDEV_MAXVERS) { 5508 printf("pNFS: too many versions\n"); 5509 error = NFSERR_BADXDR; 5510 goto nfsmout; 5511 } 5512 gotvers = 0; 5513 gotminor = 0; 5514 for (i = 0; i < j; i++) { 5515 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED); 5516 vers = fxdr_unsigned(uint32_t, *tl++); 5517 minorvers = fxdr_unsigned(uint32_t, *tl++); 5518 if (vers == NFS_VER3) 5519 minorvers = 0; 5520 if ((vers == NFS_VER4 && ((minorvers == 5521 NFSV41_MINORVERSION && gotminor == 0) || 5522 minorvers == NFSV42_MINORVERSION)) || 5523 (vers == NFS_VER3 && gotvers == 0)) { 5524 gotvers = vers; 5525 gotminor = minorvers; 5526 /* We'll take this one. */ 5527 ndi->nfsdi_versindex = i; 5528 ndi->nfsdi_vers = vers; 5529 ndi->nfsdi_minorvers = minorvers; 5530 ndi->nfsdi_rsize = fxdr_unsigned( 5531 uint32_t, *tl++); 5532 ndi->nfsdi_wsize = fxdr_unsigned( 5533 uint32_t, *tl++); 5534 if (*tl == newnfs_true) 5535 ndi->nfsdi_flags |= 5536 NFSDI_TIGHTCOUPLED; 5537 else 5538 ndi->nfsdi_flags &= 5539 ~NFSDI_TIGHTCOUPLED; 5540 } 5541 } 5542 if (gotvers == 0) { 5543 printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n"); 5544 error = NFSERR_BADXDR; 5545 goto nfsmout; 5546 } 5547 } 5548 5549 /* And the notify bits. */ 5550 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5551 bitcnt = fxdr_unsigned(int, *tl); 5552 if (bitcnt > 0) { 5553 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5554 if (notifybitsp != NULL) 5555 *notifybitsp = 5556 fxdr_unsigned(uint32_t, *tl); 5557 } 5558 if (safilled != AF_UNSPEC) { 5559 KASSERT(ndi != NULL, ("ndi is NULL")); 5560 *ndip = ndi; 5561 } else 5562 error = EPERM; 5563 if (error == 0) { 5564 /* 5565 * Now we can do a TCP connection for the correct 5566 * NFS version and IP address. 5567 */ 5568 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled, 5569 gotvers, gotminor, &dsp, p); 5570 } 5571 if (error == 0) { 5572 KASSERT(gotdspp != NULL, ("gotdspp is NULL")); 5573 *gotdspp = dsp; 5574 } 5575 } 5576 if (nd->nd_repstat != 0 && error == 0) 5577 error = nd->nd_repstat; 5578 nfsmout: 5579 if (error != 0 && ndi != NULL) 5580 nfscl_freedevinfo(ndi); 5581 m_freem(nd->nd_mrep); 5582 return (error); 5583 } 5584 5585 /* 5586 * Do the NFSv4.1 LayoutCommit. 5587 */ 5588 int 5589 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5590 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5591 int layouttype, struct ucred *cred, NFSPROC_T *p, void *stuff) 5592 { 5593 uint32_t *tl; 5594 struct nfsrv_descript nfsd, *nd = &nfsd; 5595 int error; 5596 5597 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL, 5598 0, 0); 5599 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5600 NFSX_STATEID); 5601 txdr_hyper(off, tl); 5602 tl += 2; 5603 txdr_hyper(len, tl); 5604 tl += 2; 5605 if (reclaim != 0) 5606 *tl++ = newnfs_true; 5607 else 5608 *tl++ = newnfs_false; 5609 *tl++ = txdr_unsigned(stateidp->seqid); 5610 *tl++ = stateidp->other[0]; 5611 *tl++ = stateidp->other[1]; 5612 *tl++ = stateidp->other[2]; 5613 *tl++ = newnfs_true; 5614 if (lastbyte < off) 5615 lastbyte = off; 5616 else if (lastbyte >= (off + len)) 5617 lastbyte = off + len - 1; 5618 txdr_hyper(lastbyte, tl); 5619 tl += 2; 5620 *tl++ = newnfs_false; 5621 *tl++ = txdr_unsigned(layouttype); 5622 /* All supported layouts are 0 length. */ 5623 *tl = txdr_unsigned(0); 5624 nd->nd_flag |= ND_USEGSSNAME; 5625 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5626 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5627 if (error != 0) 5628 return (error); 5629 error = nd->nd_repstat; 5630 m_freem(nd->nd_mrep); 5631 return (error); 5632 } 5633 5634 /* 5635 * Do the NFSv4.1 LayoutReturn. 5636 */ 5637 int 5638 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5639 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5640 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5641 uint32_t stat, uint32_t op, char *devid) 5642 { 5643 uint32_t *tl; 5644 struct nfsrv_descript nfsd, *nd = &nfsd; 5645 uint64_t tu64; 5646 int error; 5647 5648 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL, 5649 0, 0); 5650 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5651 if (reclaim != 0) 5652 *tl++ = newnfs_true; 5653 else 5654 *tl++ = newnfs_false; 5655 *tl++ = txdr_unsigned(layouttype); 5656 *tl++ = txdr_unsigned(iomode); 5657 *tl = txdr_unsigned(layoutreturn); 5658 if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5659 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5660 NFSX_UNSIGNED); 5661 txdr_hyper(offset, tl); 5662 tl += 2; 5663 txdr_hyper(len, tl); 5664 tl += 2; 5665 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5666 *tl++ = txdr_unsigned(stateidp->seqid); 5667 *tl++ = stateidp->other[0]; 5668 *tl++ = stateidp->other[1]; 5669 *tl++ = stateidp->other[2]; 5670 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) 5671 *tl = txdr_unsigned(0); 5672 else if (layouttype == NFSLAYOUT_FLEXFILE) { 5673 if (stat != 0) { 5674 *tl = txdr_unsigned(2 * NFSX_HYPER + 5675 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5676 NFSX_UNSIGNED); 5677 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 5678 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5679 NFSX_UNSIGNED); 5680 *tl++ = txdr_unsigned(1); /* One error. */ 5681 tu64 = 0; /* Offset. */ 5682 txdr_hyper(tu64, tl); tl += 2; 5683 tu64 = UINT64_MAX; /* Length. */ 5684 txdr_hyper(tu64, tl); tl += 2; 5685 NFSBCOPY(stateidp, tl, NFSX_STATEID); 5686 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5687 *tl++ = txdr_unsigned(1); /* One error. */ 5688 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5689 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5690 *tl++ = txdr_unsigned(stat); 5691 *tl++ = txdr_unsigned(op); 5692 } else { 5693 *tl = txdr_unsigned(2 * NFSX_UNSIGNED); 5694 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5695 /* No ioerrs. */ 5696 *tl++ = 0; 5697 } 5698 *tl = 0; /* No stats yet. */ 5699 } 5700 } 5701 nd->nd_flag |= ND_USEGSSNAME; 5702 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5703 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5704 if (error != 0) 5705 return (error); 5706 if (nd->nd_repstat == 0) { 5707 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5708 if (*tl != 0) { 5709 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5710 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5711 stateidp->other[0] = *tl++; 5712 stateidp->other[1] = *tl++; 5713 stateidp->other[2] = *tl; 5714 } 5715 } else 5716 error = nd->nd_repstat; 5717 nfsmout: 5718 m_freem(nd->nd_mrep); 5719 return (error); 5720 } 5721 5722 /* 5723 * Do the NFSv4.2 LayoutError. 5724 */ 5725 static int 5726 nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset, 5727 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5728 uint32_t stat, uint32_t op, char *devid) 5729 { 5730 uint32_t *tl; 5731 struct nfsrv_descript nfsd, *nd = &nfsd; 5732 int error; 5733 5734 nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL, 5735 0, 0); 5736 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5737 NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5738 txdr_hyper(offset, tl); tl += 2; 5739 txdr_hyper(len, tl); tl += 2; 5740 *tl++ = txdr_unsigned(stateidp->seqid); 5741 *tl++ = stateidp->other[0]; 5742 *tl++ = stateidp->other[1]; 5743 *tl++ = stateidp->other[2]; 5744 *tl++ = txdr_unsigned(1); 5745 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5746 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5747 *tl++ = txdr_unsigned(stat); 5748 *tl = txdr_unsigned(op); 5749 nd->nd_flag |= ND_USEGSSNAME; 5750 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5751 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5752 if (error != 0) 5753 return (error); 5754 if (nd->nd_repstat != 0) 5755 error = nd->nd_repstat; 5756 m_freem(nd->nd_mrep); 5757 return (error); 5758 } 5759 5760 /* 5761 * Acquire a layout and devinfo, if possible. The caller must have acquired 5762 * a reference count on the nfsclclient structure before calling this. 5763 * Return the layout in lypp with a reference count on it, if successful. 5764 */ 5765 static int 5766 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 5767 int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, 5768 uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 5769 { 5770 struct nfscllayout *lyp; 5771 struct nfsclflayout *flp; 5772 struct nfsclflayouthead flh; 5773 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose; 5774 nfsv4stateid_t stateid; 5775 struct nfsclsession *tsep; 5776 5777 *lypp = NULL; 5778 if (NFSHASFLEXFILE(nmp)) 5779 layouttype = NFSLAYOUT_FLEXFILE; 5780 else 5781 layouttype = NFSLAYOUT_NFSV4_1_FILES; 5782 /* 5783 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 5784 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 5785 * flp == NULL. 5786 */ 5787 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 5788 off, rw, &flp, &recalled); 5789 islocked = 0; 5790 if (lyp == NULL || flp == NULL) { 5791 if (recalled != 0) 5792 return (EIO); 5793 LIST_INIT(&flh); 5794 tsep = nfsmnt_mdssession(nmp); 5795 layoutlen = tsep->nfsess_maxcache - 5796 (NFSX_STATEID + 3 * NFSX_UNSIGNED); 5797 if (lyp == NULL) { 5798 stateid.seqid = 0; 5799 stateid.other[0] = stateidp->other[0]; 5800 stateid.other[1] = stateidp->other[1]; 5801 stateid.other[2] = stateidp->other[2]; 5802 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5803 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, 5804 (uint64_t)0, layouttype, layoutlen, &stateid, 5805 &retonclose, &flh, cred, p, NULL); 5806 } else { 5807 islocked = 1; 5808 stateid.seqid = lyp->nfsly_stateid.seqid; 5809 stateid.other[0] = lyp->nfsly_stateid.other[0]; 5810 stateid.other[1] = lyp->nfsly_stateid.other[1]; 5811 stateid.other[2] = lyp->nfsly_stateid.other[2]; 5812 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5813 nfhp->nfh_len, iomode, off, UINT64_MAX, 5814 (uint64_t)0, layouttype, layoutlen, &stateid, 5815 &retonclose, &flh, cred, p, NULL); 5816 } 5817 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, 5818 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, 5819 &flh, layouttype, error, NULL, cred, p); 5820 if (error == 0) 5821 *lypp = lyp; 5822 else if (islocked != 0) 5823 nfscl_rellayout(lyp, 1); 5824 } else 5825 *lypp = lyp; 5826 return (error); 5827 } 5828 5829 /* 5830 * Do a TCP connection plus exchange id and create session. 5831 * If successful, a "struct nfsclds" is linked into the list for the 5832 * mount point and a pointer to it is returned. 5833 */ 5834 static int 5835 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin, 5836 struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers, 5837 struct nfsclds **dspp, NFSPROC_T *p) 5838 { 5839 struct sockaddr_in *msad, *sad; 5840 struct sockaddr_in6 *msad6, *sad6; 5841 struct nfsclclient *clp; 5842 struct nfssockreq *nrp; 5843 struct nfsclds *dsp, *tdsp; 5844 int error, firsttry; 5845 enum nfsclds_state retv; 5846 uint32_t sequenceid = 0; 5847 5848 KASSERT(nmp->nm_sockreq.nr_cred != NULL, 5849 ("nfsrpc_fillsa: NULL nr_cred")); 5850 NFSLOCKCLSTATE(); 5851 clp = nmp->nm_clp; 5852 NFSUNLOCKCLSTATE(); 5853 if (clp == NULL) 5854 return (EPERM); 5855 if (af == AF_INET) { 5856 NFSLOCKMNT(nmp); 5857 /* 5858 * Check to see if we already have a session for this 5859 * address that is usable for a DS. 5860 * Note that the MDS's address is in a different place 5861 * than the sessions already acquired for DS's. 5862 */ 5863 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 5864 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5865 while (tdsp != NULL) { 5866 if (msad != NULL && msad->sin_family == AF_INET && 5867 sin->sin_addr.s_addr == msad->sin_addr.s_addr && 5868 sin->sin_port == msad->sin_port && 5869 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5870 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5871 *dspp = tdsp; 5872 NFSUNLOCKMNT(nmp); 5873 NFSCL_DEBUG(4, "fnd same addr\n"); 5874 return (0); 5875 } 5876 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5877 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5878 msad = (struct sockaddr_in *) 5879 tdsp->nfsclds_sockp->nr_nam; 5880 else 5881 msad = NULL; 5882 } 5883 NFSUNLOCKMNT(nmp); 5884 5885 /* No IP address match, so look for new/trunked one. */ 5886 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 5887 sad->sin_len = sizeof(*sad); 5888 sad->sin_family = AF_INET; 5889 sad->sin_port = sin->sin_port; 5890 sad->sin_addr.s_addr = sin->sin_addr.s_addr; 5891 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5892 nrp->nr_nam = (struct sockaddr *)sad; 5893 } else if (af == AF_INET6) { 5894 NFSLOCKMNT(nmp); 5895 /* 5896 * Check to see if we already have a session for this 5897 * address that is usable for a DS. 5898 * Note that the MDS's address is in a different place 5899 * than the sessions already acquired for DS's. 5900 */ 5901 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 5902 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5903 while (tdsp != NULL) { 5904 if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 5905 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 5906 &msad6->sin6_addr) && 5907 sin6->sin6_port == msad6->sin6_port && 5908 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5909 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5910 *dspp = tdsp; 5911 NFSUNLOCKMNT(nmp); 5912 return (0); 5913 } 5914 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5915 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5916 msad6 = (struct sockaddr_in6 *) 5917 tdsp->nfsclds_sockp->nr_nam; 5918 else 5919 msad6 = NULL; 5920 } 5921 NFSUNLOCKMNT(nmp); 5922 5923 /* No IP address match, so look for new/trunked one. */ 5924 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 5925 sad6->sin6_len = sizeof(*sad6); 5926 sad6->sin6_family = AF_INET6; 5927 sad6->sin6_port = sin6->sin6_port; 5928 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr, 5929 sizeof(struct in6_addr)); 5930 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5931 nrp->nr_nam = (struct sockaddr *)sad6; 5932 } else 5933 return (EPERM); 5934 5935 nrp->nr_sotype = SOCK_STREAM; 5936 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 5937 nrp->nr_prog = NFS_PROG; 5938 nrp->nr_vers = vers; 5939 5940 /* 5941 * Use the credentials that were used for the mount, which are 5942 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 5943 * Ref. counting the credentials with crhold() is probably not 5944 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 5945 * unmount, but I did it anyhow. 5946 */ 5947 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 5948 error = newnfs_connect(nmp, nrp, NULL, p, 0, false, &nrp->nr_client); 5949 NFSCL_DEBUG(3, "DS connect=%d\n", error); 5950 5951 dsp = NULL; 5952 /* Now, do the exchangeid and create session. */ 5953 if (error == 0) { 5954 if (vers == NFS_VER4) { 5955 firsttry = 0; 5956 do { 5957 error = nfsrpc_exchangeid(nmp, clp, nrp, 5958 minorvers, NFSV4EXCH_USEPNFSDS, &dsp, 5959 nrp->nr_cred, p); 5960 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 5961 if (error == NFSERR_MINORVERMISMATCH) 5962 minorvers = NFSV42_MINORVERSION; 5963 } while (error == NFSERR_MINORVERMISMATCH && 5964 firsttry++ == 0); 5965 if (error != 0) 5966 newnfs_disconnect(NULL, nrp); 5967 } else { 5968 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, 5969 M_WAITOK | M_ZERO); 5970 dsp->nfsclds_flags |= NFSCLDS_DS; 5971 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */ 5972 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 5973 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 5974 NULL, MTX_DEF); 5975 } 5976 } 5977 if (error == 0) { 5978 dsp->nfsclds_sockp = nrp; 5979 if (vers == NFS_VER4) { 5980 NFSLOCKMNT(nmp); 5981 retv = nfscl_getsameserver(nmp, dsp, &tdsp, 5982 &sequenceid); 5983 NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 5984 if (retv == NFSDSP_USETHISSESSION && 5985 nfscl_dssameconn != 0) { 5986 NFSLOCKDS(tdsp); 5987 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN; 5988 NFSUNLOCKDS(tdsp); 5989 NFSUNLOCKMNT(nmp); 5990 /* 5991 * If there is already a session for this 5992 * server, use it. 5993 */ 5994 newnfs_disconnect(NULL, nrp); 5995 nfscl_freenfsclds(dsp); 5996 *dspp = tdsp; 5997 return (0); 5998 } 5999 if (retv == NFSDSP_NOTFOUND) 6000 sequenceid = 6001 dsp->nfsclds_sess.nfsess_sequenceid; 6002 NFSUNLOCKMNT(nmp); 6003 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 6004 nrp, dsp, sequenceid, 0, nrp->nr_cred, p); 6005 NFSCL_DEBUG(3, "DS createsess=%d\n", error); 6006 } 6007 } else { 6008 NFSFREECRED(nrp->nr_cred); 6009 NFSFREEMUTEX(&nrp->nr_mtx); 6010 free(nrp->nr_nam, M_SONAME); 6011 free(nrp, M_NFSSOCKREQ); 6012 } 6013 if (error == 0) { 6014 NFSCL_DEBUG(3, "add DS session\n"); 6015 /* 6016 * Put it at the end of the list. That way the list 6017 * is ordered by when the entry was added. This matters 6018 * since the one done first is the one that should be 6019 * used for sequencid'ing any subsequent create sessions. 6020 */ 6021 NFSLOCKMNT(nmp); 6022 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 6023 NFSUNLOCKMNT(nmp); 6024 *dspp = dsp; 6025 } else if (dsp != NULL) { 6026 newnfs_disconnect(NULL, nrp); 6027 nfscl_freenfsclds(dsp); 6028 } 6029 return (error); 6030 } 6031 6032 /* 6033 * Do the NFSv4.1 Reclaim Complete. 6034 */ 6035 int 6036 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 6037 { 6038 uint32_t *tl; 6039 struct nfsrv_descript nfsd; 6040 struct nfsrv_descript *nd = &nfsd; 6041 int error; 6042 6043 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0, 6044 0); 6045 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6046 *tl = newnfs_false; 6047 nd->nd_flag |= ND_USEGSSNAME; 6048 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 6049 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 6050 if (error != 0) 6051 return (error); 6052 error = nd->nd_repstat; 6053 m_freem(nd->nd_mrep); 6054 return (error); 6055 } 6056 6057 /* 6058 * Initialize the slot tables for a session. 6059 */ 6060 static void 6061 nfscl_initsessionslots(struct nfsclsession *sep) 6062 { 6063 int i; 6064 6065 for (i = 0; i < NFSV4_CBSLOTS; i++) { 6066 if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 6067 m_freem(sep->nfsess_cbslots[i].nfssl_reply); 6068 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 6069 } 6070 for (i = 0; i < 64; i++) 6071 sep->nfsess_slotseq[i] = 0; 6072 sep->nfsess_slots = 0; 6073 } 6074 6075 /* 6076 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 6077 */ 6078 int 6079 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6080 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) 6081 { 6082 struct nfsnode *np = VTONFS(vp); 6083 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6084 struct nfscllayout *layp; 6085 struct nfscldevinfo *dip; 6086 struct nfsclflayout *rflp; 6087 struct mbuf *m, *m2; 6088 struct nfsclwritedsdorpc *drpc, *tdrpc; 6089 nfsv4stateid_t stateid; 6090 struct ucred *newcred; 6091 uint64_t lastbyte, len, off, oresid, xfer; 6092 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo; 6093 void *lckp; 6094 uint8_t *dev; 6095 void *iovbase = NULL; 6096 size_t iovlen = 0; 6097 off_t offs = 0; 6098 ssize_t resid = 0; 6099 uint32_t op; 6100 6101 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 6102 (np->n_flag & NNOLAYOUT) != 0) 6103 return (EIO); 6104 /* Now, get a reference cnt on the clientid for this mount. */ 6105 if (nfscl_getref(nmp) == 0) 6106 return (EIO); 6107 6108 /* Find an appropriate stateid. */ 6109 newcred = NFSNEWCRED(cred); 6110 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 6111 rwaccess, 1, newcred, p, &stateid, &lckp); 6112 if (error != 0) { 6113 NFSFREECRED(newcred); 6114 nfscl_relref(nmp); 6115 return (error); 6116 } 6117 /* Search for a layout for this file. */ 6118 off = uiop->uio_offset; 6119 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 6120 np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled); 6121 if (layp == NULL || rflp == NULL) { 6122 if (recalled != 0) { 6123 NFSFREECRED(newcred); 6124 if (lckp != NULL) 6125 nfscl_lockderef(lckp); 6126 nfscl_relref(nmp); 6127 return (EIO); 6128 } 6129 if (layp != NULL) { 6130 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 6131 layp = NULL; 6132 } 6133 /* Try and get a Layout, if it is supported. */ 6134 if (rwaccess == NFSV4OPEN_ACCESSWRITE || 6135 (np->n_flag & NWRITEOPENED) != 0) 6136 iolaymode = NFSLAYOUTIOMODE_RW; 6137 else 6138 iolaymode = NFSLAYOUTIOMODE_READ; 6139 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 6140 rwaccess, NULL, &stateid, off, &layp, newcred, p); 6141 if (error != 0) { 6142 NFSLOCKNODE(np); 6143 np->n_flag |= NNOLAYOUT; 6144 NFSUNLOCKNODE(np); 6145 if (lckp != NULL) 6146 nfscl_lockderef(lckp); 6147 NFSFREECRED(newcred); 6148 if (layp != NULL) 6149 nfscl_rellayout(layp, 0); 6150 nfscl_relref(nmp); 6151 return (error); 6152 } 6153 } 6154 6155 /* 6156 * Loop around finding a layout that works for the first part of 6157 * this I/O operation, and then call the function that actually 6158 * does the RPC. 6159 */ 6160 eof = 0; 6161 len = (uint64_t)uiop->uio_resid; 6162 while (len > 0 && error == 0 && eof == 0) { 6163 off = uiop->uio_offset; 6164 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 6165 if (error == 0) { 6166 oresid = xfer = (uint64_t)uiop->uio_resid; 6167 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 6168 xfer = rflp->nfsfl_end - rflp->nfsfl_off; 6169 /* 6170 * For Flex File layout with mirrored DSs, select one 6171 * of them at random for reads. For writes and commits, 6172 * do all mirrors. 6173 */ 6174 m = NULL; 6175 tdrpc = drpc = NULL; 6176 firstmirror = 0; 6177 mirrorcnt = 1; 6178 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 && 6179 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) { 6180 if (rwaccess == NFSV4OPEN_ACCESSREAD) { 6181 firstmirror = arc4random() % mirrorcnt; 6182 mirrorcnt = firstmirror + 1; 6183 } else { 6184 if (docommit == 0) { 6185 /* 6186 * Save values, so uiop can be 6187 * rolled back upon a write 6188 * error. 6189 */ 6190 offs = uiop->uio_offset; 6191 resid = uiop->uio_resid; 6192 iovbase = 6193 uiop->uio_iov->iov_base; 6194 iovlen = uiop->uio_iov->iov_len; 6195 m = nfsm_uiombuflist(uiop, len, 6196 0); 6197 } 6198 tdrpc = drpc = malloc(sizeof(*drpc) * 6199 (mirrorcnt - 1), M_TEMP, M_WAITOK | 6200 M_ZERO); 6201 } 6202 } 6203 for (i = firstmirror; i < mirrorcnt && error == 0; i++){ 6204 m2 = NULL; 6205 if (m != NULL && i < mirrorcnt - 1) 6206 m2 = m_copym(m, 0, M_COPYALL, M_WAITOK); 6207 else { 6208 m2 = m; 6209 m = NULL; 6210 } 6211 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { 6212 dev = rflp->nfsfl_ffm[i].dev; 6213 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6214 rflp->nfsfl_ffm[i].devp); 6215 } else { 6216 dev = rflp->nfsfl_dev; 6217 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6218 rflp->nfsfl_devp); 6219 } 6220 if (dip != NULL) { 6221 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE) 6222 != 0) 6223 error = nfscl_dofflayoutio(vp, 6224 uiop, iomode, must_commit, 6225 &eof, &stateid, rwaccess, 6226 dip, layp, rflp, off, xfer, 6227 i, docommit, m2, tdrpc, 6228 newcred, p); 6229 else 6230 error = nfscl_doflayoutio(vp, 6231 uiop, iomode, must_commit, 6232 &eof, &stateid, rwaccess, 6233 dip, layp, rflp, off, xfer, 6234 docommit, newcred, p); 6235 nfscl_reldevinfo(dip); 6236 } else { 6237 if (m2 != NULL) 6238 m_freem(m2); 6239 error = EIO; 6240 } 6241 tdrpc++; 6242 } 6243 if (m != NULL) 6244 m_freem(m); 6245 tdrpc = drpc; 6246 timo = hz / 50; /* Wait for 20msec. */ 6247 if (timo < 1) 6248 timo = 1; 6249 for (i = firstmirror; i < mirrorcnt - 1 && 6250 tdrpc != NULL; i++, tdrpc++) { 6251 /* 6252 * For the unused drpc entries, both inprog and 6253 * err == 0, so this loop won't break. 6254 */ 6255 while (tdrpc->inprog != 0 && tdrpc->done == 0) 6256 tsleep(&tdrpc->tsk, PVFS, "clrpcio", 6257 timo); 6258 if (error == 0 && tdrpc->err != 0) 6259 error = tdrpc->err; 6260 if (rwaccess != NFSV4OPEN_ACCESSREAD && 6261 docommit == 0 && *must_commit == 0 && 6262 tdrpc->must_commit == 1) 6263 *must_commit = 1; 6264 } 6265 free(drpc, M_TEMP); 6266 if (error == 0) { 6267 if (mirrorcnt > 1 && rwaccess == 6268 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6269 NFSLOCKCLSTATE(); 6270 layp->nfsly_flags |= NFSLY_WRITTEN; 6271 NFSUNLOCKCLSTATE(); 6272 } 6273 lastbyte = off + xfer - 1; 6274 NFSLOCKCLSTATE(); 6275 if (lastbyte > layp->nfsly_lastbyte) 6276 layp->nfsly_lastbyte = lastbyte; 6277 NFSUNLOCKCLSTATE(); 6278 } else if (error == NFSERR_OPENMODE && 6279 rwaccess == NFSV4OPEN_ACCESSREAD) { 6280 NFSLOCKMNT(nmp); 6281 nmp->nm_state |= NFSSTA_OPENMODE; 6282 NFSUNLOCKMNT(nmp); 6283 } else if ((error == NFSERR_NOSPC || 6284 error == NFSERR_IO || error == NFSERR_NXIO) && 6285 nmp->nm_minorvers == NFSV42_MINORVERSION) { 6286 if (docommit != 0) 6287 op = NFSV4OP_COMMIT; 6288 else if (rwaccess == NFSV4OPEN_ACCESSREAD) 6289 op = NFSV4OP_READ; 6290 else 6291 op = NFSV4OP_WRITE; 6292 nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh, 6293 np->n_fhp->nfh_len, off, xfer, 6294 &layp->nfsly_stateid, newcred, p, error, op, 6295 dip->nfsdi_deviceid); 6296 error = EIO; 6297 } else 6298 error = EIO; 6299 if (error == 0) 6300 len -= (oresid - (uint64_t)uiop->uio_resid); 6301 else if (mirrorcnt > 1 && rwaccess == 6302 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6303 /* 6304 * In case the rpc gets retried, roll the 6305 * uio fields changed by nfsm_uiombuflist() 6306 * back. 6307 */ 6308 uiop->uio_offset = offs; 6309 uiop->uio_resid = resid; 6310 uiop->uio_iov->iov_base = iovbase; 6311 uiop->uio_iov->iov_len = iovlen; 6312 } 6313 } 6314 } 6315 if (lckp != NULL) 6316 nfscl_lockderef(lckp); 6317 NFSFREECRED(newcred); 6318 nfscl_rellayout(layp, 0); 6319 nfscl_relref(nmp); 6320 return (error); 6321 } 6322 6323 /* 6324 * Find a file layout that will handle the first bytes of the requested 6325 * range and return the information from it needed to the I/O operation. 6326 */ 6327 int 6328 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 6329 struct nfsclflayout **retflpp) 6330 { 6331 struct nfsclflayout *flp, *nflp, *rflp; 6332 uint32_t rw; 6333 6334 rflp = NULL; 6335 rw = rwaccess; 6336 /* For reading, do the Read list first and then the Write list. */ 6337 do { 6338 if (rw == NFSV4OPEN_ACCESSREAD) 6339 flp = LIST_FIRST(&lyp->nfsly_flayread); 6340 else 6341 flp = LIST_FIRST(&lyp->nfsly_flayrw); 6342 while (flp != NULL) { 6343 nflp = LIST_NEXT(flp, nfsfl_list); 6344 if (flp->nfsfl_off > off) 6345 break; 6346 if (flp->nfsfl_end > off && 6347 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 6348 rflp = flp; 6349 flp = nflp; 6350 } 6351 if (rw == NFSV4OPEN_ACCESSREAD) 6352 rw = NFSV4OPEN_ACCESSWRITE; 6353 else 6354 rw = 0; 6355 } while (rw != 0); 6356 if (rflp != NULL) { 6357 /* This one covers the most bytes starting at off. */ 6358 *retflpp = rflp; 6359 return (0); 6360 } 6361 return (EIO); 6362 } 6363 6364 /* 6365 * Do I/O using an NFSv4.1 or NFSv4.2 file layout. 6366 */ 6367 static int 6368 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6369 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6370 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6371 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) 6372 { 6373 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 6374 int commit_thru_mds, error, stripe_index, stripe_pos, minorvers; 6375 struct nfsnode *np; 6376 struct nfsfh *fhp; 6377 struct nfsclds **dspp; 6378 6379 np = VTONFS(vp); 6380 rel_off = off - flp->nfsfl_patoff; 6381 stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK; 6382 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 6383 dp->nfsdi_stripecnt; 6384 transfer = stripe_unit_size - (rel_off % stripe_unit_size); 6385 error = 0; 6386 6387 /* Loop around, doing I/O for each stripe unit. */ 6388 while (len > 0 && error == 0) { 6389 stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 6390 dspp = nfsfldi_addr(dp, stripe_index); 6391 if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0) 6392 minorvers = NFSV42_MINORVERSION; 6393 else 6394 minorvers = NFSV41_MINORVERSION; 6395 if (len > transfer && docommit == 0) 6396 xfer = transfer; 6397 else 6398 xfer = len; 6399 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 6400 /* Dense layout. */ 6401 if (stripe_pos >= flp->nfsfl_fhcnt) 6402 return (EIO); 6403 fhp = flp->nfsfl_fh[stripe_pos]; 6404 io_off = (rel_off / (stripe_unit_size * 6405 dp->nfsdi_stripecnt)) * stripe_unit_size + 6406 rel_off % stripe_unit_size; 6407 } else { 6408 /* Sparse layout. */ 6409 if (flp->nfsfl_fhcnt > 1) { 6410 if (stripe_index >= flp->nfsfl_fhcnt) 6411 return (EIO); 6412 fhp = flp->nfsfl_fh[stripe_index]; 6413 } else if (flp->nfsfl_fhcnt == 1) 6414 fhp = flp->nfsfl_fh[0]; 6415 else 6416 fhp = np->n_fhp; 6417 io_off = off; 6418 } 6419 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { 6420 commit_thru_mds = 1; 6421 if (docommit != 0) 6422 error = EIO; 6423 } else { 6424 commit_thru_mds = 0; 6425 NFSLOCKNODE(np); 6426 np->n_flag |= NDSCOMMIT; 6427 NFSUNLOCKNODE(np); 6428 } 6429 if (docommit != 0) { 6430 if (error == 0) 6431 error = nfsrpc_commitds(vp, io_off, xfer, 6432 *dspp, fhp, NFS_VER4, minorvers, cred, p); 6433 if (error == 0) { 6434 /* 6435 * Set both eof and uio_resid = 0 to end any 6436 * loops. 6437 */ 6438 *eofp = 1; 6439 uiop->uio_resid = 0; 6440 } else { 6441 NFSLOCKNODE(np); 6442 np->n_flag &= ~NDSCOMMIT; 6443 NFSUNLOCKNODE(np); 6444 } 6445 } else if (rwflag == NFSV4OPEN_ACCESSREAD) 6446 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6447 io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p); 6448 else { 6449 error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 6450 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 6451 0, NFS_VER4, minorvers, cred, p); 6452 if (error == 0) { 6453 NFSLOCKCLSTATE(); 6454 lyp->nfsly_flags |= NFSLY_WRITTEN; 6455 NFSUNLOCKCLSTATE(); 6456 } 6457 } 6458 if (error == 0) { 6459 transfer = stripe_unit_size; 6460 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 6461 len -= xfer; 6462 off += xfer; 6463 } 6464 } 6465 return (error); 6466 } 6467 6468 /* 6469 * Do I/O using an NFSv4.1 flex file layout. 6470 */ 6471 static int 6472 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6473 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6474 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6475 uint64_t len, int mirror, int docommit, struct mbuf *mp, 6476 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6477 { 6478 uint64_t xfer; 6479 int error; 6480 struct nfsnode *np; 6481 struct nfsfh *fhp; 6482 struct nfsclds **dspp; 6483 struct ucred *tcred; 6484 struct mbuf *m, *m2; 6485 uint32_t copylen; 6486 6487 np = VTONFS(vp); 6488 error = 0; 6489 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, 6490 (uintmax_t)len); 6491 /* Loop around, doing I/O for each stripe unit. */ 6492 while (len > 0 && error == 0) { 6493 dspp = nfsfldi_addr(dp, 0); 6494 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex]; 6495 stateidp = &flp->nfsfl_ffm[mirror].st; 6496 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n", 6497 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid); 6498 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) { 6499 tcred = NFSNEWCRED(cred); 6500 tcred->cr_uid = flp->nfsfl_ffm[mirror].user; 6501 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group; 6502 tcred->cr_ngroups = 1; 6503 } else 6504 tcred = cred; 6505 if (rwflag == NFSV4OPEN_ACCESSREAD) 6506 copylen = dp->nfsdi_rsize; 6507 else { 6508 copylen = dp->nfsdi_wsize; 6509 if (len > copylen && mp != NULL) { 6510 /* 6511 * When a mirrored configuration needs to do 6512 * multiple writes to each mirror, all writes 6513 * except the last one must be a multiple of 6514 * 4 bytes. This is required so that the XDR 6515 * does not need padding. 6516 * If possible, clip the size to an exact 6517 * multiple of the mbuf length, so that the 6518 * split will be on an mbuf boundary. 6519 */ 6520 copylen &= 0xfffffffc; 6521 if (copylen > mp->m_len) 6522 copylen = copylen / mp->m_len * 6523 mp->m_len; 6524 } 6525 } 6526 NFSLOCKNODE(np); 6527 np->n_flag |= NDSCOMMIT; 6528 NFSUNLOCKNODE(np); 6529 if (len > copylen && docommit == 0) 6530 xfer = copylen; 6531 else 6532 xfer = len; 6533 if (docommit != 0) { 6534 if (error == 0) { 6535 /* 6536 * Do last mirrored DS commit with this thread. 6537 */ 6538 if (mirror < flp->nfsfl_mirrorcnt - 1) 6539 error = nfsio_commitds(vp, off, xfer, 6540 *dspp, fhp, dp->nfsdi_vers, 6541 dp->nfsdi_minorvers, drpc, tcred, 6542 p); 6543 else 6544 error = nfsrpc_commitds(vp, off, xfer, 6545 *dspp, fhp, dp->nfsdi_vers, 6546 dp->nfsdi_minorvers, tcred, p); 6547 NFSCL_DEBUG(4, "commitds=%d\n", error); 6548 if (error != 0 && error != EACCES && error != 6549 ESTALE) { 6550 NFSCL_DEBUG(4, 6551 "DS layreterr for commit\n"); 6552 nfscl_dserr(NFSV4OP_COMMIT, error, dp, 6553 lyp, *dspp); 6554 } 6555 } 6556 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error); 6557 if (error == 0) { 6558 /* 6559 * Set both eof and uio_resid = 0 to end any 6560 * loops. 6561 */ 6562 *eofp = 1; 6563 uiop->uio_resid = 0; 6564 } else { 6565 NFSLOCKNODE(np); 6566 np->n_flag &= ~NDSCOMMIT; 6567 NFSUNLOCKNODE(np); 6568 } 6569 } else if (rwflag == NFSV4OPEN_ACCESSREAD) { 6570 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6571 off, xfer, fhp, 1, dp->nfsdi_vers, 6572 dp->nfsdi_minorvers, tcred, p); 6573 NFSCL_DEBUG(4, "readds=%d\n", error); 6574 if (error != 0 && error != EACCES && error != ESTALE) { 6575 NFSCL_DEBUG(4, "DS layreterr for read\n"); 6576 nfscl_dserr(NFSV4OP_READ, error, dp, lyp, 6577 *dspp); 6578 } 6579 } else { 6580 if (flp->nfsfl_mirrorcnt == 1) { 6581 error = nfsrpc_writeds(vp, uiop, iomode, 6582 must_commit, stateidp, *dspp, off, xfer, 6583 fhp, 0, 1, dp->nfsdi_vers, 6584 dp->nfsdi_minorvers, tcred, p); 6585 if (error == 0) { 6586 NFSLOCKCLSTATE(); 6587 lyp->nfsly_flags |= NFSLY_WRITTEN; 6588 NFSUNLOCKCLSTATE(); 6589 } 6590 } else { 6591 m = mp; 6592 if (xfer < len) { 6593 /* The mbuf list must be split. */ 6594 m2 = nfsm_split(mp, xfer); 6595 if (m2 != NULL) 6596 mp = m2; 6597 else { 6598 m_freem(mp); 6599 error = EIO; 6600 } 6601 } 6602 NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n", 6603 (uintmax_t)len, (uintmax_t)xfer); 6604 /* 6605 * Do last write to a mirrored DS with this 6606 * thread. 6607 */ 6608 if (error == 0) { 6609 if (mirror < flp->nfsfl_mirrorcnt - 1) 6610 error = nfsio_writedsmir(vp, 6611 iomode, must_commit, 6612 stateidp, *dspp, off, 6613 xfer, fhp, m, 6614 dp->nfsdi_vers, 6615 dp->nfsdi_minorvers, drpc, 6616 tcred, p); 6617 else 6618 error = nfsrpc_writedsmir(vp, 6619 iomode, must_commit, 6620 stateidp, *dspp, off, 6621 xfer, fhp, m, 6622 dp->nfsdi_vers, 6623 dp->nfsdi_minorvers, tcred, 6624 p); 6625 } 6626 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); 6627 if (error != 0 && error != EACCES && error != 6628 ESTALE) { 6629 NFSCL_DEBUG(4, 6630 "DS layreterr for write\n"); 6631 nfscl_dserr(NFSV4OP_WRITE, error, dp, 6632 lyp, *dspp); 6633 } 6634 } 6635 } 6636 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error); 6637 if (error == 0) { 6638 len -= xfer; 6639 off += xfer; 6640 } 6641 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) 6642 NFSFREECRED(tcred); 6643 } 6644 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error); 6645 return (error); 6646 } 6647 6648 /* 6649 * The actual read RPC done to a DS. 6650 */ 6651 static int 6652 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 6653 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex, 6654 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) 6655 { 6656 uint32_t *tl; 6657 int attrflag, error, retlen; 6658 struct nfsrv_descript nfsd; 6659 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6660 struct nfsrv_descript *nd = &nfsd; 6661 struct nfssockreq *nrp; 6662 struct nfsvattr na; 6663 6664 nd->nd_mrep = NULL; 6665 if (vers == 0 || vers == NFS_VER4) { 6666 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, 6667 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6668 vers = NFS_VER4; 6669 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers); 6670 if (flex != 0) 6671 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6672 else 6673 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6674 } else { 6675 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh, 6676 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6677 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]); 6678 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]); 6679 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n"); 6680 } 6681 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 6682 txdr_hyper(io_off, tl); 6683 *(tl + 2) = txdr_unsigned(len); 6684 nrp = dsp->nfsclds_sockp; 6685 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp); 6686 if (nrp == NULL) 6687 /* If NULL, use the MDS socket. */ 6688 nrp = &nmp->nm_sockreq; 6689 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6690 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6691 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat, 6692 error); 6693 if (error != 0) 6694 return (error); 6695 if (vers == NFS_VER3) { 6696 error = nfscl_postop_attr(nd, &na, &attrflag, NULL); 6697 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error); 6698 if (error != 0) 6699 goto nfsmout; 6700 } 6701 if (nd->nd_repstat != 0) { 6702 error = nd->nd_repstat; 6703 goto nfsmout; 6704 } 6705 if (vers == NFS_VER3) { 6706 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6707 *eofp = fxdr_unsigned(int, *(tl + 1)); 6708 } else { 6709 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6710 *eofp = fxdr_unsigned(int, *tl); 6711 } 6712 NFSM_STRSIZ(retlen, len); 6713 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp); 6714 error = nfsm_mbufuio(nd, uiop, retlen); 6715 nfsmout: 6716 if (nd->nd_mrep != NULL) 6717 m_freem(nd->nd_mrep); 6718 return (error); 6719 } 6720 6721 /* 6722 * The actual write RPC done to a DS. 6723 */ 6724 static int 6725 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6726 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6727 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers, 6728 struct ucred *cred, NFSPROC_T *p) 6729 { 6730 uint32_t *tl; 6731 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6732 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC; 6733 int32_t backup; 6734 struct nfsrv_descript nfsd; 6735 struct nfsrv_descript *nd = &nfsd; 6736 struct nfssockreq *nrp; 6737 struct nfsvattr na; 6738 6739 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 6740 nd->nd_mrep = NULL; 6741 if (vers == 0 || vers == NFS_VER4) { 6742 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6743 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6744 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers); 6745 vers = NFS_VER4; 6746 if (flex != 0) 6747 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6748 else 6749 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6750 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6751 } else { 6752 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6753 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6754 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 6755 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 6756 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n"); 6757 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6758 } 6759 txdr_hyper(io_off, tl); 6760 tl += 2; 6761 if (vers == NFS_VER3) 6762 *tl++ = txdr_unsigned(len); 6763 *tl++ = txdr_unsigned(*iomode); 6764 *tl = txdr_unsigned(len); 6765 nfsm_uiombuf(nd, uiop, len); 6766 nrp = dsp->nfsclds_sockp; 6767 if (nrp == NULL) 6768 /* If NULL, use the MDS socket. */ 6769 nrp = &nmp->nm_sockreq; 6770 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6771 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6772 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error, 6773 nd->nd_repstat); 6774 if (error != 0) 6775 return (error); 6776 if (nd->nd_repstat != 0) { 6777 /* 6778 * In case the rpc gets retried, roll 6779 * the uio fields changed by nfsm_uiombuf() 6780 * back. 6781 */ 6782 uiop->uio_offset -= len; 6783 uiop->uio_resid += len; 6784 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len; 6785 uiop->uio_iov->iov_len += len; 6786 error = nd->nd_repstat; 6787 } else { 6788 if (vers == NFS_VER3) { 6789 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6790 NULL); 6791 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error); 6792 if (error != 0) 6793 goto nfsmout; 6794 } 6795 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6796 rlen = fxdr_unsigned(int, *tl++); 6797 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen); 6798 if (rlen == 0) { 6799 error = NFSERR_IO; 6800 goto nfsmout; 6801 } else if (rlen < len) { 6802 backup = len - rlen; 6803 uiop->uio_iov->iov_base = 6804 (char *)uiop->uio_iov->iov_base - backup; 6805 uiop->uio_iov->iov_len += backup; 6806 uiop->uio_offset -= backup; 6807 uiop->uio_resid += backup; 6808 len = rlen; 6809 } 6810 commit = fxdr_unsigned(int, *tl++); 6811 6812 /* 6813 * Return the lowest commitment level 6814 * obtained by any of the RPCs. 6815 */ 6816 if (committed == NFSWRITE_FILESYNC) 6817 committed = commit; 6818 else if (committed == NFSWRITE_DATASYNC && 6819 commit == NFSWRITE_UNSTABLE) 6820 committed = commit; 6821 if (commit_thru_mds != 0) { 6822 NFSLOCKMNT(nmp); 6823 if (!NFSHASWRITEVERF(nmp)) { 6824 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6825 NFSSETWRITEVERF(nmp); 6826 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) && 6827 *must_commit != 2) { 6828 *must_commit = 1; 6829 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6830 } 6831 NFSUNLOCKMNT(nmp); 6832 } else { 6833 NFSLOCKDS(dsp); 6834 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6835 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6836 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6837 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && 6838 *must_commit != 2) { 6839 *must_commit = 1; 6840 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6841 } 6842 NFSUNLOCKDS(dsp); 6843 } 6844 } 6845 nfsmout: 6846 if (nd->nd_mrep != NULL) 6847 m_freem(nd->nd_mrep); 6848 *iomode = committed; 6849 if (nd->nd_repstat != 0 && error == 0) 6850 error = nd->nd_repstat; 6851 return (error); 6852 } 6853 6854 /* 6855 * The actual write RPC done to a DS. 6856 * This variant is called from a separate kernel process for mirrors. 6857 * Any short write is considered an IO error. 6858 */ 6859 static int 6860 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6861 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6862 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6863 struct ucred *cred, NFSPROC_T *p) 6864 { 6865 uint32_t *tl; 6866 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6867 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen; 6868 struct nfsrv_descript nfsd; 6869 struct nfsrv_descript *nd = &nfsd; 6870 struct nfssockreq *nrp; 6871 struct nfsvattr na; 6872 6873 nd->nd_mrep = NULL; 6874 if (vers == 0 || vers == NFS_VER4) { 6875 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6876 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6877 vers = NFS_VER4; 6878 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n", 6879 minorvers); 6880 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6881 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6882 } else { 6883 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6884 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6885 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 6886 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 6887 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n"); 6888 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6889 } 6890 txdr_hyper(io_off, tl); 6891 tl += 2; 6892 if (vers == NFS_VER3) 6893 *tl++ = txdr_unsigned(len); 6894 *tl++ = txdr_unsigned(*iomode); 6895 *tl = txdr_unsigned(len); 6896 if (len > 0) { 6897 /* Put data in mbuf chain. */ 6898 nd->nd_mb->m_next = m; 6899 } 6900 nrp = dsp->nfsclds_sockp; 6901 if (nrp == NULL) 6902 /* If NULL, use the MDS socket. */ 6903 nrp = &nmp->nm_sockreq; 6904 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6905 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6906 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error, 6907 nd->nd_repstat); 6908 if (error != 0) 6909 return (error); 6910 if (nd->nd_repstat != 0) 6911 error = nd->nd_repstat; 6912 else { 6913 if (vers == NFS_VER3) { 6914 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6915 NULL); 6916 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n", 6917 error); 6918 if (error != 0) 6919 goto nfsmout; 6920 } 6921 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6922 rlen = fxdr_unsigned(int, *tl++); 6923 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, 6924 rlen); 6925 if (rlen != len) { 6926 error = NFSERR_IO; 6927 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", 6928 len, rlen); 6929 goto nfsmout; 6930 } 6931 commit = fxdr_unsigned(int, *tl++); 6932 6933 /* 6934 * Return the lowest commitment level 6935 * obtained by any of the RPCs. 6936 */ 6937 if (committed == NFSWRITE_FILESYNC) 6938 committed = commit; 6939 else if (committed == NFSWRITE_DATASYNC && 6940 commit == NFSWRITE_UNSTABLE) 6941 committed = commit; 6942 NFSLOCKDS(dsp); 6943 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6944 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6945 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6946 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && 6947 *must_commit != 2) { 6948 *must_commit = 1; 6949 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6950 } 6951 NFSUNLOCKDS(dsp); 6952 } 6953 nfsmout: 6954 if (nd->nd_mrep != NULL) 6955 m_freem(nd->nd_mrep); 6956 *iomode = committed; 6957 if (nd->nd_repstat != 0 && error == 0) 6958 error = nd->nd_repstat; 6959 return (error); 6960 } 6961 6962 /* 6963 * Start up the thread that will execute nfsrpc_writedsmir(). 6964 */ 6965 static void 6966 start_writedsmir(void *arg, int pending) 6967 { 6968 struct nfsclwritedsdorpc *drpc; 6969 6970 drpc = (struct nfsclwritedsdorpc *)arg; 6971 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode, 6972 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len, 6973 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred, 6974 drpc->p); 6975 drpc->done = 1; 6976 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err); 6977 } 6978 6979 /* 6980 * Set up the write DS mirror call for the pNFS I/O thread. 6981 */ 6982 static int 6983 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6984 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len, 6985 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6986 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6987 { 6988 int error, ret; 6989 6990 error = 0; 6991 drpc->done = 0; 6992 drpc->vp = vp; 6993 drpc->iomode = *iomode; 6994 drpc->must_commit = *must_commit; 6995 drpc->stateidp = stateidp; 6996 drpc->dsp = dsp; 6997 drpc->off = off; 6998 drpc->len = len; 6999 drpc->fhp = fhp; 7000 drpc->m = m; 7001 drpc->vers = vers; 7002 drpc->minorvers = minorvers; 7003 drpc->cred = cred; 7004 drpc->p = p; 7005 drpc->inprog = 0; 7006 ret = EIO; 7007 if (nfs_pnfsiothreads != 0) { 7008 ret = nfs_pnfsio(start_writedsmir, drpc); 7009 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret); 7010 } 7011 if (ret != 0) 7012 error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit, 7013 stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p); 7014 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error); 7015 return (error); 7016 } 7017 7018 /* 7019 * Free up the nfsclds structure. 7020 */ 7021 void 7022 nfscl_freenfsclds(struct nfsclds *dsp) 7023 { 7024 int i; 7025 7026 if (dsp == NULL) 7027 return; 7028 if (dsp->nfsclds_sockp != NULL) { 7029 NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 7030 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 7031 free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 7032 free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 7033 } 7034 NFSFREEMUTEX(&dsp->nfsclds_mtx); 7035 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 7036 for (i = 0; i < NFSV4_CBSLOTS; i++) { 7037 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 7038 m_freem( 7039 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 7040 } 7041 free(dsp, M_NFSCLDS); 7042 } 7043 7044 static enum nfsclds_state 7045 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 7046 struct nfsclds **retdspp, uint32_t *sequencep) 7047 { 7048 struct nfsclds *dsp; 7049 int fndseq; 7050 7051 /* 7052 * Search the list of nfsclds structures for one with the same 7053 * server. 7054 */ 7055 fndseq = 0; 7056 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 7057 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 7058 dsp->nfsclds_servownlen != 0 && 7059 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 7060 dsp->nfsclds_servownlen) && 7061 dsp->nfsclds_sess.nfsess_defunct == 0) { 7062 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 7063 TAILQ_FIRST(&nmp->nm_sess), dsp, 7064 dsp->nfsclds_flags); 7065 if (fndseq == 0) { 7066 /* Get sequenceid# from first entry. */ 7067 *sequencep = 7068 dsp->nfsclds_sess.nfsess_sequenceid; 7069 fndseq = 1; 7070 } 7071 /* Server major id matches. */ 7072 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 7073 *retdspp = dsp; 7074 return (NFSDSP_USETHISSESSION); 7075 } 7076 } 7077 } 7078 if (fndseq != 0) 7079 return (NFSDSP_SEQTHISSESSION); 7080 return (NFSDSP_NOTFOUND); 7081 } 7082 7083 /* 7084 * NFS commit rpc to a NFSv4.1 DS. 7085 */ 7086 static int 7087 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7088 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, 7089 NFSPROC_T *p) 7090 { 7091 uint32_t *tl; 7092 struct nfsrv_descript nfsd, *nd = &nfsd; 7093 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7094 struct nfssockreq *nrp; 7095 struct nfsvattr na; 7096 int attrflag, error; 7097 7098 nd->nd_mrep = NULL; 7099 if (vers == 0 || vers == NFS_VER4) { 7100 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, 7101 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 7102 vers = NFS_VER4; 7103 } else { 7104 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh, 7105 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 7106 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]); 7107 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]); 7108 } 7109 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers, 7110 minorvers); 7111 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7112 txdr_hyper(offset, tl); 7113 tl += 2; 7114 *tl = txdr_unsigned(cnt); 7115 nrp = dsp->nfsclds_sockp; 7116 if (nrp == NULL) 7117 /* If NULL, use the MDS socket. */ 7118 nrp = &nmp->nm_sockreq; 7119 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7120 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7121 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error, 7122 nd->nd_repstat); 7123 if (error != 0) 7124 return (error); 7125 if (nd->nd_repstat == 0) { 7126 if (vers == NFS_VER3) { 7127 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 7128 NULL); 7129 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error); 7130 if (error != 0) 7131 goto nfsmout; 7132 } 7133 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 7134 NFSLOCKDS(dsp); 7135 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 7136 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7137 error = NFSERR_STALEWRITEVERF; 7138 } 7139 NFSUNLOCKDS(dsp); 7140 } 7141 nfsmout: 7142 if (error == 0 && nd->nd_repstat != 0) 7143 error = nd->nd_repstat; 7144 m_freem(nd->nd_mrep); 7145 return (error); 7146 } 7147 7148 /* 7149 * Start up the thread that will execute nfsrpc_commitds(). 7150 */ 7151 static void 7152 start_commitds(void *arg, int pending) 7153 { 7154 struct nfsclwritedsdorpc *drpc; 7155 7156 drpc = (struct nfsclwritedsdorpc *)arg; 7157 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len, 7158 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, 7159 drpc->p); 7160 drpc->done = 1; 7161 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err); 7162 } 7163 7164 /* 7165 * Set up the commit DS mirror call for the pNFS I/O thread. 7166 */ 7167 static int 7168 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7169 struct nfsfh *fhp, int vers, int minorvers, 7170 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7171 { 7172 int error, ret; 7173 7174 error = 0; 7175 drpc->done = 0; 7176 drpc->vp = vp; 7177 drpc->off = offset; 7178 drpc->len = cnt; 7179 drpc->dsp = dsp; 7180 drpc->fhp = fhp; 7181 drpc->vers = vers; 7182 drpc->minorvers = minorvers; 7183 drpc->cred = cred; 7184 drpc->p = p; 7185 drpc->inprog = 0; 7186 ret = EIO; 7187 if (nfs_pnfsiothreads != 0) { 7188 ret = nfs_pnfsio(start_commitds, drpc); 7189 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret); 7190 } 7191 if (ret != 0) 7192 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers, 7193 minorvers, cred, p); 7194 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error); 7195 return (error); 7196 } 7197 7198 /* 7199 * NFS Advise rpc 7200 */ 7201 int 7202 nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise, 7203 struct ucred *cred, NFSPROC_T *p) 7204 { 7205 u_int32_t *tl; 7206 struct nfsrv_descript nfsd, *nd = &nfsd; 7207 nfsattrbit_t hints; 7208 int error; 7209 7210 NFSZERO_ATTRBIT(&hints); 7211 if (advise == POSIX_FADV_WILLNEED) 7212 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7213 else if (advise == POSIX_FADV_DONTNEED) 7214 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7215 else 7216 return (0); 7217 NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp); 7218 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7219 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER); 7220 txdr_hyper(offset, tl); 7221 tl += 2; 7222 txdr_hyper(cnt, tl); 7223 nfsrv_putattrbit(nd, &hints); 7224 error = nfscl_request(nd, vp, p, cred, NULL); 7225 if (error != 0) 7226 return (error); 7227 if (nd->nd_repstat != 0) 7228 error = nd->nd_repstat; 7229 m_freem(nd->nd_mrep); 7230 return (error); 7231 } 7232 7233 #ifdef notyet 7234 /* 7235 * NFS advise rpc to a NFSv4.2 DS. 7236 */ 7237 static int 7238 nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7239 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7240 struct ucred *cred, NFSPROC_T *p) 7241 { 7242 uint32_t *tl; 7243 struct nfsrv_descript nfsd, *nd = &nfsd; 7244 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7245 struct nfssockreq *nrp; 7246 nfsattrbit_t hints; 7247 int error; 7248 7249 /* For NFS DSs prior to NFSv4.2, just return OK. */ 7250 if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION) 7251 return (0); 7252 NFSZERO_ATTRBIT(&hints); 7253 if (advise == POSIX_FADV_WILLNEED) 7254 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7255 else if (advise == POSIX_FADV_DONTNEED) 7256 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7257 else 7258 return (0); 7259 nd->nd_mrep = NULL; 7260 nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh, 7261 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 7262 vers = NFS_VER4; 7263 NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers, 7264 minorvers); 7265 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7266 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7267 txdr_hyper(offset, tl); 7268 tl += 2; 7269 *tl = txdr_unsigned(cnt); 7270 nfsrv_putattrbit(nd, &hints); 7271 nrp = dsp->nfsclds_sockp; 7272 if (nrp == NULL) 7273 /* If NULL, use the MDS socket. */ 7274 nrp = &nmp->nm_sockreq; 7275 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7276 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7277 NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error, 7278 nd->nd_repstat); 7279 if (error != 0) 7280 return (error); 7281 if (nd->nd_repstat != 0) 7282 error = nd->nd_repstat; 7283 m_freem(nd->nd_mrep); 7284 return (error); 7285 } 7286 7287 /* 7288 * Start up the thread that will execute nfsrpc_commitds(). 7289 */ 7290 static void 7291 start_adviseds(void *arg, int pending) 7292 { 7293 struct nfsclwritedsdorpc *drpc; 7294 7295 drpc = (struct nfsclwritedsdorpc *)arg; 7296 drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len, 7297 drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, 7298 drpc->cred, drpc->p); 7299 drpc->done = 1; 7300 NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err); 7301 } 7302 7303 /* 7304 * Set up the commit DS mirror call for the pNFS I/O thread. 7305 */ 7306 static int 7307 nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7308 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7309 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7310 { 7311 int error, ret; 7312 7313 error = 0; 7314 drpc->done = 0; 7315 drpc->vp = vp; 7316 drpc->off = offset; 7317 drpc->len = cnt; 7318 drpc->advise = advise; 7319 drpc->dsp = dsp; 7320 drpc->fhp = fhp; 7321 drpc->vers = vers; 7322 drpc->minorvers = minorvers; 7323 drpc->cred = cred; 7324 drpc->p = p; 7325 drpc->inprog = 0; 7326 ret = EIO; 7327 if (nfs_pnfsiothreads != 0) { 7328 ret = nfs_pnfsio(start_adviseds, drpc); 7329 NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret); 7330 } 7331 if (ret != 0) 7332 error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers, 7333 minorvers, cred, p); 7334 NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error); 7335 return (error); 7336 } 7337 #endif /* notyet */ 7338 7339 /* 7340 * Do the Allocate operation, retrying for recovery. 7341 */ 7342 int 7343 nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap, 7344 int *attrflagp, struct ucred *cred, NFSPROC_T *p, void *stuff) 7345 { 7346 int error, expireret = 0, retrycnt, nostateid; 7347 uint32_t clidrev = 0; 7348 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7349 struct nfsfh *nfhp = NULL; 7350 nfsv4stateid_t stateid; 7351 off_t tmp_off; 7352 void *lckp; 7353 7354 if (len < 0) 7355 return (EINVAL); 7356 if (len == 0) 7357 return (0); 7358 tmp_off = off + len; 7359 NFSLOCKMNT(nmp); 7360 if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) { 7361 NFSUNLOCKMNT(nmp); 7362 return (EFBIG); 7363 } 7364 if (nmp->nm_clp != NULL) 7365 clidrev = nmp->nm_clp->nfsc_clientidrev; 7366 NFSUNLOCKMNT(nmp); 7367 nfhp = VTONFS(vp)->n_fhp; 7368 retrycnt = 0; 7369 do { 7370 lckp = NULL; 7371 nostateid = 0; 7372 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 7373 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); 7374 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 7375 stateid.other[2] == 0) { 7376 nostateid = 1; 7377 NFSCL_DEBUG(1, "stateid0 in allocate\n"); 7378 } 7379 7380 /* 7381 * Not finding a stateid should probably never happen, 7382 * but just return an error for this case. 7383 */ 7384 if (nostateid != 0) 7385 error = EIO; 7386 else 7387 error = nfsrpc_allocaterpc(vp, off, len, &stateid, 7388 nap, attrflagp, cred, p, stuff); 7389 if (error == NFSERR_STALESTATEID) 7390 nfscl_initiate_recovery(nmp->nm_clp); 7391 if (lckp != NULL) 7392 nfscl_lockderef(lckp); 7393 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 7394 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 7395 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 7396 (void) nfs_catnap(PZERO, error, "nfs_allocate"); 7397 } else if ((error == NFSERR_EXPIRED || 7398 error == NFSERR_BADSTATEID) && clidrev != 0) { 7399 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 7400 } 7401 retrycnt++; 7402 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 7403 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 7404 error == NFSERR_STALEDONTRECOVER || 7405 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 7406 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 7407 expireret == 0 && clidrev != 0 && retrycnt < 4)); 7408 if (error != 0 && retrycnt >= 4) 7409 error = EIO; 7410 return (error); 7411 } 7412 7413 /* 7414 * The allocate RPC. 7415 */ 7416 static int 7417 nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp, 7418 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p, 7419 void *stuff) 7420 { 7421 uint32_t *tl; 7422 int error; 7423 struct nfsrv_descript nfsd; 7424 struct nfsrv_descript *nd = &nfsd; 7425 nfsattrbit_t attrbits; 7426 7427 *attrflagp = 0; 7428 NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp); 7429 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 7430 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 7431 txdr_hyper(off, tl); tl += 2; 7432 txdr_hyper(len, tl); tl += 2; 7433 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7434 NFSGETATTR_ATTRBIT(&attrbits); 7435 nfsrv_putattrbit(nd, &attrbits); 7436 error = nfscl_request(nd, vp, p, cred, stuff); 7437 if (error != 0) 7438 return (error); 7439 if (nd->nd_repstat == 0) { 7440 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7441 error = nfsm_loadattr(nd, nap); 7442 if (error == 0) 7443 *attrflagp = NFS_LATTR_NOSHRINK; 7444 } else 7445 error = nd->nd_repstat; 7446 nfsmout: 7447 m_freem(nd->nd_mrep); 7448 return (error); 7449 } 7450 7451 /* 7452 * Set up the XDR arguments for the LayoutGet operation. 7453 */ 7454 static void 7455 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, 7456 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype, 7457 int layoutlen, int usecurstateid) 7458 { 7459 uint32_t *tl; 7460 7461 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 7462 NFSX_STATEID); 7463 *tl++ = newnfs_false; /* Don't signal availability. */ 7464 *tl++ = txdr_unsigned(layouttype); 7465 *tl++ = txdr_unsigned(iomode); 7466 txdr_hyper(offset, tl); 7467 tl += 2; 7468 txdr_hyper(len, tl); 7469 tl += 2; 7470 txdr_hyper(minlen, tl); 7471 tl += 2; 7472 if (usecurstateid != 0) { 7473 /* Special stateid for Current stateid. */ 7474 *tl++ = txdr_unsigned(1); 7475 *tl++ = 0; 7476 *tl++ = 0; 7477 *tl++ = 0; 7478 } else { 7479 *tl++ = txdr_unsigned(stateidp->seqid); 7480 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 7481 *tl++ = stateidp->other[0]; 7482 *tl++ = stateidp->other[1]; 7483 *tl++ = stateidp->other[2]; 7484 } 7485 *tl = txdr_unsigned(layoutlen); 7486 } 7487 7488 /* 7489 * Parse the reply for a successful LayoutGet operation. 7490 */ 7491 static int 7492 nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd, 7493 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp) 7494 { 7495 uint32_t *tl; 7496 struct nfsclflayout *flp, *prevflp, *tflp; 7497 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen; 7498 int m, mirrorcnt; 7499 uint64_t retlen, off; 7500 struct nfsfh *nfhp; 7501 uint8_t *cp; 7502 uid_t user; 7503 gid_t grp; 7504 7505 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n"); 7506 error = 0; 7507 flp = NULL; 7508 gotiomode = -1; 7509 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 7510 if (*tl++ != 0) 7511 *retonclosep = 1; 7512 else 7513 *retonclosep = 0; 7514 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 7515 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 7516 (int)stateidp->seqid); 7517 stateidp->other[0] = *tl++; 7518 stateidp->other[1] = *tl++; 7519 stateidp->other[2] = *tl++; 7520 cnt = fxdr_unsigned(int, *tl); 7521 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 7522 if (cnt <= 0 || cnt > 10000) { 7523 /* Don't accept more than 10000 layouts in reply. */ 7524 error = NFSERR_BADXDR; 7525 goto nfsmout; 7526 } 7527 for (i = 0; i < cnt; i++) { 7528 /* Dissect to the layout type. */ 7529 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 7530 3 * NFSX_UNSIGNED); 7531 off = fxdr_hyper(tl); tl += 2; 7532 retlen = fxdr_hyper(tl); tl += 2; 7533 iomode = fxdr_unsigned(int, *tl++); 7534 laytype = fxdr_unsigned(int, *tl); 7535 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype, 7536 (uintmax_t)off, (uintmax_t)retlen, iomode); 7537 /* Ignore length of layout body for now. */ 7538 if (laytype == NFSLAYOUT_NFSV4_1_FILES) { 7539 /* Parse the File layout up to fhcnt. */ 7540 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + 7541 NFSX_HYPER + NFSX_V4DEVICEID); 7542 fhcnt = fxdr_unsigned(int, *(tl + 4 + 7543 NFSX_V4DEVICEID / NFSX_UNSIGNED)); 7544 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7545 if (fhcnt < 0 || fhcnt > 100) { 7546 /* Don't accept more than 100 file handles. */ 7547 error = NFSERR_BADXDR; 7548 goto nfsmout; 7549 } 7550 if (fhcnt > 0) 7551 flp = malloc(sizeof(*flp) + fhcnt * 7552 sizeof(struct nfsfh *), M_NFSFLAYOUT, 7553 M_WAITOK); 7554 else 7555 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, 7556 M_WAITOK); 7557 flp->nfsfl_flags = NFSFL_FILE; 7558 flp->nfsfl_fhcnt = 0; 7559 flp->nfsfl_devp = NULL; 7560 flp->nfsfl_off = off; 7561 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7562 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7563 else 7564 flp->nfsfl_end = flp->nfsfl_off + retlen; 7565 flp->nfsfl_iomode = iomode; 7566 if (gotiomode == -1) 7567 gotiomode = flp->nfsfl_iomode; 7568 /* Ignore layout body length for now. */ 7569 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 7570 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 7571 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 7572 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 7573 mtx_lock(&nmp->nm_mtx); 7574 if (nmp->nm_minorvers > 1 && (flp->nfsfl_util & 7575 NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0) 7576 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 7577 mtx_unlock(&nmp->nm_mtx); 7578 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 7579 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 7580 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n", 7581 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff); 7582 for (j = 0; j < fhcnt; j++) { 7583 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7584 nfhlen = fxdr_unsigned(int, *tl); 7585 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 7586 error = NFSERR_BADXDR; 7587 goto nfsmout; 7588 } 7589 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, 7590 M_NFSFH, M_WAITOK); 7591 flp->nfsfl_fh[j] = nfhp; 7592 flp->nfsfl_fhcnt++; 7593 nfhp->nfh_len = nfhlen; 7594 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 7595 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 7596 } 7597 } else if (laytype == NFSLAYOUT_FLEXFILE) { 7598 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 7599 NFSX_HYPER); 7600 mirrorcnt = fxdr_unsigned(int, *(tl + 2)); 7601 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt); 7602 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) { 7603 error = NFSERR_BADXDR; 7604 goto nfsmout; 7605 } 7606 flp = malloc(sizeof(*flp) + mirrorcnt * 7607 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK); 7608 flp->nfsfl_flags = NFSFL_FLEXFILE; 7609 flp->nfsfl_mirrorcnt = mirrorcnt; 7610 for (j = 0; j < mirrorcnt; j++) 7611 flp->nfsfl_ffm[j].devp = NULL; 7612 flp->nfsfl_off = off; 7613 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7614 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7615 else 7616 flp->nfsfl_end = flp->nfsfl_off + retlen; 7617 flp->nfsfl_iomode = iomode; 7618 if (gotiomode == -1) 7619 gotiomode = flp->nfsfl_iomode; 7620 flp->nfsfl_stripeunit = fxdr_hyper(tl); 7621 NFSCL_DEBUG(4, "stripeunit=%ju\n", 7622 (uintmax_t)flp->nfsfl_stripeunit); 7623 for (j = 0; j < mirrorcnt; j++) { 7624 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7625 k = fxdr_unsigned(int, *tl); 7626 if (k < 1 || k > 128) { 7627 error = NFSERR_BADXDR; 7628 goto nfsmout; 7629 } 7630 NFSCL_DEBUG(4, "servercnt=%d\n", k); 7631 for (l = 0; l < k; l++) { 7632 NFSM_DISSECT(tl, uint32_t *, 7633 NFSX_V4DEVICEID + NFSX_STATEID + 7634 2 * NFSX_UNSIGNED); 7635 if (l == 0) { 7636 /* Just use the first server. */ 7637 NFSBCOPY(tl, 7638 flp->nfsfl_ffm[j].dev, 7639 NFSX_V4DEVICEID); 7640 tl += (NFSX_V4DEVICEID / 7641 NFSX_UNSIGNED); 7642 tl++; 7643 flp->nfsfl_ffm[j].st.seqid = 7644 *tl++; 7645 flp->nfsfl_ffm[j].st.other[0] = 7646 *tl++; 7647 flp->nfsfl_ffm[j].st.other[1] = 7648 *tl++; 7649 flp->nfsfl_ffm[j].st.other[2] = 7650 *tl++; 7651 NFSCL_DEBUG(4, "st.seqid=%u " 7652 "st.o0=0x%x st.o1=0x%x " 7653 "st.o2=0x%x\n", 7654 flp->nfsfl_ffm[j].st.seqid, 7655 flp->nfsfl_ffm[j].st.other[0], 7656 flp->nfsfl_ffm[j].st.other[1], 7657 flp->nfsfl_ffm[j].st.other[2]); 7658 } else 7659 tl += ((NFSX_V4DEVICEID + 7660 NFSX_STATEID + 7661 NFSX_UNSIGNED) / 7662 NFSX_UNSIGNED); 7663 fhcnt = fxdr_unsigned(int, *tl); 7664 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7665 if (fhcnt < 1 || 7666 fhcnt > NFSDEV_MAXVERS) { 7667 error = NFSERR_BADXDR; 7668 goto nfsmout; 7669 } 7670 for (m = 0; m < fhcnt; m++) { 7671 NFSM_DISSECT(tl, uint32_t *, 7672 NFSX_UNSIGNED); 7673 nfhlen = fxdr_unsigned(int, 7674 *tl); 7675 NFSCL_DEBUG(4, "nfhlen=%d\n", 7676 nfhlen); 7677 if (nfhlen <= 0 || nfhlen > 7678 NFSX_V4FHMAX) { 7679 error = NFSERR_BADXDR; 7680 goto nfsmout; 7681 } 7682 NFSM_DISSECT(cp, uint8_t *, 7683 NFSM_RNDUP(nfhlen)); 7684 if (l == 0) { 7685 flp->nfsfl_ffm[j].fhcnt 7686 = fhcnt; 7687 nfhp = malloc( 7688 sizeof(*nfhp) + 7689 nfhlen - 1, M_NFSFH, 7690 M_WAITOK); 7691 flp->nfsfl_ffm[j].fh[m] 7692 = nfhp; 7693 nfhp->nfh_len = nfhlen; 7694 NFSBCOPY(cp, 7695 nfhp->nfh_fh, 7696 nfhlen); 7697 NFSCL_DEBUG(4, 7698 "got fh\n"); 7699 } 7700 } 7701 /* Now, get the ffsd_user/ffds_group. */ 7702 error = nfsrv_parseug(nd, 0, &user, 7703 &grp, curthread); 7704 NFSCL_DEBUG(4, "after parseu=%d\n", 7705 error); 7706 if (error == 0) 7707 error = nfsrv_parseug(nd, 1, 7708 &user, &grp, curthread); 7709 NFSCL_DEBUG(4, "aft parseg=%d\n", 7710 grp); 7711 if (error != 0) 7712 goto nfsmout; 7713 NFSCL_DEBUG(4, "user=%d group=%d\n", 7714 user, grp); 7715 if (l == 0) { 7716 flp->nfsfl_ffm[j].user = user; 7717 flp->nfsfl_ffm[j].group = grp; 7718 NFSCL_DEBUG(4, 7719 "usr=%d grp=%d\n", user, 7720 grp); 7721 } 7722 } 7723 } 7724 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7725 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++); 7726 #ifdef notnow 7727 /* 7728 * At this time, there is no flag. 7729 * NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be 7730 * added, or it may never exist? 7731 */ 7732 mtx_lock(&nmp->nm_mtx); 7733 if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags & 7734 NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0) 7735 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 7736 mtx_unlock(&nmp->nm_mtx); 7737 #endif 7738 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl); 7739 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n", 7740 flp->nfsfl_fflags, flp->nfsfl_statshint); 7741 } else { 7742 error = NFSERR_BADXDR; 7743 goto nfsmout; 7744 } 7745 if (flp->nfsfl_iomode == gotiomode) { 7746 /* Keep the list in increasing offset order. */ 7747 tflp = LIST_FIRST(flhp); 7748 prevflp = NULL; 7749 while (tflp != NULL && 7750 tflp->nfsfl_off < flp->nfsfl_off) { 7751 prevflp = tflp; 7752 tflp = LIST_NEXT(tflp, nfsfl_list); 7753 } 7754 if (prevflp == NULL) 7755 LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 7756 else 7757 LIST_INSERT_AFTER(prevflp, flp, 7758 nfsfl_list); 7759 NFSCL_DEBUG(4, "flp inserted\n"); 7760 } else { 7761 printf("nfscl_layoutget(): got wrong iomode\n"); 7762 nfscl_freeflayout(flp); 7763 } 7764 flp = NULL; 7765 } 7766 nfsmout: 7767 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error); 7768 if (error != 0 && flp != NULL) 7769 nfscl_freeflayout(flp); 7770 return (error); 7771 } 7772 7773 /* 7774 * Parse a user/group digit string. 7775 */ 7776 static int 7777 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp, 7778 NFSPROC_T *p) 7779 { 7780 uint32_t *tl; 7781 char *cp, *str, str0[NFSV4_SMALLSTR + 1]; 7782 uint32_t len = 0; 7783 int error = 0; 7784 7785 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7786 len = fxdr_unsigned(uint32_t, *tl); 7787 str = NULL; 7788 if (len > NFSV4_OPAQUELIMIT) { 7789 error = NFSERR_BADXDR; 7790 goto nfsmout; 7791 } 7792 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len); 7793 if (len == 0) { 7794 if (dogrp != 0) 7795 *gidp = GID_NOGROUP; 7796 else 7797 *uidp = UID_NOBODY; 7798 return (0); 7799 } 7800 if (len > NFSV4_SMALLSTR) 7801 str = malloc(len + 1, M_TEMP, M_WAITOK); 7802 else 7803 str = str0; 7804 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len)); 7805 NFSBCOPY(cp, str, len); 7806 str[len] = '\0'; 7807 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str); 7808 if (dogrp != 0) 7809 error = nfsv4_strtogid(nd, str, len, gidp); 7810 else 7811 error = nfsv4_strtouid(nd, str, len, uidp); 7812 nfsmout: 7813 if (len > NFSV4_SMALLSTR) 7814 free(str, M_TEMP); 7815 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error); 7816 return (error); 7817 } 7818 7819 /* 7820 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), 7821 * so that it does both an Open and a Layoutget. 7822 */ 7823 static int 7824 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7825 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7826 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7827 struct ucred *cred, NFSPROC_T *p) 7828 { 7829 struct nfscllayout *lyp; 7830 struct nfsclflayout *flp; 7831 struct nfsclflayouthead flh; 7832 int error, islocked, layoutlen, recalled, retonclose, usecurstateid; 7833 int layouttype, laystat; 7834 nfsv4stateid_t stateid; 7835 struct nfsclsession *tsep; 7836 7837 error = 0; 7838 if (NFSHASFLEXFILE(nmp)) 7839 layouttype = NFSLAYOUT_FLEXFILE; 7840 else 7841 layouttype = NFSLAYOUT_NFSV4_1_FILES; 7842 /* 7843 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 7844 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 7845 * flp == NULL. 7846 */ 7847 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp, 7848 &recalled); 7849 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); 7850 if (lyp == NULL) 7851 islocked = 0; 7852 else if (flp != NULL) 7853 islocked = 1; 7854 else 7855 islocked = 2; 7856 if ((lyp == NULL || flp == NULL) && recalled == 0) { 7857 LIST_INIT(&flh); 7858 tsep = nfsmnt_mdssession(nmp); 7859 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 7860 3 * NFSX_UNSIGNED); 7861 if (lyp == NULL) 7862 usecurstateid = 1; 7863 else { 7864 usecurstateid = 0; 7865 stateid.seqid = lyp->nfsly_stateid.seqid; 7866 stateid.other[0] = lyp->nfsly_stateid.other[0]; 7867 stateid.other[1] = lyp->nfsly_stateid.other[1]; 7868 stateid.other[2] = lyp->nfsly_stateid.other[2]; 7869 } 7870 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, 7871 newfhp, newfhlen, mode, op, name, namelen, 7872 dpp, &stateid, usecurstateid, layouttype, layoutlen, 7873 &retonclose, &flh, &laystat, cred, p); 7874 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", 7875 laystat, error); 7876 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, 7877 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, 7878 &islocked, cred, p); 7879 } else 7880 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, 7881 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); 7882 if (islocked == 2) 7883 nfscl_rellayout(lyp, 1); 7884 else if (islocked == 1) 7885 nfscl_rellayout(lyp, 0); 7886 return (error); 7887 } 7888 7889 /* 7890 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS 7891 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are 7892 * handled by nfsrpc_openrpc(). 7893 * For the case where op == NULL, dvp is the directory. When op != NULL, it 7894 * can be NULL. 7895 */ 7896 static int 7897 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7898 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7899 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7900 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, 7901 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, 7902 int *laystatp, struct ucred *cred, NFSPROC_T *p) 7903 { 7904 uint32_t *tl; 7905 struct nfsrv_descript nfsd, *nd = &nfsd; 7906 struct nfscldeleg *ndp = NULL; 7907 struct nfsvattr nfsva; 7908 struct nfsclsession *tsep; 7909 uint32_t rflags, deleg; 7910 nfsattrbit_t attrbits; 7911 int error, ret, acesize, limitby, iomode; 7912 7913 *dpp = NULL; 7914 *laystatp = ENXIO; 7915 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL, 7916 0, 0); 7917 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 7918 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 7919 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 7920 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 7921 tsep = nfsmnt_mdssession(nmp); 7922 *tl++ = tsep->nfsess_clientid.lval[0]; 7923 *tl = tsep->nfsess_clientid.lval[1]; 7924 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 7925 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7926 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 7927 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 7928 nfsm_strtom(nd, name, namelen); 7929 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7930 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7931 NFSZERO_ATTRBIT(&attrbits); 7932 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 7933 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 7934 nfsrv_putattrbit(nd, &attrbits); 7935 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7936 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 7937 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) 7938 iomode = NFSLAYOUTIOMODE_RW; 7939 else 7940 iomode = NFSLAYOUTIOMODE_READ; 7941 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, 7942 layouttype, layoutlen, usecurstateid); 7943 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 7944 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 7945 if (error != 0) 7946 return (error); 7947 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 7948 if (nd->nd_repstat != 0) 7949 *laystatp = nd->nd_repstat; 7950 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7951 /* ND_NOMOREDATA will be set if the Open operation failed. */ 7952 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7953 6 * NFSX_UNSIGNED); 7954 op->nfso_stateid.seqid = *tl++; 7955 op->nfso_stateid.other[0] = *tl++; 7956 op->nfso_stateid.other[1] = *tl++; 7957 op->nfso_stateid.other[2] = *tl; 7958 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 7959 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 7960 if (error != 0) 7961 goto nfsmout; 7962 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 7963 deleg = fxdr_unsigned(u_int32_t, *tl); 7964 if (deleg == NFSV4OPEN_DELEGATEREAD || 7965 deleg == NFSV4OPEN_DELEGATEWRITE) { 7966 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 7967 NFSCLFLAGS_FIRSTDELEG)) 7968 op->nfso_own->nfsow_clp->nfsc_flags |= 7969 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 7970 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, 7971 M_NFSCLDELEG, M_WAITOK); 7972 LIST_INIT(&ndp->nfsdl_owner); 7973 LIST_INIT(&ndp->nfsdl_lock); 7974 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 7975 ndp->nfsdl_fhlen = newfhlen; 7976 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 7977 newnfs_copyincred(cred, &ndp->nfsdl_cred); 7978 nfscl_lockinit(&ndp->nfsdl_rwlock); 7979 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7980 NFSX_UNSIGNED); 7981 ndp->nfsdl_stateid.seqid = *tl++; 7982 ndp->nfsdl_stateid.other[0] = *tl++; 7983 ndp->nfsdl_stateid.other[1] = *tl++; 7984 ndp->nfsdl_stateid.other[2] = *tl++; 7985 ret = fxdr_unsigned(int, *tl); 7986 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 7987 ndp->nfsdl_flags = NFSCLDL_WRITE; 7988 /* 7989 * Indicates how much the file can grow. 7990 */ 7991 NFSM_DISSECT(tl, u_int32_t *, 7992 3 * NFSX_UNSIGNED); 7993 limitby = fxdr_unsigned(int, *tl++); 7994 switch (limitby) { 7995 case NFSV4OPEN_LIMITSIZE: 7996 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 7997 break; 7998 case NFSV4OPEN_LIMITBLOCKS: 7999 ndp->nfsdl_sizelimit = 8000 fxdr_unsigned(u_int64_t, *tl++); 8001 ndp->nfsdl_sizelimit *= 8002 fxdr_unsigned(u_int64_t, *tl); 8003 break; 8004 default: 8005 error = NFSERR_BADXDR; 8006 goto nfsmout; 8007 }; 8008 } else 8009 ndp->nfsdl_flags = NFSCLDL_READ; 8010 if (ret != 0) 8011 ndp->nfsdl_flags |= NFSCLDL_RECALL; 8012 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false, 8013 &ret, &acesize, p); 8014 if (error != 0) 8015 goto nfsmout; 8016 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 8017 error = NFSERR_BADXDR; 8018 goto nfsmout; 8019 } 8020 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || 8021 nfscl_assumeposixlocks) 8022 op->nfso_posixlock = 1; 8023 else 8024 op->nfso_posixlock = 0; 8025 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8026 /* If the 2nd element == NFS_OK, the Getattr succeeded. */ 8027 if (*++tl == 0) { 8028 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 8029 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 8030 NULL, NULL, NULL, p, cred); 8031 if (error != 0) 8032 goto nfsmout; 8033 if (ndp != NULL) { 8034 ndp->nfsdl_change = nfsva.na_filerev; 8035 ndp->nfsdl_modtime = nfsva.na_mtime; 8036 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8037 *dpp = ndp; 8038 ndp = NULL; 8039 } 8040 /* 8041 * At this point, the Open has succeeded, so set 8042 * nd_repstat = NFS_OK. If the Layoutget failed, 8043 * this function just won't return a layout. 8044 */ 8045 if (nd->nd_repstat == 0) { 8046 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8047 *laystatp = fxdr_unsigned(int, *++tl); 8048 if (*laystatp == 0) { 8049 error = nfsrv_parselayoutget(nmp, nd, 8050 stateidp, retonclosep, flhp); 8051 if (error != 0) 8052 *laystatp = error; 8053 } 8054 } else 8055 nd->nd_repstat = 0; /* Return 0 for Open. */ 8056 } 8057 } 8058 if (nd->nd_repstat != 0 && error == 0) 8059 error = nd->nd_repstat; 8060 nfsmout: 8061 free(ndp, M_NFSCLDELEG); 8062 m_freem(nd->nd_mrep); 8063 return (error); 8064 } 8065 8066 /* 8067 * Similar nfsrpc_createv4(), but also does the LayoutGet operation. 8068 * Used only for mounts with pNFS enabled. 8069 */ 8070 static int 8071 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8072 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8073 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8074 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8075 int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp, 8076 int usecurstateid, int layouttype, int layoutlen, int *retonclosep, 8077 struct nfsclflayouthead *flhp, int *laystatp) 8078 { 8079 uint32_t *tl; 8080 int error = 0, deleg, newone, ret, acesize, limitby; 8081 struct nfsrv_descript nfsd, *nd = &nfsd; 8082 struct nfsclopen *op; 8083 struct nfscldeleg *dp = NULL; 8084 struct nfsnode *np; 8085 struct nfsfh *nfhp; 8086 struct nfsclsession *tsep; 8087 nfsattrbit_t attrbits; 8088 nfsv4stateid_t stateid; 8089 struct nfsmount *nmp; 8090 8091 nmp = VFSTONFS(dvp->v_mount); 8092 np = VTONFS(dvp); 8093 *laystatp = ENXIO; 8094 *unlockedp = 0; 8095 *nfhpp = NULL; 8096 *dpp = NULL; 8097 *attrflagp = 0; 8098 *dattrflagp = 0; 8099 if (namelen > NFS_MAXNAMLEN) 8100 return (ENAMETOOLONG); 8101 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp); 8102 /* 8103 * For V4, this is actually an Open op. 8104 */ 8105 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 8106 *tl++ = txdr_unsigned(owp->nfsow_seqid); 8107 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 8108 NFSV4OPEN_ACCESSREAD); 8109 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 8110 tsep = nfsmnt_mdssession(nmp); 8111 *tl++ = tsep->nfsess_clientid.lval[0]; 8112 *tl = tsep->nfsess_clientid.lval[1]; 8113 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 8114 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8115 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 8116 if ((fmode & O_EXCL) != 0) { 8117 if (NFSHASSESSPERSIST(nmp)) { 8118 /* Use GUARDED for persistent sessions. */ 8119 *tl = txdr_unsigned(NFSCREATE_GUARDED); 8120 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8121 } else { 8122 /* Otherwise, use EXCLUSIVE4_1. */ 8123 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 8124 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 8125 *tl++ = cverf.lval[0]; 8126 *tl = cverf.lval[1]; 8127 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8128 } 8129 } else { 8130 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 8131 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8132 } 8133 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8134 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 8135 nfsm_strtom(nd, name, namelen); 8136 /* Get the new file's handle and attributes, plus save the FH. */ 8137 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 8138 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); 8139 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 8140 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8141 NFSGETATTR_ATTRBIT(&attrbits); 8142 nfsrv_putattrbit(nd, &attrbits); 8143 /* Get the directory's post-op attributes. */ 8144 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8145 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8146 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 8147 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8148 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8149 nfsrv_putattrbit(nd, &attrbits); 8150 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8151 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); 8152 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 8153 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, 8154 layouttype, layoutlen, usecurstateid); 8155 error = nfscl_request(nd, dvp, p, cred, dstuff); 8156 if (error != 0) 8157 return (error); 8158 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, 8159 error); 8160 if (nd->nd_repstat != 0) 8161 *laystatp = nd->nd_repstat; 8162 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 8163 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8164 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); 8165 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8166 6 * NFSX_UNSIGNED); 8167 stateid.seqid = *tl++; 8168 stateid.other[0] = *tl++; 8169 stateid.other[1] = *tl++; 8170 stateid.other[2] = *tl; 8171 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8172 if (error != 0) 8173 goto nfsmout; 8174 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 8175 deleg = fxdr_unsigned(int, *tl); 8176 if (deleg == NFSV4OPEN_DELEGATEREAD || 8177 deleg == NFSV4OPEN_DELEGATEWRITE) { 8178 if (!(owp->nfsow_clp->nfsc_flags & 8179 NFSCLFLAGS_FIRSTDELEG)) 8180 owp->nfsow_clp->nfsc_flags |= 8181 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 8182 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, 8183 M_NFSCLDELEG, M_WAITOK); 8184 LIST_INIT(&dp->nfsdl_owner); 8185 LIST_INIT(&dp->nfsdl_lock); 8186 dp->nfsdl_clp = owp->nfsow_clp; 8187 newnfs_copyincred(cred, &dp->nfsdl_cred); 8188 nfscl_lockinit(&dp->nfsdl_rwlock); 8189 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8190 NFSX_UNSIGNED); 8191 dp->nfsdl_stateid.seqid = *tl++; 8192 dp->nfsdl_stateid.other[0] = *tl++; 8193 dp->nfsdl_stateid.other[1] = *tl++; 8194 dp->nfsdl_stateid.other[2] = *tl++; 8195 ret = fxdr_unsigned(int, *tl); 8196 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 8197 dp->nfsdl_flags = NFSCLDL_WRITE; 8198 /* 8199 * Indicates how much the file can grow. 8200 */ 8201 NFSM_DISSECT(tl, u_int32_t *, 8202 3 * NFSX_UNSIGNED); 8203 limitby = fxdr_unsigned(int, *tl++); 8204 switch (limitby) { 8205 case NFSV4OPEN_LIMITSIZE: 8206 dp->nfsdl_sizelimit = fxdr_hyper(tl); 8207 break; 8208 case NFSV4OPEN_LIMITBLOCKS: 8209 dp->nfsdl_sizelimit = 8210 fxdr_unsigned(u_int64_t, *tl++); 8211 dp->nfsdl_sizelimit *= 8212 fxdr_unsigned(u_int64_t, *tl); 8213 break; 8214 default: 8215 error = NFSERR_BADXDR; 8216 goto nfsmout; 8217 }; 8218 } else { 8219 dp->nfsdl_flags = NFSCLDL_READ; 8220 } 8221 if (ret != 0) 8222 dp->nfsdl_flags |= NFSCLDL_RECALL; 8223 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false, 8224 &ret, &acesize, p); 8225 if (error != 0) 8226 goto nfsmout; 8227 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 8228 error = NFSERR_BADXDR; 8229 goto nfsmout; 8230 } 8231 8232 /* Now, we should have the status for the SaveFH. */ 8233 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8234 if (*++tl == 0) { 8235 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); 8236 /* 8237 * Now, process the GetFH and Getattr for the newly 8238 * created file. nfscl_mtofh() will set 8239 * ND_NOMOREDATA if these weren't successful. 8240 */ 8241 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 8242 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); 8243 if (error != 0) 8244 goto nfsmout; 8245 } else 8246 nd->nd_flag |= ND_NOMOREDATA; 8247 /* Now we have the PutFH and Getattr for the directory. */ 8248 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8249 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8250 if (*++tl != 0) 8251 nd->nd_flag |= ND_NOMOREDATA; 8252 else { 8253 NFSM_DISSECT(tl, uint32_t *, 2 * 8254 NFSX_UNSIGNED); 8255 if (*++tl != 0) 8256 nd->nd_flag |= ND_NOMOREDATA; 8257 } 8258 } 8259 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8260 /* Load the directory attributes. */ 8261 error = nfsm_loadattr(nd, dnap); 8262 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); 8263 if (error != 0) 8264 goto nfsmout; 8265 *dattrflagp = 1; 8266 if (dp != NULL && *attrflagp != 0) { 8267 dp->nfsdl_change = nnap->na_filerev; 8268 dp->nfsdl_modtime = nnap->na_mtime; 8269 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8270 } 8271 /* 8272 * We can now complete the Open state. 8273 */ 8274 nfhp = *nfhpp; 8275 if (dp != NULL) { 8276 dp->nfsdl_fhlen = nfhp->nfh_len; 8277 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, 8278 nfhp->nfh_len); 8279 } 8280 /* 8281 * Get an Open structure that will be 8282 * attached to the OpenOwner, acquired already. 8283 */ 8284 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 8285 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 8286 cred, p, NULL, &op, &newone, NULL, 0, false); 8287 if (error != 0) 8288 goto nfsmout; 8289 op->nfso_stateid = stateid; 8290 newnfs_copyincred(cred, &op->nfso_cred); 8291 8292 nfscl_openrelease(nmp, op, error, newone); 8293 *unlockedp = 1; 8294 8295 /* Now, handle the RestoreFH and LayoutGet. */ 8296 if (nd->nd_repstat == 0) { 8297 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 8298 *laystatp = fxdr_unsigned(int, *(tl + 3)); 8299 if (*laystatp == 0) { 8300 error = nfsrv_parselayoutget(nmp, nd, 8301 stateidp, retonclosep, flhp); 8302 if (error != 0) 8303 *laystatp = error; 8304 } 8305 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", 8306 error); 8307 } else 8308 nd->nd_repstat = 0; 8309 } 8310 } 8311 if (nd->nd_repstat != 0 && error == 0) 8312 error = nd->nd_repstat; 8313 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) 8314 nfscl_initiate_recovery(owp->nfsow_clp); 8315 nfsmout: 8316 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); 8317 if (error == 0) 8318 *dpp = dp; 8319 else 8320 free(dp, M_NFSCLDELEG); 8321 m_freem(nd->nd_mrep); 8322 return (error); 8323 } 8324 8325 /* 8326 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. 8327 */ 8328 static int 8329 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8330 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8331 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8332 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8333 int *dattrflagp, void *dstuff, int *unlockedp) 8334 { 8335 struct nfscllayout *lyp; 8336 struct nfsclflayouthead flh; 8337 struct nfsfh *nfhp; 8338 struct nfsclsession *tsep; 8339 struct nfsmount *nmp; 8340 nfsv4stateid_t stateid; 8341 int error, layoutlen, layouttype, retonclose, laystat; 8342 8343 error = 0; 8344 nmp = VFSTONFS(dvp->v_mount); 8345 if (NFSHASFLEXFILE(nmp)) 8346 layouttype = NFSLAYOUT_FLEXFILE; 8347 else 8348 layouttype = NFSLAYOUT_NFSV4_1_FILES; 8349 LIST_INIT(&flh); 8350 tsep = nfsmnt_mdssession(nmp); 8351 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); 8352 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, 8353 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 8354 dstuff, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose, 8355 &flh, &laystat); 8356 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", 8357 laystat, error); 8358 lyp = NULL; 8359 if (laystat == 0) { 8360 nfhp = *nfhpp; 8361 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, 8362 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, 8363 layouttype, laystat, NULL, cred, p); 8364 } else 8365 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, 8366 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, 8367 cred, p); 8368 if (laystat == 0) 8369 nfscl_rellayout(lyp, 0); 8370 return (error); 8371 } 8372 8373 /* 8374 * Process the results of a layoutget() operation. 8375 */ 8376 static int 8377 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, 8378 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, 8379 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype, 8380 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) 8381 { 8382 struct nfsclflayout *tflp; 8383 struct nfscldevinfo *dip; 8384 uint8_t *dev; 8385 int i, mirrorcnt; 8386 8387 if (laystat == NFSERR_UNKNLAYOUTTYPE) { 8388 NFSLOCKMNT(nmp); 8389 if (!NFSHASFLEXFILE(nmp)) { 8390 /* Switch to using Flex File Layout. */ 8391 nmp->nm_state |= NFSSTA_FLEXFILE; 8392 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 8393 /* Disable pNFS. */ 8394 NFSCL_DEBUG(1, "disable PNFS\n"); 8395 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE); 8396 } 8397 NFSUNLOCKMNT(nmp); 8398 } 8399 if (laystat == 0) { 8400 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); 8401 LIST_FOREACH(tflp, flhp, nfsfl_list) { 8402 if (layouttype == NFSLAYOUT_FLEXFILE) 8403 mirrorcnt = tflp->nfsfl_mirrorcnt; 8404 else 8405 mirrorcnt = 1; 8406 for (i = 0; i < mirrorcnt; i++) { 8407 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp); 8408 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); 8409 if (laystat != 0) { 8410 if (layouttype == NFSLAYOUT_FLEXFILE) 8411 dev = tflp->nfsfl_ffm[i].dev; 8412 else 8413 dev = tflp->nfsfl_dev; 8414 laystat = nfsrpc_getdeviceinfo(nmp, dev, 8415 layouttype, notifybit, &dip, cred, 8416 p); 8417 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", 8418 laystat); 8419 if (laystat != 0) 8420 goto out; 8421 laystat = nfscl_adddevinfo(nmp, dip, i, 8422 tflp); 8423 if (laystat != 0) 8424 printf("nfsrpc_layoutgetresout" 8425 ": cannot add\n"); 8426 } 8427 } 8428 } 8429 } 8430 out: 8431 if (laystat == 0) { 8432 /* 8433 * nfscl_layout() always returns with the nfsly_lock 8434 * set to a refcnt (shared lock). 8435 * Passing in dvp is sufficient, since it is only used to 8436 * get the fsid for the file system. 8437 */ 8438 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, 8439 layouttype, retonclose, flhp, lypp, cred, p); 8440 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", 8441 laystat); 8442 if (laystat == 0 && islockedp != NULL) 8443 *islockedp = 1; 8444 } 8445 return (laystat); 8446 } 8447 8448 /* 8449 * nfs copy_file_range operation. 8450 */ 8451 int 8452 nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp, 8453 off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp, 8454 struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap, 8455 struct ucred *cred, bool consecutive, bool *must_commitp) 8456 { 8457 int commit, error, expireret = 0, retrycnt; 8458 u_int32_t clidrev = 0; 8459 struct nfsmount *nmp = VFSTONFS(invp->v_mount); 8460 struct nfsfh *innfhp = NULL, *outnfhp = NULL; 8461 nfsv4stateid_t instateid, outstateid; 8462 void *inlckp, *outlckp; 8463 8464 if (nmp->nm_clp != NULL) 8465 clidrev = nmp->nm_clp->nfsc_clientidrev; 8466 innfhp = VTONFS(invp)->n_fhp; 8467 outnfhp = VTONFS(outvp)->n_fhp; 8468 retrycnt = 0; 8469 do { 8470 /* Get both stateids. */ 8471 inlckp = NULL; 8472 nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len, 8473 NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid, 8474 &inlckp); 8475 outlckp = NULL; 8476 nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len, 8477 NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid, 8478 &outlckp); 8479 8480 error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp, 8481 &instateid, &outstateid, innap, inattrflagp, outnap, 8482 outattrflagp, consecutive, &commit, cred, curthread); 8483 if (error == 0) { 8484 if (commit != NFSWRITE_FILESYNC) 8485 *must_commitp = true; 8486 *inoffp += *lenp; 8487 *outoffp += *lenp; 8488 } else if (error == NFSERR_STALESTATEID) 8489 nfscl_initiate_recovery(nmp->nm_clp); 8490 if (inlckp != NULL) 8491 nfscl_lockderef(inlckp); 8492 if (outlckp != NULL) 8493 nfscl_lockderef(outlckp); 8494 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8495 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8496 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 8497 (void) nfs_catnap(PZERO, error, "nfs_cfr"); 8498 } else if ((error == NFSERR_EXPIRED || 8499 error == NFSERR_BADSTATEID) && clidrev != 0) { 8500 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 8501 curthread); 8502 } 8503 retrycnt++; 8504 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 8505 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8506 error == NFSERR_STALEDONTRECOVER || 8507 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 8508 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 8509 expireret == 0 && clidrev != 0 && retrycnt < 4)); 8510 if (error != 0 && (retrycnt >= 4 || 8511 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8512 error == NFSERR_STALEDONTRECOVER)) 8513 error = EIO; 8514 return (error); 8515 } 8516 8517 /* 8518 * The copy RPC. 8519 */ 8520 static int 8521 nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff, 8522 size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp, 8523 struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap, 8524 int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred, 8525 NFSPROC_T *p) 8526 { 8527 uint32_t *tl; 8528 int error; 8529 struct nfsrv_descript nfsd; 8530 struct nfsrv_descript *nd = &nfsd; 8531 struct nfsmount *nmp; 8532 nfsattrbit_t attrbits; 8533 uint64_t len; 8534 8535 nmp = VFSTONFS(outvp->v_mount); 8536 *inattrflagp = *outattrflagp = 0; 8537 *commitp = NFSWRITE_UNSTABLE; 8538 len = *lenp; 8539 *lenp = 0; 8540 if (len > nfs_maxcopyrange) 8541 len = nfs_maxcopyrange; 8542 NFSCL_REQSTART(nd, NFSPROC_COPY, invp); 8543 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8544 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8545 NFSGETATTR_ATTRBIT(&attrbits); 8546 nfsrv_putattrbit(nd, &attrbits); 8547 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8548 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8549 nfsm_fhtom(nd, VTONFS(outvp)->n_fhp->nfh_fh, 8550 VTONFS(outvp)->n_fhp->nfh_len, 0); 8551 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8552 *tl = txdr_unsigned(NFSV4OP_COPY); 8553 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); 8554 nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID); 8555 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED); 8556 txdr_hyper(inoff, tl); tl += 2; 8557 txdr_hyper(outoff, tl); tl += 2; 8558 txdr_hyper(len, tl); tl += 2; 8559 if (consecutive) 8560 *tl++ = newnfs_true; 8561 else 8562 *tl++ = newnfs_false; 8563 *tl++ = newnfs_true; 8564 *tl++ = 0; 8565 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8566 NFSWRITEGETATTR_ATTRBIT(&attrbits); 8567 nfsrv_putattrbit(nd, &attrbits); 8568 error = nfscl_request(nd, invp, p, cred, NULL); 8569 if (error != 0) 8570 return (error); 8571 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8572 /* Get the input file's attributes. */ 8573 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8574 if (*(tl + 1) == 0) { 8575 error = nfsm_loadattr(nd, innap); 8576 if (error != 0) 8577 goto nfsmout; 8578 *inattrflagp = 1; 8579 } else 8580 nd->nd_flag |= ND_NOMOREDATA; 8581 } 8582 /* Skip over return stat for PutFH. */ 8583 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8584 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8585 if (*++tl != 0) 8586 nd->nd_flag |= ND_NOMOREDATA; 8587 } 8588 /* Skip over return stat for Copy. */ 8589 if ((nd->nd_flag & ND_NOMOREDATA) == 0) 8590 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8591 if (nd->nd_repstat == 0) { 8592 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8593 if (*tl != 0) { 8594 /* There should be no callback ids. */ 8595 error = NFSERR_BADXDR; 8596 goto nfsmout; 8597 } 8598 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED + 8599 NFSX_VERF); 8600 len = fxdr_hyper(tl); tl += 2; 8601 *commitp = fxdr_unsigned(int, *tl++); 8602 NFSLOCKMNT(nmp); 8603 if (!NFSHASWRITEVERF(nmp)) { 8604 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8605 NFSSETWRITEVERF(nmp); 8606 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 8607 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8608 nd->nd_repstat = NFSERR_STALEWRITEVERF; 8609 } 8610 NFSUNLOCKMNT(nmp); 8611 tl += (NFSX_VERF / NFSX_UNSIGNED); 8612 if (nd->nd_repstat == 0 && *++tl != newnfs_true) 8613 /* Must be a synchronous copy. */ 8614 nd->nd_repstat = NFSERR_NOTSUPP; 8615 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8616 error = nfsm_loadattr(nd, outnap); 8617 if (error == 0) 8618 *outattrflagp = NFS_LATTR_NOSHRINK; 8619 if (nd->nd_repstat == 0) 8620 *lenp = len; 8621 } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) { 8622 /* 8623 * For the case where consecutive is not supported, but 8624 * synchronous is supported, we can try consecutive == false 8625 * by returning this error. Otherwise, return NFSERR_NOTSUPP, 8626 * since Copy cannot be done. 8627 */ 8628 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8629 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8630 if (!consecutive || *++tl == newnfs_false) 8631 nd->nd_repstat = NFSERR_NOTSUPP; 8632 } else 8633 nd->nd_repstat = NFSERR_BADXDR; 8634 } 8635 if (error == 0) 8636 error = nd->nd_repstat; 8637 nfsmout: 8638 m_freem(nd->nd_mrep); 8639 return (error); 8640 } 8641 8642 /* 8643 * Seek operation. 8644 */ 8645 int 8646 nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content, 8647 struct ucred *cred, struct nfsvattr *nap, int *attrflagp) 8648 { 8649 int error, expireret = 0, retrycnt; 8650 u_int32_t clidrev = 0; 8651 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 8652 struct nfsnode *np = VTONFS(vp); 8653 struct nfsfh *nfhp = NULL; 8654 nfsv4stateid_t stateid; 8655 void *lckp; 8656 8657 if (nmp->nm_clp != NULL) 8658 clidrev = nmp->nm_clp->nfsc_clientidrev; 8659 nfhp = np->n_fhp; 8660 retrycnt = 0; 8661 do { 8662 lckp = NULL; 8663 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 8664 NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp); 8665 error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content, 8666 nap, attrflagp, cred); 8667 if (error == NFSERR_STALESTATEID) 8668 nfscl_initiate_recovery(nmp->nm_clp); 8669 if (lckp != NULL) 8670 nfscl_lockderef(lckp); 8671 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8672 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8673 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 8674 (void) nfs_catnap(PZERO, error, "nfs_seek"); 8675 } else if ((error == NFSERR_EXPIRED || 8676 error == NFSERR_BADSTATEID) && clidrev != 0) { 8677 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 8678 curthread); 8679 } 8680 retrycnt++; 8681 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8682 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8683 error == NFSERR_BADSESSION || 8684 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 8685 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 8686 expireret == 0 && clidrev != 0 && retrycnt < 4) || 8687 (error == NFSERR_OPENMODE && retrycnt < 4)); 8688 if (error && retrycnt >= 4) 8689 error = EIO; 8690 return (error); 8691 } 8692 8693 /* 8694 * The seek RPC. 8695 */ 8696 static int 8697 nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp, 8698 int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred) 8699 { 8700 uint32_t *tl; 8701 int error; 8702 struct nfsrv_descript nfsd; 8703 struct nfsrv_descript *nd = &nfsd; 8704 nfsattrbit_t attrbits; 8705 8706 *attrflagp = 0; 8707 NFSCL_REQSTART(nd, NFSPROC_SEEK, vp); 8708 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 8709 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 8710 txdr_hyper(*offp, tl); tl += 2; 8711 *tl++ = txdr_unsigned(content); 8712 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8713 NFSGETATTR_ATTRBIT(&attrbits); 8714 nfsrv_putattrbit(nd, &attrbits); 8715 error = nfscl_request(nd, vp, curthread, cred, NULL); 8716 if (error != 0) 8717 return (error); 8718 if (nd->nd_repstat == 0) { 8719 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER); 8720 if (*tl++ == newnfs_true) 8721 *eofp = true; 8722 else 8723 *eofp = false; 8724 *offp = fxdr_hyper(tl); 8725 /* Just skip over Getattr op status. */ 8726 error = nfsm_loadattr(nd, nap); 8727 if (error == 0) 8728 *attrflagp = 1; 8729 } 8730 error = nd->nd_repstat; 8731 nfsmout: 8732 m_freem(nd->nd_mrep); 8733 return (error); 8734 } 8735 8736 /* 8737 * The getextattr RPC. 8738 */ 8739 int 8740 nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp, 8741 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 8742 { 8743 uint32_t *tl; 8744 int error; 8745 struct nfsrv_descript nfsd; 8746 struct nfsrv_descript *nd = &nfsd; 8747 nfsattrbit_t attrbits; 8748 uint32_t len, len2; 8749 8750 *attrflagp = 0; 8751 NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp); 8752 nfsm_strtom(nd, name, strlen(name)); 8753 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8754 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8755 NFSGETATTR_ATTRBIT(&attrbits); 8756 nfsrv_putattrbit(nd, &attrbits); 8757 error = nfscl_request(nd, vp, p, cred, NULL); 8758 if (error != 0) 8759 return (error); 8760 if (nd->nd_repstat == 0) { 8761 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8762 len = fxdr_unsigned(uint32_t, *tl); 8763 /* Sanity check lengths. */ 8764 if (uiop != NULL && len > 0 && len <= IOSIZE_MAX && 8765 uiop->uio_resid <= UINT32_MAX) { 8766 len2 = uiop->uio_resid; 8767 if (len2 >= len) 8768 error = nfsm_mbufuio(nd, uiop, len); 8769 else { 8770 error = nfsm_mbufuio(nd, uiop, len2); 8771 if (error == 0) { 8772 /* 8773 * nfsm_mbufuio() advances to a multiple 8774 * of 4, so round up len2 as well. Then 8775 * we need to advance over the rest of 8776 * the data, rounding up the remaining 8777 * length. 8778 */ 8779 len2 = NFSM_RNDUP(len2); 8780 len2 = NFSM_RNDUP(len - len2); 8781 if (len2 > 0) 8782 error = nfsm_advance(nd, len2, 8783 -1); 8784 } 8785 } 8786 } else if (uiop == NULL && len > 0) { 8787 /* Just wants the length and not the data. */ 8788 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 8789 } else if (len > 0) 8790 error = ENOATTR; 8791 if (error != 0) 8792 goto nfsmout; 8793 *lenp = len; 8794 /* Just skip over Getattr op status. */ 8795 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8796 error = nfsm_loadattr(nd, nap); 8797 if (error == 0) 8798 *attrflagp = 1; 8799 } 8800 if (error == 0) 8801 error = nd->nd_repstat; 8802 nfsmout: 8803 m_freem(nd->nd_mrep); 8804 return (error); 8805 } 8806 8807 /* 8808 * The setextattr RPC. 8809 */ 8810 int 8811 nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop, 8812 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 8813 { 8814 uint32_t *tl; 8815 int error; 8816 struct nfsrv_descript nfsd; 8817 struct nfsrv_descript *nd = &nfsd; 8818 nfsattrbit_t attrbits; 8819 8820 *attrflagp = 0; 8821 NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp); 8822 if (uiop->uio_resid > nd->nd_maxreq) { 8823 /* nd_maxreq is set by NFSCL_REQSTART(). */ 8824 m_freem(nd->nd_mreq); 8825 return (EINVAL); 8826 } 8827 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8828 *tl = txdr_unsigned(NFSV4SXATTR_EITHER); 8829 nfsm_strtom(nd, name, strlen(name)); 8830 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8831 *tl = txdr_unsigned(uiop->uio_resid); 8832 nfsm_uiombuf(nd, uiop, uiop->uio_resid); 8833 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8834 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8835 NFSGETATTR_ATTRBIT(&attrbits); 8836 nfsrv_putattrbit(nd, &attrbits); 8837 error = nfscl_request(nd, vp, p, cred, NULL); 8838 if (error != 0) 8839 return (error); 8840 if (nd->nd_repstat == 0) { 8841 /* Just skip over the reply and Getattr op status. */ 8842 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 8843 NFSX_UNSIGNED); 8844 error = nfsm_loadattr(nd, nap); 8845 if (error == 0) 8846 *attrflagp = 1; 8847 } 8848 if (error == 0) 8849 error = nd->nd_repstat; 8850 nfsmout: 8851 m_freem(nd->nd_mrep); 8852 return (error); 8853 } 8854 8855 /* 8856 * The removeextattr RPC. 8857 */ 8858 int 8859 nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap, 8860 int *attrflagp, struct ucred *cred, NFSPROC_T *p) 8861 { 8862 uint32_t *tl; 8863 int error; 8864 struct nfsrv_descript nfsd; 8865 struct nfsrv_descript *nd = &nfsd; 8866 nfsattrbit_t attrbits; 8867 8868 *attrflagp = 0; 8869 NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp); 8870 nfsm_strtom(nd, name, strlen(name)); 8871 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8872 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8873 NFSGETATTR_ATTRBIT(&attrbits); 8874 nfsrv_putattrbit(nd, &attrbits); 8875 error = nfscl_request(nd, vp, p, cred, NULL); 8876 if (error != 0) 8877 return (error); 8878 if (nd->nd_repstat == 0) { 8879 /* Just skip over the reply and Getattr op status. */ 8880 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 8881 NFSX_UNSIGNED); 8882 error = nfsm_loadattr(nd, nap); 8883 if (error == 0) 8884 *attrflagp = 1; 8885 } 8886 if (error == 0) 8887 error = nd->nd_repstat; 8888 nfsmout: 8889 m_freem(nd->nd_mrep); 8890 return (error); 8891 } 8892 8893 /* 8894 * The listextattr RPC. 8895 */ 8896 int 8897 nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop, 8898 size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp, 8899 struct ucred *cred, NFSPROC_T *p) 8900 { 8901 uint32_t *tl; 8902 int cnt, error, i, len; 8903 struct nfsrv_descript nfsd; 8904 struct nfsrv_descript *nd = &nfsd; 8905 nfsattrbit_t attrbits; 8906 u_char c; 8907 8908 *attrflagp = 0; 8909 NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp); 8910 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 8911 txdr_hyper(*cookiep, tl); tl += 2; 8912 *tl++ = txdr_unsigned(*lenp); 8913 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8914 NFSGETATTR_ATTRBIT(&attrbits); 8915 nfsrv_putattrbit(nd, &attrbits); 8916 error = nfscl_request(nd, vp, p, cred, NULL); 8917 if (error != 0) 8918 return (error); 8919 *eofp = true; 8920 *lenp = 0; 8921 if (nd->nd_repstat == 0) { 8922 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 8923 *cookiep = fxdr_hyper(tl); tl += 2; 8924 cnt = fxdr_unsigned(int, *tl); 8925 if (cnt < 0) { 8926 error = EBADRPC; 8927 goto nfsmout; 8928 } 8929 for (i = 0; i < cnt; i++) { 8930 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8931 len = fxdr_unsigned(int, *tl); 8932 if (len <= 0 || len > EXTATTR_MAXNAMELEN) { 8933 error = EBADRPC; 8934 goto nfsmout; 8935 } 8936 if (uiop == NULL) 8937 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 8938 else if (uiop->uio_resid >= len + 1) { 8939 c = len; 8940 error = uiomove(&c, sizeof(c), uiop); 8941 if (error == 0) 8942 error = nfsm_mbufuio(nd, uiop, len); 8943 } else { 8944 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 8945 *eofp = false; 8946 } 8947 if (error != 0) 8948 goto nfsmout; 8949 *lenp += (len + 1); 8950 } 8951 /* Get the eof and skip over the Getattr op status. */ 8952 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); 8953 /* 8954 * *eofp is set false above, because it wasn't able to copy 8955 * all of the reply. 8956 */ 8957 if (*eofp && *tl == 0) 8958 *eofp = false; 8959 error = nfsm_loadattr(nd, nap); 8960 if (error == 0) 8961 *attrflagp = 1; 8962 } 8963 if (error == 0) 8964 error = nd->nd_repstat; 8965 nfsmout: 8966 m_freem(nd->nd_mrep); 8967 return (error); 8968 } 8969 8970 /* 8971 * Split an mbuf list. For non-M_EXTPG mbufs, just use m_split(). 8972 */ 8973 static struct mbuf * 8974 nfsm_split(struct mbuf *mp, uint64_t xfer) 8975 { 8976 struct mbuf *m, *m2; 8977 vm_page_t pg; 8978 int i, j, left, pgno, plen, trim; 8979 char *cp, *cp2; 8980 8981 if ((mp->m_flags & M_EXTPG) == 0) { 8982 m = m_split(mp, xfer, M_WAITOK); 8983 return (m); 8984 } 8985 8986 /* Find the correct mbuf to split at. */ 8987 for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next) 8988 xfer -= m->m_len; 8989 if (m == NULL) 8990 return (NULL); 8991 8992 /* If xfer == m->m_len, we can just split the mbuf list. */ 8993 if (xfer == m->m_len) { 8994 m2 = m->m_next; 8995 m->m_next = NULL; 8996 return (m2); 8997 } 8998 8999 /* Find the page to split at. */ 9000 pgno = 0; 9001 left = xfer; 9002 do { 9003 if (pgno == 0) 9004 plen = m_epg_pagelen(m, 0, m->m_epg_1st_off); 9005 else 9006 plen = m_epg_pagelen(m, pgno, 0); 9007 if (left <= plen) 9008 break; 9009 left -= plen; 9010 pgno++; 9011 } while (pgno < m->m_epg_npgs); 9012 if (pgno == m->m_epg_npgs) 9013 panic("nfsm_split: eroneous ext_pgs mbuf"); 9014 9015 m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs); 9016 m2->m_epg_flags |= EPG_FLAG_ANON; 9017 9018 /* 9019 * If left < plen, allocate a new page for the new mbuf 9020 * and copy the data after left in the page to this new 9021 * page. 9022 */ 9023 if (left < plen) { 9024 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP | 9025 VM_ALLOC_WIRED); 9026 m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg); 9027 m2->m_epg_npgs = 1; 9028 9029 /* Copy the data after left to the new page. */ 9030 trim = plen - left; 9031 cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); 9032 if (pgno == 0) 9033 cp += m->m_epg_1st_off; 9034 cp += left; 9035 cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]); 9036 if (pgno == m->m_epg_npgs - 1) 9037 m2->m_epg_last_len = trim; 9038 else { 9039 cp2 += PAGE_SIZE - trim; 9040 m2->m_epg_1st_off = PAGE_SIZE - trim; 9041 m2->m_epg_last_len = m->m_epg_last_len; 9042 } 9043 memcpy(cp2, cp, trim); 9044 m2->m_len = trim; 9045 } else { 9046 m2->m_len = 0; 9047 m2->m_epg_last_len = m->m_epg_last_len; 9048 } 9049 9050 /* Move the pages beyond pgno to the new mbuf. */ 9051 for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) { 9052 m2->m_epg_pa[j] = m->m_epg_pa[i]; 9053 /* Never moves page 0. */ 9054 m2->m_len += m_epg_pagelen(m, i, 0); 9055 } 9056 m2->m_epg_npgs = j; 9057 m->m_epg_npgs = pgno + 1; 9058 m->m_epg_last_len = left; 9059 m->m_len = xfer; 9060 9061 m2->m_next = m->m_next; 9062 m->m_next = NULL; 9063 return (m2); 9064 } 9065 9066 /* 9067 * Do the NFSv4.1 Bind Connection to Session. 9068 * Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c). 9069 */ 9070 void 9071 nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr) 9072 { 9073 struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg; 9074 uint32_t res, *tl; 9075 struct nfsrv_descript nfsd; 9076 struct nfsrv_descript *nd = &nfsd; 9077 struct rpc_callextra ext; 9078 struct timeval utimeout; 9079 enum clnt_stat stat; 9080 int error; 9081 9082 nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL, 9083 NFS_VER4, rcp->minorvers); 9084 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 9085 memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID); 9086 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9087 *tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH); 9088 *tl = newnfs_false; 9089 9090 memset(&ext, 0, sizeof(ext)); 9091 utimeout.tv_sec = 30; 9092 utimeout.tv_usec = 0; 9093 ext.rc_auth = authunix_create(cr); 9094 nd->nd_mrep = NULL; 9095 stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq, 9096 &nd->nd_mrep, utimeout); 9097 AUTH_DESTROY(ext.rc_auth); 9098 if (stat != RPC_SUCCESS) { 9099 printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat); 9100 return; 9101 } 9102 if (nd->nd_mrep == NULL) { 9103 printf("nfsrpc_bindconnsess: no reply args\n"); 9104 return; 9105 } 9106 error = 0; 9107 newnfs_realign(&nd->nd_mrep, M_WAITOK); 9108 nd->nd_md = nd->nd_mrep; 9109 nd->nd_dpos = mtod(nd->nd_md, char *); 9110 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9111 nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++); 9112 if (nd->nd_repstat == NFSERR_OK) { 9113 res = fxdr_unsigned(uint32_t, *tl); 9114 if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res), 9115 -1)) != 0) 9116 goto nfsmout; 9117 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 9118 4 * NFSX_UNSIGNED); 9119 tl += 3; 9120 if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) { 9121 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9122 res = fxdr_unsigned(uint32_t, *tl); 9123 if (res != NFSCDFS4_BOTH) 9124 printf("nfsrpc_bindconnsess: did not " 9125 "return FS4_BOTH\n"); 9126 } else 9127 printf("nfsrpc_bindconnsess: not same " 9128 "sessionid\n"); 9129 } else if (nd->nd_repstat != NFSERR_BADSESSION) 9130 printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat); 9131 nfsmout: 9132 if (error != 0) 9133 printf("nfsrpc_bindconnsess: reply bad xdr\n"); 9134 m_freem(nd->nd_mrep); 9135 } 9136