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