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 error = nfsm_uiombuf(nd, uiop, len); 2108 if (error != 0) { 2109 m_freem(nd->nd_mreq); 2110 free(nd, M_TEMP); 2111 return (error); 2112 } 2113 /* 2114 * Although it is tempting to do a normal Getattr Op in the 2115 * NFSv4 compound, the result can be a nearly hung client 2116 * system if the Getattr asks for Owner and/or OwnerGroup. 2117 * It occurs when the client can't map either the Owner or 2118 * Owner_group name in the Getattr reply to a uid/gid. When 2119 * there is a cache miss, the kernel does an upcall to the 2120 * nfsuserd. Then, it can try and read the local /etc/passwd 2121 * or /etc/group file. It can then block in getnewbuf(), 2122 * waiting for dirty writes to be pushed to the NFS server. 2123 * The only reason this doesn't result in a complete 2124 * deadlock, is that the upcall times out and allows 2125 * the write to complete. However, progress is so slow 2126 * that it might just as well be deadlocked. 2127 * As such, we get the rest of the attributes, but not 2128 * Owner or Owner_group. 2129 * nb: nfscl_loadattrcache() needs to be told that these 2130 * partial attributes from a write rpc are being 2131 * passed in, via a argument flag. 2132 */ 2133 if (nd->nd_flag & ND_NFSV4) { 2134 NFSWRITEGETATTR_ATTRBIT(&attrbits); 2135 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2136 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2137 (void) nfsrv_putattrbit(nd, &attrbits); 2138 } 2139 error = nfscl_request(nd, vp, p, cred); 2140 if (error) { 2141 free(nd, M_TEMP); 2142 return (error); 2143 } 2144 if (nd->nd_repstat) { 2145 /* 2146 * In case the rpc gets retried, roll 2147 * the uio fields changed by nfsm_uiombuf() 2148 * back. 2149 */ 2150 uiop->uio_offset -= len; 2151 uiop->uio_resid += len; 2152 uiop->uio_iov->iov_base = 2153 (char *)uiop->uio_iov->iov_base - len; 2154 uiop->uio_iov->iov_len += len; 2155 } 2156 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2157 error = nfscl_wcc_data(nd, vp, nap, attrflagp, 2158 &wccflag, &tmp_off); 2159 if (error) 2160 goto nfsmout; 2161 } 2162 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2163 (ND_NFSV4 | ND_NOMOREDATA) && 2164 nd->nd_repstat == NFSERR_NOTSAME && do_append) { 2165 /* 2166 * Verify of the file's size failed, so redo the 2167 * write using the file's size as returned in 2168 * the wcc attributes. 2169 */ 2170 if (tmp_off + tsiz <= nmp->nm_maxfilesize) { 2171 do_append = false; 2172 uiop->uio_offset = tmp_off; 2173 m_freem(nd->nd_mrep); 2174 nd->nd_mrep = NULL; 2175 continue; 2176 } else 2177 nd->nd_repstat = EFBIG; 2178 } 2179 if (!nd->nd_repstat) { 2180 if (do_append) { 2181 /* Strip off the Write reply status. */ 2182 do_append = false; 2183 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 2184 } 2185 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2186 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED 2187 + NFSX_VERF); 2188 rlen = fxdr_unsigned(int, *tl++); 2189 if (rlen == 0) { 2190 error = NFSERR_IO; 2191 goto nfsmout; 2192 } else if (rlen < len) { 2193 backup = len - rlen; 2194 uiop->uio_iov->iov_base = 2195 (char *)uiop->uio_iov->iov_base - 2196 backup; 2197 uiop->uio_iov->iov_len += backup; 2198 uiop->uio_offset -= backup; 2199 uiop->uio_resid += backup; 2200 len = rlen; 2201 } 2202 commit = fxdr_unsigned(int, *tl++); 2203 2204 /* 2205 * Return the lowest commitment level 2206 * obtained by any of the RPCs. 2207 */ 2208 if (committed == NFSWRITE_FILESYNC) 2209 committed = commit; 2210 else if (committed == NFSWRITE_DATASYNC && 2211 commit == NFSWRITE_UNSTABLE) 2212 committed = commit; 2213 NFSLOCKMNT(nmp); 2214 if (!NFSHASWRITEVERF(nmp)) { 2215 NFSBCOPY((caddr_t)tl, 2216 (caddr_t)&nmp->nm_verf[0], 2217 NFSX_VERF); 2218 NFSSETWRITEVERF(nmp); 2219 } else if (NFSBCMP(tl, nmp->nm_verf, 2220 NFSX_VERF) && *must_commit != 2) { 2221 *must_commit = 1; 2222 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 2223 } 2224 NFSUNLOCKMNT(nmp); 2225 } 2226 if (nd->nd_flag & ND_NFSV4) 2227 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2228 if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) { 2229 error = nfsm_loadattr(nd, nap); 2230 if (!error) 2231 *attrflagp = NFS_LATTR_NOSHRINK; 2232 } 2233 } else { 2234 error = nd->nd_repstat; 2235 } 2236 if (error) 2237 goto nfsmout; 2238 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4)); 2239 m_freem(nd->nd_mrep); 2240 nd->nd_mrep = NULL; 2241 tsiz -= len; 2242 } 2243 nfsmout: 2244 if (nd->nd_mrep != NULL) 2245 m_freem(nd->nd_mrep); 2246 *iomode = committed; 2247 if (nd->nd_repstat && !error) 2248 error = nd->nd_repstat; 2249 free(nd, M_TEMP); 2250 return (error); 2251 } 2252 2253 /* 2254 * Do an nfs deallocate operation. 2255 */ 2256 int 2257 nfsrpc_deallocate(vnode_t vp, off_t offs, off_t len, struct nfsvattr *nap, 2258 int *attrflagp, struct ucred *cred, NFSPROC_T *p) 2259 { 2260 int error, expireret = 0, openerr, retrycnt; 2261 uint32_t clidrev = 0; 2262 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 2263 struct nfsfh *nfhp; 2264 nfsv4stateid_t stateid; 2265 void *lckp; 2266 2267 if (nmp->nm_clp != NULL) 2268 clidrev = nmp->nm_clp->nfsc_clientidrev; 2269 retrycnt = 0; 2270 do { 2271 lckp = NULL; 2272 openerr = 1; 2273 nfhp = VTONFS(vp)->n_fhp; 2274 error = nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 2275 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); 2276 if (error != 0) { 2277 /* 2278 * No Open stateid, so try and open the file 2279 * now. 2280 */ 2281 openerr = nfsrpc_open(vp, FWRITE, cred, p); 2282 if (openerr == 0) 2283 nfscl_getstateid(vp, nfhp->nfh_fh, 2284 nfhp->nfh_len, NFSV4OPEN_ACCESSWRITE, 0, 2285 cred, p, &stateid, &lckp); 2286 } 2287 error = nfsrpc_deallocaterpc(vp, offs, len, &stateid, nap, 2288 attrflagp, cred, p); 2289 if (error == NFSERR_STALESTATEID) 2290 nfscl_initiate_recovery(nmp->nm_clp); 2291 if (lckp != NULL) 2292 nfscl_lockderef(lckp); 2293 if (openerr == 0) 2294 nfsrpc_close(vp, 0, p); 2295 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 2296 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2297 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 2298 (void) nfs_catnap(PZERO, error, "nfs_deallocate"); 2299 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && 2300 error == NFSERR_BADSTATEID)) && clidrev != 0) { 2301 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 2302 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { 2303 error = EIO; 2304 } 2305 retrycnt++; 2306 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 2307 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2308 error == NFSERR_BADSESSION || 2309 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 2310 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 2311 expireret == 0 && clidrev != 0 && retrycnt < 4)); 2312 if (error && retrycnt >= 4) 2313 error = EIO; 2314 return (error); 2315 } 2316 2317 /* 2318 * The actual deallocate RPC. 2319 */ 2320 static int 2321 nfsrpc_deallocaterpc(vnode_t vp, off_t offs, off_t len, 2322 nfsv4stateid_t *stateidp, struct nfsvattr *nap, int *attrflagp, 2323 struct ucred *cred, NFSPROC_T *p) 2324 { 2325 uint32_t *tl; 2326 struct nfsnode *np = VTONFS(vp); 2327 int error, wccflag; 2328 struct nfsrv_descript nfsd; 2329 struct nfsrv_descript *nd = &nfsd; 2330 nfsattrbit_t attrbits; 2331 2332 *attrflagp = 0; 2333 NFSCL_REQSTART(nd, NFSPROC_DEALLOCATE, vp, cred); 2334 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 2335 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER); 2336 txdr_hyper(offs, tl); 2337 tl += 2; 2338 txdr_hyper(len, tl); 2339 NFSWRITEGETATTR_ATTRBIT(&attrbits); 2340 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 2341 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2342 nfsrv_putattrbit(nd, &attrbits); 2343 error = nfscl_request(nd, vp, p, cred); 2344 if (error != 0) 2345 return (error); 2346 wccflag = 0; 2347 error = nfscl_wcc_data(nd, vp, nap, attrflagp, &wccflag, NULL); 2348 if (error != 0) 2349 goto nfsmout; 2350 if (nd->nd_repstat == 0) { 2351 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 2352 error = nfsm_loadattr(nd, nap); 2353 if (error != 0) 2354 goto nfsmout; 2355 *attrflagp = NFS_LATTR_NOSHRINK; 2356 } 2357 NFSWRITERPC_SETTIME(wccflag, np, nap, 1); 2358 nfsmout: 2359 m_freem(nd->nd_mrep); 2360 if (nd->nd_repstat != 0 && error == 0) 2361 error = nd->nd_repstat; 2362 return (error); 2363 } 2364 2365 /* 2366 * nfs mknod rpc 2367 * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the 2368 * mode set to specify the file type and the size field for rdev. 2369 */ 2370 int 2371 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2372 u_int32_t rdev, __enum_uint8(vtype) vtyp, struct ucred *cred, NFSPROC_T *p, 2373 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 2374 int *attrflagp, int *dattrflagp) 2375 { 2376 u_int32_t *tl; 2377 int error = 0; 2378 struct nfsrv_descript nfsd, *nd = &nfsd; 2379 nfsattrbit_t attrbits; 2380 2381 *nfhpp = NULL; 2382 *attrflagp = 0; 2383 *dattrflagp = 0; 2384 if (namelen > NFS_MAXNAMLEN) 2385 return (ENAMETOOLONG); 2386 NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp, cred); 2387 if (nd->nd_flag & ND_NFSV4) { 2388 if (vtyp == VBLK || vtyp == VCHR) { 2389 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 2390 *tl++ = vtonfsv34_type(vtyp); 2391 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 2392 *tl = txdr_unsigned(NFSMINOR(rdev)); 2393 } else { 2394 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2395 *tl = vtonfsv34_type(vtyp); 2396 } 2397 } 2398 (void) nfsm_strtom(nd, name, namelen); 2399 if (nd->nd_flag & ND_NFSV3) { 2400 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2401 *tl = vtonfsv34_type(vtyp); 2402 } 2403 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 2404 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2405 if ((nd->nd_flag & ND_NFSV3) && 2406 (vtyp == VCHR || vtyp == VBLK)) { 2407 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2408 *tl++ = txdr_unsigned(NFSMAJOR(rdev)); 2409 *tl = txdr_unsigned(NFSMINOR(rdev)); 2410 } 2411 if (nd->nd_flag & ND_NFSV4) { 2412 NFSGETATTR_ATTRBIT(&attrbits); 2413 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2414 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2415 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2416 (void) nfsrv_putattrbit(nd, &attrbits); 2417 } 2418 if (nd->nd_flag & ND_NFSV2) 2419 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev); 2420 error = nfscl_request(nd, dvp, p, cred); 2421 if (error) 2422 return (error); 2423 if (nd->nd_flag & ND_NFSV4) 2424 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 2425 if (!nd->nd_repstat) { 2426 if (nd->nd_flag & ND_NFSV4) { 2427 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2428 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2429 if (error) 2430 goto nfsmout; 2431 } 2432 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2433 if (error) 2434 goto nfsmout; 2435 } 2436 if (nd->nd_flag & ND_NFSV3) 2437 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 2438 if (!error && nd->nd_repstat) 2439 error = nd->nd_repstat; 2440 nfsmout: 2441 m_freem(nd->nd_mrep); 2442 return (error); 2443 } 2444 2445 /* 2446 * nfs file create call 2447 * Mostly just call the approriate routine. (I separated out v4, so that 2448 * error recovery wouldn't be as difficult.) 2449 */ 2450 int 2451 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2452 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 2453 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 2454 int *attrflagp, int *dattrflagp) 2455 { 2456 int error = 0, newone, expireret = 0, retrycnt, unlocked; 2457 struct nfsclowner *owp; 2458 struct nfscldeleg *dp; 2459 struct nfsmount *nmp = VFSTONFS(dvp->v_mount); 2460 u_int32_t clidrev; 2461 2462 if (NFSHASNFSV4(nmp)) { 2463 retrycnt = 0; 2464 do { 2465 dp = NULL; 2466 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE | 2467 NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone, 2468 NULL, 1, true); 2469 if (error) 2470 return (error); 2471 if (nmp->nm_clp != NULL) 2472 clidrev = nmp->nm_clp->nfsc_clientidrev; 2473 else 2474 clidrev = 0; 2475 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || 2476 nfs_numnfscbd == 0 || retrycnt > 0) 2477 error = nfsrpc_createv4(dvp, name, namelen, vap, cverf, 2478 fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 2479 attrflagp, dattrflagp, &unlocked); 2480 else 2481 error = nfsrpc_getcreatelayout(dvp, name, namelen, vap, 2482 cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp, 2483 attrflagp, dattrflagp, &unlocked); 2484 /* 2485 * There is no need to invalidate cached attributes here, 2486 * since new post-delegation issue attributes are always 2487 * returned by nfsrpc_createv4() and these will update the 2488 * attribute cache. 2489 */ 2490 if (dp != NULL) 2491 (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp, 2492 (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp); 2493 nfscl_ownerrelease(nmp, owp, error, newone, unlocked); 2494 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 2495 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2496 error == NFSERR_BADSESSION) { 2497 (void) nfs_catnap(PZERO, error, "nfs_open"); 2498 } else if ((error == NFSERR_EXPIRED || 2499 error == NFSERR_BADSTATEID) && clidrev != 0) { 2500 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 2501 retrycnt++; 2502 } 2503 } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID || 2504 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 2505 error == NFSERR_BADSESSION || 2506 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 2507 expireret == 0 && clidrev != 0 && retrycnt < 4)); 2508 if (error && retrycnt >= 4) 2509 error = EIO; 2510 } else { 2511 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf, 2512 fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp); 2513 } 2514 return (error); 2515 } 2516 2517 /* 2518 * The create rpc for v2 and 3. 2519 */ 2520 static int 2521 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2522 nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p, 2523 struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp, 2524 int *attrflagp, int *dattrflagp) 2525 { 2526 u_int32_t *tl; 2527 int error = 0; 2528 struct nfsrv_descript nfsd, *nd = &nfsd; 2529 2530 *nfhpp = NULL; 2531 *attrflagp = 0; 2532 *dattrflagp = 0; 2533 if (namelen > NFS_MAXNAMLEN) 2534 return (ENAMETOOLONG); 2535 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred); 2536 (void) nfsm_strtom(nd, name, namelen); 2537 if (nd->nd_flag & ND_NFSV3) { 2538 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2539 if (fmode & O_EXCL) { 2540 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2541 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2542 *tl++ = cverf.lval[0]; 2543 *tl = cverf.lval[1]; 2544 } else { 2545 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2546 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2547 } 2548 } else { 2549 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0); 2550 } 2551 error = nfscl_request(nd, dvp, p, cred); 2552 if (error) 2553 return (error); 2554 if (nd->nd_repstat == 0) { 2555 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2556 if (error) 2557 goto nfsmout; 2558 } 2559 if (nd->nd_flag & ND_NFSV3) 2560 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 2561 if (nd->nd_repstat != 0 && error == 0) 2562 error = nd->nd_repstat; 2563 nfsmout: 2564 m_freem(nd->nd_mrep); 2565 return (error); 2566 } 2567 2568 static int 2569 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap, 2570 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 2571 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 2572 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 2573 int *dattrflagp, int *unlockedp) 2574 { 2575 u_int32_t *tl; 2576 int error = 0, deleg, newone, ret, acesize, limitby; 2577 struct nfsrv_descript nfsd, *nd = &nfsd; 2578 struct nfsclopen *op; 2579 struct nfscldeleg *dp = NULL; 2580 struct nfsnode *np; 2581 struct nfsfh *nfhp; 2582 nfsattrbit_t attrbits; 2583 nfsv4stateid_t stateid; 2584 u_int32_t rflags; 2585 struct nfsmount *nmp; 2586 struct nfsclsession *tsep; 2587 2588 nmp = VFSTONFS(dvp->v_mount); 2589 np = VTONFS(dvp); 2590 *unlockedp = 0; 2591 *nfhpp = NULL; 2592 *dpp = NULL; 2593 *attrflagp = 0; 2594 *dattrflagp = 0; 2595 if (namelen > NFS_MAXNAMLEN) 2596 return (ENAMETOOLONG); 2597 NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp, cred); 2598 /* 2599 * For V4, this is actually an Open op. 2600 */ 2601 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 2602 *tl++ = txdr_unsigned(owp->nfsow_seqid); 2603 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 2604 NFSV4OPEN_ACCESSREAD); 2605 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 2606 tsep = nfsmnt_mdssession(nmp); 2607 *tl++ = tsep->nfsess_clientid.lval[0]; 2608 *tl = tsep->nfsess_clientid.lval[1]; 2609 (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 2610 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2611 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 2612 if (fmode & O_EXCL) { 2613 if (NFSHASNFSV4N(nmp)) { 2614 if (NFSHASSESSPERSIST(nmp)) { 2615 /* Use GUARDED for persistent sessions. */ 2616 *tl = txdr_unsigned(NFSCREATE_GUARDED); 2617 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2618 } else { 2619 /* Otherwise, use EXCLUSIVE4_1. */ 2620 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 2621 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2622 *tl++ = cverf.lval[0]; 2623 *tl = cverf.lval[1]; 2624 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2625 } 2626 } else { 2627 /* NFSv4.0 */ 2628 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2629 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2630 *tl++ = cverf.lval[0]; 2631 *tl = cverf.lval[1]; 2632 } 2633 } else { 2634 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2635 nfscl_fillsattr(nd, vap, dvp, 0, 0); 2636 } 2637 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2638 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 2639 (void) nfsm_strtom(nd, name, namelen); 2640 /* Get the new file's handle and attributes. */ 2641 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2642 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2643 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2644 NFSGETATTR_ATTRBIT(&attrbits); 2645 (void) nfsrv_putattrbit(nd, &attrbits); 2646 /* Get the directory's post-op attributes. */ 2647 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2648 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2649 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 2650 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2651 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2652 (void) nfsrv_putattrbit(nd, &attrbits); 2653 error = nfscl_request(nd, dvp, p, cred); 2654 if (error) 2655 return (error); 2656 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 2657 if (nd->nd_repstat == 0) { 2658 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2659 6 * NFSX_UNSIGNED); 2660 stateid.seqid = *tl++; 2661 stateid.other[0] = *tl++; 2662 stateid.other[1] = *tl++; 2663 stateid.other[2] = *tl; 2664 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 2665 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2666 if (error) 2667 goto nfsmout; 2668 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2669 deleg = fxdr_unsigned(int, *tl); 2670 if (deleg == NFSV4OPEN_DELEGATEREAD || 2671 deleg == NFSV4OPEN_DELEGATEWRITE) { 2672 if (!(owp->nfsow_clp->nfsc_flags & 2673 NFSCLFLAGS_FIRSTDELEG)) 2674 owp->nfsow_clp->nfsc_flags |= 2675 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 2676 dp = malloc( 2677 sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 2678 M_NFSCLDELEG, M_WAITOK); 2679 LIST_INIT(&dp->nfsdl_owner); 2680 LIST_INIT(&dp->nfsdl_lock); 2681 dp->nfsdl_clp = owp->nfsow_clp; 2682 newnfs_copyincred(cred, &dp->nfsdl_cred); 2683 nfscl_lockinit(&dp->nfsdl_rwlock); 2684 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2685 NFSX_UNSIGNED); 2686 dp->nfsdl_stateid.seqid = *tl++; 2687 dp->nfsdl_stateid.other[0] = *tl++; 2688 dp->nfsdl_stateid.other[1] = *tl++; 2689 dp->nfsdl_stateid.other[2] = *tl++; 2690 ret = fxdr_unsigned(int, *tl); 2691 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 2692 dp->nfsdl_flags = NFSCLDL_WRITE; 2693 /* 2694 * Indicates how much the file can grow. 2695 */ 2696 NFSM_DISSECT(tl, u_int32_t *, 2697 3 * NFSX_UNSIGNED); 2698 limitby = fxdr_unsigned(int, *tl++); 2699 switch (limitby) { 2700 case NFSV4OPEN_LIMITSIZE: 2701 dp->nfsdl_sizelimit = fxdr_hyper(tl); 2702 break; 2703 case NFSV4OPEN_LIMITBLOCKS: 2704 dp->nfsdl_sizelimit = 2705 fxdr_unsigned(u_int64_t, *tl++); 2706 dp->nfsdl_sizelimit *= 2707 fxdr_unsigned(u_int64_t, *tl); 2708 break; 2709 default: 2710 error = NFSERR_BADXDR; 2711 goto nfsmout; 2712 } 2713 } else { 2714 dp->nfsdl_flags = NFSCLDL_READ; 2715 } 2716 if (ret) 2717 dp->nfsdl_flags |= NFSCLDL_RECALL; 2718 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false, 2719 &ret, &acesize, p); 2720 if (error) 2721 goto nfsmout; 2722 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 2723 error = NFSERR_BADXDR; 2724 goto nfsmout; 2725 } 2726 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2727 if (error) 2728 goto nfsmout; 2729 /* Get rid of the PutFH and Getattr status values. */ 2730 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2731 /* Load the directory attributes. */ 2732 error = nfsm_loadattr(nd, dnap); 2733 if (error) 2734 goto nfsmout; 2735 *dattrflagp = 1; 2736 if (dp != NULL && *attrflagp) { 2737 dp->nfsdl_change = nnap->na_filerev; 2738 dp->nfsdl_modtime = nnap->na_mtime; 2739 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 2740 } 2741 /* 2742 * We can now complete the Open state. 2743 */ 2744 nfhp = *nfhpp; 2745 if (dp != NULL) { 2746 dp->nfsdl_fhlen = nfhp->nfh_len; 2747 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 2748 } 2749 /* 2750 * Get an Open structure that will be 2751 * attached to the OpenOwner, acquired already. 2752 */ 2753 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 2754 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 2755 cred, p, NULL, &op, &newone, NULL, 0, false); 2756 if (error) 2757 goto nfsmout; 2758 op->nfso_stateid = stateid; 2759 newnfs_copyincred(cred, &op->nfso_cred); 2760 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 2761 do { 2762 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 2763 nfhp->nfh_len, op, cred, p); 2764 if (ret == NFSERR_DELAY) 2765 (void) nfs_catnap(PZERO, ret, "nfs_create"); 2766 } while (ret == NFSERR_DELAY); 2767 error = ret; 2768 } 2769 2770 /* 2771 * If the server is handing out delegations, but we didn't 2772 * get one because an OpenConfirm was required, try the 2773 * Open again, to get a delegation. This is a harmless no-op, 2774 * from a server's point of view. 2775 */ 2776 if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 2777 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 2778 !error && dp == NULL) { 2779 KASSERT(!NFSHASNFSV4N(nmp), 2780 ("nfsrpc_createv4: result confirm")); 2781 do { 2782 ret = nfsrpc_openrpc(VFSTONFS(dvp->v_mount), dvp, 2783 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 2784 nfhp->nfh_fh, nfhp->nfh_len, 2785 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2786 name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2787 if (ret == NFSERR_DELAY) 2788 (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2789 } while (ret == NFSERR_DELAY); 2790 if (ret) { 2791 if (dp != NULL) { 2792 free(dp, M_NFSCLDELEG); 2793 dp = NULL; 2794 } 2795 if (ret == NFSERR_STALECLIENTID || 2796 ret == NFSERR_STALEDONTRECOVER || 2797 ret == NFSERR_BADSESSION) 2798 error = ret; 2799 } 2800 } 2801 nfscl_openrelease(nmp, op, error, newone); 2802 *unlockedp = 1; 2803 } 2804 if (nd->nd_repstat != 0 && error == 0) 2805 error = nd->nd_repstat; 2806 if (error == NFSERR_STALECLIENTID) 2807 nfscl_initiate_recovery(owp->nfsow_clp); 2808 nfsmout: 2809 if (!error) 2810 *dpp = dp; 2811 else if (dp != NULL) 2812 free(dp, M_NFSCLDELEG); 2813 m_freem(nd->nd_mrep); 2814 return (error); 2815 } 2816 2817 /* 2818 * Nfs remove rpc 2819 */ 2820 int 2821 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2822 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp) 2823 { 2824 u_int32_t *tl; 2825 struct nfsrv_descript nfsd, *nd = &nfsd; 2826 struct nfsnode *np; 2827 struct nfsmount *nmp; 2828 nfsv4stateid_t dstateid; 2829 int error, ret = 0, i; 2830 2831 *dattrflagp = 0; 2832 if (namelen > NFS_MAXNAMLEN) 2833 return (ENAMETOOLONG); 2834 nmp = VFSTONFS(dvp->v_mount); 2835 tryagain: 2836 if (NFSHASNFSV4(nmp) && ret == 0) { 2837 ret = nfscl_removedeleg(vp, p, &dstateid); 2838 if (ret == 1) { 2839 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp, cred); 2840 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2841 NFSX_UNSIGNED); 2842 if (NFSHASNFSV4N(nmp)) 2843 *tl++ = 0; 2844 else 2845 *tl++ = dstateid.seqid; 2846 *tl++ = dstateid.other[0]; 2847 *tl++ = dstateid.other[1]; 2848 *tl++ = dstateid.other[2]; 2849 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2850 np = VTONFS(dvp); 2851 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, 2852 np->n_fhp->nfh_len, 0); 2853 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2854 *tl = txdr_unsigned(NFSV4OP_REMOVE); 2855 } 2856 } else { 2857 ret = 0; 2858 } 2859 if (ret == 0) 2860 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp, cred); 2861 (void) nfsm_strtom(nd, name, namelen); 2862 error = nfscl_request(nd, dvp, p, cred); 2863 if (error) 2864 return (error); 2865 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2866 /* For NFSv4, parse out any Delereturn replies. */ 2867 if (ret > 0 && nd->nd_repstat != 0 && 2868 (nd->nd_flag & ND_NOMOREDATA)) { 2869 /* 2870 * If the Delegreturn failed, try again without 2871 * it. The server will Recall, as required. 2872 */ 2873 m_freem(nd->nd_mrep); 2874 goto tryagain; 2875 } 2876 for (i = 0; i < (ret * 2); i++) { 2877 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2878 ND_NFSV4) { 2879 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2880 if (*(tl + 1)) 2881 nd->nd_flag |= ND_NOMOREDATA; 2882 } 2883 } 2884 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 2885 } 2886 if (nd->nd_repstat && !error) 2887 error = nd->nd_repstat; 2888 nfsmout: 2889 m_freem(nd->nd_mrep); 2890 return (error); 2891 } 2892 2893 /* 2894 * Do an nfs rename rpc. 2895 */ 2896 int 2897 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2898 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2899 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2900 int *fattrflagp, int *tattrflagp) 2901 { 2902 u_int32_t *tl; 2903 struct nfsrv_descript nfsd, *nd = &nfsd; 2904 struct nfsmount *nmp; 2905 struct nfsnode *np; 2906 nfsattrbit_t attrbits; 2907 nfsv4stateid_t fdstateid, tdstateid; 2908 int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2909 2910 *fattrflagp = 0; 2911 *tattrflagp = 0; 2912 nmp = VFSTONFS(fdvp->v_mount); 2913 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2914 return (ENAMETOOLONG); 2915 tryagain: 2916 if (NFSHASNFSV4(nmp) && ret == 0) { 2917 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2918 &tdstateid, &gottd, p); 2919 if (gotfd && gottd) { 2920 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp, cred); 2921 } else if (gotfd) { 2922 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp, cred); 2923 } else if (gottd) { 2924 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp, cred); 2925 } 2926 if (gotfd) { 2927 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2928 if (NFSHASNFSV4N(nmp)) 2929 *tl++ = 0; 2930 else 2931 *tl++ = fdstateid.seqid; 2932 *tl++ = fdstateid.other[0]; 2933 *tl++ = fdstateid.other[1]; 2934 *tl = fdstateid.other[2]; 2935 if (gottd) { 2936 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2937 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2938 np = VTONFS(tvp); 2939 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, 2940 np->n_fhp->nfh_len, 0); 2941 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2942 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2943 } 2944 } 2945 if (gottd) { 2946 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2947 if (NFSHASNFSV4N(nmp)) 2948 *tl++ = 0; 2949 else 2950 *tl++ = tdstateid.seqid; 2951 *tl++ = tdstateid.other[0]; 2952 *tl++ = tdstateid.other[1]; 2953 *tl = tdstateid.other[2]; 2954 } 2955 if (ret > 0) { 2956 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2957 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2958 np = VTONFS(fdvp); 2959 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, 2960 np->n_fhp->nfh_len, 0); 2961 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2962 *tl = txdr_unsigned(NFSV4OP_SAVEFH); 2963 } 2964 } else { 2965 ret = 0; 2966 } 2967 if (ret == 0) 2968 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp, cred); 2969 if (nd->nd_flag & ND_NFSV4) { 2970 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2971 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2972 NFSWCCATTR_ATTRBIT(&attrbits); 2973 (void) nfsrv_putattrbit(nd, &attrbits); 2974 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2975 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2976 (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2977 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2978 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2979 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2980 (void) nfsrv_putattrbit(nd, &attrbits); 2981 nd->nd_flag |= ND_V4WCCATTR; 2982 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2983 *tl = txdr_unsigned(NFSV4OP_RENAME); 2984 } 2985 (void) nfsm_strtom(nd, fnameptr, fnamelen); 2986 if (!(nd->nd_flag & ND_NFSV4)) 2987 (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, 2988 VTONFS(tdvp)->n_fhp->nfh_len, 0); 2989 (void) nfsm_strtom(nd, tnameptr, tnamelen); 2990 error = nfscl_request(nd, fdvp, p, cred); 2991 if (error) 2992 return (error); 2993 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2994 /* For NFSv4, parse out any Delereturn replies. */ 2995 if (ret > 0 && nd->nd_repstat != 0 && 2996 (nd->nd_flag & ND_NOMOREDATA)) { 2997 /* 2998 * If the Delegreturn failed, try again without 2999 * it. The server will Recall, as required. 3000 */ 3001 m_freem(nd->nd_mrep); 3002 goto tryagain; 3003 } 3004 for (i = 0; i < (ret * 2); i++) { 3005 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 3006 ND_NFSV4) { 3007 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3008 if (*(tl + 1)) { 3009 if (i == 1 && ret > 1) { 3010 /* 3011 * If the Delegreturn failed, try again 3012 * without it. The server will Recall, as 3013 * required. 3014 * If ret > 1, the second iteration of this 3015 * loop is the second DelegReturn result. 3016 */ 3017 m_freem(nd->nd_mrep); 3018 goto tryagain; 3019 } else { 3020 nd->nd_flag |= ND_NOMOREDATA; 3021 } 3022 } 3023 } 3024 } 3025 /* Now, the first wcc attribute reply. */ 3026 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 3027 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3028 if (*(tl + 1)) 3029 nd->nd_flag |= ND_NOMOREDATA; 3030 } 3031 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, NULL); 3032 /* and the second wcc attribute reply. */ 3033 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 3034 !error) { 3035 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3036 if (*(tl + 1)) 3037 nd->nd_flag |= ND_NOMOREDATA; 3038 } 3039 if (!error) 3040 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 3041 NULL, NULL); 3042 } 3043 if (nd->nd_repstat && !error) 3044 error = nd->nd_repstat; 3045 nfsmout: 3046 m_freem(nd->nd_mrep); 3047 return (error); 3048 } 3049 3050 /* 3051 * nfs hard link create rpc 3052 */ 3053 int 3054 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 3055 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 3056 struct nfsvattr *nap, int *attrflagp, int *dattrflagp) 3057 { 3058 u_int32_t *tl; 3059 struct nfsrv_descript nfsd, *nd = &nfsd; 3060 nfsattrbit_t attrbits; 3061 int error = 0; 3062 3063 *attrflagp = 0; 3064 *dattrflagp = 0; 3065 if (namelen > NFS_MAXNAMLEN) 3066 return (ENAMETOOLONG); 3067 NFSCL_REQSTART(nd, NFSPROC_LINK, vp, cred); 3068 if (nd->nd_flag & ND_NFSV4) { 3069 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3070 *tl = txdr_unsigned(NFSV4OP_PUTFH); 3071 } 3072 (void)nfsm_fhtom(VFSTONFS(dvp->v_mount), nd, VTONFS(dvp)->n_fhp->nfh_fh, 3073 VTONFS(dvp)->n_fhp->nfh_len, 0); 3074 if (nd->nd_flag & ND_NFSV4) { 3075 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3076 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3077 NFSWCCATTR_ATTRBIT(&attrbits); 3078 (void) nfsrv_putattrbit(nd, &attrbits); 3079 nd->nd_flag |= ND_V4WCCATTR; 3080 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3081 *tl = txdr_unsigned(NFSV4OP_LINK); 3082 } 3083 (void) nfsm_strtom(nd, name, namelen); 3084 error = nfscl_request(nd, vp, p, cred); 3085 if (error) 3086 return (error); 3087 if (nd->nd_flag & ND_NFSV3) { 3088 error = nfscl_postop_attr(nd, nap, attrflagp); 3089 if (!error) 3090 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 3091 NULL, NULL); 3092 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 3093 /* 3094 * First, parse out the PutFH and Getattr result. 3095 */ 3096 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3097 if (!(*(tl + 1))) 3098 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3099 if (*(tl + 1)) 3100 nd->nd_flag |= ND_NOMOREDATA; 3101 /* 3102 * Get the pre-op attributes. 3103 */ 3104 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3105 } 3106 if (nd->nd_repstat && !error) 3107 error = nd->nd_repstat; 3108 nfsmout: 3109 m_freem(nd->nd_mrep); 3110 return (error); 3111 } 3112 3113 /* 3114 * nfs symbolic link create rpc 3115 */ 3116 int 3117 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target, 3118 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 3119 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 3120 int *dattrflagp) 3121 { 3122 u_int32_t *tl; 3123 struct nfsrv_descript nfsd, *nd = &nfsd; 3124 struct nfsmount *nmp; 3125 int slen, error = 0; 3126 3127 *nfhpp = NULL; 3128 *attrflagp = 0; 3129 *dattrflagp = 0; 3130 nmp = VFSTONFS(dvp->v_mount); 3131 slen = strlen(target); 3132 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 3133 return (ENAMETOOLONG); 3134 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp, cred); 3135 if (nd->nd_flag & ND_NFSV4) { 3136 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3137 *tl = txdr_unsigned(NFLNK); 3138 (void) nfsm_strtom(nd, target, slen); 3139 } 3140 (void) nfsm_strtom(nd, name, namelen); 3141 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 3142 nfscl_fillsattr(nd, vap, dvp, 0, 0); 3143 if (!(nd->nd_flag & ND_NFSV4)) 3144 (void) nfsm_strtom(nd, target, slen); 3145 if (nd->nd_flag & ND_NFSV2) 3146 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 3147 error = nfscl_request(nd, dvp, p, cred); 3148 if (error) 3149 return (error); 3150 if (nd->nd_flag & ND_NFSV4) 3151 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3152 if ((nd->nd_flag & ND_NFSV3) && !error) { 3153 if (!nd->nd_repstat) 3154 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 3155 if (!error) 3156 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 3157 NULL, NULL); 3158 } 3159 if (nd->nd_repstat && !error) 3160 error = nd->nd_repstat; 3161 m_freem(nd->nd_mrep); 3162 /* 3163 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 3164 * Only do this if vfs.nfs.ignore_eexist is set. 3165 * Never do this for NFSv4.1 or later minor versions, since sessions 3166 * should guarantee "exactly once" RPC semantics. 3167 */ 3168 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 3169 nmp->nm_minorvers == 0)) 3170 error = 0; 3171 return (error); 3172 } 3173 3174 /* 3175 * nfs make dir rpc 3176 */ 3177 int 3178 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 3179 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 3180 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 3181 int *dattrflagp) 3182 { 3183 u_int32_t *tl; 3184 struct nfsrv_descript nfsd, *nd = &nfsd; 3185 nfsattrbit_t attrbits; 3186 int error = 0; 3187 struct nfsfh *fhp; 3188 struct nfsmount *nmp; 3189 3190 *nfhpp = NULL; 3191 *attrflagp = 0; 3192 *dattrflagp = 0; 3193 nmp = VFSTONFS(dvp->v_mount); 3194 fhp = VTONFS(dvp)->n_fhp; 3195 if (namelen > NFS_MAXNAMLEN) 3196 return (ENAMETOOLONG); 3197 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp, cred); 3198 if (nd->nd_flag & ND_NFSV4) { 3199 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3200 *tl = txdr_unsigned(NFDIR); 3201 } 3202 (void) nfsm_strtom(nd, name, namelen); 3203 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 3204 if (nd->nd_flag & ND_NFSV4) { 3205 NFSGETATTR_ATTRBIT(&attrbits); 3206 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3207 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3208 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3209 (void) nfsrv_putattrbit(nd, &attrbits); 3210 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3211 *tl = txdr_unsigned(NFSV4OP_PUTFH); 3212 (void)nfsm_fhtom(nmp, nd, fhp->nfh_fh, fhp->nfh_len, 0); 3213 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3214 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3215 (void) nfsrv_putattrbit(nd, &attrbits); 3216 } 3217 error = nfscl_request(nd, dvp, p, cred); 3218 if (error) 3219 return (error); 3220 if (nd->nd_flag & ND_NFSV4) 3221 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3222 if (!nd->nd_repstat && !error) { 3223 if (nd->nd_flag & ND_NFSV4) { 3224 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3225 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 3226 } 3227 if (!error) 3228 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 3229 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 3230 /* Get rid of the PutFH and Getattr status values. */ 3231 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 3232 /* Load the directory attributes. */ 3233 error = nfsm_loadattr(nd, dnap); 3234 if (error == 0) 3235 *dattrflagp = 1; 3236 } 3237 } 3238 if ((nd->nd_flag & ND_NFSV3) && !error) 3239 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3240 if (nd->nd_repstat && !error) 3241 error = nd->nd_repstat; 3242 nfsmout: 3243 m_freem(nd->nd_mrep); 3244 /* 3245 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 3246 * Only do this if vfs.nfs.ignore_eexist is set. 3247 * Never do this for NFSv4.1 or later minor versions, since sessions 3248 * should guarantee "exactly once" RPC semantics. 3249 */ 3250 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 3251 nmp->nm_minorvers == 0)) 3252 error = 0; 3253 return (error); 3254 } 3255 3256 /* 3257 * nfs remove directory call 3258 */ 3259 int 3260 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 3261 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp) 3262 { 3263 struct nfsrv_descript nfsd, *nd = &nfsd; 3264 int error = 0; 3265 3266 *dattrflagp = 0; 3267 if (namelen > NFS_MAXNAMLEN) 3268 return (ENAMETOOLONG); 3269 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp, cred); 3270 (void) nfsm_strtom(nd, name, namelen); 3271 error = nfscl_request(nd, dvp, p, cred); 3272 if (error) 3273 return (error); 3274 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 3275 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3276 if (nd->nd_repstat && !error) 3277 error = nd->nd_repstat; 3278 m_freem(nd->nd_mrep); 3279 /* 3280 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 3281 */ 3282 if (error == ENOENT) 3283 error = 0; 3284 return (error); 3285 } 3286 3287 /* 3288 * Readdir rpc. 3289 * Always returns with either uio_resid unchanged, if you are at the 3290 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 3291 * filled in. 3292 * I felt this would allow caching of directory blocks more easily 3293 * than returning a pertially filled block. 3294 * Directory offset cookies: 3295 * Oh my, what to do with them... 3296 * I can think of three ways to deal with them: 3297 * 1 - have the layer above these RPCs maintain a map between logical 3298 * directory byte offsets and the NFS directory offset cookies 3299 * 2 - pass the opaque directory offset cookies up into userland 3300 * and let the libc functions deal with them, via the system call 3301 * 3 - return them to userland in the "struct dirent", so future versions 3302 * of libc can use them and do whatever is necessary to make things work 3303 * above these rpc calls, in the meantime 3304 * For now, I do #3 by "hiding" the directory offset cookies after the 3305 * d_name field in struct dirent. This is space inside d_reclen that 3306 * will be ignored by anything that doesn't know about them. 3307 * The directory offset cookies are filled in as the last 8 bytes of 3308 * each directory entry, after d_name. Someday, the userland libc 3309 * functions may be able to use these. In the meantime, it satisfies 3310 * OpenBSD's requirements for cookies being returned. 3311 * If expects the directory offset cookie for the read to be in uio_offset 3312 * and returns the one for the next entry after this directory block in 3313 * there, as well. 3314 */ 3315 int 3316 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3317 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3318 int *eofp) 3319 { 3320 int len, left; 3321 struct dirent *dp = NULL; 3322 u_int32_t *tl; 3323 nfsquad_t cookie, ncookie; 3324 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 3325 struct nfsnode *dnp = VTONFS(vp); 3326 struct nfsvattr nfsva; 3327 struct nfsrv_descript nfsd, *nd = &nfsd; 3328 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3329 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 3330 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3331 char *cp; 3332 nfsattrbit_t attrbits, dattrbits; 3333 u_int32_t rderr, *tl2 = NULL; 3334 size_t tresid; 3335 3336 KASSERT(uiop->uio_iovcnt == 1 && 3337 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 3338 ("nfs readdirrpc bad uio")); 3339 ncookie.lval[0] = ncookie.lval[1] = 0; 3340 /* 3341 * There is no point in reading a lot more than uio_resid, however 3342 * adding one additional DIRBLKSIZ makes sense. Since uio_resid 3343 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 3344 * will never make readsize > nm_readdirsize. 3345 */ 3346 readsize = nmp->nm_readdirsize; 3347 if (readsize > uiop->uio_resid) 3348 readsize = uiop->uio_resid + DIRBLKSIZ; 3349 3350 *attrflagp = 0; 3351 if (eofp) 3352 *eofp = 0; 3353 tresid = uiop->uio_resid; 3354 cookie.lval[0] = cookiep->nfsuquad[0]; 3355 cookie.lval[1] = cookiep->nfsuquad[1]; 3356 nd->nd_mrep = NULL; 3357 3358 /* 3359 * For NFSv4, first create the "." and ".." entries. 3360 */ 3361 if (NFSHASNFSV4(nmp)) { 3362 reqsize = 6 * NFSX_UNSIGNED; 3363 NFSGETATTR_ATTRBIT(&dattrbits); 3364 NFSZERO_ATTRBIT(&attrbits); 3365 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3366 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 3367 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3368 NFSATTRBIT_MOUNTEDONFILEID)) { 3369 NFSSETBIT_ATTRBIT(&attrbits, 3370 NFSATTRBIT_MOUNTEDONFILEID); 3371 gotmnton = 1; 3372 } else { 3373 /* 3374 * Must fake it. Use the fileno, except when the 3375 * fsid is != to that of the directory. For that 3376 * case, generate a fake fileno that is not the same. 3377 */ 3378 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3379 gotmnton = 0; 3380 } 3381 3382 /* 3383 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3384 */ 3385 if (uiop->uio_offset == 0) { 3386 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred); 3387 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3388 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3389 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3390 (void) nfsrv_putattrbit(nd, &attrbits); 3391 error = nfscl_request(nd, vp, p, cred); 3392 if (error) 3393 return (error); 3394 dotfileid = 0; /* Fake out the compiler. */ 3395 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3396 error = nfsm_loadattr(nd, &nfsva); 3397 if (error != 0) 3398 goto nfsmout; 3399 dotfileid = nfsva.na_fileid; 3400 } 3401 if (nd->nd_repstat == 0) { 3402 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3403 len = fxdr_unsigned(int, *(tl + 4)); 3404 if (len > 0 && len <= NFSX_V4FHMAX) 3405 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3406 else 3407 error = EPERM; 3408 if (!error) { 3409 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3410 nfsva.na_mntonfileno = UINT64_MAX; 3411 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3412 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3413 NULL, NULL, NULL, p, cred); 3414 if (error) { 3415 dotdotfileid = dotfileid; 3416 } else if (gotmnton) { 3417 if (nfsva.na_mntonfileno != UINT64_MAX) 3418 dotdotfileid = nfsva.na_mntonfileno; 3419 else 3420 dotdotfileid = nfsva.na_fileid; 3421 } else if (nfsva.na_filesid[0] == 3422 dnp->n_vattr.na_filesid[0] && 3423 nfsva.na_filesid[1] == 3424 dnp->n_vattr.na_filesid[1]) { 3425 dotdotfileid = nfsva.na_fileid; 3426 } else { 3427 do { 3428 fakefileno--; 3429 } while (fakefileno == 3430 nfsva.na_fileid); 3431 dotdotfileid = fakefileno; 3432 } 3433 } 3434 } else if (nd->nd_repstat == NFSERR_NOENT) { 3435 /* 3436 * Lookupp returns NFSERR_NOENT when we are 3437 * at the root, so just use the current dir. 3438 */ 3439 nd->nd_repstat = 0; 3440 dotdotfileid = dotfileid; 3441 } else { 3442 error = nd->nd_repstat; 3443 } 3444 m_freem(nd->nd_mrep); 3445 if (error) 3446 return (error); 3447 nd->nd_mrep = NULL; 3448 dp = (struct dirent *)uiop->uio_iov->iov_base; 3449 dp->d_pad0 = dp->d_pad1 = 0; 3450 dp->d_off = 0; 3451 dp->d_type = DT_DIR; 3452 dp->d_fileno = dotfileid; 3453 dp->d_namlen = 1; 3454 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3455 dp->d_name[0] = '.'; 3456 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3457 /* 3458 * Just make these offset cookie 0. 3459 */ 3460 tl = (u_int32_t *)&dp->d_name[8]; 3461 *tl++ = 0; 3462 *tl = 0; 3463 blksiz += dp->d_reclen; 3464 uiop->uio_resid -= dp->d_reclen; 3465 uiop->uio_offset += dp->d_reclen; 3466 uiop->uio_iov->iov_base = 3467 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3468 uiop->uio_iov->iov_len -= dp->d_reclen; 3469 dp = (struct dirent *)uiop->uio_iov->iov_base; 3470 dp->d_pad0 = dp->d_pad1 = 0; 3471 dp->d_off = 0; 3472 dp->d_type = DT_DIR; 3473 dp->d_fileno = dotdotfileid; 3474 dp->d_namlen = 2; 3475 *((uint64_t *)dp->d_name) = 0; 3476 dp->d_name[0] = '.'; 3477 dp->d_name[1] = '.'; 3478 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3479 /* 3480 * Just make these offset cookie 0. 3481 */ 3482 tl = (u_int32_t *)&dp->d_name[8]; 3483 *tl++ = 0; 3484 *tl = 0; 3485 blksiz += dp->d_reclen; 3486 uiop->uio_resid -= dp->d_reclen; 3487 uiop->uio_offset += dp->d_reclen; 3488 uiop->uio_iov->iov_base = 3489 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3490 uiop->uio_iov->iov_len -= dp->d_reclen; 3491 } 3492 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 3493 } else { 3494 reqsize = 5 * NFSX_UNSIGNED; 3495 } 3496 3497 /* 3498 * Loop around doing readdir rpc's of size readsize. 3499 * The stopping criteria is EOF or buffer full. 3500 */ 3501 while (more_dirs && bigenough) { 3502 *attrflagp = 0; 3503 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp, cred); 3504 if (nd->nd_flag & ND_NFSV2) { 3505 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3506 *tl++ = cookie.lval[1]; 3507 *tl = txdr_unsigned(readsize); 3508 } else { 3509 NFSM_BUILD(tl, u_int32_t *, reqsize); 3510 *tl++ = cookie.lval[0]; 3511 *tl++ = cookie.lval[1]; 3512 if (cookie.qval == 0) { 3513 *tl++ = 0; 3514 *tl++ = 0; 3515 } else { 3516 NFSLOCKNODE(dnp); 3517 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3518 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3519 NFSUNLOCKNODE(dnp); 3520 } 3521 if (nd->nd_flag & ND_NFSV4) { 3522 *tl++ = txdr_unsigned(readsize); 3523 *tl = txdr_unsigned(readsize); 3524 (void) nfsrv_putattrbit(nd, &attrbits); 3525 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3526 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3527 (void) nfsrv_putattrbit(nd, &dattrbits); 3528 } else { 3529 *tl = txdr_unsigned(readsize); 3530 } 3531 } 3532 error = nfscl_request(nd, vp, p, cred); 3533 if (error) 3534 return (error); 3535 if (!(nd->nd_flag & ND_NFSV2)) { 3536 if (nd->nd_flag & ND_NFSV3) 3537 error = nfscl_postop_attr(nd, nap, attrflagp); 3538 if (!nd->nd_repstat && !error) { 3539 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3540 NFSLOCKNODE(dnp); 3541 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3542 dnp->n_cookieverf.nfsuquad[1] = *tl; 3543 NFSUNLOCKNODE(dnp); 3544 } 3545 } 3546 if (nd->nd_repstat || error) { 3547 if (!error) 3548 error = nd->nd_repstat; 3549 goto nfsmout; 3550 } 3551 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3552 more_dirs = fxdr_unsigned(int, *tl); 3553 if (!more_dirs) 3554 tryformoredirs = 0; 3555 3556 /* loop through the dir entries, doctoring them to 4bsd form */ 3557 while (more_dirs && bigenough) { 3558 if (nd->nd_flag & ND_NFSV4) { 3559 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3560 ncookie.lval[0] = *tl++; 3561 ncookie.lval[1] = *tl++; 3562 len = fxdr_unsigned(int, *tl); 3563 } else if (nd->nd_flag & ND_NFSV3) { 3564 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3565 nfsva.na_fileid = fxdr_hyper(tl); 3566 tl += 2; 3567 len = fxdr_unsigned(int, *tl); 3568 } else { 3569 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3570 nfsva.na_fileid = fxdr_unsigned(uint64_t, 3571 *tl++); 3572 len = fxdr_unsigned(int, *tl); 3573 } 3574 if (len <= 0 || len > NFS_MAXNAMLEN) { 3575 error = EBADRPC; 3576 goto nfsmout; 3577 } 3578 tlen = roundup2(len, 8); 3579 if (tlen == len) 3580 tlen += 8; /* To ensure null termination. */ 3581 left = DIRBLKSIZ - blksiz; 3582 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3583 NFSBZERO(uiop->uio_iov->iov_base, left); 3584 dp->d_reclen += left; 3585 uiop->uio_iov->iov_base = 3586 (char *)uiop->uio_iov->iov_base + left; 3587 uiop->uio_iov->iov_len -= left; 3588 uiop->uio_resid -= left; 3589 uiop->uio_offset += left; 3590 blksiz = 0; 3591 } 3592 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3593 uiop->uio_resid) 3594 bigenough = 0; 3595 if (bigenough) { 3596 dp = (struct dirent *)uiop->uio_iov->iov_base; 3597 dp->d_pad0 = dp->d_pad1 = 0; 3598 dp->d_off = 0; 3599 dp->d_namlen = len; 3600 dp->d_reclen = _GENERIC_DIRLEN(len) + 3601 NFSX_HYPER; 3602 dp->d_type = DT_UNKNOWN; 3603 blksiz += dp->d_reclen; 3604 if (blksiz == DIRBLKSIZ) 3605 blksiz = 0; 3606 uiop->uio_resid -= DIRHDSIZ; 3607 uiop->uio_offset += DIRHDSIZ; 3608 uiop->uio_iov->iov_base = 3609 (char *)uiop->uio_iov->iov_base + DIRHDSIZ; 3610 uiop->uio_iov->iov_len -= DIRHDSIZ; 3611 error = nfsm_mbufuio(nd, uiop, len); 3612 if (error) 3613 goto nfsmout; 3614 cp = uiop->uio_iov->iov_base; 3615 tlen -= len; 3616 NFSBZERO(cp, tlen); 3617 cp += tlen; /* points to cookie storage */ 3618 tl2 = (u_int32_t *)cp; 3619 uiop->uio_iov->iov_base = 3620 (char *)uiop->uio_iov->iov_base + tlen + 3621 NFSX_HYPER; 3622 uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; 3623 uiop->uio_resid -= tlen + NFSX_HYPER; 3624 uiop->uio_offset += (tlen + NFSX_HYPER); 3625 } else { 3626 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3627 if (error) 3628 goto nfsmout; 3629 } 3630 if (nd->nd_flag & ND_NFSV4) { 3631 rderr = 0; 3632 nfsva.na_mntonfileno = UINT64_MAX; 3633 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3634 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3635 NULL, NULL, &rderr, p, cred); 3636 if (error) 3637 goto nfsmout; 3638 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3639 } else if (nd->nd_flag & ND_NFSV3) { 3640 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3641 ncookie.lval[0] = *tl++; 3642 ncookie.lval[1] = *tl++; 3643 } else { 3644 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3645 ncookie.lval[0] = 0; 3646 ncookie.lval[1] = *tl++; 3647 } 3648 if (bigenough) { 3649 if (nd->nd_flag & ND_NFSV4) { 3650 if (rderr) { 3651 dp->d_fileno = 0; 3652 } else { 3653 if (gotmnton) { 3654 if (nfsva.na_mntonfileno != UINT64_MAX) 3655 dp->d_fileno = nfsva.na_mntonfileno; 3656 else 3657 dp->d_fileno = nfsva.na_fileid; 3658 } else if (nfsva.na_filesid[0] == 3659 dnp->n_vattr.na_filesid[0] && 3660 nfsva.na_filesid[1] == 3661 dnp->n_vattr.na_filesid[1]) { 3662 dp->d_fileno = nfsva.na_fileid; 3663 } else { 3664 do { 3665 fakefileno--; 3666 } while (fakefileno == 3667 nfsva.na_fileid); 3668 dp->d_fileno = fakefileno; 3669 } 3670 dp->d_type = vtonfs_dtype(nfsva.na_type); 3671 } 3672 } else { 3673 dp->d_fileno = nfsva.na_fileid; 3674 } 3675 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3676 ncookie.lval[0]; 3677 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3678 ncookie.lval[1]; 3679 } 3680 more_dirs = fxdr_unsigned(int, *tl); 3681 } 3682 /* 3683 * If at end of rpc data, get the eof boolean 3684 */ 3685 if (!more_dirs) { 3686 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3687 eof = fxdr_unsigned(int, *tl); 3688 if (tryformoredirs) 3689 more_dirs = !eof; 3690 if (nd->nd_flag & ND_NFSV4) { 3691 error = nfscl_postop_attr(nd, nap, attrflagp); 3692 if (error) 3693 goto nfsmout; 3694 } 3695 } 3696 m_freem(nd->nd_mrep); 3697 nd->nd_mrep = NULL; 3698 } 3699 /* 3700 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3701 * by increasing d_reclen for the last record. 3702 */ 3703 if (blksiz > 0) { 3704 left = DIRBLKSIZ - blksiz; 3705 NFSBZERO(uiop->uio_iov->iov_base, left); 3706 dp->d_reclen += left; 3707 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 3708 left; 3709 uiop->uio_iov->iov_len -= left; 3710 uiop->uio_resid -= left; 3711 uiop->uio_offset += left; 3712 } 3713 3714 /* 3715 * If returning no data, assume end of file. 3716 * If not bigenough, return not end of file, since you aren't 3717 * returning all the data 3718 * Otherwise, return the eof flag from the server. 3719 */ 3720 if (eofp) { 3721 if (tresid == ((size_t)(uiop->uio_resid))) 3722 *eofp = 1; 3723 else if (!bigenough) 3724 *eofp = 0; 3725 else 3726 *eofp = eof; 3727 } 3728 3729 /* 3730 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3731 */ 3732 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { 3733 dp = (struct dirent *)uiop->uio_iov->iov_base; 3734 NFSBZERO(dp, DIRBLKSIZ); 3735 dp->d_type = DT_UNKNOWN; 3736 tl = (u_int32_t *)&dp->d_name[4]; 3737 *tl++ = cookie.lval[0]; 3738 *tl = cookie.lval[1]; 3739 dp->d_reclen = DIRBLKSIZ; 3740 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 3741 DIRBLKSIZ; 3742 uiop->uio_iov->iov_len -= DIRBLKSIZ; 3743 uiop->uio_resid -= DIRBLKSIZ; 3744 uiop->uio_offset += DIRBLKSIZ; 3745 } 3746 3747 nfsmout: 3748 if (nd->nd_mrep != NULL) 3749 m_freem(nd->nd_mrep); 3750 return (error); 3751 } 3752 3753 /* 3754 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 3755 * (Also used for NFS V4 when mount flag set.) 3756 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 3757 */ 3758 int 3759 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3760 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3761 int *eofp) 3762 { 3763 int len, left; 3764 struct dirent *dp = NULL; 3765 u_int32_t *tl; 3766 vnode_t newvp = NULLVP; 3767 struct nfsrv_descript nfsd, *nd = &nfsd; 3768 struct nameidata nami, *ndp = &nami; 3769 struct componentname *cnp = &ndp->ni_cnd; 3770 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 3771 struct nfsnode *dnp = VTONFS(vp), *np; 3772 struct nfsvattr nfsva; 3773 struct nfsfh *nfhp; 3774 nfsquad_t cookie, ncookie; 3775 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3776 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 3777 int isdotdot = 0, unlocknewvp = 0; 3778 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3779 u_int64_t fileno = 0; 3780 char *cp; 3781 nfsattrbit_t attrbits, dattrbits; 3782 size_t tresid; 3783 u_int32_t *tl2 = NULL, rderr; 3784 struct timespec dctime, ts; 3785 bool attr_ok; 3786 3787 KASSERT(uiop->uio_iovcnt == 1 && 3788 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 3789 ("nfs readdirplusrpc bad uio")); 3790 ncookie.lval[0] = ncookie.lval[1] = 0; 3791 timespecclear(&dctime); 3792 *attrflagp = 0; 3793 if (eofp != NULL) 3794 *eofp = 0; 3795 ndp->ni_dvp = vp; 3796 nd->nd_mrep = NULL; 3797 cookie.lval[0] = cookiep->nfsuquad[0]; 3798 cookie.lval[1] = cookiep->nfsuquad[1]; 3799 tresid = uiop->uio_resid; 3800 3801 /* 3802 * For NFSv4, first create the "." and ".." entries. 3803 */ 3804 if (NFSHASNFSV4(nmp)) { 3805 NFSGETATTR_ATTRBIT(&dattrbits); 3806 NFSZERO_ATTRBIT(&attrbits); 3807 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3808 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3809 NFSATTRBIT_MOUNTEDONFILEID)) { 3810 NFSSETBIT_ATTRBIT(&attrbits, 3811 NFSATTRBIT_MOUNTEDONFILEID); 3812 gotmnton = 1; 3813 } else { 3814 /* 3815 * Must fake it. Use the fileno, except when the 3816 * fsid is != to that of the directory. For that 3817 * case, generate a fake fileno that is not the same. 3818 */ 3819 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3820 gotmnton = 0; 3821 } 3822 3823 /* 3824 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3825 */ 3826 if (uiop->uio_offset == 0) { 3827 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred); 3828 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3829 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3830 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3831 (void) nfsrv_putattrbit(nd, &attrbits); 3832 error = nfscl_request(nd, vp, p, cred); 3833 if (error) 3834 return (error); 3835 dotfileid = 0; /* Fake out the compiler. */ 3836 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3837 error = nfsm_loadattr(nd, &nfsva); 3838 if (error != 0) 3839 goto nfsmout; 3840 dctime = nfsva.na_ctime; 3841 dotfileid = nfsva.na_fileid; 3842 } 3843 if (nd->nd_repstat == 0) { 3844 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3845 len = fxdr_unsigned(int, *(tl + 4)); 3846 if (len > 0 && len <= NFSX_V4FHMAX) 3847 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3848 else 3849 error = EPERM; 3850 if (!error) { 3851 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3852 nfsva.na_mntonfileno = UINT64_MAX; 3853 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3854 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3855 NULL, NULL, NULL, p, cred); 3856 if (error) { 3857 dotdotfileid = dotfileid; 3858 } else if (gotmnton) { 3859 if (nfsva.na_mntonfileno != UINT64_MAX) 3860 dotdotfileid = nfsva.na_mntonfileno; 3861 else 3862 dotdotfileid = nfsva.na_fileid; 3863 } else if (nfsva.na_filesid[0] == 3864 dnp->n_vattr.na_filesid[0] && 3865 nfsva.na_filesid[1] == 3866 dnp->n_vattr.na_filesid[1]) { 3867 dotdotfileid = nfsva.na_fileid; 3868 } else { 3869 do { 3870 fakefileno--; 3871 } while (fakefileno == 3872 nfsva.na_fileid); 3873 dotdotfileid = fakefileno; 3874 } 3875 } 3876 } else if (nd->nd_repstat == NFSERR_NOENT) { 3877 /* 3878 * Lookupp returns NFSERR_NOENT when we are 3879 * at the root, so just use the current dir. 3880 */ 3881 nd->nd_repstat = 0; 3882 dotdotfileid = dotfileid; 3883 } else { 3884 error = nd->nd_repstat; 3885 } 3886 m_freem(nd->nd_mrep); 3887 if (error) 3888 return (error); 3889 nd->nd_mrep = NULL; 3890 dp = (struct dirent *)uiop->uio_iov->iov_base; 3891 dp->d_pad0 = dp->d_pad1 = 0; 3892 dp->d_off = 0; 3893 dp->d_type = DT_DIR; 3894 dp->d_fileno = dotfileid; 3895 dp->d_namlen = 1; 3896 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3897 dp->d_name[0] = '.'; 3898 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3899 /* 3900 * Just make these offset cookie 0. 3901 */ 3902 tl = (u_int32_t *)&dp->d_name[8]; 3903 *tl++ = 0; 3904 *tl = 0; 3905 blksiz += dp->d_reclen; 3906 uiop->uio_resid -= dp->d_reclen; 3907 uiop->uio_offset += dp->d_reclen; 3908 uiop->uio_iov->iov_base = 3909 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3910 uiop->uio_iov->iov_len -= dp->d_reclen; 3911 dp = (struct dirent *)uiop->uio_iov->iov_base; 3912 dp->d_pad0 = dp->d_pad1 = 0; 3913 dp->d_off = 0; 3914 dp->d_type = DT_DIR; 3915 dp->d_fileno = dotdotfileid; 3916 dp->d_namlen = 2; 3917 *((uint64_t *)dp->d_name) = 0; 3918 dp->d_name[0] = '.'; 3919 dp->d_name[1] = '.'; 3920 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3921 /* 3922 * Just make these offset cookie 0. 3923 */ 3924 tl = (u_int32_t *)&dp->d_name[8]; 3925 *tl++ = 0; 3926 *tl = 0; 3927 blksiz += dp->d_reclen; 3928 uiop->uio_resid -= dp->d_reclen; 3929 uiop->uio_offset += dp->d_reclen; 3930 uiop->uio_iov->iov_base = 3931 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3932 uiop->uio_iov->iov_len -= dp->d_reclen; 3933 } 3934 NFSREADDIRPLUS_ATTRBIT(&attrbits); 3935 if (gotmnton) 3936 NFSSETBIT_ATTRBIT(&attrbits, 3937 NFSATTRBIT_MOUNTEDONFILEID); 3938 if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3939 NFSATTRBIT_TIMECREATE)) 3940 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); 3941 } 3942 3943 /* 3944 * Loop around doing readdir rpc's of size nm_readdirsize. 3945 * The stopping criteria is EOF or buffer full. 3946 */ 3947 while (more_dirs && bigenough) { 3948 *attrflagp = 0; 3949 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp, cred); 3950 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 3951 *tl++ = cookie.lval[0]; 3952 *tl++ = cookie.lval[1]; 3953 if (cookie.qval == 0) { 3954 *tl++ = 0; 3955 *tl++ = 0; 3956 } else { 3957 NFSLOCKNODE(dnp); 3958 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3959 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3960 NFSUNLOCKNODE(dnp); 3961 } 3962 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 3963 *tl = txdr_unsigned(nmp->nm_readdirsize); 3964 if (nd->nd_flag & ND_NFSV4) { 3965 (void) nfsrv_putattrbit(nd, &attrbits); 3966 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3967 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3968 (void) nfsrv_putattrbit(nd, &dattrbits); 3969 } 3970 nanouptime(&ts); 3971 error = nfscl_request(nd, vp, p, cred); 3972 if (error) 3973 return (error); 3974 if (nd->nd_flag & ND_NFSV3) 3975 error = nfscl_postop_attr(nd, nap, attrflagp); 3976 if (nd->nd_repstat || error) { 3977 if (!error) 3978 error = nd->nd_repstat; 3979 goto nfsmout; 3980 } 3981 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 3982 dctime = nap->na_ctime; 3983 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3984 NFSLOCKNODE(dnp); 3985 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3986 dnp->n_cookieverf.nfsuquad[1] = *tl++; 3987 NFSUNLOCKNODE(dnp); 3988 more_dirs = fxdr_unsigned(int, *tl); 3989 if (!more_dirs) 3990 tryformoredirs = 0; 3991 3992 /* loop through the dir entries, doctoring them to 4bsd form */ 3993 while (more_dirs && bigenough) { 3994 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 3995 if (nd->nd_flag & ND_NFSV4) { 3996 ncookie.lval[0] = *tl++; 3997 ncookie.lval[1] = *tl++; 3998 } else { 3999 fileno = fxdr_hyper(tl); 4000 tl += 2; 4001 } 4002 len = fxdr_unsigned(int, *tl); 4003 if (len <= 0 || len > NFS_MAXNAMLEN) { 4004 error = EBADRPC; 4005 goto nfsmout; 4006 } 4007 tlen = roundup2(len, 8); 4008 if (tlen == len) 4009 tlen += 8; /* To ensure null termination. */ 4010 left = DIRBLKSIZ - blksiz; 4011 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 4012 NFSBZERO(uiop->uio_iov->iov_base, left); 4013 dp->d_reclen += left; 4014 uiop->uio_iov->iov_base = 4015 (char *)uiop->uio_iov->iov_base + left; 4016 uiop->uio_iov->iov_len -= left; 4017 uiop->uio_resid -= left; 4018 uiop->uio_offset += left; 4019 blksiz = 0; 4020 } 4021 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 4022 uiop->uio_resid) 4023 bigenough = 0; 4024 if (bigenough) { 4025 dp = (struct dirent *)uiop->uio_iov->iov_base; 4026 dp->d_pad0 = dp->d_pad1 = 0; 4027 dp->d_off = 0; 4028 dp->d_namlen = len; 4029 dp->d_reclen = _GENERIC_DIRLEN(len) + 4030 NFSX_HYPER; 4031 dp->d_type = DT_UNKNOWN; 4032 blksiz += dp->d_reclen; 4033 if (blksiz == DIRBLKSIZ) 4034 blksiz = 0; 4035 uiop->uio_resid -= DIRHDSIZ; 4036 uiop->uio_offset += DIRHDSIZ; 4037 uiop->uio_iov->iov_base = 4038 (char *)uiop->uio_iov->iov_base + DIRHDSIZ; 4039 uiop->uio_iov->iov_len -= DIRHDSIZ; 4040 cnp->cn_nameptr = uiop->uio_iov->iov_base; 4041 cnp->cn_namelen = len; 4042 NFSCNHASHZERO(cnp); 4043 error = nfsm_mbufuio(nd, uiop, len); 4044 if (error) 4045 goto nfsmout; 4046 cp = uiop->uio_iov->iov_base; 4047 tlen -= len; 4048 NFSBZERO(cp, tlen); 4049 cp += tlen; /* points to cookie storage */ 4050 tl2 = (u_int32_t *)cp; 4051 if (len == 2 && cnp->cn_nameptr[0] == '.' && 4052 cnp->cn_nameptr[1] == '.') 4053 isdotdot = 1; 4054 else 4055 isdotdot = 0; 4056 uiop->uio_iov->iov_base = 4057 (char *)uiop->uio_iov->iov_base + tlen + 4058 NFSX_HYPER; 4059 uiop->uio_iov->iov_len -= tlen + NFSX_HYPER; 4060 uiop->uio_resid -= tlen + NFSX_HYPER; 4061 uiop->uio_offset += (tlen + NFSX_HYPER); 4062 } else { 4063 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 4064 if (error) 4065 goto nfsmout; 4066 } 4067 nfhp = NULL; 4068 if (nd->nd_flag & ND_NFSV3) { 4069 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 4070 ncookie.lval[0] = *tl++; 4071 ncookie.lval[1] = *tl++; 4072 attrflag = fxdr_unsigned(int, *tl); 4073 if (attrflag) { 4074 error = nfsm_loadattr(nd, &nfsva); 4075 if (error) 4076 goto nfsmout; 4077 } 4078 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 4079 if (*tl) { 4080 error = nfsm_getfh(nd, &nfhp); 4081 if (error) 4082 goto nfsmout; 4083 } 4084 if (!attrflag && nfhp != NULL) { 4085 free(nfhp, M_NFSFH); 4086 nfhp = NULL; 4087 } 4088 } else { 4089 rderr = 0; 4090 nfsva.na_mntonfileno = 0xffffffff; 4091 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 4092 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 4093 NULL, NULL, &rderr, p, cred); 4094 if (error) 4095 goto nfsmout; 4096 } 4097 4098 if (bigenough) { 4099 if (nd->nd_flag & ND_NFSV4) { 4100 if (rderr) { 4101 dp->d_fileno = 0; 4102 } else if (gotmnton) { 4103 if (nfsva.na_mntonfileno != 0xffffffff) 4104 dp->d_fileno = nfsva.na_mntonfileno; 4105 else 4106 dp->d_fileno = nfsva.na_fileid; 4107 } else if (nfsva.na_filesid[0] == 4108 dnp->n_vattr.na_filesid[0] && 4109 nfsva.na_filesid[1] == 4110 dnp->n_vattr.na_filesid[1]) { 4111 dp->d_fileno = nfsva.na_fileid; 4112 } else { 4113 do { 4114 fakefileno--; 4115 } while (fakefileno == 4116 nfsva.na_fileid); 4117 dp->d_fileno = fakefileno; 4118 } 4119 } else { 4120 dp->d_fileno = fileno; 4121 } 4122 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 4123 ncookie.lval[0]; 4124 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 4125 ncookie.lval[1]; 4126 4127 if (nfhp != NULL) { 4128 attr_ok = true; 4129 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 4130 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 4131 VREF(vp); 4132 newvp = vp; 4133 unlocknewvp = 0; 4134 free(nfhp, M_NFSFH); 4135 np = dnp; 4136 } else if (isdotdot != 0) { 4137 /* 4138 * Skip doing a nfscl_nget() call for "..". 4139 * There's a race between acquiring the nfs 4140 * node here and lookups that look for the 4141 * directory being read (in the parent). 4142 * It would try to get a lock on ".." here, 4143 * owning the lock on the directory being 4144 * read. Lookup will hold the lock on ".." 4145 * and try to acquire the lock on the 4146 * directory being read. 4147 * If the directory is unlocked/relocked, 4148 * then there is a LOR with the buflock 4149 * vp is relocked. 4150 */ 4151 free(nfhp, M_NFSFH); 4152 } else { 4153 error = nfscl_nget(vp->v_mount, vp, 4154 nfhp, cnp, p, &np, LK_EXCLUSIVE); 4155 if (!error) { 4156 newvp = NFSTOV(np); 4157 unlocknewvp = 1; 4158 /* 4159 * If n_localmodtime >= time before RPC, 4160 * then a file modification operation, 4161 * such as VOP_SETATTR() of size, has 4162 * occurred while the Lookup RPC and 4163 * acquisition of the vnode happened. As 4164 * such, the attributes might be stale, 4165 * with possibly an incorrect size. 4166 */ 4167 NFSLOCKNODE(np); 4168 if (timespecisset( 4169 &np->n_localmodtime) && 4170 timespeccmp(&np->n_localmodtime, 4171 &ts, >=)) { 4172 NFSCL_DEBUG(4, "nfsrpc_readdirplus:" 4173 " localmod stale attributes\n"); 4174 attr_ok = false; 4175 } 4176 NFSUNLOCKNODE(np); 4177 } 4178 } 4179 nfhp = NULL; 4180 if (newvp != NULLVP) { 4181 if (attr_ok) 4182 error = nfscl_loadattrcache(&newvp, 4183 &nfsva, NULL, 0, 0); 4184 if (error) { 4185 if (unlocknewvp) 4186 vput(newvp); 4187 else 4188 vrele(newvp); 4189 goto nfsmout; 4190 } 4191 dp->d_type = 4192 vtonfs_dtype(np->n_vattr.na_type); 4193 ndp->ni_vp = newvp; 4194 NFSCNHASH(cnp, HASHINIT); 4195 if (cnp->cn_namelen <= NCHNAMLEN && 4196 ndp->ni_dvp != ndp->ni_vp && 4197 (newvp->v_type != VDIR || 4198 dctime.tv_sec != 0)) { 4199 cache_enter_time_flags(ndp->ni_dvp, 4200 ndp->ni_vp, cnp, 4201 &nfsva.na_ctime, 4202 newvp->v_type != VDIR ? NULL : 4203 &dctime, VFS_CACHE_DROPOLD); 4204 } 4205 if (unlocknewvp) 4206 vput(newvp); 4207 else 4208 vrele(newvp); 4209 newvp = NULLVP; 4210 } 4211 } 4212 } else if (nfhp != NULL) { 4213 free(nfhp, M_NFSFH); 4214 } 4215 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4216 more_dirs = fxdr_unsigned(int, *tl); 4217 } 4218 /* 4219 * If at end of rpc data, get the eof boolean 4220 */ 4221 if (!more_dirs) { 4222 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4223 eof = fxdr_unsigned(int, *tl); 4224 if (tryformoredirs) 4225 more_dirs = !eof; 4226 if (nd->nd_flag & ND_NFSV4) { 4227 error = nfscl_postop_attr(nd, nap, attrflagp); 4228 if (error) 4229 goto nfsmout; 4230 } 4231 } 4232 m_freem(nd->nd_mrep); 4233 nd->nd_mrep = NULL; 4234 } 4235 /* 4236 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 4237 * by increasing d_reclen for the last record. 4238 */ 4239 if (blksiz > 0) { 4240 left = DIRBLKSIZ - blksiz; 4241 NFSBZERO(uiop->uio_iov->iov_base, left); 4242 dp->d_reclen += left; 4243 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 4244 left; 4245 uiop->uio_iov->iov_len -= left; 4246 uiop->uio_resid -= left; 4247 uiop->uio_offset += left; 4248 } 4249 4250 /* 4251 * If returning no data, assume end of file. 4252 * If not bigenough, return not end of file, since you aren't 4253 * returning all the data 4254 * Otherwise, return the eof flag from the server. 4255 */ 4256 if (eofp != NULL) { 4257 if (tresid == uiop->uio_resid) 4258 *eofp = 1; 4259 else if (!bigenough) 4260 *eofp = 0; 4261 else 4262 *eofp = eof; 4263 } 4264 4265 /* 4266 * Add extra empty records to any remaining DIRBLKSIZ chunks. 4267 */ 4268 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { 4269 dp = (struct dirent *)uiop->uio_iov->iov_base; 4270 NFSBZERO(dp, DIRBLKSIZ); 4271 dp->d_type = DT_UNKNOWN; 4272 tl = (u_int32_t *)&dp->d_name[4]; 4273 *tl++ = cookie.lval[0]; 4274 *tl = cookie.lval[1]; 4275 dp->d_reclen = DIRBLKSIZ; 4276 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 4277 DIRBLKSIZ; 4278 uiop->uio_iov->iov_len -= DIRBLKSIZ; 4279 uiop->uio_resid -= DIRBLKSIZ; 4280 uiop->uio_offset += DIRBLKSIZ; 4281 } 4282 4283 nfsmout: 4284 if (nd->nd_mrep != NULL) 4285 m_freem(nd->nd_mrep); 4286 return (error); 4287 } 4288 4289 /* 4290 * Nfs commit rpc 4291 */ 4292 int 4293 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 4294 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 4295 { 4296 u_int32_t *tl; 4297 struct nfsrv_descript nfsd, *nd = &nfsd; 4298 nfsattrbit_t attrbits; 4299 int error; 4300 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4301 4302 *attrflagp = 0; 4303 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp, cred); 4304 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4305 txdr_hyper(offset, tl); 4306 tl += 2; 4307 *tl = txdr_unsigned(cnt); 4308 if (nd->nd_flag & ND_NFSV4) { 4309 /* 4310 * And do a Getattr op. 4311 */ 4312 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4313 *tl = txdr_unsigned(NFSV4OP_GETATTR); 4314 NFSGETATTR_ATTRBIT(&attrbits); 4315 (void) nfsrv_putattrbit(nd, &attrbits); 4316 } 4317 error = nfscl_request(nd, vp, p, cred); 4318 if (error) 4319 return (error); 4320 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, NULL); 4321 if (!error && !nd->nd_repstat) { 4322 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 4323 NFSLOCKMNT(nmp); 4324 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { 4325 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 4326 nd->nd_repstat = NFSERR_STALEWRITEVERF; 4327 } 4328 NFSUNLOCKMNT(nmp); 4329 if (nd->nd_flag & ND_NFSV4) 4330 error = nfscl_postop_attr(nd, nap, attrflagp); 4331 } 4332 nfsmout: 4333 if (!error && nd->nd_repstat) 4334 error = nd->nd_repstat; 4335 m_freem(nd->nd_mrep); 4336 return (error); 4337 } 4338 4339 /* 4340 * NFS byte range lock rpc. 4341 * (Mostly just calls one of the three lower level RPC routines.) 4342 */ 4343 int 4344 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 4345 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 4346 { 4347 struct nfscllockowner *lp; 4348 struct nfsclclient *clp; 4349 struct nfsfh *nfhp; 4350 struct nfsrv_descript nfsd, *nd = &nfsd; 4351 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4352 u_int64_t off, len; 4353 off_t start, end; 4354 u_int32_t clidrev = 0; 4355 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 4356 int callcnt, dorpc; 4357 4358 /* 4359 * Convert the flock structure into a start and end and do POSIX 4360 * bounds checking. 4361 */ 4362 switch (fl->l_whence) { 4363 case SEEK_SET: 4364 case SEEK_CUR: 4365 /* 4366 * Caller is responsible for adding any necessary offset 4367 * when SEEK_CUR is used. 4368 */ 4369 start = fl->l_start; 4370 off = fl->l_start; 4371 break; 4372 case SEEK_END: 4373 start = size + fl->l_start; 4374 off = size + fl->l_start; 4375 break; 4376 default: 4377 return (EINVAL); 4378 } 4379 if (start < 0) 4380 return (EINVAL); 4381 if (fl->l_len != 0) { 4382 end = start + fl->l_len - 1; 4383 if (end < start) 4384 return (EINVAL); 4385 } 4386 4387 len = fl->l_len; 4388 if (len == 0) 4389 len = NFS64BITSSET; 4390 retrycnt = 0; 4391 do { 4392 nd->nd_repstat = 0; 4393 if (op == F_GETLK) { 4394 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); 4395 if (error) 4396 return (error); 4397 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 4398 if (!error) { 4399 clidrev = clp->nfsc_clientidrev; 4400 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 4401 p, id, flags); 4402 } else if (error == -1) { 4403 error = 0; 4404 } 4405 nfscl_clientrelease(clp); 4406 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 4407 /* 4408 * We must loop around for all lockowner cases. 4409 */ 4410 callcnt = 0; 4411 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); 4412 if (error) 4413 return (error); 4414 do { 4415 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 4416 clp, id, flags, &lp, &dorpc); 4417 /* 4418 * If it returns a NULL lp, we're done. 4419 */ 4420 if (lp == NULL) { 4421 if (callcnt == 0) 4422 nfscl_clientrelease(clp); 4423 else 4424 nfscl_releasealllocks(clp, vp, p, id, flags); 4425 return (error); 4426 } 4427 if (nmp->nm_clp != NULL) 4428 clidrev = nmp->nm_clp->nfsc_clientidrev; 4429 else 4430 clidrev = 0; 4431 /* 4432 * If the server doesn't support Posix lock semantics, 4433 * only allow locks on the entire file, since it won't 4434 * handle overlapping byte ranges. 4435 * There might still be a problem when a lock 4436 * upgrade/downgrade (read<->write) occurs, since the 4437 * server "might" expect an unlock first? 4438 */ 4439 if (dorpc && (lp->nfsl_open->nfso_posixlock || 4440 (off == 0 && len == NFS64BITSSET))) { 4441 /* 4442 * Since the lock records will go away, we must 4443 * wait for grace and delay here. 4444 */ 4445 do { 4446 error = nfsrpc_locku(nd, nmp, lp, off, len, 4447 NFSV4LOCKT_READ, cred, p, 0); 4448 if ((nd->nd_repstat == NFSERR_GRACE || 4449 nd->nd_repstat == NFSERR_DELAY) && 4450 error == 0) 4451 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 4452 "nfs_advlock"); 4453 } while ((nd->nd_repstat == NFSERR_GRACE || 4454 nd->nd_repstat == NFSERR_DELAY) && error == 0); 4455 } 4456 callcnt++; 4457 } while (error == 0 && nd->nd_repstat == 0); 4458 nfscl_releasealllocks(clp, vp, p, id, flags); 4459 } else if (op == F_SETLK) { 4460 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 4461 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 4462 if (error || donelocally) { 4463 return (error); 4464 } 4465 if (nmp->nm_clp != NULL) 4466 clidrev = nmp->nm_clp->nfsc_clientidrev; 4467 else 4468 clidrev = 0; 4469 nfhp = VTONFS(vp)->n_fhp; 4470 if (!lp->nfsl_open->nfso_posixlock && 4471 (off != 0 || len != NFS64BITSSET)) { 4472 error = EINVAL; 4473 } else { 4474 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 4475 nfhp->nfh_len, lp, newone, reclaim, off, 4476 len, fl->l_type, cred, p, 0); 4477 } 4478 if (!error) 4479 error = nd->nd_repstat; 4480 nfscl_lockrelease(lp, error, newone); 4481 } else { 4482 error = EINVAL; 4483 } 4484 if (!error) 4485 error = nd->nd_repstat; 4486 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 4487 error == NFSERR_STALEDONTRECOVER || 4488 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 4489 error == NFSERR_BADSESSION) { 4490 (void) nfs_catnap(PZERO, error, "nfs_advlock"); 4491 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 4492 && clidrev != 0) { 4493 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 4494 retrycnt++; 4495 } 4496 } while (error == NFSERR_GRACE || 4497 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 4498 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 4499 error == NFSERR_BADSESSION || 4500 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 4501 expireret == 0 && clidrev != 0 && retrycnt < 4)); 4502 if (error && retrycnt >= 4) 4503 error = EIO; 4504 return (error); 4505 } 4506 4507 /* 4508 * The lower level routine for the LockT case. 4509 */ 4510 int 4511 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 4512 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 4513 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 4514 { 4515 u_int32_t *tl; 4516 int error, type, size; 4517 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4518 struct nfsnode *np; 4519 struct nfsmount *nmp; 4520 struct nfsclsession *tsep; 4521 4522 nmp = VFSTONFS(vp->v_mount); 4523 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp, cred); 4524 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4525 if (fl->l_type == F_RDLCK) 4526 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4527 else 4528 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4529 txdr_hyper(off, tl); 4530 tl += 2; 4531 txdr_hyper(len, tl); 4532 tl += 2; 4533 tsep = nfsmnt_mdssession(nmp); 4534 *tl++ = tsep->nfsess_clientid.lval[0]; 4535 *tl = tsep->nfsess_clientid.lval[1]; 4536 nfscl_filllockowner(id, own, flags); 4537 np = VTONFS(vp); 4538 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 4539 np->n_fhp->nfh_len); 4540 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 4541 error = nfscl_request(nd, vp, p, cred); 4542 if (error) 4543 return (error); 4544 if (nd->nd_repstat == 0) { 4545 fl->l_type = F_UNLCK; 4546 } else if (nd->nd_repstat == NFSERR_DENIED) { 4547 nd->nd_repstat = 0; 4548 fl->l_whence = SEEK_SET; 4549 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4550 fl->l_start = fxdr_hyper(tl); 4551 tl += 2; 4552 len = fxdr_hyper(tl); 4553 tl += 2; 4554 if (len == NFS64BITSSET) 4555 fl->l_len = 0; 4556 else 4557 fl->l_len = len; 4558 type = fxdr_unsigned(int, *tl++); 4559 if (type == NFSV4LOCKT_WRITE) 4560 fl->l_type = F_WRLCK; 4561 else 4562 fl->l_type = F_RDLCK; 4563 /* 4564 * XXX For now, I have no idea what to do with the 4565 * conflicting lock_owner, so I'll just set the pid == 0 4566 * and skip over the lock_owner. 4567 */ 4568 fl->l_pid = (pid_t)0; 4569 tl += 2; 4570 size = fxdr_unsigned(int, *tl); 4571 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4572 error = EBADRPC; 4573 if (!error) 4574 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4575 } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 4576 nfscl_initiate_recovery(clp); 4577 nfsmout: 4578 m_freem(nd->nd_mrep); 4579 return (error); 4580 } 4581 4582 /* 4583 * Lower level function that performs the LockU RPC. 4584 */ 4585 static int 4586 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 4587 struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 4588 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 4589 { 4590 u_int32_t *tl; 4591 int error; 4592 4593 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 4594 lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0, cred); 4595 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 4596 *tl++ = txdr_unsigned(type); 4597 *tl = txdr_unsigned(lp->nfsl_seqid); 4598 if (nfstest_outofseq && 4599 (arc4random() % nfstest_outofseq) == 0) 4600 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4601 tl++; 4602 if (NFSHASNFSV4N(nmp)) 4603 *tl++ = 0; 4604 else 4605 *tl++ = lp->nfsl_stateid.seqid; 4606 *tl++ = lp->nfsl_stateid.other[0]; 4607 *tl++ = lp->nfsl_stateid.other[1]; 4608 *tl++ = lp->nfsl_stateid.other[2]; 4609 txdr_hyper(off, tl); 4610 tl += 2; 4611 txdr_hyper(len, tl); 4612 if (syscred) 4613 nd->nd_flag |= ND_USEGSSNAME; 4614 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4615 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4616 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4617 if (error) 4618 return (error); 4619 if (nd->nd_repstat == 0) { 4620 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4621 lp->nfsl_stateid.seqid = *tl++; 4622 lp->nfsl_stateid.other[0] = *tl++; 4623 lp->nfsl_stateid.other[1] = *tl++; 4624 lp->nfsl_stateid.other[2] = *tl; 4625 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4626 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4627 nfsmout: 4628 m_freem(nd->nd_mrep); 4629 return (error); 4630 } 4631 4632 /* 4633 * The actual Lock RPC. 4634 */ 4635 int 4636 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 4637 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 4638 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 4639 NFSPROC_T *p, int syscred) 4640 { 4641 u_int32_t *tl; 4642 int error, size; 4643 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4644 struct nfsclsession *tsep; 4645 4646 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0, 4647 cred); 4648 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4649 if (type == F_RDLCK) 4650 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4651 else 4652 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4653 *tl++ = txdr_unsigned(reclaim); 4654 txdr_hyper(off, tl); 4655 tl += 2; 4656 txdr_hyper(len, tl); 4657 tl += 2; 4658 if (newone) { 4659 *tl = newnfs_true; 4660 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 4661 2 * NFSX_UNSIGNED + NFSX_HYPER); 4662 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 4663 if (NFSHASNFSV4N(nmp)) 4664 *tl++ = 0; 4665 else 4666 *tl++ = lp->nfsl_open->nfso_stateid.seqid; 4667 *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 4668 *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 4669 *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 4670 *tl++ = txdr_unsigned(lp->nfsl_seqid); 4671 tsep = nfsmnt_mdssession(nmp); 4672 *tl++ = tsep->nfsess_clientid.lval[0]; 4673 *tl = tsep->nfsess_clientid.lval[1]; 4674 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4675 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4676 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4677 } else { 4678 *tl = newnfs_false; 4679 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 4680 if (NFSHASNFSV4N(nmp)) 4681 *tl++ = 0; 4682 else 4683 *tl++ = lp->nfsl_stateid.seqid; 4684 *tl++ = lp->nfsl_stateid.other[0]; 4685 *tl++ = lp->nfsl_stateid.other[1]; 4686 *tl++ = lp->nfsl_stateid.other[2]; 4687 *tl = txdr_unsigned(lp->nfsl_seqid); 4688 if (nfstest_outofseq && 4689 (arc4random() % nfstest_outofseq) == 0) 4690 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4691 } 4692 if (syscred) 4693 nd->nd_flag |= ND_USEGSSNAME; 4694 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 4695 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4696 if (error) 4697 return (error); 4698 if (newone) 4699 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 4700 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4701 if (nd->nd_repstat == 0) { 4702 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4703 lp->nfsl_stateid.seqid = *tl++; 4704 lp->nfsl_stateid.other[0] = *tl++; 4705 lp->nfsl_stateid.other[1] = *tl++; 4706 lp->nfsl_stateid.other[2] = *tl; 4707 } else if (nd->nd_repstat == NFSERR_DENIED) { 4708 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4709 size = fxdr_unsigned(int, *(tl + 7)); 4710 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4711 error = EBADRPC; 4712 if (!error) 4713 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4714 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4715 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4716 nfsmout: 4717 m_freem(nd->nd_mrep); 4718 return (error); 4719 } 4720 4721 /* 4722 * nfs statfs rpc 4723 * (always called with the vp for the mount point) 4724 */ 4725 int 4726 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 4727 uint32_t *leasep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, 4728 int *attrflagp) 4729 { 4730 u_int32_t *tl = NULL; 4731 struct nfsrv_descript nfsd, *nd = &nfsd; 4732 struct nfsmount *nmp; 4733 nfsattrbit_t attrbits; 4734 int error; 4735 4736 *attrflagp = 0; 4737 nmp = VFSTONFS(vp->v_mount); 4738 if (NFSHASNFSV4(nmp)) { 4739 /* 4740 * For V4, you actually do a getattr. 4741 */ 4742 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); 4743 if (leasep != NULL) 4744 NFSROOTFS_GETATTRBIT(&attrbits); 4745 else 4746 NFSSTATFS_GETATTRBIT(&attrbits); 4747 (void) nfsrv_putattrbit(nd, &attrbits); 4748 nd->nd_flag |= ND_USEGSSNAME; 4749 error = nfscl_request(nd, vp, p, cred); 4750 if (error) 4751 return (error); 4752 if (nd->nd_repstat == 0) { 4753 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4754 NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL, 4755 p, cred); 4756 if (!error) { 4757 nmp->nm_fsid[0] = nap->na_filesid[0]; 4758 nmp->nm_fsid[1] = nap->na_filesid[1]; 4759 NFSSETHASSETFSID(nmp); 4760 *attrflagp = 1; 4761 } 4762 } else { 4763 error = nd->nd_repstat; 4764 } 4765 if (error) 4766 goto nfsmout; 4767 } else { 4768 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp, NULL); 4769 error = nfscl_request(nd, vp, p, cred); 4770 if (error) 4771 return (error); 4772 if (nd->nd_flag & ND_NFSV3) { 4773 error = nfscl_postop_attr(nd, nap, attrflagp); 4774 if (error) 4775 goto nfsmout; 4776 } 4777 if (nd->nd_repstat) { 4778 error = nd->nd_repstat; 4779 goto nfsmout; 4780 } 4781 NFSM_DISSECT(tl, u_int32_t *, 4782 NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 4783 } 4784 if (NFSHASNFSV3(nmp)) { 4785 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 4786 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 4787 sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 4788 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 4789 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 4790 sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 4791 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 4792 } else if (NFSHASNFSV4(nmp) == 0) { 4793 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 4794 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 4795 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 4796 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 4797 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 4798 } 4799 nfsmout: 4800 m_freem(nd->nd_mrep); 4801 return (error); 4802 } 4803 4804 /* 4805 * nfs pathconf rpc 4806 */ 4807 int 4808 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 4809 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 4810 { 4811 struct nfsrv_descript nfsd, *nd = &nfsd; 4812 struct nfsmount *nmp; 4813 u_int32_t *tl; 4814 nfsattrbit_t attrbits; 4815 int error; 4816 struct nfsnode *np; 4817 4818 *attrflagp = 0; 4819 nmp = VFSTONFS(vp->v_mount); 4820 if (NFSHASNFSV4(nmp)) { 4821 np = VTONFS(vp); 4822 if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 && 4823 nmp->nm_fhsize == 0) { 4824 /* Attempt to get the actual root file handle. */ 4825 error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 4826 cred, p); 4827 if (error != 0) 4828 return (EACCES); 4829 if (np->n_fhp->nfh_len == NFSX_FHMAX + 1) 4830 nfscl_statfs(vp, cred, p); 4831 } 4832 /* 4833 * For V4, you actually do a getattr. 4834 */ 4835 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); 4836 NFSPATHCONF_GETATTRBIT(&attrbits); 4837 (void) nfsrv_putattrbit(nd, &attrbits); 4838 nd->nd_flag |= ND_USEGSSNAME; 4839 error = nfscl_request(nd, vp, p, cred); 4840 if (error) 4841 return (error); 4842 if (nd->nd_repstat == 0) { 4843 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4844 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 4845 cred); 4846 if (!error) 4847 *attrflagp = 1; 4848 } else { 4849 error = nd->nd_repstat; 4850 } 4851 } else { 4852 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp, NULL); 4853 error = nfscl_request(nd, vp, p, cred); 4854 if (error) 4855 return (error); 4856 error = nfscl_postop_attr(nd, nap, attrflagp); 4857 if (nd->nd_repstat && !error) 4858 error = nd->nd_repstat; 4859 if (!error) { 4860 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 4861 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 4862 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 4863 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 4864 pc->pc_chownrestricted = 4865 fxdr_unsigned(u_int32_t, *tl++); 4866 pc->pc_caseinsensitive = 4867 fxdr_unsigned(u_int32_t, *tl++); 4868 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 4869 } 4870 } 4871 nfsmout: 4872 m_freem(nd->nd_mrep); 4873 return (error); 4874 } 4875 4876 /* 4877 * nfs version 3 fsinfo rpc call 4878 */ 4879 int 4880 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 4881 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 4882 { 4883 u_int32_t *tl; 4884 struct nfsrv_descript nfsd, *nd = &nfsd; 4885 int error; 4886 4887 *attrflagp = 0; 4888 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp, NULL); 4889 error = nfscl_request(nd, vp, p, cred); 4890 if (error) 4891 return (error); 4892 error = nfscl_postop_attr(nd, nap, attrflagp); 4893 if (nd->nd_repstat && !error) 4894 error = nd->nd_repstat; 4895 if (!error) { 4896 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 4897 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 4898 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 4899 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 4900 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 4901 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 4902 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 4903 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 4904 fsp->fs_maxfilesize = fxdr_hyper(tl); 4905 tl += 2; 4906 fxdr_nfsv3time(tl, &fsp->fs_timedelta); 4907 tl += 2; 4908 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 4909 } 4910 nfsmout: 4911 m_freem(nd->nd_mrep); 4912 return (error); 4913 } 4914 4915 /* 4916 * This function performs the Renew RPC. 4917 */ 4918 int 4919 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, 4920 NFSPROC_T *p) 4921 { 4922 u_int32_t *tl; 4923 struct nfsrv_descript nfsd; 4924 struct nfsrv_descript *nd = &nfsd; 4925 struct nfsmount *nmp; 4926 int error; 4927 struct nfssockreq *nrp; 4928 struct nfsclsession *tsep; 4929 4930 nmp = clp->nfsc_nmp; 4931 if (nmp == NULL) 4932 return (0); 4933 if (dsp == NULL) 4934 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0, 4935 0, cred); 4936 else 4937 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, 4938 &dsp->nfsclds_sess, 0, 0, NULL); 4939 if (!NFSHASNFSV4N(nmp)) { 4940 /* NFSv4.1 just uses a Sequence Op and not a Renew. */ 4941 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4942 tsep = nfsmnt_mdssession(nmp); 4943 *tl++ = tsep->nfsess_clientid.lval[0]; 4944 *tl = tsep->nfsess_clientid.lval[1]; 4945 } 4946 nrp = NULL; 4947 if (dsp != NULL) 4948 nrp = dsp->nfsclds_sockp; 4949 if (nrp == NULL) 4950 /* If NULL, use the MDS socket. */ 4951 nrp = &nmp->nm_sockreq; 4952 nd->nd_flag |= ND_USEGSSNAME; 4953 if (dsp == NULL) 4954 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4955 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4956 else { 4957 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 4958 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 4959 if (error == ENXIO) 4960 nfscl_cancelreqs(dsp); 4961 } 4962 if (error) 4963 return (error); 4964 error = nd->nd_repstat; 4965 m_freem(nd->nd_mrep); 4966 return (error); 4967 } 4968 4969 /* 4970 * This function performs the Releaselockowner RPC. 4971 */ 4972 int 4973 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 4974 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 4975 { 4976 struct nfsrv_descript nfsd, *nd = &nfsd; 4977 u_int32_t *tl; 4978 int error; 4979 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4980 struct nfsclsession *tsep; 4981 4982 if (NFSHASNFSV4N(nmp)) { 4983 /* For NFSv4.1, do a FreeStateID. */ 4984 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, 4985 NULL, 0, 0, cred); 4986 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); 4987 } else { 4988 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, 4989 NULL, 0, 0, NULL); 4990 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 4991 tsep = nfsmnt_mdssession(nmp); 4992 *tl++ = tsep->nfsess_clientid.lval[0]; 4993 *tl = tsep->nfsess_clientid.lval[1]; 4994 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4995 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4996 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4997 } 4998 nd->nd_flag |= ND_USEGSSNAME; 4999 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5000 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5001 if (error) 5002 return (error); 5003 error = nd->nd_repstat; 5004 m_freem(nd->nd_mrep); 5005 return (error); 5006 } 5007 5008 /* 5009 * This function performs the Compound to get the mount pt FH. 5010 */ 5011 int 5012 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 5013 NFSPROC_T *p) 5014 { 5015 u_int32_t *tl; 5016 struct nfsrv_descript nfsd; 5017 struct nfsrv_descript *nd = &nfsd; 5018 u_char *cp, *cp2, *fhp; 5019 int error, cnt, len, setnil; 5020 u_int32_t *opcntp; 5021 5022 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0, 5023 0, NULL); 5024 cp = dirpath; 5025 cnt = 0; 5026 do { 5027 setnil = 0; 5028 while (*cp == '/') 5029 cp++; 5030 cp2 = cp; 5031 while (*cp2 != '\0' && *cp2 != '/') 5032 cp2++; 5033 if (*cp2 == '/') { 5034 setnil = 1; 5035 *cp2 = '\0'; 5036 } 5037 if (cp2 != cp) { 5038 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 5039 *tl = txdr_unsigned(NFSV4OP_LOOKUP); 5040 nfsm_strtom(nd, cp, strlen(cp)); 5041 cnt++; 5042 } 5043 if (setnil) 5044 *cp2++ = '/'; 5045 cp = cp2; 5046 } while (*cp != '\0'); 5047 if (NFSHASNFSV4N(nmp)) 5048 /* Has a Sequence Op done by nfscl_reqstart(). */ 5049 *opcntp = txdr_unsigned(3 + cnt); 5050 else 5051 *opcntp = txdr_unsigned(2 + cnt); 5052 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 5053 *tl = txdr_unsigned(NFSV4OP_GETFH); 5054 nd->nd_flag |= ND_USEGSSNAME; 5055 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5056 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5057 if (error) 5058 return (error); 5059 if (nd->nd_repstat == 0) { 5060 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 5061 tl += (2 + 2 * cnt); 5062 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 5063 len > NFSX_FHMAX) { 5064 nd->nd_repstat = NFSERR_BADXDR; 5065 } else { 5066 fhp = malloc(len + 1, M_TEMP, M_WAITOK); 5067 nd->nd_repstat = nfsrv_mtostr(nd, fhp, len); 5068 if (nd->nd_repstat == 0) { 5069 NFSLOCKMNT(nmp); 5070 if (nmp->nm_fhsize == 0) { 5071 NFSBCOPY(fhp, nmp->nm_fh, len); 5072 nmp->nm_fhsize = len; 5073 } 5074 NFSUNLOCKMNT(nmp); 5075 } 5076 free(fhp, M_TEMP); 5077 } 5078 } 5079 error = nd->nd_repstat; 5080 nfsmout: 5081 m_freem(nd->nd_mrep); 5082 return (error); 5083 } 5084 5085 /* 5086 * This function performs the Delegreturn RPC. 5087 */ 5088 int 5089 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 5090 struct nfsmount *nmp, NFSPROC_T *p, int syscred) 5091 { 5092 u_int32_t *tl; 5093 struct nfsrv_descript nfsd; 5094 struct nfsrv_descript *nd = &nfsd; 5095 int error; 5096 5097 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 5098 dp->nfsdl_fhlen, NULL, NULL, 0, 0, cred); 5099 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 5100 if (NFSHASNFSV4N(nmp)) 5101 *tl++ = 0; 5102 else 5103 *tl++ = dp->nfsdl_stateid.seqid; 5104 *tl++ = dp->nfsdl_stateid.other[0]; 5105 *tl++ = dp->nfsdl_stateid.other[1]; 5106 *tl = dp->nfsdl_stateid.other[2]; 5107 if (syscred) 5108 nd->nd_flag |= ND_USEGSSNAME; 5109 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5110 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5111 if (error) 5112 return (error); 5113 error = nd->nd_repstat; 5114 m_freem(nd->nd_mrep); 5115 return (error); 5116 } 5117 5118 /* 5119 * nfs getacl call. 5120 */ 5121 int 5122 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) 5123 { 5124 struct nfsrv_descript nfsd, *nd = &nfsd; 5125 int error; 5126 nfsattrbit_t attrbits; 5127 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 5128 5129 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 5130 return (EOPNOTSUPP); 5131 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp, cred); 5132 NFSZERO_ATTRBIT(&attrbits); 5133 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 5134 (void) nfsrv_putattrbit(nd, &attrbits); 5135 error = nfscl_request(nd, vp, p, cred); 5136 if (error) 5137 return (error); 5138 if (!nd->nd_repstat) 5139 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 5140 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 5141 else 5142 error = nd->nd_repstat; 5143 m_freem(nd->nd_mrep); 5144 return (error); 5145 } 5146 5147 /* 5148 * nfs setacl call. 5149 */ 5150 int 5151 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) 5152 { 5153 int error; 5154 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 5155 5156 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 5157 return (EOPNOTSUPP); 5158 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL); 5159 return (error); 5160 } 5161 5162 /* 5163 * nfs setacl call. 5164 */ 5165 static int 5166 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 5167 struct acl *aclp, nfsv4stateid_t *stateidp) 5168 { 5169 struct nfsrv_descript nfsd, *nd = &nfsd; 5170 int error; 5171 nfsattrbit_t attrbits; 5172 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 5173 5174 if (!NFSHASNFSV4(nmp)) 5175 return (EOPNOTSUPP); 5176 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp, cred); 5177 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 5178 NFSZERO_ATTRBIT(&attrbits); 5179 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 5180 (void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0, 5181 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); 5182 error = nfscl_request(nd, vp, p, cred); 5183 if (error) 5184 return (error); 5185 /* Don't care about the pre/postop attributes */ 5186 m_freem(nd->nd_mrep); 5187 return (nd->nd_repstat); 5188 } 5189 5190 /* 5191 * Do the NFSv4.1 Exchange ID. 5192 */ 5193 int 5194 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, 5195 struct nfssockreq *nrp, int minorvers, uint32_t exchflags, 5196 struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p) 5197 { 5198 uint32_t *tl, v41flags; 5199 struct nfsrv_descript nfsd; 5200 struct nfsrv_descript *nd = &nfsd; 5201 struct nfsclds *dsp; 5202 struct timespec verstime; 5203 int error, len; 5204 5205 *dspp = NULL; 5206 if (minorvers == 0) 5207 minorvers = nmp->nm_minorvers; 5208 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, 5209 NFS_VER4, minorvers, NULL); 5210 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5211 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ 5212 *tl = txdr_unsigned(clp->nfsc_rev); 5213 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 5214 5215 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 5216 *tl++ = txdr_unsigned(exchflags); 5217 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); 5218 5219 /* Set the implementation id4 */ 5220 *tl = txdr_unsigned(1); 5221 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 5222 (void) nfsm_strtom(nd, version, strlen(version)); 5223 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 5224 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 5225 verstime.tv_nsec = 0; 5226 txdr_nfsv4time(&verstime, tl); 5227 nd->nd_flag |= ND_USEGSSNAME; 5228 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 5229 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5230 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, 5231 (int)nd->nd_repstat); 5232 if (error != 0) 5233 return (error); 5234 if (nd->nd_repstat == 0) { 5235 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); 5236 len = fxdr_unsigned(int, *(tl + 7)); 5237 if (len < 0 || len > NFSV4_OPAQUELIMIT) { 5238 error = NFSERR_BADXDR; 5239 goto nfsmout; 5240 } 5241 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, 5242 M_WAITOK | M_ZERO); 5243 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; 5244 dsp->nfsclds_servownlen = len; 5245 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; 5246 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; 5247 dsp->nfsclds_sess.nfsess_sequenceid = 5248 fxdr_unsigned(uint32_t, *tl++); 5249 v41flags = fxdr_unsigned(uint32_t, *tl); 5250 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && 5251 NFSHASPNFSOPT(nmp)) { 5252 NFSCL_DEBUG(1, "set PNFS\n"); 5253 NFSLOCKMNT(nmp); 5254 nmp->nm_state |= NFSSTA_PNFS; 5255 NFSUNLOCKMNT(nmp); 5256 dsp->nfsclds_flags |= NFSCLDS_MDS; 5257 } 5258 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) 5259 dsp->nfsclds_flags |= NFSCLDS_DS; 5260 if (minorvers == NFSV42_MINORVERSION) 5261 dsp->nfsclds_flags |= NFSCLDS_MINORV2; 5262 if (len > 0) 5263 nd->nd_repstat = nfsrv_mtostr(nd, 5264 dsp->nfsclds_serverown, len); 5265 if (nd->nd_repstat == 0) { 5266 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 5267 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 5268 NULL, MTX_DEF); 5269 nfscl_initsessionslots(&dsp->nfsclds_sess); 5270 *dspp = dsp; 5271 } else 5272 free(dsp, M_NFSCLDS); 5273 } 5274 error = nd->nd_repstat; 5275 nfsmout: 5276 m_freem(nd->nd_mrep); 5277 return (error); 5278 } 5279 5280 /* 5281 * Do the NFSv4.1 Create Session. 5282 */ 5283 int 5284 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, 5285 struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds, 5286 struct ucred *cred, NFSPROC_T *p) 5287 { 5288 uint32_t crflags, maxval, *tl; 5289 struct nfsrv_descript nfsd; 5290 struct nfsrv_descript *nd = &nfsd; 5291 int error, irdcnt, minorvers; 5292 5293 /* Make sure nm_rsize, nm_wsize is set. */ 5294 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0) 5295 nmp->nm_rsize = NFS_MAXBSIZE; 5296 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0) 5297 nmp->nm_wsize = NFS_MAXBSIZE; 5298 if (dsp == NULL) 5299 minorvers = nmp->nm_minorvers; 5300 else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0) 5301 minorvers = NFSV42_MINORVERSION; 5302 else 5303 minorvers = NFSV41_MINORVERSION; 5304 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, 5305 NFS_VER4, minorvers, NULL); 5306 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5307 *tl++ = sep->nfsess_clientid.lval[0]; 5308 *tl++ = sep->nfsess_clientid.lval[1]; 5309 *tl++ = txdr_unsigned(sequenceid); 5310 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); 5311 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0) 5312 crflags |= NFSV4CRSESS_CONNBACKCHAN; 5313 *tl = txdr_unsigned(crflags); 5314 5315 /* Fill in fore channel attributes. */ 5316 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5317 *tl++ = 0; /* Header pad size */ 5318 if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >= 5319 nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) { 5320 /* 5321 * NFSv4.2 Extended Attribute operations may want to do 5322 * requests/replies that are larger than nm_rsize/nm_wsize. 5323 */ 5324 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); 5325 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); 5326 } else { 5327 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR); 5328 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR); 5329 } 5330 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 5331 *tl++ = txdr_unsigned(20); /* Max operations */ 5332 *tl++ = txdr_unsigned(64); /* Max slots */ 5333 *tl = 0; /* No rdma ird */ 5334 5335 /* Fill in back channel attributes. */ 5336 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5337 *tl++ = 0; /* Header pad size */ 5338 *tl++ = txdr_unsigned(10000); /* Max request size */ 5339 *tl++ = txdr_unsigned(10000); /* Max response size */ 5340 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 5341 *tl++ = txdr_unsigned(4); /* Max operations */ 5342 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ 5343 *tl = 0; /* No rdma ird */ 5344 5345 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); 5346 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ 5347 5348 /* Allow AUTH_SYS callbacks as uid, gid == 0. */ 5349 *tl++ = txdr_unsigned(1); /* Auth_sys only */ 5350 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ 5351 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ 5352 *tl++ = 0; /* Null machine name */ 5353 *tl++ = 0; /* Uid == 0 */ 5354 *tl++ = 0; /* Gid == 0 */ 5355 *tl = 0; /* No additional gids */ 5356 nd->nd_flag |= ND_USEGSSNAME; 5357 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, 5358 NFS_VER4, NULL, 1, NULL, NULL); 5359 if (error != 0) 5360 return (error); 5361 if (nd->nd_repstat == 0) { 5362 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 5363 2 * NFSX_UNSIGNED); 5364 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); 5365 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 5366 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); 5367 crflags = fxdr_unsigned(uint32_t, *tl); 5368 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { 5369 NFSLOCKMNT(nmp); 5370 nmp->nm_state |= NFSSTA_SESSPERSIST; 5371 NFSUNLOCKMNT(nmp); 5372 } 5373 5374 /* Get the fore channel slot count. */ 5375 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5376 tl++; /* Skip the header pad size. */ 5377 5378 /* Make sure nm_wsize is small enough. */ 5379 maxval = fxdr_unsigned(uint32_t, *tl++); 5380 while (maxval < nmp->nm_wsize + NFS_MAXXDR) { 5381 if (nmp->nm_wsize > 8096) 5382 nmp->nm_wsize /= 2; 5383 else 5384 break; 5385 } 5386 sep->nfsess_maxreq = maxval; 5387 5388 /* Make sure nm_rsize is small enough. */ 5389 maxval = fxdr_unsigned(uint32_t, *tl++); 5390 while (maxval < nmp->nm_rsize + NFS_MAXXDR) { 5391 if (nmp->nm_rsize > 8096) 5392 nmp->nm_rsize /= 2; 5393 else 5394 break; 5395 } 5396 sep->nfsess_maxresp = maxval; 5397 5398 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); 5399 tl++; 5400 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); 5401 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); 5402 irdcnt = fxdr_unsigned(int, *tl); 5403 if (irdcnt < 0 || irdcnt > 1) { 5404 error = NFSERR_BADXDR; 5405 goto nfsmout; 5406 } 5407 if (irdcnt > 0) 5408 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 5409 5410 /* and the back channel slot count. */ 5411 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5412 tl += 5; 5413 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 5414 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 5415 } 5416 error = nd->nd_repstat; 5417 nfsmout: 5418 m_freem(nd->nd_mrep); 5419 return (error); 5420 } 5421 5422 /* 5423 * Do the NFSv4.1 Destroy Client. 5424 */ 5425 int 5426 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 5427 struct ucred *cred, NFSPROC_T *p) 5428 { 5429 uint32_t *tl; 5430 struct nfsrv_descript nfsd; 5431 struct nfsrv_descript *nd = &nfsd; 5432 int error; 5433 struct nfsclsession *tsep; 5434 5435 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0, 5436 0, NULL); 5437 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5438 tsep = nfsmnt_mdssession(nmp); 5439 *tl++ = tsep->nfsess_clientid.lval[0]; 5440 *tl = tsep->nfsess_clientid.lval[1]; 5441 nd->nd_flag |= ND_USEGSSNAME; 5442 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5443 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5444 if (error != 0) 5445 return (error); 5446 error = nd->nd_repstat; 5447 m_freem(nd->nd_mrep); 5448 return (error); 5449 } 5450 5451 /* 5452 * Do the NFSv4.1 LayoutGet. 5453 */ 5454 static int 5455 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 5456 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype, 5457 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep, 5458 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p) 5459 { 5460 struct nfsrv_descript nfsd, *nd = &nfsd; 5461 int error; 5462 5463 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0, 5464 0, cred); 5465 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, 5466 layouttype, layoutlen, 0); 5467 nd->nd_flag |= ND_USEGSSNAME; 5468 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5469 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5470 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); 5471 if (error != 0) 5472 return (error); 5473 if (nd->nd_repstat == 0) 5474 error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep, 5475 flhp); 5476 if (error == 0 && nd->nd_repstat != 0) 5477 error = nd->nd_repstat; 5478 m_freem(nd->nd_mrep); 5479 return (error); 5480 } 5481 5482 /* 5483 * Do the NFSv4.1 Get Device Info. 5484 */ 5485 int 5486 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 5487 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 5488 NFSPROC_T *p) 5489 { 5490 uint32_t cnt, *tl, vers, minorvers; 5491 struct nfsrv_descript nfsd; 5492 struct nfsrv_descript *nd = &nfsd; 5493 struct sockaddr_in sin, ssin; 5494 struct sockaddr_in6 sin6, ssin6; 5495 struct nfsclds *dsp = NULL, **dspp, **gotdspp; 5496 struct nfscldevinfo *ndi; 5497 int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j; 5498 int stripecnt; 5499 uint8_t stripeindex; 5500 sa_family_t af, safilled; 5501 5502 ssin.sin_port = 0; /* To shut up compiler. */ 5503 ssin.sin_addr.s_addr = 0; /* ditto */ 5504 *ndip = NULL; 5505 ndi = NULL; 5506 gotdspp = NULL; 5507 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0, 5508 0, cred); 5509 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5510 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 5511 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5512 *tl++ = txdr_unsigned(layouttype); 5513 *tl++ = txdr_unsigned(100000); 5514 if (notifybitsp != NULL && *notifybitsp != 0) { 5515 *tl = txdr_unsigned(1); /* One word of bits. */ 5516 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5517 *tl = txdr_unsigned(*notifybitsp); 5518 } else 5519 *tl = txdr_unsigned(0); 5520 nd->nd_flag |= ND_USEGSSNAME; 5521 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5522 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5523 if (error != 0) 5524 return (error); 5525 if (nd->nd_repstat == 0) { 5526 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5527 if (layouttype != fxdr_unsigned(int, *tl)) 5528 printf("EEK! devinfo layout type not same!\n"); 5529 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) { 5530 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5531 stripecnt = fxdr_unsigned(int, *tl); 5532 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 5533 if (stripecnt < 1 || stripecnt > 4096) { 5534 printf("pNFS File layout devinfo stripecnt %d:" 5535 " out of range\n", stripecnt); 5536 error = NFSERR_BADXDR; 5537 goto nfsmout; 5538 } 5539 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * 5540 NFSX_UNSIGNED); 5541 addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 5542 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 5543 if (addrcnt < 1 || addrcnt > 128) { 5544 printf("NFS devinfo addrcnt %d: out of range\n", 5545 addrcnt); 5546 error = NFSERR_BADXDR; 5547 goto nfsmout; 5548 } 5549 5550 /* 5551 * Now we know how many stripe indices and addresses, so 5552 * we can allocate the structure the correct size. 5553 */ 5554 i = (stripecnt * sizeof(uint8_t)) / 5555 sizeof(struct nfsclds *) + 1; 5556 NFSCL_DEBUG(4, "stripeindices=%d\n", i); 5557 ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 5558 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | 5559 M_ZERO); 5560 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5561 NFSX_V4DEVICEID); 5562 ndi->nfsdi_refcnt = 0; 5563 ndi->nfsdi_flags = NFSDI_FILELAYOUT; 5564 ndi->nfsdi_stripecnt = stripecnt; 5565 ndi->nfsdi_addrcnt = addrcnt; 5566 /* Fill in the stripe indices. */ 5567 for (i = 0; i < stripecnt; i++) { 5568 stripeindex = fxdr_unsigned(uint8_t, *tl++); 5569 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 5570 if (stripeindex >= addrcnt) { 5571 printf("pNFS File Layout devinfo" 5572 " stripeindex %d: too big\n", 5573 (int)stripeindex); 5574 error = NFSERR_BADXDR; 5575 goto nfsmout; 5576 } 5577 nfsfldi_setstripeindex(ndi, i, stripeindex); 5578 } 5579 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 5580 /* For Flex File, we only get one address list. */ 5581 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *), 5582 M_NFSDEVINFO, M_WAITOK | M_ZERO); 5583 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5584 NFSX_V4DEVICEID); 5585 ndi->nfsdi_refcnt = 0; 5586 ndi->nfsdi_flags = NFSDI_FLEXFILE; 5587 addrcnt = ndi->nfsdi_addrcnt = 1; 5588 } 5589 5590 /* Now, dissect the server address(es). */ 5591 safilled = AF_UNSPEC; 5592 for (i = 0; i < addrcnt; i++) { 5593 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5594 cnt = fxdr_unsigned(uint32_t, *tl); 5595 if (cnt == 0) { 5596 printf("NFS devinfo 0 len addrlist\n"); 5597 error = NFSERR_BADXDR; 5598 goto nfsmout; 5599 } 5600 dspp = nfsfldi_addr(ndi, i); 5601 safilled = AF_UNSPEC; 5602 for (j = 0; j < cnt; j++) { 5603 error = nfsv4_getipaddr(nd, &sin, &sin6, &af, 5604 &isudp); 5605 if (error != 0 && error != EPERM) { 5606 error = NFSERR_BADXDR; 5607 goto nfsmout; 5608 } 5609 if (error == 0 && isudp == 0) { 5610 /* 5611 * The priority is: 5612 * - Same address family. 5613 * Save the address and dspp, so that 5614 * the connection can be done after 5615 * parsing is complete. 5616 */ 5617 if (safilled == AF_UNSPEC || 5618 (af == nmp->nm_nam->sa_family && 5619 safilled != nmp->nm_nam->sa_family) 5620 ) { 5621 if (af == AF_INET) 5622 ssin = sin; 5623 else 5624 ssin6 = sin6; 5625 safilled = af; 5626 gotdspp = dspp; 5627 } 5628 } 5629 } 5630 } 5631 5632 gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */ 5633 gotminor = NFSV41_MINORVERSION; 5634 /* For Flex File, we will take one of the versions to use. */ 5635 if (layouttype == NFSLAYOUT_FLEXFILE) { 5636 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5637 j = fxdr_unsigned(int, *tl); 5638 if (j < 1 || j > NFSDEV_MAXVERS) { 5639 printf("pNFS: too many versions\n"); 5640 error = NFSERR_BADXDR; 5641 goto nfsmout; 5642 } 5643 gotvers = 0; 5644 gotminor = 0; 5645 for (i = 0; i < j; i++) { 5646 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED); 5647 vers = fxdr_unsigned(uint32_t, *tl++); 5648 minorvers = fxdr_unsigned(uint32_t, *tl++); 5649 if (vers == NFS_VER3) 5650 minorvers = 0; 5651 if ((vers == NFS_VER4 && ((minorvers == 5652 NFSV41_MINORVERSION && gotminor == 0) || 5653 minorvers == NFSV42_MINORVERSION)) || 5654 (vers == NFS_VER3 && gotvers == 0)) { 5655 gotvers = vers; 5656 gotminor = minorvers; 5657 /* We'll take this one. */ 5658 ndi->nfsdi_versindex = i; 5659 ndi->nfsdi_vers = vers; 5660 ndi->nfsdi_minorvers = minorvers; 5661 ndi->nfsdi_rsize = fxdr_unsigned( 5662 uint32_t, *tl++); 5663 ndi->nfsdi_wsize = fxdr_unsigned( 5664 uint32_t, *tl++); 5665 if (*tl == newnfs_true) 5666 ndi->nfsdi_flags |= 5667 NFSDI_TIGHTCOUPLED; 5668 else 5669 ndi->nfsdi_flags &= 5670 ~NFSDI_TIGHTCOUPLED; 5671 } 5672 } 5673 if (gotvers == 0) { 5674 printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n"); 5675 error = NFSERR_BADXDR; 5676 goto nfsmout; 5677 } 5678 } 5679 5680 /* And the notify bits. */ 5681 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5682 bitcnt = fxdr_unsigned(int, *tl); 5683 if (bitcnt > 0) { 5684 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5685 if (notifybitsp != NULL) 5686 *notifybitsp = 5687 fxdr_unsigned(uint32_t, *tl); 5688 } 5689 if (safilled != AF_UNSPEC) { 5690 KASSERT(ndi != NULL, ("ndi is NULL")); 5691 *ndip = ndi; 5692 } else 5693 error = EPERM; 5694 if (error == 0) { 5695 /* 5696 * Now we can do a TCP connection for the correct 5697 * NFS version and IP address. 5698 */ 5699 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled, 5700 gotvers, gotminor, &dsp, p); 5701 } 5702 if (error == 0) { 5703 KASSERT(gotdspp != NULL, ("gotdspp is NULL")); 5704 *gotdspp = dsp; 5705 } 5706 } 5707 if (nd->nd_repstat != 0 && error == 0) 5708 error = nd->nd_repstat; 5709 nfsmout: 5710 if (error != 0 && ndi != NULL) 5711 nfscl_freedevinfo(ndi); 5712 m_freem(nd->nd_mrep); 5713 return (error); 5714 } 5715 5716 /* 5717 * Do the NFSv4.1 LayoutCommit. 5718 */ 5719 int 5720 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5721 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5722 int layouttype, struct ucred *cred, NFSPROC_T *p) 5723 { 5724 uint32_t *tl; 5725 struct nfsrv_descript nfsd, *nd = &nfsd; 5726 int error; 5727 5728 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL, 5729 0, 0, cred); 5730 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5731 NFSX_STATEID); 5732 txdr_hyper(off, tl); 5733 tl += 2; 5734 txdr_hyper(len, tl); 5735 tl += 2; 5736 if (reclaim != 0) 5737 *tl++ = newnfs_true; 5738 else 5739 *tl++ = newnfs_false; 5740 *tl++ = txdr_unsigned(stateidp->seqid); 5741 *tl++ = stateidp->other[0]; 5742 *tl++ = stateidp->other[1]; 5743 *tl++ = stateidp->other[2]; 5744 *tl++ = newnfs_true; 5745 if (lastbyte < off) 5746 lastbyte = off; 5747 else if (lastbyte >= (off + len)) 5748 lastbyte = off + len - 1; 5749 txdr_hyper(lastbyte, tl); 5750 tl += 2; 5751 *tl++ = newnfs_false; 5752 *tl++ = txdr_unsigned(layouttype); 5753 /* All supported layouts are 0 length. */ 5754 *tl = txdr_unsigned(0); 5755 nd->nd_flag |= ND_USEGSSNAME; 5756 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5757 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5758 if (error != 0) 5759 return (error); 5760 error = nd->nd_repstat; 5761 m_freem(nd->nd_mrep); 5762 return (error); 5763 } 5764 5765 /* 5766 * Do the NFSv4.1 LayoutReturn. 5767 */ 5768 int 5769 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5770 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5771 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5772 uint32_t stat, uint32_t op, char *devid) 5773 { 5774 uint32_t *tl; 5775 struct nfsrv_descript nfsd, *nd = &nfsd; 5776 uint64_t tu64; 5777 int error; 5778 5779 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL, 5780 0, 0, cred); 5781 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5782 if (reclaim != 0) 5783 *tl++ = newnfs_true; 5784 else 5785 *tl++ = newnfs_false; 5786 *tl++ = txdr_unsigned(layouttype); 5787 *tl++ = txdr_unsigned(iomode); 5788 *tl = txdr_unsigned(layoutreturn); 5789 if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5790 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5791 NFSX_UNSIGNED); 5792 txdr_hyper(offset, tl); 5793 tl += 2; 5794 txdr_hyper(len, tl); 5795 tl += 2; 5796 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5797 *tl++ = txdr_unsigned(stateidp->seqid); 5798 *tl++ = stateidp->other[0]; 5799 *tl++ = stateidp->other[1]; 5800 *tl++ = stateidp->other[2]; 5801 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) 5802 *tl = txdr_unsigned(0); 5803 else if (layouttype == NFSLAYOUT_FLEXFILE) { 5804 if (stat != 0) { 5805 *tl = txdr_unsigned(2 * NFSX_HYPER + 5806 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5807 NFSX_UNSIGNED); 5808 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 5809 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5810 NFSX_UNSIGNED); 5811 *tl++ = txdr_unsigned(1); /* One error. */ 5812 tu64 = 0; /* Offset. */ 5813 txdr_hyper(tu64, tl); tl += 2; 5814 tu64 = UINT64_MAX; /* Length. */ 5815 txdr_hyper(tu64, tl); tl += 2; 5816 NFSBCOPY(stateidp, tl, NFSX_STATEID); 5817 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5818 *tl++ = txdr_unsigned(1); /* One error. */ 5819 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5820 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5821 *tl++ = txdr_unsigned(stat); 5822 *tl++ = txdr_unsigned(op); 5823 } else { 5824 *tl = txdr_unsigned(2 * NFSX_UNSIGNED); 5825 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5826 /* No ioerrs. */ 5827 *tl++ = 0; 5828 } 5829 *tl = 0; /* No stats yet. */ 5830 } 5831 } 5832 nd->nd_flag |= ND_USEGSSNAME; 5833 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5834 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5835 if (error != 0) 5836 return (error); 5837 if (nd->nd_repstat == 0) { 5838 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5839 if (*tl != 0) { 5840 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5841 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5842 stateidp->other[0] = *tl++; 5843 stateidp->other[1] = *tl++; 5844 stateidp->other[2] = *tl; 5845 } 5846 } else 5847 error = nd->nd_repstat; 5848 nfsmout: 5849 m_freem(nd->nd_mrep); 5850 return (error); 5851 } 5852 5853 /* 5854 * Do the NFSv4.2 LayoutError. 5855 */ 5856 static int 5857 nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset, 5858 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5859 uint32_t stat, uint32_t op, char *devid) 5860 { 5861 uint32_t *tl; 5862 struct nfsrv_descript nfsd, *nd = &nfsd; 5863 int error; 5864 5865 nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL, 5866 0, 0, cred); 5867 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5868 NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5869 txdr_hyper(offset, tl); tl += 2; 5870 txdr_hyper(len, tl); tl += 2; 5871 *tl++ = txdr_unsigned(stateidp->seqid); 5872 *tl++ = stateidp->other[0]; 5873 *tl++ = stateidp->other[1]; 5874 *tl++ = stateidp->other[2]; 5875 *tl++ = txdr_unsigned(1); 5876 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5877 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5878 *tl++ = txdr_unsigned(stat); 5879 *tl = txdr_unsigned(op); 5880 nd->nd_flag |= ND_USEGSSNAME; 5881 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5882 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5883 if (error != 0) 5884 return (error); 5885 if (nd->nd_repstat != 0) 5886 error = nd->nd_repstat; 5887 m_freem(nd->nd_mrep); 5888 return (error); 5889 } 5890 5891 /* 5892 * Acquire a layout and devinfo, if possible. The caller must have acquired 5893 * a reference count on the nfsclclient structure before calling this. 5894 * Return the layout in lypp with a reference count on it, if successful. 5895 */ 5896 static int 5897 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 5898 int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, 5899 uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 5900 { 5901 struct nfscllayout *lyp; 5902 struct nfsclflayout *flp; 5903 struct nfsclflayouthead flh; 5904 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose; 5905 nfsv4stateid_t stateid; 5906 struct nfsclsession *tsep; 5907 5908 *lypp = NULL; 5909 if (NFSHASFLEXFILE(nmp)) 5910 layouttype = NFSLAYOUT_FLEXFILE; 5911 else 5912 layouttype = NFSLAYOUT_NFSV4_1_FILES; 5913 /* 5914 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 5915 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 5916 * flp == NULL. 5917 */ 5918 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 5919 off, rw, &flp, &recalled); 5920 islocked = 0; 5921 if (lyp == NULL || flp == NULL) { 5922 if (recalled != 0) 5923 return (EIO); 5924 LIST_INIT(&flh); 5925 tsep = nfsmnt_mdssession(nmp); 5926 layoutlen = tsep->nfsess_maxcache - 5927 (NFSX_STATEID + 3 * NFSX_UNSIGNED); 5928 if (lyp == NULL) { 5929 stateid.seqid = 0; 5930 stateid.other[0] = stateidp->other[0]; 5931 stateid.other[1] = stateidp->other[1]; 5932 stateid.other[2] = stateidp->other[2]; 5933 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5934 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, 5935 (uint64_t)0, layouttype, layoutlen, &stateid, 5936 &retonclose, &flh, cred, p); 5937 } else { 5938 islocked = 1; 5939 stateid.seqid = lyp->nfsly_stateid.seqid; 5940 stateid.other[0] = lyp->nfsly_stateid.other[0]; 5941 stateid.other[1] = lyp->nfsly_stateid.other[1]; 5942 stateid.other[2] = lyp->nfsly_stateid.other[2]; 5943 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5944 nfhp->nfh_len, iomode, off, UINT64_MAX, 5945 (uint64_t)0, layouttype, layoutlen, &stateid, 5946 &retonclose, &flh, cred, p); 5947 } 5948 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, 5949 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, 5950 &flh, layouttype, error, NULL, cred, p); 5951 if (error == 0) 5952 *lypp = lyp; 5953 else if (islocked != 0) 5954 nfscl_rellayout(lyp, 1); 5955 } else 5956 *lypp = lyp; 5957 return (error); 5958 } 5959 5960 /* 5961 * Do a TCP connection plus exchange id and create session. 5962 * If successful, a "struct nfsclds" is linked into the list for the 5963 * mount point and a pointer to it is returned. 5964 */ 5965 static int 5966 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin, 5967 struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers, 5968 struct nfsclds **dspp, NFSPROC_T *p) 5969 { 5970 struct sockaddr_in *msad, *sad; 5971 struct sockaddr_in6 *msad6, *sad6; 5972 struct nfsclclient *clp; 5973 struct nfssockreq *nrp; 5974 struct nfsclds *dsp, *tdsp; 5975 int error, firsttry; 5976 enum nfsclds_state retv; 5977 uint32_t sequenceid = 0; 5978 5979 KASSERT(nmp->nm_sockreq.nr_cred != NULL, 5980 ("nfsrpc_fillsa: NULL nr_cred")); 5981 NFSLOCKCLSTATE(); 5982 clp = nmp->nm_clp; 5983 NFSUNLOCKCLSTATE(); 5984 if (clp == NULL) 5985 return (EPERM); 5986 if (af == AF_INET) { 5987 NFSLOCKMNT(nmp); 5988 /* 5989 * Check to see if we already have a session for this 5990 * address that is usable for a DS. 5991 * Note that the MDS's address is in a different place 5992 * than the sessions already acquired for DS's. 5993 */ 5994 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 5995 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5996 while (tdsp != NULL) { 5997 if (msad != NULL && msad->sin_family == AF_INET && 5998 sin->sin_addr.s_addr == msad->sin_addr.s_addr && 5999 sin->sin_port == msad->sin_port && 6000 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 6001 tdsp->nfsclds_sess.nfsess_defunct == 0) { 6002 *dspp = tdsp; 6003 NFSUNLOCKMNT(nmp); 6004 NFSCL_DEBUG(4, "fnd same addr\n"); 6005 return (0); 6006 } 6007 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 6008 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 6009 msad = (struct sockaddr_in *) 6010 tdsp->nfsclds_sockp->nr_nam; 6011 else 6012 msad = NULL; 6013 } 6014 NFSUNLOCKMNT(nmp); 6015 6016 /* No IP address match, so look for new/trunked one. */ 6017 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 6018 sad->sin_len = sizeof(*sad); 6019 sad->sin_family = AF_INET; 6020 sad->sin_port = sin->sin_port; 6021 sad->sin_addr.s_addr = sin->sin_addr.s_addr; 6022 if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) { 6023 /* For pNFS, a separate server principal is needed. */ 6024 nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST, 6025 M_NFSSOCKREQ, M_WAITOK | M_ZERO); 6026 /* 6027 * Use the latter part of nr_srvprinc as a temporary 6028 * buffer for the IP address. 6029 */ 6030 inet_ntoa_r(sad->sin_addr, 6031 &nrp->nr_srvprinc[NI_MAXSERV]); 6032 NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n", 6033 &nrp->nr_srvprinc[NI_MAXSERV]); 6034 if (!rpc_gss_ip_to_srv_principal_call( 6035 &nrp->nr_srvprinc[NI_MAXSERV], "nfs", 6036 nrp->nr_srvprinc)) 6037 nrp->nr_srvprinc[0] = '\0'; 6038 NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n", 6039 nrp->nr_srvprinc); 6040 } else 6041 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, 6042 M_WAITOK | M_ZERO); 6043 nrp->nr_nam = (struct sockaddr *)sad; 6044 } else if (af == AF_INET6) { 6045 NFSLOCKMNT(nmp); 6046 /* 6047 * Check to see if we already have a session for this 6048 * address that is usable for a DS. 6049 * Note that the MDS's address is in a different place 6050 * than the sessions already acquired for DS's. 6051 */ 6052 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 6053 tdsp = TAILQ_FIRST(&nmp->nm_sess); 6054 while (tdsp != NULL) { 6055 if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 6056 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 6057 &msad6->sin6_addr) && 6058 sin6->sin6_port == msad6->sin6_port && 6059 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 6060 tdsp->nfsclds_sess.nfsess_defunct == 0) { 6061 *dspp = tdsp; 6062 NFSUNLOCKMNT(nmp); 6063 return (0); 6064 } 6065 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 6066 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 6067 msad6 = (struct sockaddr_in6 *) 6068 tdsp->nfsclds_sockp->nr_nam; 6069 else 6070 msad6 = NULL; 6071 } 6072 NFSUNLOCKMNT(nmp); 6073 6074 /* No IP address match, so look for new/trunked one. */ 6075 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 6076 sad6->sin6_len = sizeof(*sad6); 6077 sad6->sin6_family = AF_INET6; 6078 sad6->sin6_port = sin6->sin6_port; 6079 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr, 6080 sizeof(struct in6_addr)); 6081 if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) { 6082 /* For pNFS, a separate server principal is needed. */ 6083 nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST, 6084 M_NFSSOCKREQ, M_WAITOK | M_ZERO); 6085 /* 6086 * Use the latter part of nr_srvprinc as a temporary 6087 * buffer for the IP address. 6088 */ 6089 inet_ntop(AF_INET6, &sad6->sin6_addr, 6090 &nrp->nr_srvprinc[NI_MAXSERV], NI_MAXHOST); 6091 NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n", 6092 &nrp->nr_srvprinc[NI_MAXSERV]); 6093 if (!rpc_gss_ip_to_srv_principal_call( 6094 &nrp->nr_srvprinc[NI_MAXSERV], "nfs", 6095 nrp->nr_srvprinc)) 6096 nrp->nr_srvprinc[0] = '\0'; 6097 NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n", 6098 nrp->nr_srvprinc); 6099 } else 6100 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, 6101 M_WAITOK | M_ZERO); 6102 nrp->nr_nam = (struct sockaddr *)sad6; 6103 } else 6104 return (EPERM); 6105 6106 nrp->nr_sotype = SOCK_STREAM; 6107 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 6108 nrp->nr_prog = NFS_PROG; 6109 nrp->nr_vers = vers; 6110 6111 /* 6112 * Use the credentials that were used for the mount, which are 6113 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 6114 * Ref. counting the credentials with crhold() is probably not 6115 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 6116 * unmount, but I did it anyhow. 6117 */ 6118 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 6119 error = newnfs_connect(nmp, nrp, NULL, p, 0, false, &nrp->nr_client); 6120 NFSCL_DEBUG(3, "DS connect=%d\n", error); 6121 6122 dsp = NULL; 6123 /* Now, do the exchangeid and create session. */ 6124 if (error == 0) { 6125 if (vers == NFS_VER4) { 6126 firsttry = 0; 6127 do { 6128 error = nfsrpc_exchangeid(nmp, clp, nrp, 6129 minorvers, NFSV4EXCH_USEPNFSDS, &dsp, 6130 nrp->nr_cred, p); 6131 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 6132 if (error == NFSERR_MINORVERMISMATCH) 6133 minorvers = NFSV42_MINORVERSION; 6134 } while (error == NFSERR_MINORVERMISMATCH && 6135 firsttry++ == 0); 6136 if (error != 0) 6137 newnfs_disconnect(NULL, nrp); 6138 } else { 6139 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, 6140 M_WAITOK | M_ZERO); 6141 dsp->nfsclds_flags |= NFSCLDS_DS; 6142 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */ 6143 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 6144 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 6145 NULL, MTX_DEF); 6146 } 6147 } 6148 if (error == 0) { 6149 dsp->nfsclds_sockp = nrp; 6150 if (vers == NFS_VER4) { 6151 NFSLOCKMNT(nmp); 6152 retv = nfscl_getsameserver(nmp, dsp, &tdsp, 6153 &sequenceid); 6154 NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 6155 if (retv == NFSDSP_USETHISSESSION && 6156 nfscl_dssameconn != 0) { 6157 NFSLOCKDS(tdsp); 6158 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN; 6159 NFSUNLOCKDS(tdsp); 6160 NFSUNLOCKMNT(nmp); 6161 /* 6162 * If there is already a session for this 6163 * server, use it. 6164 */ 6165 newnfs_disconnect(NULL, nrp); 6166 nfscl_freenfsclds(dsp); 6167 *dspp = tdsp; 6168 return (0); 6169 } 6170 if (retv == NFSDSP_NOTFOUND) 6171 sequenceid = 6172 dsp->nfsclds_sess.nfsess_sequenceid; 6173 NFSUNLOCKMNT(nmp); 6174 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 6175 nrp, dsp, sequenceid, 0, nrp->nr_cred, p); 6176 NFSCL_DEBUG(3, "DS createsess=%d\n", error); 6177 } 6178 } else { 6179 NFSFREECRED(nrp->nr_cred); 6180 NFSFREEMUTEX(&nrp->nr_mtx); 6181 free(nrp->nr_nam, M_SONAME); 6182 free(nrp, M_NFSSOCKREQ); 6183 } 6184 if (error == 0) { 6185 NFSCL_DEBUG(3, "add DS session\n"); 6186 /* 6187 * Put it at the end of the list. That way the list 6188 * is ordered by when the entry was added. This matters 6189 * since the one done first is the one that should be 6190 * used for sequencid'ing any subsequent create sessions. 6191 */ 6192 NFSLOCKMNT(nmp); 6193 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 6194 NFSUNLOCKMNT(nmp); 6195 *dspp = dsp; 6196 } else if (dsp != NULL) { 6197 newnfs_disconnect(NULL, nrp); 6198 nfscl_freenfsclds(dsp); 6199 } 6200 return (error); 6201 } 6202 6203 /* 6204 * Do the NFSv4.1 Reclaim Complete. 6205 */ 6206 int 6207 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 6208 { 6209 uint32_t *tl; 6210 struct nfsrv_descript nfsd; 6211 struct nfsrv_descript *nd = &nfsd; 6212 int error; 6213 6214 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0, 6215 0, cred); 6216 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6217 *tl = newnfs_false; 6218 nd->nd_flag |= ND_USEGSSNAME; 6219 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 6220 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 6221 if (error != 0) 6222 return (error); 6223 error = nd->nd_repstat; 6224 m_freem(nd->nd_mrep); 6225 return (error); 6226 } 6227 6228 /* 6229 * Initialize the slot tables for a session. 6230 */ 6231 static void 6232 nfscl_initsessionslots(struct nfsclsession *sep) 6233 { 6234 int i; 6235 6236 for (i = 0; i < NFSV4_CBSLOTS; i++) { 6237 if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 6238 m_freem(sep->nfsess_cbslots[i].nfssl_reply); 6239 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 6240 } 6241 for (i = 0; i < 64; i++) 6242 sep->nfsess_slotseq[i] = 0; 6243 sep->nfsess_slots = 0; 6244 sep->nfsess_badslots = 0; 6245 } 6246 6247 /* 6248 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 6249 */ 6250 int 6251 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6252 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) 6253 { 6254 struct nfsnode *np = VTONFS(vp); 6255 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6256 struct nfscllayout *layp; 6257 struct nfscldevinfo *dip; 6258 struct nfsclflayout *rflp; 6259 struct mbuf *m, *m2; 6260 struct nfsclwritedsdorpc *drpc, *tdrpc; 6261 nfsv4stateid_t stateid; 6262 struct ucred *newcred; 6263 uint64_t lastbyte, len, off, oresid, xfer; 6264 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo; 6265 void *lckp; 6266 uint8_t *dev; 6267 void *iovbase = NULL; 6268 size_t iovlen = 0; 6269 off_t offs = 0; 6270 ssize_t resid = 0; 6271 uint32_t op; 6272 6273 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 6274 (np->n_flag & NNOLAYOUT) != 0) 6275 return (EIO); 6276 /* Now, get a reference cnt on the clientid for this mount. */ 6277 if (nfscl_getref(nmp) == 0) 6278 return (EIO); 6279 6280 /* Find an appropriate stateid. */ 6281 newcred = NFSNEWCRED(cred); 6282 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 6283 rwaccess, 1, newcred, p, &stateid, &lckp); 6284 if (error != 0) { 6285 NFSFREECRED(newcred); 6286 nfscl_relref(nmp); 6287 return (error); 6288 } 6289 /* Search for a layout for this file. */ 6290 off = uiop->uio_offset; 6291 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 6292 np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled); 6293 if (layp == NULL || rflp == NULL) { 6294 if (recalled != 0) { 6295 NFSFREECRED(newcred); 6296 if (lckp != NULL) 6297 nfscl_lockderef(lckp); 6298 nfscl_relref(nmp); 6299 return (EIO); 6300 } 6301 if (layp != NULL) { 6302 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 6303 layp = NULL; 6304 } 6305 /* Try and get a Layout, if it is supported. */ 6306 if (rwaccess == NFSV4OPEN_ACCESSWRITE || 6307 (np->n_flag & NWRITEOPENED) != 0) 6308 iolaymode = NFSLAYOUTIOMODE_RW; 6309 else 6310 iolaymode = NFSLAYOUTIOMODE_READ; 6311 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 6312 rwaccess, NULL, &stateid, off, &layp, newcred, p); 6313 if (error != 0) { 6314 NFSLOCKNODE(np); 6315 np->n_flag |= NNOLAYOUT; 6316 NFSUNLOCKNODE(np); 6317 if (lckp != NULL) 6318 nfscl_lockderef(lckp); 6319 NFSFREECRED(newcred); 6320 if (layp != NULL) 6321 nfscl_rellayout(layp, 0); 6322 nfscl_relref(nmp); 6323 return (error); 6324 } 6325 } 6326 6327 /* 6328 * Loop around finding a layout that works for the first part of 6329 * this I/O operation, and then call the function that actually 6330 * does the RPC. 6331 */ 6332 eof = 0; 6333 len = (uint64_t)uiop->uio_resid; 6334 while (len > 0 && error == 0 && eof == 0) { 6335 off = uiop->uio_offset; 6336 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 6337 if (error == 0) { 6338 oresid = xfer = (uint64_t)uiop->uio_resid; 6339 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 6340 xfer = rflp->nfsfl_end - rflp->nfsfl_off; 6341 /* 6342 * For Flex File layout with mirrored DSs, select one 6343 * of them at random for reads. For writes and commits, 6344 * do all mirrors. 6345 */ 6346 m = NULL; 6347 tdrpc = drpc = NULL; 6348 firstmirror = 0; 6349 mirrorcnt = 1; 6350 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 && 6351 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) { 6352 if (rwaccess == NFSV4OPEN_ACCESSREAD) { 6353 firstmirror = arc4random() % mirrorcnt; 6354 mirrorcnt = firstmirror + 1; 6355 } else { 6356 if (docommit == 0) { 6357 /* 6358 * Save values, so uiop can be 6359 * rolled back upon a write 6360 * error. 6361 */ 6362 offs = uiop->uio_offset; 6363 resid = uiop->uio_resid; 6364 iovbase = 6365 uiop->uio_iov->iov_base; 6366 iovlen = uiop->uio_iov->iov_len; 6367 m = nfsm_uiombuflist(uiop, len, 6368 0); 6369 if (m == NULL) { 6370 error = EFAULT; 6371 break; 6372 } 6373 } 6374 tdrpc = drpc = malloc(sizeof(*drpc) * 6375 (mirrorcnt - 1), M_TEMP, M_WAITOK | 6376 M_ZERO); 6377 } 6378 } 6379 for (i = firstmirror; i < mirrorcnt && error == 0; i++){ 6380 m2 = NULL; 6381 if (m != NULL && i < mirrorcnt - 1) 6382 m2 = m_copym(m, 0, M_COPYALL, M_WAITOK); 6383 else { 6384 m2 = m; 6385 m = NULL; 6386 } 6387 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { 6388 dev = rflp->nfsfl_ffm[i].dev; 6389 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6390 rflp->nfsfl_ffm[i].devp); 6391 } else { 6392 dev = rflp->nfsfl_dev; 6393 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6394 rflp->nfsfl_devp); 6395 } 6396 if (dip != NULL) { 6397 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE) 6398 != 0) 6399 error = nfscl_dofflayoutio(vp, 6400 uiop, iomode, must_commit, 6401 &eof, &stateid, rwaccess, 6402 dip, layp, rflp, off, xfer, 6403 i, docommit, m2, tdrpc, 6404 newcred, p); 6405 else 6406 error = nfscl_doflayoutio(vp, 6407 uiop, iomode, must_commit, 6408 &eof, &stateid, rwaccess, 6409 dip, layp, rflp, off, xfer, 6410 docommit, newcred, p); 6411 nfscl_reldevinfo(dip); 6412 } else { 6413 if (m2 != NULL) 6414 m_freem(m2); 6415 error = EIO; 6416 } 6417 tdrpc++; 6418 } 6419 if (m != NULL) 6420 m_freem(m); 6421 tdrpc = drpc; 6422 timo = hz / 50; /* Wait for 20msec. */ 6423 if (timo < 1) 6424 timo = 1; 6425 for (i = firstmirror; i < mirrorcnt - 1 && 6426 tdrpc != NULL; i++, tdrpc++) { 6427 /* 6428 * For the unused drpc entries, both inprog and 6429 * err == 0, so this loop won't break. 6430 */ 6431 while (tdrpc->inprog != 0 && tdrpc->done == 0) 6432 tsleep(&tdrpc->tsk, PVFS, "clrpcio", 6433 timo); 6434 if (error == 0 && tdrpc->err != 0) 6435 error = tdrpc->err; 6436 if (rwaccess != NFSV4OPEN_ACCESSREAD && 6437 docommit == 0 && *must_commit == 0 && 6438 tdrpc->must_commit == 1) 6439 *must_commit = 1; 6440 } 6441 free(drpc, M_TEMP); 6442 if (error == 0) { 6443 if (mirrorcnt > 1 && rwaccess == 6444 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6445 NFSLOCKCLSTATE(); 6446 layp->nfsly_flags |= NFSLY_WRITTEN; 6447 NFSUNLOCKCLSTATE(); 6448 } 6449 lastbyte = off + xfer - 1; 6450 NFSLOCKCLSTATE(); 6451 if (lastbyte > layp->nfsly_lastbyte) 6452 layp->nfsly_lastbyte = lastbyte; 6453 NFSUNLOCKCLSTATE(); 6454 } else if (error == NFSERR_OPENMODE && 6455 rwaccess == NFSV4OPEN_ACCESSREAD) { 6456 NFSLOCKMNT(nmp); 6457 nmp->nm_state |= NFSSTA_OPENMODE; 6458 NFSUNLOCKMNT(nmp); 6459 } else if ((error == NFSERR_NOSPC || 6460 error == NFSERR_IO || error == NFSERR_NXIO) && 6461 nmp->nm_minorvers == NFSV42_MINORVERSION) { 6462 if (docommit != 0) 6463 op = NFSV4OP_COMMIT; 6464 else if (rwaccess == NFSV4OPEN_ACCESSREAD) 6465 op = NFSV4OP_READ; 6466 else 6467 op = NFSV4OP_WRITE; 6468 nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh, 6469 np->n_fhp->nfh_len, off, xfer, 6470 &layp->nfsly_stateid, newcred, p, error, op, 6471 dip->nfsdi_deviceid); 6472 error = EIO; 6473 } else 6474 error = EIO; 6475 if (error == 0) 6476 len -= (oresid - (uint64_t)uiop->uio_resid); 6477 else if (mirrorcnt > 1 && rwaccess == 6478 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6479 /* 6480 * In case the rpc gets retried, roll the 6481 * uio fields changed by nfsm_uiombuflist() 6482 * back. 6483 */ 6484 uiop->uio_offset = offs; 6485 uiop->uio_resid = resid; 6486 uiop->uio_iov->iov_base = iovbase; 6487 uiop->uio_iov->iov_len = iovlen; 6488 } 6489 } 6490 } 6491 if (lckp != NULL) 6492 nfscl_lockderef(lckp); 6493 NFSFREECRED(newcred); 6494 nfscl_rellayout(layp, 0); 6495 nfscl_relref(nmp); 6496 return (error); 6497 } 6498 6499 /* 6500 * Find a file layout that will handle the first bytes of the requested 6501 * range and return the information from it needed to the I/O operation. 6502 */ 6503 int 6504 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 6505 struct nfsclflayout **retflpp) 6506 { 6507 struct nfsclflayout *flp, *nflp, *rflp; 6508 uint32_t rw; 6509 6510 rflp = NULL; 6511 rw = rwaccess; 6512 /* For reading, do the Read list first and then the Write list. */ 6513 do { 6514 if (rw == NFSV4OPEN_ACCESSREAD) 6515 flp = LIST_FIRST(&lyp->nfsly_flayread); 6516 else 6517 flp = LIST_FIRST(&lyp->nfsly_flayrw); 6518 while (flp != NULL) { 6519 nflp = LIST_NEXT(flp, nfsfl_list); 6520 if (flp->nfsfl_off > off) 6521 break; 6522 if (flp->nfsfl_end > off && 6523 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 6524 rflp = flp; 6525 flp = nflp; 6526 } 6527 if (rw == NFSV4OPEN_ACCESSREAD) 6528 rw = NFSV4OPEN_ACCESSWRITE; 6529 else 6530 rw = 0; 6531 } while (rw != 0); 6532 if (rflp != NULL) { 6533 /* This one covers the most bytes starting at off. */ 6534 *retflpp = rflp; 6535 return (0); 6536 } 6537 return (EIO); 6538 } 6539 6540 /* 6541 * Do I/O using an NFSv4.1 or NFSv4.2 file layout. 6542 */ 6543 static int 6544 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6545 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6546 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6547 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) 6548 { 6549 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 6550 int commit_thru_mds, error, stripe_index, stripe_pos, minorvers; 6551 struct nfsnode *np; 6552 struct nfsfh *fhp; 6553 struct nfsclds **dspp; 6554 6555 np = VTONFS(vp); 6556 rel_off = off - flp->nfsfl_patoff; 6557 stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK; 6558 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 6559 dp->nfsdi_stripecnt; 6560 transfer = stripe_unit_size - (rel_off % stripe_unit_size); 6561 error = 0; 6562 6563 /* Loop around, doing I/O for each stripe unit. */ 6564 while (len > 0 && error == 0) { 6565 stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 6566 dspp = nfsfldi_addr(dp, stripe_index); 6567 if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0) 6568 minorvers = NFSV42_MINORVERSION; 6569 else 6570 minorvers = NFSV41_MINORVERSION; 6571 if (len > transfer && docommit == 0) 6572 xfer = transfer; 6573 else 6574 xfer = len; 6575 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 6576 /* Dense layout. */ 6577 if (stripe_pos >= flp->nfsfl_fhcnt) 6578 return (EIO); 6579 fhp = flp->nfsfl_fh[stripe_pos]; 6580 io_off = (rel_off / (stripe_unit_size * 6581 dp->nfsdi_stripecnt)) * stripe_unit_size + 6582 rel_off % stripe_unit_size; 6583 } else { 6584 /* Sparse layout. */ 6585 if (flp->nfsfl_fhcnt > 1) { 6586 if (stripe_index >= flp->nfsfl_fhcnt) 6587 return (EIO); 6588 fhp = flp->nfsfl_fh[stripe_index]; 6589 } else if (flp->nfsfl_fhcnt == 1) 6590 fhp = flp->nfsfl_fh[0]; 6591 else 6592 fhp = np->n_fhp; 6593 io_off = off; 6594 } 6595 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { 6596 commit_thru_mds = 1; 6597 if (docommit != 0) 6598 error = EIO; 6599 } else { 6600 commit_thru_mds = 0; 6601 NFSLOCKNODE(np); 6602 np->n_flag |= NDSCOMMIT; 6603 NFSUNLOCKNODE(np); 6604 } 6605 if (docommit != 0) { 6606 if (error == 0) 6607 error = nfsrpc_commitds(vp, io_off, xfer, 6608 *dspp, fhp, NFS_VER4, minorvers, cred, p); 6609 if (error == 0) { 6610 /* 6611 * Set both eof and uio_resid = 0 to end any 6612 * loops. 6613 */ 6614 *eofp = 1; 6615 uiop->uio_resid = 0; 6616 } else { 6617 NFSLOCKNODE(np); 6618 np->n_flag &= ~NDSCOMMIT; 6619 NFSUNLOCKNODE(np); 6620 } 6621 } else if (rwflag == NFSV4OPEN_ACCESSREAD) 6622 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6623 io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p); 6624 else { 6625 error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 6626 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 6627 0, NFS_VER4, minorvers, cred, p); 6628 if (error == 0) { 6629 NFSLOCKCLSTATE(); 6630 lyp->nfsly_flags |= NFSLY_WRITTEN; 6631 NFSUNLOCKCLSTATE(); 6632 } 6633 } 6634 if (error == 0) { 6635 transfer = stripe_unit_size; 6636 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 6637 len -= xfer; 6638 off += xfer; 6639 } 6640 } 6641 return (error); 6642 } 6643 6644 /* 6645 * Do I/O using an NFSv4.1 flex file layout. 6646 */ 6647 static int 6648 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6649 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6650 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6651 uint64_t len, int mirror, int docommit, struct mbuf *mp, 6652 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6653 { 6654 uint64_t xfer; 6655 int error; 6656 struct nfsnode *np; 6657 struct nfsfh *fhp; 6658 struct nfsclds **dspp; 6659 struct ucred *tcred; 6660 struct mbuf *m, *m2; 6661 uint32_t copylen; 6662 6663 np = VTONFS(vp); 6664 error = 0; 6665 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, 6666 (uintmax_t)len); 6667 /* Loop around, doing I/O for each stripe unit. */ 6668 while (len > 0 && error == 0) { 6669 dspp = nfsfldi_addr(dp, 0); 6670 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex]; 6671 stateidp = &flp->nfsfl_ffm[mirror].st; 6672 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n", 6673 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid); 6674 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) { 6675 tcred = NFSNEWCRED(cred); 6676 tcred->cr_uid = flp->nfsfl_ffm[mirror].user; 6677 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group; 6678 tcred->cr_ngroups = 1; 6679 } else 6680 tcred = cred; 6681 if (rwflag == NFSV4OPEN_ACCESSREAD) 6682 copylen = dp->nfsdi_rsize; 6683 else { 6684 copylen = dp->nfsdi_wsize; 6685 if (len > copylen && mp != NULL) { 6686 /* 6687 * When a mirrored configuration needs to do 6688 * multiple writes to each mirror, all writes 6689 * except the last one must be a multiple of 6690 * 4 bytes. This is required so that the XDR 6691 * does not need padding. 6692 * If possible, clip the size to an exact 6693 * multiple of the mbuf length, so that the 6694 * split will be on an mbuf boundary. 6695 */ 6696 copylen &= 0xfffffffc; 6697 if (copylen > mp->m_len) 6698 copylen = copylen / mp->m_len * 6699 mp->m_len; 6700 } 6701 } 6702 NFSLOCKNODE(np); 6703 np->n_flag |= NDSCOMMIT; 6704 NFSUNLOCKNODE(np); 6705 if (len > copylen && docommit == 0) 6706 xfer = copylen; 6707 else 6708 xfer = len; 6709 if (docommit != 0) { 6710 if (error == 0) { 6711 /* 6712 * Do last mirrored DS commit with this thread. 6713 */ 6714 if (mirror < flp->nfsfl_mirrorcnt - 1) 6715 error = nfsio_commitds(vp, off, xfer, 6716 *dspp, fhp, dp->nfsdi_vers, 6717 dp->nfsdi_minorvers, drpc, tcred, 6718 p); 6719 else 6720 error = nfsrpc_commitds(vp, off, xfer, 6721 *dspp, fhp, dp->nfsdi_vers, 6722 dp->nfsdi_minorvers, tcred, p); 6723 NFSCL_DEBUG(4, "commitds=%d\n", error); 6724 if (error != 0 && error != EACCES && error != 6725 ESTALE) { 6726 NFSCL_DEBUG(4, 6727 "DS layreterr for commit\n"); 6728 nfscl_dserr(NFSV4OP_COMMIT, error, dp, 6729 lyp, *dspp); 6730 } 6731 } 6732 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error); 6733 if (error == 0) { 6734 /* 6735 * Set both eof and uio_resid = 0 to end any 6736 * loops. 6737 */ 6738 *eofp = 1; 6739 uiop->uio_resid = 0; 6740 } else { 6741 NFSLOCKNODE(np); 6742 np->n_flag &= ~NDSCOMMIT; 6743 NFSUNLOCKNODE(np); 6744 } 6745 } else if (rwflag == NFSV4OPEN_ACCESSREAD) { 6746 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6747 off, xfer, fhp, 1, dp->nfsdi_vers, 6748 dp->nfsdi_minorvers, tcred, p); 6749 NFSCL_DEBUG(4, "readds=%d\n", error); 6750 if (error != 0 && error != EACCES && error != ESTALE) { 6751 NFSCL_DEBUG(4, "DS layreterr for read\n"); 6752 nfscl_dserr(NFSV4OP_READ, error, dp, lyp, 6753 *dspp); 6754 } 6755 } else { 6756 if (flp->nfsfl_mirrorcnt == 1) { 6757 error = nfsrpc_writeds(vp, uiop, iomode, 6758 must_commit, stateidp, *dspp, off, xfer, 6759 fhp, 0, 1, dp->nfsdi_vers, 6760 dp->nfsdi_minorvers, tcred, p); 6761 if (error == 0) { 6762 NFSLOCKCLSTATE(); 6763 lyp->nfsly_flags |= NFSLY_WRITTEN; 6764 NFSUNLOCKCLSTATE(); 6765 } 6766 } else { 6767 m = mp; 6768 if (xfer < len) { 6769 /* The mbuf list must be split. */ 6770 m2 = nfsm_split(mp, xfer); 6771 if (m2 != NULL) 6772 mp = m2; 6773 else { 6774 m_freem(mp); 6775 error = EIO; 6776 } 6777 } 6778 NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n", 6779 (uintmax_t)len, (uintmax_t)xfer); 6780 /* 6781 * Do last write to a mirrored DS with this 6782 * thread. 6783 */ 6784 if (error == 0) { 6785 if (mirror < flp->nfsfl_mirrorcnt - 1) 6786 error = nfsio_writedsmir(vp, 6787 iomode, must_commit, 6788 stateidp, *dspp, off, 6789 xfer, fhp, m, 6790 dp->nfsdi_vers, 6791 dp->nfsdi_minorvers, drpc, 6792 tcred, p); 6793 else 6794 error = nfsrpc_writedsmir(vp, 6795 iomode, must_commit, 6796 stateidp, *dspp, off, 6797 xfer, fhp, m, 6798 dp->nfsdi_vers, 6799 dp->nfsdi_minorvers, tcred, 6800 p); 6801 } 6802 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); 6803 if (error != 0 && error != EACCES && error != 6804 ESTALE) { 6805 NFSCL_DEBUG(4, 6806 "DS layreterr for write\n"); 6807 nfscl_dserr(NFSV4OP_WRITE, error, dp, 6808 lyp, *dspp); 6809 } 6810 } 6811 } 6812 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error); 6813 if (error == 0) { 6814 len -= xfer; 6815 off += xfer; 6816 } 6817 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) 6818 NFSFREECRED(tcred); 6819 } 6820 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error); 6821 return (error); 6822 } 6823 6824 /* 6825 * The actual read RPC done to a DS. 6826 */ 6827 static int 6828 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 6829 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex, 6830 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) 6831 { 6832 uint32_t *tl; 6833 int attrflag, error, retlen; 6834 struct nfsrv_descript nfsd; 6835 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6836 struct nfsrv_descript *nd = &nfsd; 6837 struct nfssockreq *nrp; 6838 struct nfsvattr na; 6839 6840 nd->nd_mrep = NULL; 6841 if (vers == 0 || vers == NFS_VER4) { 6842 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, 6843 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 6844 NULL); 6845 vers = NFS_VER4; 6846 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers); 6847 if (flex != 0) 6848 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6849 else 6850 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6851 } else { 6852 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh, 6853 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 6854 NULL); 6855 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]); 6856 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]); 6857 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n"); 6858 } 6859 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 6860 txdr_hyper(io_off, tl); 6861 *(tl + 2) = txdr_unsigned(len); 6862 nrp = dsp->nfsclds_sockp; 6863 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp); 6864 if (nrp == NULL) 6865 /* If NULL, use the MDS socket. */ 6866 nrp = &nmp->nm_sockreq; 6867 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6868 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6869 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat, 6870 error); 6871 if (error != 0) 6872 return (error); 6873 if (vers == NFS_VER3) { 6874 error = nfscl_postop_attr(nd, &na, &attrflag); 6875 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error); 6876 if (error != 0) 6877 goto nfsmout; 6878 } 6879 if (nd->nd_repstat != 0) { 6880 error = nd->nd_repstat; 6881 goto nfsmout; 6882 } 6883 if (vers == NFS_VER3) { 6884 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6885 *eofp = fxdr_unsigned(int, *(tl + 1)); 6886 } else { 6887 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6888 *eofp = fxdr_unsigned(int, *tl); 6889 } 6890 NFSM_STRSIZ(retlen, len); 6891 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp); 6892 error = nfsm_mbufuio(nd, uiop, retlen); 6893 nfsmout: 6894 if (nd->nd_mrep != NULL) 6895 m_freem(nd->nd_mrep); 6896 return (error); 6897 } 6898 6899 /* 6900 * The actual write RPC done to a DS. 6901 */ 6902 static int 6903 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6904 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6905 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers, 6906 struct ucred *cred, NFSPROC_T *p) 6907 { 6908 uint32_t *tl; 6909 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6910 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC; 6911 int32_t backup; 6912 struct nfsrv_descript nfsd; 6913 struct nfsrv_descript *nd = &nfsd; 6914 struct nfssockreq *nrp; 6915 struct nfsvattr na; 6916 6917 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 6918 nd->nd_mrep = NULL; 6919 if (vers == 0 || vers == NFS_VER4) { 6920 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6921 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 6922 NULL); 6923 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers); 6924 vers = NFS_VER4; 6925 if (flex != 0) 6926 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6927 else 6928 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6929 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6930 } else { 6931 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6932 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 6933 NULL); 6934 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 6935 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 6936 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n"); 6937 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6938 } 6939 txdr_hyper(io_off, tl); 6940 tl += 2; 6941 if (vers == NFS_VER3) 6942 *tl++ = txdr_unsigned(len); 6943 *tl++ = txdr_unsigned(*iomode); 6944 *tl = txdr_unsigned(len); 6945 error = nfsm_uiombuf(nd, uiop, len); 6946 if (error != 0) { 6947 m_freem(nd->nd_mreq); 6948 return (error); 6949 } 6950 nrp = dsp->nfsclds_sockp; 6951 if (nrp == NULL) 6952 /* If NULL, use the MDS socket. */ 6953 nrp = &nmp->nm_sockreq; 6954 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6955 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6956 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error, 6957 nd->nd_repstat); 6958 if (error != 0) 6959 return (error); 6960 if (nd->nd_repstat != 0) { 6961 /* 6962 * In case the rpc gets retried, roll 6963 * the uio fields changed by nfsm_uiombuf() 6964 * back. 6965 */ 6966 uiop->uio_offset -= len; 6967 uiop->uio_resid += len; 6968 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len; 6969 uiop->uio_iov->iov_len += len; 6970 error = nd->nd_repstat; 6971 } else { 6972 if (vers == NFS_VER3) { 6973 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6974 NULL); 6975 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error); 6976 if (error != 0) 6977 goto nfsmout; 6978 } 6979 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6980 rlen = fxdr_unsigned(int, *tl++); 6981 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen); 6982 if (rlen == 0) { 6983 error = NFSERR_IO; 6984 goto nfsmout; 6985 } else if (rlen < len) { 6986 backup = len - rlen; 6987 uiop->uio_iov->iov_base = 6988 (char *)uiop->uio_iov->iov_base - backup; 6989 uiop->uio_iov->iov_len += backup; 6990 uiop->uio_offset -= backup; 6991 uiop->uio_resid += backup; 6992 len = rlen; 6993 } 6994 commit = fxdr_unsigned(int, *tl++); 6995 6996 /* 6997 * Return the lowest commitment level 6998 * obtained by any of the RPCs. 6999 */ 7000 if (committed == NFSWRITE_FILESYNC) 7001 committed = commit; 7002 else if (committed == NFSWRITE_DATASYNC && 7003 commit == NFSWRITE_UNSTABLE) 7004 committed = commit; 7005 if (commit_thru_mds != 0) { 7006 NFSLOCKMNT(nmp); 7007 if (!NFSHASWRITEVERF(nmp)) { 7008 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 7009 NFSSETWRITEVERF(nmp); 7010 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) && 7011 *must_commit != 2) { 7012 *must_commit = 1; 7013 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 7014 } 7015 NFSUNLOCKMNT(nmp); 7016 } else { 7017 NFSLOCKDS(dsp); 7018 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 7019 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7020 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 7021 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && 7022 *must_commit != 2) { 7023 *must_commit = 1; 7024 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7025 } 7026 NFSUNLOCKDS(dsp); 7027 } 7028 } 7029 nfsmout: 7030 if (nd->nd_mrep != NULL) 7031 m_freem(nd->nd_mrep); 7032 *iomode = committed; 7033 if (nd->nd_repstat != 0 && error == 0) 7034 error = nd->nd_repstat; 7035 return (error); 7036 } 7037 7038 /* 7039 * The actual write RPC done to a DS. 7040 * This variant is called from a separate kernel process for mirrors. 7041 * Any short write is considered an IO error. 7042 */ 7043 static int 7044 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, 7045 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 7046 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 7047 struct ucred *cred, NFSPROC_T *p) 7048 { 7049 uint32_t *tl; 7050 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7051 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen; 7052 struct nfsrv_descript nfsd; 7053 struct nfsrv_descript *nd = &nfsd; 7054 struct nfssockreq *nrp; 7055 struct nfsvattr na; 7056 7057 nd->nd_mrep = NULL; 7058 if (vers == 0 || vers == NFS_VER4) { 7059 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 7060 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7061 NULL); 7062 vers = NFS_VER4; 7063 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n", 7064 minorvers); 7065 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 7066 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 7067 } else { 7068 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 7069 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7070 NULL); 7071 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 7072 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 7073 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n"); 7074 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 7075 } 7076 txdr_hyper(io_off, tl); 7077 tl += 2; 7078 if (vers == NFS_VER3) 7079 *tl++ = txdr_unsigned(len); 7080 *tl++ = txdr_unsigned(*iomode); 7081 *tl = txdr_unsigned(len); 7082 if (len > 0) { 7083 /* Put data in mbuf chain. */ 7084 nd->nd_mb->m_next = m; 7085 } 7086 nrp = dsp->nfsclds_sockp; 7087 if (nrp == NULL) 7088 /* If NULL, use the MDS socket. */ 7089 nrp = &nmp->nm_sockreq; 7090 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7091 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7092 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error, 7093 nd->nd_repstat); 7094 if (error != 0) 7095 return (error); 7096 if (nd->nd_repstat != 0) 7097 error = nd->nd_repstat; 7098 else { 7099 if (vers == NFS_VER3) { 7100 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 7101 NULL); 7102 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n", 7103 error); 7104 if (error != 0) 7105 goto nfsmout; 7106 } 7107 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 7108 rlen = fxdr_unsigned(int, *tl++); 7109 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, 7110 rlen); 7111 if (rlen != len) { 7112 error = NFSERR_IO; 7113 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", 7114 len, rlen); 7115 goto nfsmout; 7116 } 7117 commit = fxdr_unsigned(int, *tl++); 7118 7119 /* 7120 * Return the lowest commitment level 7121 * obtained by any of the RPCs. 7122 */ 7123 if (committed == NFSWRITE_FILESYNC) 7124 committed = commit; 7125 else if (committed == NFSWRITE_DATASYNC && 7126 commit == NFSWRITE_UNSTABLE) 7127 committed = commit; 7128 NFSLOCKDS(dsp); 7129 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 7130 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7131 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 7132 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && 7133 *must_commit != 2) { 7134 *must_commit = 1; 7135 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7136 } 7137 NFSUNLOCKDS(dsp); 7138 } 7139 nfsmout: 7140 if (nd->nd_mrep != NULL) 7141 m_freem(nd->nd_mrep); 7142 *iomode = committed; 7143 if (nd->nd_repstat != 0 && error == 0) 7144 error = nd->nd_repstat; 7145 return (error); 7146 } 7147 7148 /* 7149 * Start up the thread that will execute nfsrpc_writedsmir(). 7150 */ 7151 static void 7152 start_writedsmir(void *arg, int pending) 7153 { 7154 struct nfsclwritedsdorpc *drpc; 7155 7156 drpc = (struct nfsclwritedsdorpc *)arg; 7157 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode, 7158 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len, 7159 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred, 7160 drpc->p); 7161 drpc->done = 1; 7162 crfree(drpc->cred); 7163 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err); 7164 } 7165 7166 /* 7167 * Set up the write DS mirror call for the pNFS I/O thread. 7168 */ 7169 static int 7170 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit, 7171 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len, 7172 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 7173 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7174 { 7175 int error, ret; 7176 7177 error = 0; 7178 drpc->done = 0; 7179 drpc->vp = vp; 7180 drpc->iomode = *iomode; 7181 drpc->must_commit = *must_commit; 7182 drpc->stateidp = stateidp; 7183 drpc->dsp = dsp; 7184 drpc->off = off; 7185 drpc->len = len; 7186 drpc->fhp = fhp; 7187 drpc->m = m; 7188 drpc->vers = vers; 7189 drpc->minorvers = minorvers; 7190 drpc->cred = crhold(cred); 7191 drpc->p = p; 7192 drpc->inprog = 0; 7193 ret = EIO; 7194 if (nfs_pnfsiothreads != 0) { 7195 ret = nfs_pnfsio(start_writedsmir, drpc); 7196 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret); 7197 } 7198 if (ret != 0) { 7199 error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit, 7200 stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p); 7201 crfree(drpc->cred); 7202 } 7203 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error); 7204 return (error); 7205 } 7206 7207 /* 7208 * Free up the nfsclds structure. 7209 */ 7210 void 7211 nfscl_freenfsclds(struct nfsclds *dsp) 7212 { 7213 int i; 7214 7215 if (dsp == NULL) 7216 return; 7217 if (dsp->nfsclds_sockp != NULL) { 7218 NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 7219 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 7220 free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 7221 free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 7222 } 7223 NFSFREEMUTEX(&dsp->nfsclds_mtx); 7224 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 7225 for (i = 0; i < NFSV4_CBSLOTS; i++) { 7226 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 7227 m_freem( 7228 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 7229 } 7230 free(dsp, M_NFSCLDS); 7231 } 7232 7233 static enum nfsclds_state 7234 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 7235 struct nfsclds **retdspp, uint32_t *sequencep) 7236 { 7237 struct nfsclds *dsp; 7238 int fndseq; 7239 7240 /* 7241 * Search the list of nfsclds structures for one with the same 7242 * server. 7243 */ 7244 fndseq = 0; 7245 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 7246 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 7247 dsp->nfsclds_servownlen != 0 && 7248 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 7249 dsp->nfsclds_servownlen) && 7250 dsp->nfsclds_sess.nfsess_defunct == 0) { 7251 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 7252 TAILQ_FIRST(&nmp->nm_sess), dsp, 7253 dsp->nfsclds_flags); 7254 if (fndseq == 0) { 7255 /* Get sequenceid# from first entry. */ 7256 *sequencep = 7257 dsp->nfsclds_sess.nfsess_sequenceid; 7258 fndseq = 1; 7259 } 7260 /* Server major id matches. */ 7261 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 7262 *retdspp = dsp; 7263 return (NFSDSP_USETHISSESSION); 7264 } 7265 } 7266 } 7267 if (fndseq != 0) 7268 return (NFSDSP_SEQTHISSESSION); 7269 return (NFSDSP_NOTFOUND); 7270 } 7271 7272 /* 7273 * NFS commit rpc to a NFSv4.1 DS. 7274 */ 7275 static int 7276 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7277 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, 7278 NFSPROC_T *p) 7279 { 7280 uint32_t *tl; 7281 struct nfsrv_descript nfsd, *nd = &nfsd; 7282 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7283 struct nfssockreq *nrp; 7284 struct nfsvattr na; 7285 int attrflag, error; 7286 7287 nd->nd_mrep = NULL; 7288 if (vers == 0 || vers == NFS_VER4) { 7289 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, 7290 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7291 NULL); 7292 vers = NFS_VER4; 7293 } else { 7294 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh, 7295 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7296 NULL); 7297 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]); 7298 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]); 7299 } 7300 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers, 7301 minorvers); 7302 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7303 txdr_hyper(offset, tl); 7304 tl += 2; 7305 *tl = txdr_unsigned(cnt); 7306 nrp = dsp->nfsclds_sockp; 7307 if (nrp == NULL) 7308 /* If NULL, use the MDS socket. */ 7309 nrp = &nmp->nm_sockreq; 7310 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7311 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7312 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error, 7313 nd->nd_repstat); 7314 if (error != 0) 7315 return (error); 7316 if (nd->nd_repstat == 0) { 7317 if (vers == NFS_VER3) { 7318 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 7319 NULL); 7320 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error); 7321 if (error != 0) 7322 goto nfsmout; 7323 } 7324 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 7325 NFSLOCKDS(dsp); 7326 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 7327 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7328 error = NFSERR_STALEWRITEVERF; 7329 } 7330 NFSUNLOCKDS(dsp); 7331 } 7332 nfsmout: 7333 if (error == 0 && nd->nd_repstat != 0) 7334 error = nd->nd_repstat; 7335 m_freem(nd->nd_mrep); 7336 return (error); 7337 } 7338 7339 /* 7340 * Start up the thread that will execute nfsrpc_commitds(). 7341 */ 7342 static void 7343 start_commitds(void *arg, int pending) 7344 { 7345 struct nfsclwritedsdorpc *drpc; 7346 7347 drpc = (struct nfsclwritedsdorpc *)arg; 7348 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len, 7349 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, 7350 drpc->p); 7351 drpc->done = 1; 7352 crfree(drpc->cred); 7353 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err); 7354 } 7355 7356 /* 7357 * Set up the commit DS mirror call for the pNFS I/O thread. 7358 */ 7359 static int 7360 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7361 struct nfsfh *fhp, int vers, int minorvers, 7362 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7363 { 7364 int error, ret; 7365 7366 error = 0; 7367 drpc->done = 0; 7368 drpc->vp = vp; 7369 drpc->off = offset; 7370 drpc->len = cnt; 7371 drpc->dsp = dsp; 7372 drpc->fhp = fhp; 7373 drpc->vers = vers; 7374 drpc->minorvers = minorvers; 7375 drpc->cred = crhold(cred); 7376 drpc->p = p; 7377 drpc->inprog = 0; 7378 ret = EIO; 7379 if (nfs_pnfsiothreads != 0) { 7380 ret = nfs_pnfsio(start_commitds, drpc); 7381 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret); 7382 } 7383 if (ret != 0) { 7384 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers, 7385 minorvers, cred, p); 7386 crfree(drpc->cred); 7387 } 7388 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error); 7389 return (error); 7390 } 7391 7392 /* 7393 * NFS Advise rpc 7394 */ 7395 int 7396 nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise, 7397 struct ucred *cred, NFSPROC_T *p) 7398 { 7399 u_int32_t *tl; 7400 struct nfsrv_descript nfsd, *nd = &nfsd; 7401 nfsattrbit_t hints; 7402 int error; 7403 7404 NFSZERO_ATTRBIT(&hints); 7405 if (advise == POSIX_FADV_WILLNEED) 7406 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7407 else if (advise == POSIX_FADV_DONTNEED) 7408 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7409 else 7410 return (0); 7411 NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp, cred); 7412 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7413 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER); 7414 txdr_hyper(offset, tl); 7415 tl += 2; 7416 txdr_hyper(cnt, tl); 7417 nfsrv_putattrbit(nd, &hints); 7418 error = nfscl_request(nd, vp, p, cred); 7419 if (error != 0) 7420 return (error); 7421 if (nd->nd_repstat != 0) 7422 error = nd->nd_repstat; 7423 m_freem(nd->nd_mrep); 7424 return (error); 7425 } 7426 7427 #ifdef notyet 7428 /* 7429 * NFS advise rpc to a NFSv4.2 DS. 7430 */ 7431 static int 7432 nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7433 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7434 struct ucred *cred, NFSPROC_T *p) 7435 { 7436 uint32_t *tl; 7437 struct nfsrv_descript nfsd, *nd = &nfsd; 7438 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7439 struct nfssockreq *nrp; 7440 nfsattrbit_t hints; 7441 int error; 7442 7443 /* For NFS DSs prior to NFSv4.2, just return OK. */ 7444 if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION) 7445 return (0); 7446 NFSZERO_ATTRBIT(&hints); 7447 if (advise == POSIX_FADV_WILLNEED) 7448 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7449 else if (advise == POSIX_FADV_DONTNEED) 7450 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7451 else 7452 return (0); 7453 nd->nd_mrep = NULL; 7454 nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh, 7455 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); 7456 vers = NFS_VER4; 7457 NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers, 7458 minorvers); 7459 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7460 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7461 txdr_hyper(offset, tl); 7462 tl += 2; 7463 *tl = txdr_unsigned(cnt); 7464 nfsrv_putattrbit(nd, &hints); 7465 nrp = dsp->nfsclds_sockp; 7466 if (nrp == NULL) 7467 /* If NULL, use the MDS socket. */ 7468 nrp = &nmp->nm_sockreq; 7469 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7470 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7471 NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error, 7472 nd->nd_repstat); 7473 if (error != 0) 7474 return (error); 7475 if (nd->nd_repstat != 0) 7476 error = nd->nd_repstat; 7477 m_freem(nd->nd_mrep); 7478 return (error); 7479 } 7480 7481 /* 7482 * Start up the thread that will execute nfsrpc_commitds(). 7483 */ 7484 static void 7485 start_adviseds(void *arg, int pending) 7486 { 7487 struct nfsclwritedsdorpc *drpc; 7488 7489 drpc = (struct nfsclwritedsdorpc *)arg; 7490 drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len, 7491 drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, 7492 drpc->cred, drpc->p); 7493 drpc->done = 1; 7494 crfree(drpc->cred); 7495 NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err); 7496 } 7497 7498 /* 7499 * Set up the advise DS mirror call for the pNFS I/O thread. 7500 */ 7501 static int 7502 nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7503 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7504 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7505 { 7506 int error, ret; 7507 7508 error = 0; 7509 drpc->done = 0; 7510 drpc->vp = vp; 7511 drpc->off = offset; 7512 drpc->len = cnt; 7513 drpc->advise = advise; 7514 drpc->dsp = dsp; 7515 drpc->fhp = fhp; 7516 drpc->vers = vers; 7517 drpc->minorvers = minorvers; 7518 drpc->cred = crhold(cred); 7519 drpc->p = p; 7520 drpc->inprog = 0; 7521 ret = EIO; 7522 if (nfs_pnfsiothreads != 0) { 7523 ret = nfs_pnfsio(start_adviseds, drpc); 7524 NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret); 7525 } 7526 if (ret != 0) { 7527 error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers, 7528 minorvers, cred, p); 7529 crfree(drpc->cred); 7530 } 7531 NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error); 7532 return (error); 7533 } 7534 #endif /* notyet */ 7535 7536 /* 7537 * Do the Allocate operation, retrying for recovery. 7538 */ 7539 int 7540 nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap, 7541 int *attrflagp, struct ucred *cred, NFSPROC_T *p) 7542 { 7543 int error, expireret = 0, retrycnt, nostateid; 7544 uint32_t clidrev = 0; 7545 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7546 struct nfsfh *nfhp = NULL; 7547 nfsv4stateid_t stateid; 7548 off_t tmp_off; 7549 void *lckp; 7550 7551 if (len < 0) 7552 return (EINVAL); 7553 if (len == 0) 7554 return (0); 7555 tmp_off = off + len; 7556 NFSLOCKMNT(nmp); 7557 if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) { 7558 NFSUNLOCKMNT(nmp); 7559 return (EFBIG); 7560 } 7561 if (nmp->nm_clp != NULL) 7562 clidrev = nmp->nm_clp->nfsc_clientidrev; 7563 NFSUNLOCKMNT(nmp); 7564 nfhp = VTONFS(vp)->n_fhp; 7565 retrycnt = 0; 7566 do { 7567 lckp = NULL; 7568 nostateid = 0; 7569 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 7570 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); 7571 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 7572 stateid.other[2] == 0) { 7573 nostateid = 1; 7574 NFSCL_DEBUG(1, "stateid0 in allocate\n"); 7575 } 7576 7577 /* 7578 * Not finding a stateid should probably never happen, 7579 * but just return an error for this case. 7580 */ 7581 if (nostateid != 0) 7582 error = EIO; 7583 else 7584 error = nfsrpc_allocaterpc(vp, off, len, &stateid, 7585 nap, attrflagp, cred, p); 7586 if (error == NFSERR_STALESTATEID) 7587 nfscl_initiate_recovery(nmp->nm_clp); 7588 if (lckp != NULL) 7589 nfscl_lockderef(lckp); 7590 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 7591 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 7592 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 7593 (void) nfs_catnap(PZERO, error, "nfs_allocate"); 7594 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && 7595 error == NFSERR_BADSTATEID)) && clidrev != 0) { 7596 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 7597 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { 7598 error = EIO; 7599 } 7600 retrycnt++; 7601 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 7602 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 7603 error == NFSERR_STALEDONTRECOVER || 7604 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 7605 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 7606 expireret == 0 && clidrev != 0 && retrycnt < 4)); 7607 if (error != 0 && retrycnt >= 4) 7608 error = EIO; 7609 return (error); 7610 } 7611 7612 /* 7613 * The allocate RPC. 7614 */ 7615 static int 7616 nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp, 7617 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 7618 { 7619 uint32_t *tl; 7620 int error; 7621 struct nfsrv_descript nfsd; 7622 struct nfsrv_descript *nd = &nfsd; 7623 nfsattrbit_t attrbits; 7624 7625 *attrflagp = 0; 7626 NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp, cred); 7627 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 7628 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 7629 txdr_hyper(off, tl); tl += 2; 7630 txdr_hyper(len, tl); tl += 2; 7631 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7632 NFSGETATTR_ATTRBIT(&attrbits); 7633 nfsrv_putattrbit(nd, &attrbits); 7634 error = nfscl_request(nd, vp, p, cred); 7635 if (error != 0) 7636 return (error); 7637 if (nd->nd_repstat == 0) { 7638 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7639 error = nfsm_loadattr(nd, nap); 7640 if (error == 0) 7641 *attrflagp = NFS_LATTR_NOSHRINK; 7642 } else 7643 error = nd->nd_repstat; 7644 nfsmout: 7645 m_freem(nd->nd_mrep); 7646 return (error); 7647 } 7648 7649 /* 7650 * Set up the XDR arguments for the LayoutGet operation. 7651 */ 7652 static void 7653 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, 7654 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype, 7655 int layoutlen, int usecurstateid) 7656 { 7657 uint32_t *tl; 7658 7659 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 7660 NFSX_STATEID); 7661 *tl++ = newnfs_false; /* Don't signal availability. */ 7662 *tl++ = txdr_unsigned(layouttype); 7663 *tl++ = txdr_unsigned(iomode); 7664 txdr_hyper(offset, tl); 7665 tl += 2; 7666 txdr_hyper(len, tl); 7667 tl += 2; 7668 txdr_hyper(minlen, tl); 7669 tl += 2; 7670 if (usecurstateid != 0) { 7671 /* Special stateid for Current stateid. */ 7672 *tl++ = txdr_unsigned(1); 7673 *tl++ = 0; 7674 *tl++ = 0; 7675 *tl++ = 0; 7676 } else { 7677 *tl++ = txdr_unsigned(stateidp->seqid); 7678 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 7679 *tl++ = stateidp->other[0]; 7680 *tl++ = stateidp->other[1]; 7681 *tl++ = stateidp->other[2]; 7682 } 7683 *tl = txdr_unsigned(layoutlen); 7684 } 7685 7686 /* 7687 * Parse the reply for a successful LayoutGet operation. 7688 */ 7689 static int 7690 nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd, 7691 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp) 7692 { 7693 uint32_t *tl; 7694 struct nfsclflayout *flp, *prevflp, *tflp; 7695 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen; 7696 int m, mirrorcnt; 7697 uint64_t retlen, off; 7698 struct nfsfh *nfhp; 7699 uint8_t *cp; 7700 uid_t user; 7701 gid_t grp; 7702 7703 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n"); 7704 error = 0; 7705 flp = NULL; 7706 gotiomode = -1; 7707 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 7708 if (*tl++ != 0) 7709 *retonclosep = 1; 7710 else 7711 *retonclosep = 0; 7712 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 7713 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 7714 (int)stateidp->seqid); 7715 stateidp->other[0] = *tl++; 7716 stateidp->other[1] = *tl++; 7717 stateidp->other[2] = *tl++; 7718 cnt = fxdr_unsigned(int, *tl); 7719 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 7720 if (cnt <= 0 || cnt > 10000) { 7721 /* Don't accept more than 10000 layouts in reply. */ 7722 error = NFSERR_BADXDR; 7723 goto nfsmout; 7724 } 7725 for (i = 0; i < cnt; i++) { 7726 /* Dissect to the layout type. */ 7727 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 7728 3 * NFSX_UNSIGNED); 7729 off = fxdr_hyper(tl); tl += 2; 7730 retlen = fxdr_hyper(tl); tl += 2; 7731 iomode = fxdr_unsigned(int, *tl++); 7732 laytype = fxdr_unsigned(int, *tl); 7733 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype, 7734 (uintmax_t)off, (uintmax_t)retlen, iomode); 7735 /* Ignore length of layout body for now. */ 7736 if (laytype == NFSLAYOUT_NFSV4_1_FILES) { 7737 /* Parse the File layout up to fhcnt. */ 7738 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + 7739 NFSX_HYPER + NFSX_V4DEVICEID); 7740 fhcnt = fxdr_unsigned(int, *(tl + 4 + 7741 NFSX_V4DEVICEID / NFSX_UNSIGNED)); 7742 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7743 if (fhcnt < 0 || fhcnt > 100) { 7744 /* Don't accept more than 100 file handles. */ 7745 error = NFSERR_BADXDR; 7746 goto nfsmout; 7747 } 7748 if (fhcnt > 0) 7749 flp = malloc(sizeof(*flp) + fhcnt * 7750 sizeof(struct nfsfh *), M_NFSFLAYOUT, 7751 M_WAITOK); 7752 else 7753 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, 7754 M_WAITOK); 7755 flp->nfsfl_flags = NFSFL_FILE; 7756 flp->nfsfl_fhcnt = 0; 7757 flp->nfsfl_devp = NULL; 7758 flp->nfsfl_off = off; 7759 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7760 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7761 else 7762 flp->nfsfl_end = flp->nfsfl_off + retlen; 7763 flp->nfsfl_iomode = iomode; 7764 if (gotiomode == -1) 7765 gotiomode = flp->nfsfl_iomode; 7766 /* Ignore layout body length for now. */ 7767 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 7768 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 7769 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 7770 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 7771 mtx_lock(&nmp->nm_mtx); 7772 if (nmp->nm_minorvers > 1 && (flp->nfsfl_util & 7773 NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0) 7774 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 7775 mtx_unlock(&nmp->nm_mtx); 7776 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 7777 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 7778 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n", 7779 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff); 7780 for (j = 0; j < fhcnt; j++) { 7781 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7782 nfhlen = fxdr_unsigned(int, *tl); 7783 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 7784 error = NFSERR_BADXDR; 7785 goto nfsmout; 7786 } 7787 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, 7788 M_NFSFH, M_WAITOK); 7789 flp->nfsfl_fh[j] = nfhp; 7790 flp->nfsfl_fhcnt++; 7791 nfhp->nfh_len = nfhlen; 7792 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 7793 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 7794 } 7795 } else if (laytype == NFSLAYOUT_FLEXFILE) { 7796 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 7797 NFSX_HYPER); 7798 mirrorcnt = fxdr_unsigned(int, *(tl + 2)); 7799 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt); 7800 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) { 7801 error = NFSERR_BADXDR; 7802 goto nfsmout; 7803 } 7804 flp = malloc(sizeof(*flp) + mirrorcnt * 7805 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK); 7806 flp->nfsfl_flags = NFSFL_FLEXFILE; 7807 flp->nfsfl_mirrorcnt = mirrorcnt; 7808 for (j = 0; j < mirrorcnt; j++) 7809 flp->nfsfl_ffm[j].devp = NULL; 7810 flp->nfsfl_off = off; 7811 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7812 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7813 else 7814 flp->nfsfl_end = flp->nfsfl_off + retlen; 7815 flp->nfsfl_iomode = iomode; 7816 if (gotiomode == -1) 7817 gotiomode = flp->nfsfl_iomode; 7818 flp->nfsfl_stripeunit = fxdr_hyper(tl); 7819 NFSCL_DEBUG(4, "stripeunit=%ju\n", 7820 (uintmax_t)flp->nfsfl_stripeunit); 7821 for (j = 0; j < mirrorcnt; j++) { 7822 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7823 k = fxdr_unsigned(int, *tl); 7824 if (k < 1 || k > 128) { 7825 error = NFSERR_BADXDR; 7826 goto nfsmout; 7827 } 7828 NFSCL_DEBUG(4, "servercnt=%d\n", k); 7829 for (l = 0; l < k; l++) { 7830 NFSM_DISSECT(tl, uint32_t *, 7831 NFSX_V4DEVICEID + NFSX_STATEID + 7832 2 * NFSX_UNSIGNED); 7833 if (l == 0) { 7834 /* Just use the first server. */ 7835 NFSBCOPY(tl, 7836 flp->nfsfl_ffm[j].dev, 7837 NFSX_V4DEVICEID); 7838 tl += (NFSX_V4DEVICEID / 7839 NFSX_UNSIGNED); 7840 tl++; 7841 flp->nfsfl_ffm[j].st.seqid = 7842 *tl++; 7843 flp->nfsfl_ffm[j].st.other[0] = 7844 *tl++; 7845 flp->nfsfl_ffm[j].st.other[1] = 7846 *tl++; 7847 flp->nfsfl_ffm[j].st.other[2] = 7848 *tl++; 7849 NFSCL_DEBUG(4, "st.seqid=%u " 7850 "st.o0=0x%x st.o1=0x%x " 7851 "st.o2=0x%x\n", 7852 flp->nfsfl_ffm[j].st.seqid, 7853 flp->nfsfl_ffm[j].st.other[0], 7854 flp->nfsfl_ffm[j].st.other[1], 7855 flp->nfsfl_ffm[j].st.other[2]); 7856 } else 7857 tl += ((NFSX_V4DEVICEID + 7858 NFSX_STATEID + 7859 NFSX_UNSIGNED) / 7860 NFSX_UNSIGNED); 7861 fhcnt = fxdr_unsigned(int, *tl); 7862 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7863 if (fhcnt < 1 || 7864 fhcnt > NFSDEV_MAXVERS) { 7865 error = NFSERR_BADXDR; 7866 goto nfsmout; 7867 } 7868 for (m = 0; m < fhcnt; m++) { 7869 NFSM_DISSECT(tl, uint32_t *, 7870 NFSX_UNSIGNED); 7871 nfhlen = fxdr_unsigned(int, 7872 *tl); 7873 NFSCL_DEBUG(4, "nfhlen=%d\n", 7874 nfhlen); 7875 if (nfhlen <= 0 || nfhlen > 7876 NFSX_V4FHMAX) { 7877 error = NFSERR_BADXDR; 7878 goto nfsmout; 7879 } 7880 NFSM_DISSECT(cp, uint8_t *, 7881 NFSM_RNDUP(nfhlen)); 7882 if (l == 0) { 7883 flp->nfsfl_ffm[j].fhcnt 7884 = fhcnt; 7885 nfhp = malloc( 7886 sizeof(*nfhp) + 7887 nfhlen - 1, M_NFSFH, 7888 M_WAITOK); 7889 flp->nfsfl_ffm[j].fh[m] 7890 = nfhp; 7891 nfhp->nfh_len = nfhlen; 7892 NFSBCOPY(cp, 7893 nfhp->nfh_fh, 7894 nfhlen); 7895 NFSCL_DEBUG(4, 7896 "got fh\n"); 7897 } 7898 } 7899 /* Now, get the ffsd_user/ffds_group. */ 7900 error = nfsrv_parseug(nd, 0, &user, 7901 &grp, curthread); 7902 NFSCL_DEBUG(4, "after parseu=%d\n", 7903 error); 7904 if (error == 0) 7905 error = nfsrv_parseug(nd, 1, 7906 &user, &grp, curthread); 7907 NFSCL_DEBUG(4, "aft parseg=%d\n", 7908 grp); 7909 if (error != 0) 7910 goto nfsmout; 7911 NFSCL_DEBUG(4, "user=%d group=%d\n", 7912 user, grp); 7913 if (l == 0) { 7914 flp->nfsfl_ffm[j].user = user; 7915 flp->nfsfl_ffm[j].group = grp; 7916 NFSCL_DEBUG(4, 7917 "usr=%d grp=%d\n", user, 7918 grp); 7919 } 7920 } 7921 } 7922 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7923 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++); 7924 #ifdef notnow 7925 /* 7926 * At this time, there is no flag. 7927 * NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be 7928 * added, or it may never exist? 7929 */ 7930 mtx_lock(&nmp->nm_mtx); 7931 if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags & 7932 NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0) 7933 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 7934 mtx_unlock(&nmp->nm_mtx); 7935 #endif 7936 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl); 7937 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n", 7938 flp->nfsfl_fflags, flp->nfsfl_statshint); 7939 } else { 7940 error = NFSERR_BADXDR; 7941 goto nfsmout; 7942 } 7943 if (flp->nfsfl_iomode == gotiomode) { 7944 /* Keep the list in increasing offset order. */ 7945 tflp = LIST_FIRST(flhp); 7946 prevflp = NULL; 7947 while (tflp != NULL && 7948 tflp->nfsfl_off < flp->nfsfl_off) { 7949 prevflp = tflp; 7950 tflp = LIST_NEXT(tflp, nfsfl_list); 7951 } 7952 if (prevflp == NULL) 7953 LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 7954 else 7955 LIST_INSERT_AFTER(prevflp, flp, 7956 nfsfl_list); 7957 NFSCL_DEBUG(4, "flp inserted\n"); 7958 } else { 7959 printf("nfscl_layoutget(): got wrong iomode\n"); 7960 nfscl_freeflayout(flp); 7961 } 7962 flp = NULL; 7963 } 7964 nfsmout: 7965 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error); 7966 if (error != 0 && flp != NULL) 7967 nfscl_freeflayout(flp); 7968 return (error); 7969 } 7970 7971 /* 7972 * Parse a user/group digit string. 7973 */ 7974 static int 7975 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp, 7976 NFSPROC_T *p) 7977 { 7978 uint32_t *tl; 7979 char *cp, *str, str0[NFSV4_SMALLSTR + 1]; 7980 uint32_t len = 0; 7981 int error = 0; 7982 7983 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7984 len = fxdr_unsigned(uint32_t, *tl); 7985 str = NULL; 7986 if (len > NFSV4_OPAQUELIMIT) { 7987 error = NFSERR_BADXDR; 7988 goto nfsmout; 7989 } 7990 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len); 7991 if (len == 0) { 7992 if (dogrp != 0) 7993 *gidp = GID_NOGROUP; 7994 else 7995 *uidp = UID_NOBODY; 7996 return (0); 7997 } 7998 if (len > NFSV4_SMALLSTR) 7999 str = malloc(len + 1, M_TEMP, M_WAITOK); 8000 else 8001 str = str0; 8002 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len)); 8003 NFSBCOPY(cp, str, len); 8004 str[len] = '\0'; 8005 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str); 8006 if (dogrp != 0) 8007 error = nfsv4_strtogid(nd, str, len, gidp); 8008 else 8009 error = nfsv4_strtouid(nd, str, len, uidp); 8010 nfsmout: 8011 if (len > NFSV4_SMALLSTR) 8012 free(str, M_TEMP); 8013 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error); 8014 return (error); 8015 } 8016 8017 /* 8018 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), 8019 * so that it does both an Open and a Layoutget. 8020 */ 8021 static int 8022 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 8023 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 8024 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 8025 struct ucred *cred, NFSPROC_T *p) 8026 { 8027 struct nfscllayout *lyp; 8028 struct nfsclflayout *flp; 8029 struct nfsclflayouthead flh; 8030 int error, islocked, layoutlen, recalled, retonclose, usecurstateid; 8031 int layouttype, laystat; 8032 nfsv4stateid_t stateid; 8033 struct nfsclsession *tsep; 8034 8035 error = 0; 8036 if (NFSHASFLEXFILE(nmp)) 8037 layouttype = NFSLAYOUT_FLEXFILE; 8038 else 8039 layouttype = NFSLAYOUT_NFSV4_1_FILES; 8040 /* 8041 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 8042 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 8043 * flp == NULL. 8044 */ 8045 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp, 8046 &recalled); 8047 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); 8048 if (lyp == NULL) 8049 islocked = 0; 8050 else if (flp != NULL) 8051 islocked = 1; 8052 else 8053 islocked = 2; 8054 if ((lyp == NULL || flp == NULL) && recalled == 0) { 8055 LIST_INIT(&flh); 8056 tsep = nfsmnt_mdssession(nmp); 8057 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 8058 3 * NFSX_UNSIGNED); 8059 if (lyp == NULL) 8060 usecurstateid = 1; 8061 else { 8062 usecurstateid = 0; 8063 stateid.seqid = lyp->nfsly_stateid.seqid; 8064 stateid.other[0] = lyp->nfsly_stateid.other[0]; 8065 stateid.other[1] = lyp->nfsly_stateid.other[1]; 8066 stateid.other[2] = lyp->nfsly_stateid.other[2]; 8067 } 8068 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, 8069 newfhp, newfhlen, mode, op, name, namelen, 8070 dpp, &stateid, usecurstateid, layouttype, layoutlen, 8071 &retonclose, &flh, &laystat, cred, p); 8072 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", 8073 laystat, error); 8074 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, 8075 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, 8076 &islocked, cred, p); 8077 } else 8078 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, 8079 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); 8080 if (islocked == 2) 8081 nfscl_rellayout(lyp, 1); 8082 else if (islocked == 1) 8083 nfscl_rellayout(lyp, 0); 8084 return (error); 8085 } 8086 8087 /* 8088 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS 8089 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are 8090 * handled by nfsrpc_openrpc(). 8091 * For the case where op == NULL, dvp is the directory. When op != NULL, it 8092 * can be NULL. 8093 */ 8094 static int 8095 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 8096 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 8097 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 8098 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, 8099 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, 8100 int *laystatp, struct ucred *cred, NFSPROC_T *p) 8101 { 8102 uint32_t *tl; 8103 struct nfsrv_descript nfsd, *nd = &nfsd; 8104 struct nfscldeleg *ndp = NULL; 8105 struct nfsvattr nfsva; 8106 struct nfsclsession *tsep; 8107 uint32_t rflags, deleg; 8108 nfsattrbit_t attrbits; 8109 int error, ret, acesize, limitby, iomode; 8110 8111 *dpp = NULL; 8112 *laystatp = ENXIO; 8113 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL, 8114 0, 0, cred); 8115 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 8116 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 8117 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 8118 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 8119 tsep = nfsmnt_mdssession(nmp); 8120 *tl++ = tsep->nfsess_clientid.lval[0]; 8121 *tl = tsep->nfsess_clientid.lval[1]; 8122 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 8123 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8124 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 8125 if (NFSHASNFSV4N(nmp)) { 8126 *tl = txdr_unsigned(NFSV4OPEN_CLAIMFH); 8127 } else { 8128 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 8129 nfsm_strtom(nd, name, namelen); 8130 } 8131 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8132 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8133 NFSZERO_ATTRBIT(&attrbits); 8134 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 8135 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 8136 nfsrv_putattrbit(nd, &attrbits); 8137 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8138 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 8139 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) 8140 iomode = NFSLAYOUTIOMODE_RW; 8141 else 8142 iomode = NFSLAYOUTIOMODE_READ; 8143 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, 8144 layouttype, layoutlen, usecurstateid); 8145 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 8146 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 8147 if (error != 0) 8148 return (error); 8149 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 8150 if (nd->nd_repstat != 0) 8151 *laystatp = nd->nd_repstat; 8152 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8153 /* ND_NOMOREDATA will be set if the Open operation failed. */ 8154 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8155 6 * NFSX_UNSIGNED); 8156 op->nfso_stateid.seqid = *tl++; 8157 op->nfso_stateid.other[0] = *tl++; 8158 op->nfso_stateid.other[1] = *tl++; 8159 op->nfso_stateid.other[2] = *tl; 8160 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 8161 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8162 if (error != 0) 8163 goto nfsmout; 8164 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 8165 deleg = fxdr_unsigned(u_int32_t, *tl); 8166 if (deleg == NFSV4OPEN_DELEGATEREAD || 8167 deleg == NFSV4OPEN_DELEGATEWRITE) { 8168 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 8169 NFSCLFLAGS_FIRSTDELEG)) 8170 op->nfso_own->nfsow_clp->nfsc_flags |= 8171 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 8172 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, 8173 M_NFSCLDELEG, M_WAITOK); 8174 LIST_INIT(&ndp->nfsdl_owner); 8175 LIST_INIT(&ndp->nfsdl_lock); 8176 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 8177 ndp->nfsdl_fhlen = newfhlen; 8178 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 8179 newnfs_copyincred(cred, &ndp->nfsdl_cred); 8180 nfscl_lockinit(&ndp->nfsdl_rwlock); 8181 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8182 NFSX_UNSIGNED); 8183 ndp->nfsdl_stateid.seqid = *tl++; 8184 ndp->nfsdl_stateid.other[0] = *tl++; 8185 ndp->nfsdl_stateid.other[1] = *tl++; 8186 ndp->nfsdl_stateid.other[2] = *tl++; 8187 ret = fxdr_unsigned(int, *tl); 8188 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 8189 ndp->nfsdl_flags = NFSCLDL_WRITE; 8190 /* 8191 * Indicates how much the file can grow. 8192 */ 8193 NFSM_DISSECT(tl, u_int32_t *, 8194 3 * NFSX_UNSIGNED); 8195 limitby = fxdr_unsigned(int, *tl++); 8196 switch (limitby) { 8197 case NFSV4OPEN_LIMITSIZE: 8198 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 8199 break; 8200 case NFSV4OPEN_LIMITBLOCKS: 8201 ndp->nfsdl_sizelimit = 8202 fxdr_unsigned(u_int64_t, *tl++); 8203 ndp->nfsdl_sizelimit *= 8204 fxdr_unsigned(u_int64_t, *tl); 8205 break; 8206 default: 8207 error = NFSERR_BADXDR; 8208 goto nfsmout; 8209 }; 8210 } else 8211 ndp->nfsdl_flags = NFSCLDL_READ; 8212 if (ret != 0) 8213 ndp->nfsdl_flags |= NFSCLDL_RECALL; 8214 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false, 8215 &ret, &acesize, p); 8216 if (error != 0) 8217 goto nfsmout; 8218 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 8219 error = NFSERR_BADXDR; 8220 goto nfsmout; 8221 } 8222 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || 8223 nfscl_assumeposixlocks) 8224 op->nfso_posixlock = 1; 8225 else 8226 op->nfso_posixlock = 0; 8227 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8228 /* If the 2nd element == NFS_OK, the Getattr succeeded. */ 8229 if (*++tl == 0) { 8230 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 8231 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 8232 NULL, NULL, NULL, p, cred); 8233 if (error != 0) 8234 goto nfsmout; 8235 if (ndp != NULL) { 8236 ndp->nfsdl_change = nfsva.na_filerev; 8237 ndp->nfsdl_modtime = nfsva.na_mtime; 8238 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8239 *dpp = ndp; 8240 ndp = NULL; 8241 } 8242 /* 8243 * At this point, the Open has succeeded, so set 8244 * nd_repstat = NFS_OK. If the Layoutget failed, 8245 * this function just won't return a layout. 8246 */ 8247 if (nd->nd_repstat == 0) { 8248 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8249 *laystatp = fxdr_unsigned(int, *++tl); 8250 if (*laystatp == 0) { 8251 error = nfsrv_parselayoutget(nmp, nd, 8252 stateidp, retonclosep, flhp); 8253 if (error != 0) 8254 *laystatp = error; 8255 } 8256 } else 8257 nd->nd_repstat = 0; /* Return 0 for Open. */ 8258 } 8259 } 8260 if (nd->nd_repstat != 0 && error == 0) 8261 error = nd->nd_repstat; 8262 nfsmout: 8263 free(ndp, M_NFSCLDELEG); 8264 m_freem(nd->nd_mrep); 8265 return (error); 8266 } 8267 8268 /* 8269 * Similar nfsrpc_createv4(), but also does the LayoutGet operation. 8270 * Used only for mounts with pNFS enabled. 8271 */ 8272 static int 8273 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8274 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8275 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8276 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8277 int *dattrflagp, int *unlockedp, nfsv4stateid_t *stateidp, 8278 int usecurstateid, int layouttype, int layoutlen, int *retonclosep, 8279 struct nfsclflayouthead *flhp, int *laystatp) 8280 { 8281 uint32_t *tl; 8282 int error = 0, deleg, newone, ret, acesize, limitby; 8283 struct nfsrv_descript nfsd, *nd = &nfsd; 8284 struct nfsclopen *op; 8285 struct nfscldeleg *dp = NULL; 8286 struct nfsnode *np; 8287 struct nfsfh *nfhp; 8288 struct nfsclsession *tsep; 8289 nfsattrbit_t attrbits; 8290 nfsv4stateid_t stateid; 8291 struct nfsmount *nmp; 8292 8293 nmp = VFSTONFS(dvp->v_mount); 8294 np = VTONFS(dvp); 8295 *laystatp = ENXIO; 8296 *unlockedp = 0; 8297 *nfhpp = NULL; 8298 *dpp = NULL; 8299 *attrflagp = 0; 8300 *dattrflagp = 0; 8301 if (namelen > NFS_MAXNAMLEN) 8302 return (ENAMETOOLONG); 8303 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp, cred); 8304 /* 8305 * For V4, this is actually an Open op. 8306 */ 8307 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 8308 *tl++ = txdr_unsigned(owp->nfsow_seqid); 8309 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 8310 NFSV4OPEN_ACCESSREAD); 8311 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 8312 tsep = nfsmnt_mdssession(nmp); 8313 *tl++ = tsep->nfsess_clientid.lval[0]; 8314 *tl = tsep->nfsess_clientid.lval[1]; 8315 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 8316 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8317 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 8318 if ((fmode & O_EXCL) != 0) { 8319 if (NFSHASSESSPERSIST(nmp)) { 8320 /* Use GUARDED for persistent sessions. */ 8321 *tl = txdr_unsigned(NFSCREATE_GUARDED); 8322 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8323 } else { 8324 /* Otherwise, use EXCLUSIVE4_1. */ 8325 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 8326 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 8327 *tl++ = cverf.lval[0]; 8328 *tl = cverf.lval[1]; 8329 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8330 } 8331 } else { 8332 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 8333 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8334 } 8335 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8336 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 8337 nfsm_strtom(nd, name, namelen); 8338 /* Get the new file's handle and attributes, plus save the FH. */ 8339 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 8340 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); 8341 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 8342 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8343 NFSGETATTR_ATTRBIT(&attrbits); 8344 nfsrv_putattrbit(nd, &attrbits); 8345 /* Get the directory's post-op attributes. */ 8346 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8347 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8348 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 8349 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8350 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8351 nfsrv_putattrbit(nd, &attrbits); 8352 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8353 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); 8354 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 8355 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, 8356 layouttype, layoutlen, usecurstateid); 8357 error = nfscl_request(nd, dvp, p, cred); 8358 if (error != 0) 8359 return (error); 8360 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, 8361 error); 8362 if (nd->nd_repstat != 0) 8363 *laystatp = nd->nd_repstat; 8364 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 8365 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8366 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); 8367 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8368 6 * NFSX_UNSIGNED); 8369 stateid.seqid = *tl++; 8370 stateid.other[0] = *tl++; 8371 stateid.other[1] = *tl++; 8372 stateid.other[2] = *tl; 8373 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8374 if (error != 0) 8375 goto nfsmout; 8376 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 8377 deleg = fxdr_unsigned(int, *tl); 8378 if (deleg == NFSV4OPEN_DELEGATEREAD || 8379 deleg == NFSV4OPEN_DELEGATEWRITE) { 8380 if (!(owp->nfsow_clp->nfsc_flags & 8381 NFSCLFLAGS_FIRSTDELEG)) 8382 owp->nfsow_clp->nfsc_flags |= 8383 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 8384 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, 8385 M_NFSCLDELEG, M_WAITOK); 8386 LIST_INIT(&dp->nfsdl_owner); 8387 LIST_INIT(&dp->nfsdl_lock); 8388 dp->nfsdl_clp = owp->nfsow_clp; 8389 newnfs_copyincred(cred, &dp->nfsdl_cred); 8390 nfscl_lockinit(&dp->nfsdl_rwlock); 8391 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8392 NFSX_UNSIGNED); 8393 dp->nfsdl_stateid.seqid = *tl++; 8394 dp->nfsdl_stateid.other[0] = *tl++; 8395 dp->nfsdl_stateid.other[1] = *tl++; 8396 dp->nfsdl_stateid.other[2] = *tl++; 8397 ret = fxdr_unsigned(int, *tl); 8398 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 8399 dp->nfsdl_flags = NFSCLDL_WRITE; 8400 /* 8401 * Indicates how much the file can grow. 8402 */ 8403 NFSM_DISSECT(tl, u_int32_t *, 8404 3 * NFSX_UNSIGNED); 8405 limitby = fxdr_unsigned(int, *tl++); 8406 switch (limitby) { 8407 case NFSV4OPEN_LIMITSIZE: 8408 dp->nfsdl_sizelimit = fxdr_hyper(tl); 8409 break; 8410 case NFSV4OPEN_LIMITBLOCKS: 8411 dp->nfsdl_sizelimit = 8412 fxdr_unsigned(u_int64_t, *tl++); 8413 dp->nfsdl_sizelimit *= 8414 fxdr_unsigned(u_int64_t, *tl); 8415 break; 8416 default: 8417 error = NFSERR_BADXDR; 8418 goto nfsmout; 8419 }; 8420 } else { 8421 dp->nfsdl_flags = NFSCLDL_READ; 8422 } 8423 if (ret != 0) 8424 dp->nfsdl_flags |= NFSCLDL_RECALL; 8425 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false, 8426 &ret, &acesize, p); 8427 if (error != 0) 8428 goto nfsmout; 8429 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 8430 error = NFSERR_BADXDR; 8431 goto nfsmout; 8432 } 8433 8434 /* Now, we should have the status for the SaveFH. */ 8435 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8436 if (*++tl == 0) { 8437 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); 8438 /* 8439 * Now, process the GetFH and Getattr for the newly 8440 * created file. nfscl_mtofh() will set 8441 * ND_NOMOREDATA if these weren't successful. 8442 */ 8443 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 8444 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); 8445 if (error != 0) 8446 goto nfsmout; 8447 } else 8448 nd->nd_flag |= ND_NOMOREDATA; 8449 /* Now we have the PutFH and Getattr for the directory. */ 8450 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8451 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8452 if (*++tl != 0) 8453 nd->nd_flag |= ND_NOMOREDATA; 8454 else { 8455 NFSM_DISSECT(tl, uint32_t *, 2 * 8456 NFSX_UNSIGNED); 8457 if (*++tl != 0) 8458 nd->nd_flag |= ND_NOMOREDATA; 8459 } 8460 } 8461 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8462 /* Load the directory attributes. */ 8463 error = nfsm_loadattr(nd, dnap); 8464 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); 8465 if (error != 0) 8466 goto nfsmout; 8467 *dattrflagp = 1; 8468 if (dp != NULL && *attrflagp != 0) { 8469 dp->nfsdl_change = nnap->na_filerev; 8470 dp->nfsdl_modtime = nnap->na_mtime; 8471 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8472 } 8473 /* 8474 * We can now complete the Open state. 8475 */ 8476 nfhp = *nfhpp; 8477 if (dp != NULL) { 8478 dp->nfsdl_fhlen = nfhp->nfh_len; 8479 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, 8480 nfhp->nfh_len); 8481 } 8482 /* 8483 * Get an Open structure that will be 8484 * attached to the OpenOwner, acquired already. 8485 */ 8486 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 8487 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 8488 cred, p, NULL, &op, &newone, NULL, 0, false); 8489 if (error != 0) 8490 goto nfsmout; 8491 op->nfso_stateid = stateid; 8492 newnfs_copyincred(cred, &op->nfso_cred); 8493 8494 nfscl_openrelease(nmp, op, error, newone); 8495 *unlockedp = 1; 8496 8497 /* Now, handle the RestoreFH and LayoutGet. */ 8498 if (nd->nd_repstat == 0) { 8499 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 8500 *laystatp = fxdr_unsigned(int, *(tl + 3)); 8501 if (*laystatp == 0) { 8502 error = nfsrv_parselayoutget(nmp, nd, 8503 stateidp, retonclosep, flhp); 8504 if (error != 0) 8505 *laystatp = error; 8506 } 8507 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", 8508 error); 8509 } else 8510 nd->nd_repstat = 0; 8511 } 8512 } 8513 if (nd->nd_repstat != 0 && error == 0) 8514 error = nd->nd_repstat; 8515 if (error == NFSERR_STALECLIENTID) 8516 nfscl_initiate_recovery(owp->nfsow_clp); 8517 nfsmout: 8518 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); 8519 if (error == 0) 8520 *dpp = dp; 8521 else 8522 free(dp, M_NFSCLDELEG); 8523 m_freem(nd->nd_mrep); 8524 return (error); 8525 } 8526 8527 /* 8528 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. 8529 */ 8530 static int 8531 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8532 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8533 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8534 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8535 int *dattrflagp, int *unlockedp) 8536 { 8537 struct nfscllayout *lyp; 8538 struct nfsclflayouthead flh; 8539 struct nfsfh *nfhp; 8540 struct nfsclsession *tsep; 8541 struct nfsmount *nmp; 8542 nfsv4stateid_t stateid; 8543 int error, layoutlen, layouttype, retonclose, laystat; 8544 8545 error = 0; 8546 nmp = VFSTONFS(dvp->v_mount); 8547 if (NFSHASFLEXFILE(nmp)) 8548 layouttype = NFSLAYOUT_FLEXFILE; 8549 else 8550 layouttype = NFSLAYOUT_NFSV4_1_FILES; 8551 LIST_INIT(&flh); 8552 tsep = nfsmnt_mdssession(nmp); 8553 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); 8554 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, 8555 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 8556 unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose, 8557 &flh, &laystat); 8558 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", 8559 laystat, error); 8560 lyp = NULL; 8561 if (laystat == 0) { 8562 nfhp = *nfhpp; 8563 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, 8564 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, 8565 layouttype, laystat, NULL, cred, p); 8566 } else 8567 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, 8568 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, 8569 cred, p); 8570 if (laystat == 0) 8571 nfscl_rellayout(lyp, 0); 8572 return (error); 8573 } 8574 8575 /* 8576 * Process the results of a layoutget() operation. 8577 */ 8578 static int 8579 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, 8580 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, 8581 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype, 8582 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) 8583 { 8584 struct nfsclflayout *tflp; 8585 struct nfscldevinfo *dip; 8586 uint8_t *dev; 8587 int i, mirrorcnt; 8588 8589 if (laystat == NFSERR_UNKNLAYOUTTYPE) { 8590 NFSLOCKMNT(nmp); 8591 if (!NFSHASFLEXFILE(nmp)) { 8592 /* Switch to using Flex File Layout. */ 8593 nmp->nm_state |= NFSSTA_FLEXFILE; 8594 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 8595 /* Disable pNFS. */ 8596 NFSCL_DEBUG(1, "disable PNFS\n"); 8597 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE); 8598 } 8599 NFSUNLOCKMNT(nmp); 8600 } 8601 if (laystat == 0) { 8602 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); 8603 LIST_FOREACH(tflp, flhp, nfsfl_list) { 8604 if (layouttype == NFSLAYOUT_FLEXFILE) 8605 mirrorcnt = tflp->nfsfl_mirrorcnt; 8606 else 8607 mirrorcnt = 1; 8608 for (i = 0; i < mirrorcnt; i++) { 8609 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp); 8610 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); 8611 if (laystat != 0) { 8612 if (layouttype == NFSLAYOUT_FLEXFILE) 8613 dev = tflp->nfsfl_ffm[i].dev; 8614 else 8615 dev = tflp->nfsfl_dev; 8616 laystat = nfsrpc_getdeviceinfo(nmp, dev, 8617 layouttype, notifybit, &dip, cred, 8618 p); 8619 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", 8620 laystat); 8621 if (laystat != 0) 8622 goto out; 8623 laystat = nfscl_adddevinfo(nmp, dip, i, 8624 tflp); 8625 if (laystat != 0) 8626 printf("nfsrpc_layoutgetresout" 8627 ": cannot add\n"); 8628 } 8629 } 8630 } 8631 } 8632 out: 8633 if (laystat == 0) { 8634 /* 8635 * nfscl_layout() always returns with the nfsly_lock 8636 * set to a refcnt (shared lock). 8637 * Passing in dvp is sufficient, since it is only used to 8638 * get the fsid for the file system. 8639 */ 8640 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, 8641 layouttype, retonclose, flhp, lypp, cred, p); 8642 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", 8643 laystat); 8644 if (laystat == 0 && islockedp != NULL) 8645 *islockedp = 1; 8646 } 8647 return (laystat); 8648 } 8649 8650 /* 8651 * nfs copy_file_range operation. 8652 */ 8653 int 8654 nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp, 8655 off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp, 8656 struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap, 8657 struct ucred *cred, bool consecutive, bool *must_commitp) 8658 { 8659 int commit, error, expireret = 0, retrycnt; 8660 u_int32_t clidrev = 0; 8661 struct nfsmount *nmp = VFSTONFS(invp->v_mount); 8662 struct nfsfh *innfhp = NULL, *outnfhp = NULL; 8663 nfsv4stateid_t instateid, outstateid; 8664 void *inlckp, *outlckp; 8665 8666 if (nmp->nm_clp != NULL) 8667 clidrev = nmp->nm_clp->nfsc_clientidrev; 8668 innfhp = VTONFS(invp)->n_fhp; 8669 outnfhp = VTONFS(outvp)->n_fhp; 8670 retrycnt = 0; 8671 do { 8672 /* Get both stateids. */ 8673 inlckp = NULL; 8674 nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len, 8675 NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid, 8676 &inlckp); 8677 outlckp = NULL; 8678 nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len, 8679 NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid, 8680 &outlckp); 8681 8682 error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp, 8683 &instateid, &outstateid, innap, inattrflagp, outnap, 8684 outattrflagp, consecutive, &commit, cred, curthread); 8685 if (error == 0) { 8686 if (commit != NFSWRITE_FILESYNC) 8687 *must_commitp = true; 8688 *inoffp += *lenp; 8689 *outoffp += *lenp; 8690 } else if (error == NFSERR_STALESTATEID) 8691 nfscl_initiate_recovery(nmp->nm_clp); 8692 if (inlckp != NULL) 8693 nfscl_lockderef(inlckp); 8694 if (outlckp != NULL) 8695 nfscl_lockderef(outlckp); 8696 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8697 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8698 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 8699 (void) nfs_catnap(PZERO, error, "nfs_cfr"); 8700 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && 8701 error == NFSERR_BADSTATEID)) && clidrev != 0) { 8702 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 8703 curthread); 8704 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { 8705 error = EIO; 8706 } 8707 retrycnt++; 8708 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 8709 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8710 error == NFSERR_STALEDONTRECOVER || 8711 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 8712 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 8713 expireret == 0 && clidrev != 0 && retrycnt < 4)); 8714 if (error != 0 && (retrycnt >= 4 || 8715 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8716 error == NFSERR_STALEDONTRECOVER)) 8717 error = EIO; 8718 return (error); 8719 } 8720 8721 /* 8722 * The copy RPC. 8723 */ 8724 static int 8725 nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff, 8726 size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp, 8727 struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap, 8728 int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred, 8729 NFSPROC_T *p) 8730 { 8731 uint32_t *tl; 8732 int error; 8733 struct nfsrv_descript nfsd; 8734 struct nfsrv_descript *nd = &nfsd; 8735 struct nfsmount *nmp; 8736 nfsattrbit_t attrbits; 8737 struct vattr va; 8738 uint64_t len; 8739 8740 nmp = VFSTONFS(outvp->v_mount); 8741 *inattrflagp = *outattrflagp = 0; 8742 *commitp = NFSWRITE_UNSTABLE; 8743 len = *lenp; 8744 *lenp = 0; 8745 if (len > nfs_maxcopyrange) 8746 len = nfs_maxcopyrange; 8747 NFSCL_REQSTART(nd, NFSPROC_COPY, invp, cred); 8748 /* 8749 * First do a Setattr of atime to the server's clock 8750 * time. The FreeBSD "collective" was of the opinion 8751 * that setting atime was necessary for this syscall. 8752 * Do the Setattr before the Copy, so that it can be 8753 * handled well if the server replies NFSERR_DELAY to 8754 * the Setattr operation. 8755 */ 8756 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8757 *tl = txdr_unsigned(NFSV4OP_SETATTR); 8758 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); 8759 VATTR_NULL(&va); 8760 va.va_atime.tv_sec = va.va_atime.tv_nsec = 0; 8761 va.va_vaflags = VA_UTIMES_NULL; 8762 nfscl_fillsattr(nd, &va, invp, 0, 0); 8763 8764 /* Now Getattr the invp attributes. */ 8765 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8766 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8767 NFSGETATTR_ATTRBIT(&attrbits); 8768 nfsrv_putattrbit(nd, &attrbits); 8769 8770 /* Set outvp. */ 8771 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8772 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8773 (void)nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh, 8774 VTONFS(outvp)->n_fhp->nfh_len, 0); 8775 8776 /* Do the Copy. */ 8777 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8778 *tl = txdr_unsigned(NFSV4OP_COPY); 8779 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); 8780 nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID); 8781 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED); 8782 txdr_hyper(inoff, tl); tl += 2; 8783 txdr_hyper(outoff, tl); tl += 2; 8784 txdr_hyper(len, tl); tl += 2; 8785 if (consecutive) 8786 *tl++ = newnfs_true; 8787 else 8788 *tl++ = newnfs_false; 8789 *tl++ = newnfs_true; 8790 *tl++ = 0; 8791 8792 /* Get the outvp attributes. */ 8793 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8794 NFSWRITEGETATTR_ATTRBIT(&attrbits); 8795 nfsrv_putattrbit(nd, &attrbits); 8796 8797 error = nfscl_request(nd, invp, p, cred); 8798 if (error != 0) 8799 return (error); 8800 /* Skip over the Setattr reply. */ 8801 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8802 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8803 if (*(tl + 1) == 0) { 8804 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8805 if (error != 0) 8806 goto nfsmout; 8807 } else 8808 nd->nd_flag |= ND_NOMOREDATA; 8809 } 8810 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8811 /* Get the input file's attributes. */ 8812 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8813 if (*(tl + 1) == 0) { 8814 error = nfsm_loadattr(nd, innap); 8815 if (error != 0) 8816 goto nfsmout; 8817 *inattrflagp = 1; 8818 } else 8819 nd->nd_flag |= ND_NOMOREDATA; 8820 } 8821 /* Skip over return stat for PutFH. */ 8822 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8823 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8824 if (*++tl != 0) 8825 nd->nd_flag |= ND_NOMOREDATA; 8826 } 8827 /* Skip over return stat for Copy. */ 8828 if ((nd->nd_flag & ND_NOMOREDATA) == 0) 8829 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8830 if (nd->nd_repstat == 0) { 8831 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8832 if (*tl != 0) { 8833 /* There should be no callback ids. */ 8834 error = NFSERR_BADXDR; 8835 goto nfsmout; 8836 } 8837 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED + 8838 NFSX_VERF); 8839 len = fxdr_hyper(tl); tl += 2; 8840 *commitp = fxdr_unsigned(int, *tl++); 8841 NFSLOCKMNT(nmp); 8842 if (!NFSHASWRITEVERF(nmp)) { 8843 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8844 NFSSETWRITEVERF(nmp); 8845 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 8846 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8847 nd->nd_repstat = NFSERR_STALEWRITEVERF; 8848 } 8849 NFSUNLOCKMNT(nmp); 8850 tl += (NFSX_VERF / NFSX_UNSIGNED); 8851 if (nd->nd_repstat == 0 && *++tl != newnfs_true) 8852 /* Must be a synchronous copy. */ 8853 nd->nd_repstat = NFSERR_NOTSUPP; 8854 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8855 error = nfsm_loadattr(nd, outnap); 8856 if (error == 0) 8857 *outattrflagp = NFS_LATTR_NOSHRINK; 8858 if (nd->nd_repstat == 0) 8859 *lenp = len; 8860 } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) { 8861 /* 8862 * For the case where consecutive is not supported, but 8863 * synchronous is supported, we can try consecutive == false 8864 * by returning this error. Otherwise, return NFSERR_NOTSUPP, 8865 * since Copy cannot be done. 8866 */ 8867 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8868 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8869 if (!consecutive || *++tl == newnfs_false) 8870 nd->nd_repstat = NFSERR_NOTSUPP; 8871 } else 8872 nd->nd_repstat = NFSERR_BADXDR; 8873 } 8874 if (error == 0) 8875 error = nd->nd_repstat; 8876 nfsmout: 8877 m_freem(nd->nd_mrep); 8878 return (error); 8879 } 8880 8881 /* 8882 * Seek operation. 8883 */ 8884 int 8885 nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content, 8886 struct ucred *cred, struct nfsvattr *nap, int *attrflagp) 8887 { 8888 int error, expireret = 0, retrycnt; 8889 u_int32_t clidrev = 0; 8890 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 8891 struct nfsnode *np = VTONFS(vp); 8892 struct nfsfh *nfhp = NULL; 8893 nfsv4stateid_t stateid; 8894 void *lckp; 8895 8896 if (nmp->nm_clp != NULL) 8897 clidrev = nmp->nm_clp->nfsc_clientidrev; 8898 nfhp = np->n_fhp; 8899 retrycnt = 0; 8900 do { 8901 lckp = NULL; 8902 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 8903 NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp); 8904 error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content, 8905 nap, attrflagp, cred); 8906 if (error == NFSERR_STALESTATEID) 8907 nfscl_initiate_recovery(nmp->nm_clp); 8908 if (lckp != NULL) 8909 nfscl_lockderef(lckp); 8910 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8911 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8912 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 8913 (void) nfs_catnap(PZERO, error, "nfs_seek"); 8914 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && 8915 error == NFSERR_BADSTATEID)) && clidrev != 0) { 8916 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 8917 curthread); 8918 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { 8919 error = EIO; 8920 } 8921 retrycnt++; 8922 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8923 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8924 error == NFSERR_BADSESSION || 8925 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 8926 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 8927 expireret == 0 && clidrev != 0 && retrycnt < 4) || 8928 (error == NFSERR_OPENMODE && retrycnt < 4)); 8929 if (error && retrycnt >= 4) 8930 error = EIO; 8931 return (error); 8932 } 8933 8934 /* 8935 * The seek RPC. 8936 */ 8937 static int 8938 nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp, 8939 int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred) 8940 { 8941 uint32_t *tl; 8942 int error; 8943 struct nfsrv_descript nfsd; 8944 struct nfsrv_descript *nd = &nfsd; 8945 nfsattrbit_t attrbits; 8946 8947 *attrflagp = 0; 8948 NFSCL_REQSTART(nd, NFSPROC_SEEK, vp, cred); 8949 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 8950 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 8951 txdr_hyper(*offp, tl); tl += 2; 8952 *tl++ = txdr_unsigned(content); 8953 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8954 NFSGETATTR_ATTRBIT(&attrbits); 8955 nfsrv_putattrbit(nd, &attrbits); 8956 error = nfscl_request(nd, vp, curthread, cred); 8957 if (error != 0) 8958 return (error); 8959 if (nd->nd_repstat == 0) { 8960 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER); 8961 if (*tl++ == newnfs_true) 8962 *eofp = true; 8963 else 8964 *eofp = false; 8965 *offp = fxdr_hyper(tl); 8966 /* Just skip over Getattr op status. */ 8967 error = nfsm_loadattr(nd, nap); 8968 if (error == 0) 8969 *attrflagp = 1; 8970 } 8971 error = nd->nd_repstat; 8972 nfsmout: 8973 m_freem(nd->nd_mrep); 8974 return (error); 8975 } 8976 8977 /* 8978 * The getextattr RPC. 8979 */ 8980 int 8981 nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp, 8982 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 8983 { 8984 uint32_t *tl; 8985 int error; 8986 struct nfsrv_descript nfsd; 8987 struct nfsrv_descript *nd = &nfsd; 8988 nfsattrbit_t attrbits; 8989 uint32_t len, len2; 8990 8991 *attrflagp = 0; 8992 NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp, cred); 8993 nfsm_strtom(nd, name, strlen(name)); 8994 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8995 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8996 NFSGETATTR_ATTRBIT(&attrbits); 8997 nfsrv_putattrbit(nd, &attrbits); 8998 error = nfscl_request(nd, vp, p, cred); 8999 if (error != 0) 9000 return (error); 9001 if (nd->nd_repstat == 0) { 9002 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 9003 len = fxdr_unsigned(uint32_t, *tl); 9004 /* Sanity check lengths. */ 9005 if (uiop != NULL && len > 0 && len <= IOSIZE_MAX && 9006 uiop->uio_resid <= UINT32_MAX) { 9007 len2 = uiop->uio_resid; 9008 if (len2 >= len) 9009 error = nfsm_mbufuio(nd, uiop, len); 9010 else { 9011 error = nfsm_mbufuio(nd, uiop, len2); 9012 if (error == 0) { 9013 /* 9014 * nfsm_mbufuio() advances to a multiple 9015 * of 4, so round up len2 as well. Then 9016 * we need to advance over the rest of 9017 * the data, rounding up the remaining 9018 * length. 9019 */ 9020 len2 = NFSM_RNDUP(len2); 9021 len2 = NFSM_RNDUP(len - len2); 9022 if (len2 > 0) 9023 error = nfsm_advance(nd, len2, 9024 -1); 9025 } 9026 } 9027 } else if (uiop == NULL && len > 0) { 9028 /* Just wants the length and not the data. */ 9029 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 9030 } else if (len > 0) 9031 error = ENOATTR; 9032 if (error != 0) 9033 goto nfsmout; 9034 *lenp = len; 9035 /* Just skip over Getattr op status. */ 9036 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9037 error = nfsm_loadattr(nd, nap); 9038 if (error == 0) 9039 *attrflagp = 1; 9040 } 9041 if (error == 0) 9042 error = nd->nd_repstat; 9043 nfsmout: 9044 m_freem(nd->nd_mrep); 9045 return (error); 9046 } 9047 9048 /* 9049 * The setextattr RPC. 9050 */ 9051 int 9052 nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop, 9053 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 9054 { 9055 uint32_t *tl; 9056 int error; 9057 struct nfsrv_descript nfsd; 9058 struct nfsrv_descript *nd = &nfsd; 9059 nfsattrbit_t attrbits; 9060 9061 *attrflagp = 0; 9062 NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp, cred); 9063 if (uiop->uio_resid > nd->nd_maxreq) { 9064 /* nd_maxreq is set by NFSCL_REQSTART(). */ 9065 m_freem(nd->nd_mreq); 9066 return (EINVAL); 9067 } 9068 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9069 *tl = txdr_unsigned(NFSV4SXATTR_EITHER); 9070 nfsm_strtom(nd, name, strlen(name)); 9071 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9072 *tl = txdr_unsigned(uiop->uio_resid); 9073 error = nfsm_uiombuf(nd, uiop, uiop->uio_resid); 9074 if (error != 0) { 9075 m_freem(nd->nd_mreq); 9076 return (error); 9077 } 9078 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9079 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9080 NFSGETATTR_ATTRBIT(&attrbits); 9081 nfsrv_putattrbit(nd, &attrbits); 9082 error = nfscl_request(nd, vp, p, cred); 9083 if (error != 0) 9084 return (error); 9085 if (nd->nd_repstat == 0) { 9086 /* Just skip over the reply and Getattr op status. */ 9087 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 9088 NFSX_UNSIGNED); 9089 error = nfsm_loadattr(nd, nap); 9090 if (error == 0) 9091 *attrflagp = 1; 9092 } 9093 if (error == 0) 9094 error = nd->nd_repstat; 9095 nfsmout: 9096 m_freem(nd->nd_mrep); 9097 return (error); 9098 } 9099 9100 /* 9101 * The removeextattr RPC. 9102 */ 9103 int 9104 nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap, 9105 int *attrflagp, struct ucred *cred, NFSPROC_T *p) 9106 { 9107 uint32_t *tl; 9108 int error; 9109 struct nfsrv_descript nfsd; 9110 struct nfsrv_descript *nd = &nfsd; 9111 nfsattrbit_t attrbits; 9112 9113 *attrflagp = 0; 9114 NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp, cred); 9115 nfsm_strtom(nd, name, strlen(name)); 9116 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9117 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9118 NFSGETATTR_ATTRBIT(&attrbits); 9119 nfsrv_putattrbit(nd, &attrbits); 9120 error = nfscl_request(nd, vp, p, cred); 9121 if (error != 0) 9122 return (error); 9123 if (nd->nd_repstat == 0) { 9124 /* Just skip over the reply and Getattr op status. */ 9125 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 9126 NFSX_UNSIGNED); 9127 error = nfsm_loadattr(nd, nap); 9128 if (error == 0) 9129 *attrflagp = 1; 9130 } 9131 if (error == 0) 9132 error = nd->nd_repstat; 9133 nfsmout: 9134 m_freem(nd->nd_mrep); 9135 return (error); 9136 } 9137 9138 /* 9139 * The listextattr RPC. 9140 */ 9141 int 9142 nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop, 9143 size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp, 9144 struct ucred *cred, NFSPROC_T *p) 9145 { 9146 uint32_t *tl; 9147 int cnt, error, i, len; 9148 struct nfsrv_descript nfsd; 9149 struct nfsrv_descript *nd = &nfsd; 9150 nfsattrbit_t attrbits; 9151 u_char c; 9152 9153 *attrflagp = 0; 9154 NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp, cred); 9155 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 9156 txdr_hyper(*cookiep, tl); tl += 2; 9157 *tl++ = txdr_unsigned(*lenp); 9158 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9159 NFSGETATTR_ATTRBIT(&attrbits); 9160 nfsrv_putattrbit(nd, &attrbits); 9161 error = nfscl_request(nd, vp, p, cred); 9162 if (error != 0) 9163 return (error); 9164 *eofp = true; 9165 *lenp = 0; 9166 if (nd->nd_repstat == 0) { 9167 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 9168 *cookiep = fxdr_hyper(tl); tl += 2; 9169 cnt = fxdr_unsigned(int, *tl); 9170 if (cnt < 0) { 9171 error = EBADRPC; 9172 goto nfsmout; 9173 } 9174 for (i = 0; i < cnt; i++) { 9175 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 9176 len = fxdr_unsigned(int, *tl); 9177 if (len <= 0 || len > EXTATTR_MAXNAMELEN) { 9178 error = EBADRPC; 9179 goto nfsmout; 9180 } 9181 if (uiop == NULL) 9182 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 9183 else if (uiop->uio_resid >= len + 1) { 9184 c = len; 9185 error = uiomove(&c, sizeof(c), uiop); 9186 if (error == 0) 9187 error = nfsm_mbufuio(nd, uiop, len); 9188 } else { 9189 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 9190 *eofp = false; 9191 } 9192 if (error != 0) 9193 goto nfsmout; 9194 *lenp += (len + 1); 9195 } 9196 /* Get the eof and skip over the Getattr op status. */ 9197 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); 9198 /* 9199 * *eofp is set false above, because it wasn't able to copy 9200 * all of the reply. 9201 */ 9202 if (*eofp && *tl == 0) 9203 *eofp = false; 9204 error = nfsm_loadattr(nd, nap); 9205 if (error == 0) 9206 *attrflagp = 1; 9207 } 9208 if (error == 0) 9209 error = nd->nd_repstat; 9210 nfsmout: 9211 m_freem(nd->nd_mrep); 9212 return (error); 9213 } 9214 9215 /* 9216 * Split an mbuf list. For non-M_EXTPG mbufs, just use m_split(). 9217 */ 9218 static struct mbuf * 9219 nfsm_split(struct mbuf *mp, uint64_t xfer) 9220 { 9221 struct mbuf *m, *m2; 9222 vm_page_t pg; 9223 int i, j, left, pgno, plen, trim; 9224 char *cp, *cp2; 9225 9226 if ((mp->m_flags & M_EXTPG) == 0) { 9227 m = m_split(mp, xfer, M_WAITOK); 9228 return (m); 9229 } 9230 9231 /* Find the correct mbuf to split at. */ 9232 for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next) 9233 xfer -= m->m_len; 9234 if (m == NULL) 9235 return (NULL); 9236 9237 /* If xfer == m->m_len, we can just split the mbuf list. */ 9238 if (xfer == m->m_len) { 9239 m2 = m->m_next; 9240 m->m_next = NULL; 9241 return (m2); 9242 } 9243 9244 /* Find the page to split at. */ 9245 pgno = 0; 9246 left = xfer; 9247 do { 9248 if (pgno == 0) 9249 plen = m_epg_pagelen(m, 0, m->m_epg_1st_off); 9250 else 9251 plen = m_epg_pagelen(m, pgno, 0); 9252 if (left <= plen) 9253 break; 9254 left -= plen; 9255 pgno++; 9256 } while (pgno < m->m_epg_npgs); 9257 if (pgno == m->m_epg_npgs) 9258 panic("nfsm_split: eroneous ext_pgs mbuf"); 9259 9260 m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs); 9261 m2->m_epg_flags |= EPG_FLAG_ANON; 9262 9263 /* 9264 * If left < plen, allocate a new page for the new mbuf 9265 * and copy the data after left in the page to this new 9266 * page. 9267 */ 9268 if (left < plen) { 9269 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP | 9270 VM_ALLOC_WIRED); 9271 m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg); 9272 m2->m_epg_npgs = 1; 9273 9274 /* Copy the data after left to the new page. */ 9275 trim = plen - left; 9276 cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); 9277 if (pgno == 0) 9278 cp += m->m_epg_1st_off; 9279 cp += left; 9280 cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]); 9281 if (pgno == m->m_epg_npgs - 1) 9282 m2->m_epg_last_len = trim; 9283 else { 9284 cp2 += PAGE_SIZE - trim; 9285 m2->m_epg_1st_off = PAGE_SIZE - trim; 9286 m2->m_epg_last_len = m->m_epg_last_len; 9287 } 9288 memcpy(cp2, cp, trim); 9289 m2->m_len = trim; 9290 } else { 9291 m2->m_len = 0; 9292 m2->m_epg_last_len = m->m_epg_last_len; 9293 } 9294 9295 /* Move the pages beyond pgno to the new mbuf. */ 9296 for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) { 9297 m2->m_epg_pa[j] = m->m_epg_pa[i]; 9298 /* Never moves page 0. */ 9299 m2->m_len += m_epg_pagelen(m, i, 0); 9300 } 9301 m2->m_epg_npgs = j; 9302 m->m_epg_npgs = pgno + 1; 9303 m->m_epg_last_len = left; 9304 m->m_len = xfer; 9305 9306 m2->m_next = m->m_next; 9307 m->m_next = NULL; 9308 return (m2); 9309 } 9310 9311 /* 9312 * Do the NFSv4.1 Bind Connection to Session. 9313 * Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c). 9314 */ 9315 void 9316 nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr) 9317 { 9318 struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg; 9319 uint32_t res, *tl; 9320 struct nfsrv_descript nfsd; 9321 struct nfsrv_descript *nd = &nfsd; 9322 struct rpc_callextra ext; 9323 struct timeval utimeout; 9324 enum clnt_stat stat; 9325 int error; 9326 9327 nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL, 9328 NFS_VER4, rcp->minorvers, NULL); 9329 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 9330 memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID); 9331 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9332 *tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH); 9333 *tl = newnfs_false; 9334 9335 memset(&ext, 0, sizeof(ext)); 9336 utimeout.tv_sec = 30; 9337 utimeout.tv_usec = 0; 9338 ext.rc_auth = authunix_create(cr); 9339 nd->nd_mrep = NULL; 9340 stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq, 9341 &nd->nd_mrep, utimeout); 9342 AUTH_DESTROY(ext.rc_auth); 9343 if (stat != RPC_SUCCESS) { 9344 printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat); 9345 return; 9346 } 9347 if (nd->nd_mrep == NULL) { 9348 printf("nfsrpc_bindconnsess: no reply args\n"); 9349 return; 9350 } 9351 error = 0; 9352 newnfs_realign(&nd->nd_mrep, M_WAITOK); 9353 nd->nd_md = nd->nd_mrep; 9354 nd->nd_dpos = mtod(nd->nd_md, char *); 9355 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9356 nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++); 9357 if (nd->nd_repstat == NFSERR_OK) { 9358 res = fxdr_unsigned(uint32_t, *tl); 9359 if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res), 9360 -1)) != 0) 9361 goto nfsmout; 9362 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 9363 4 * NFSX_UNSIGNED); 9364 tl += 3; 9365 if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) { 9366 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9367 res = fxdr_unsigned(uint32_t, *tl); 9368 if (res != NFSCDFS4_BOTH) 9369 printf("nfsrpc_bindconnsess: did not " 9370 "return FS4_BOTH\n"); 9371 } else 9372 printf("nfsrpc_bindconnsess: not same " 9373 "sessionid\n"); 9374 } else if (nd->nd_repstat != NFSERR_BADSESSION) 9375 printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat); 9376 nfsmout: 9377 if (error != 0) 9378 printf("nfsrpc_bindconnsess: reply bad xdr\n"); 9379 m_freem(nd->nd_mrep); 9380 } 9381 9382 /* 9383 * Do roughly what nfs_statfs() does for NFSv4, but when called with a shared 9384 * locked vnode. 9385 */ 9386 static void 9387 nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td) 9388 { 9389 struct nfsvattr nfsva; 9390 struct nfsfsinfo fs; 9391 struct nfsstatfs sb; 9392 struct mount *mp; 9393 struct nfsmount *nmp; 9394 uint32_t lease; 9395 int attrflag, error; 9396 9397 mp = vp->v_mount; 9398 nmp = VFSTONFS(mp); 9399 error = nfsrpc_statfs(vp, &sb, &fs, &lease, cred, td, &nfsva, 9400 &attrflag); 9401 if (attrflag != 0) 9402 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); 9403 if (error == 0) { 9404 NFSLOCKCLSTATE(); 9405 if (nmp->nm_clp != NULL) 9406 nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease); 9407 NFSUNLOCKCLSTATE(); 9408 mtx_lock(&nmp->nm_mtx); 9409 nfscl_loadfsinfo(nmp, &fs); 9410 nfscl_loadsbinfo(nmp, &sb, &mp->mnt_stat); 9411 mp->mnt_stat.f_iosize = newnfs_iosize(nmp); 9412 mtx_unlock(&nmp->nm_mtx); 9413 } 9414 } 9415