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