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