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