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