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