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