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