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