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