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