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