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, NFSSATTR_NEWFILE, 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, NFSSATTR_NEWFILE, 2649 0); 2650 } else { 2651 /* Otherwise, use EXCLUSIVE4_1. */ 2652 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 2653 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2654 *tl++ = cverf.lval[0]; 2655 *tl = cverf.lval[1]; 2656 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 2657 0); 2658 } 2659 } else { 2660 /* NFSv4.0 */ 2661 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE); 2662 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 2663 *tl++ = cverf.lval[0]; 2664 *tl = cverf.lval[1]; 2665 } 2666 } else { 2667 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 2668 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); 2669 } 2670 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2671 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 2672 (void) nfsm_strtom(nd, name, namelen); 2673 /* Get the new file's handle and attributes. */ 2674 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2675 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 2676 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2677 NFSGETATTR_ATTRBIT(&attrbits); 2678 (void) nfsrv_putattrbit(nd, &attrbits); 2679 /* Get the directory's post-op attributes. */ 2680 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2681 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2682 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 2683 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2684 *tl = txdr_unsigned(NFSV4OP_GETATTR); 2685 (void) nfsrv_putattrbit(nd, &attrbits); 2686 error = nfscl_request(nd, dvp, p, cred); 2687 if (error) 2688 return (error); 2689 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 2690 if (nd->nd_repstat == 0) { 2691 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2692 6 * NFSX_UNSIGNED); 2693 stateid.seqid = *tl++; 2694 stateid.other[0] = *tl++; 2695 stateid.other[1] = *tl++; 2696 stateid.other[2] = *tl; 2697 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 2698 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 2699 if (error) 2700 goto nfsmout; 2701 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 2702 deleg = fxdr_unsigned(int, *tl); 2703 if (deleg == NFSV4OPEN_DELEGATEREAD || 2704 deleg == NFSV4OPEN_DELEGATEWRITE) { 2705 if (!(owp->nfsow_clp->nfsc_flags & 2706 NFSCLFLAGS_FIRSTDELEG)) 2707 owp->nfsow_clp->nfsc_flags |= 2708 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 2709 dp = malloc( 2710 sizeof (struct nfscldeleg) + NFSX_V4FHMAX, 2711 M_NFSCLDELEG, M_WAITOK); 2712 LIST_INIT(&dp->nfsdl_owner); 2713 LIST_INIT(&dp->nfsdl_lock); 2714 dp->nfsdl_clp = owp->nfsow_clp; 2715 newnfs_copyincred(cred, &dp->nfsdl_cred); 2716 nfscl_lockinit(&dp->nfsdl_rwlock); 2717 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 2718 NFSX_UNSIGNED); 2719 dp->nfsdl_stateid.seqid = *tl++; 2720 dp->nfsdl_stateid.other[0] = *tl++; 2721 dp->nfsdl_stateid.other[1] = *tl++; 2722 dp->nfsdl_stateid.other[2] = *tl++; 2723 ret = fxdr_unsigned(int, *tl); 2724 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 2725 dp->nfsdl_flags = NFSCLDL_WRITE; 2726 /* 2727 * Indicates how much the file can grow. 2728 */ 2729 NFSM_DISSECT(tl, u_int32_t *, 2730 3 * NFSX_UNSIGNED); 2731 limitby = fxdr_unsigned(int, *tl++); 2732 switch (limitby) { 2733 case NFSV4OPEN_LIMITSIZE: 2734 dp->nfsdl_sizelimit = fxdr_hyper(tl); 2735 break; 2736 case NFSV4OPEN_LIMITBLOCKS: 2737 dp->nfsdl_sizelimit = 2738 fxdr_unsigned(u_int64_t, *tl++); 2739 dp->nfsdl_sizelimit *= 2740 fxdr_unsigned(u_int64_t, *tl); 2741 break; 2742 default: 2743 error = NFSERR_BADXDR; 2744 goto nfsmout; 2745 } 2746 } else { 2747 dp->nfsdl_flags = NFSCLDL_READ; 2748 } 2749 if (ret) 2750 dp->nfsdl_flags |= NFSCLDL_RECALL; 2751 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false, 2752 &ret, &acesize, p); 2753 if (error) 2754 goto nfsmout; 2755 } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && 2756 NFSHASNFSV4N(nmp)) { 2757 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 2758 deleg = fxdr_unsigned(uint32_t, *tl); 2759 if (deleg == NFSV4OPEN_CONTENTION || 2760 deleg == NFSV4OPEN_RESOURCE) 2761 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 2762 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 2763 error = NFSERR_BADXDR; 2764 goto nfsmout; 2765 } 2766 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 2767 if (error) 2768 goto nfsmout; 2769 /* Get rid of the PutFH and Getattr status values. */ 2770 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 2771 /* Load the directory attributes. */ 2772 error = nfsm_loadattr(nd, dnap); 2773 if (error) 2774 goto nfsmout; 2775 *dattrflagp = 1; 2776 if (dp != NULL && *attrflagp) { 2777 dp->nfsdl_change = nnap->na_filerev; 2778 dp->nfsdl_modtime = nnap->na_mtime; 2779 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 2780 } 2781 /* 2782 * We can now complete the Open state. 2783 */ 2784 nfhp = *nfhpp; 2785 if (dp != NULL) { 2786 dp->nfsdl_fhlen = nfhp->nfh_len; 2787 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len); 2788 } 2789 /* 2790 * Get an Open structure that will be 2791 * attached to the OpenOwner, acquired already. 2792 */ 2793 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 2794 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 2795 cred, p, NULL, &op, &newone, NULL, 0, false); 2796 if (error) 2797 goto nfsmout; 2798 op->nfso_stateid = stateid; 2799 newnfs_copyincred(cred, &op->nfso_cred); 2800 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) { 2801 do { 2802 ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh, 2803 nfhp->nfh_len, op, cred, p); 2804 if (ret == NFSERR_DELAY) 2805 (void) nfs_catnap(PZERO, ret, "nfs_create"); 2806 } while (ret == NFSERR_DELAY); 2807 error = ret; 2808 } 2809 2810 /* 2811 * If the server is handing out delegations, but we didn't 2812 * get one because an OpenConfirm was required, try the 2813 * Open again, to get a delegation. This is a harmless no-op, 2814 * from a server's point of view. 2815 */ 2816 if ((rflags & NFSV4OPEN_RESULTCONFIRM) && 2817 (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) && 2818 !error && dp == NULL) { 2819 KASSERT(!NFSHASNFSV4N(nmp), 2820 ("nfsrpc_createv4: result confirm")); 2821 do { 2822 ret = nfsrpc_openrpc(VFSTONFS(dvp->v_mount), dvp, 2823 np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 2824 nfhp->nfh_fh, nfhp->nfh_len, 2825 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op, 2826 name, namelen, &dp, 0, 0x0, cred, p, 0, 1); 2827 if (ret == NFSERR_DELAY) 2828 (void) nfs_catnap(PZERO, ret, "nfs_crt2"); 2829 } while (ret == NFSERR_DELAY); 2830 if (ret) { 2831 if (dp != NULL) { 2832 free(dp, M_NFSCLDELEG); 2833 dp = NULL; 2834 } 2835 if (ret == NFSERR_STALECLIENTID || 2836 ret == NFSERR_STALEDONTRECOVER || 2837 ret == NFSERR_BADSESSION) 2838 error = ret; 2839 } 2840 } 2841 nfscl_openrelease(nmp, op, error, newone); 2842 *unlockedp = 1; 2843 } 2844 if (nd->nd_repstat != 0 && error == 0) 2845 error = nd->nd_repstat; 2846 if (error == NFSERR_STALECLIENTID) 2847 nfscl_initiate_recovery(owp->nfsow_clp); 2848 nfsmout: 2849 if (!error) 2850 *dpp = dp; 2851 else if (dp != NULL) 2852 free(dp, M_NFSCLDELEG); 2853 m_freem(nd->nd_mrep); 2854 return (error); 2855 } 2856 2857 /* 2858 * Nfs remove rpc 2859 */ 2860 int 2861 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp, 2862 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp) 2863 { 2864 u_int32_t *tl; 2865 struct nfsrv_descript nfsd, *nd = &nfsd; 2866 struct nfsnode *np; 2867 struct nfsmount *nmp; 2868 nfsv4stateid_t dstateid; 2869 int error, ret = 0, i; 2870 2871 *dattrflagp = 0; 2872 if (namelen > NFS_MAXNAMLEN) 2873 return (ENAMETOOLONG); 2874 nmp = VFSTONFS(dvp->v_mount); 2875 tryagain: 2876 if (NFSHASNFSV4(nmp) && ret == 0) { 2877 ret = nfscl_removedeleg(vp, p, &dstateid); 2878 if (ret == 1) { 2879 NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp, cred); 2880 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 2881 NFSX_UNSIGNED); 2882 if (NFSHASNFSV4N(nmp)) 2883 *tl++ = 0; 2884 else 2885 *tl++ = dstateid.seqid; 2886 *tl++ = dstateid.other[0]; 2887 *tl++ = dstateid.other[1]; 2888 *tl++ = dstateid.other[2]; 2889 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2890 np = VTONFS(dvp); 2891 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, 2892 np->n_fhp->nfh_len, 0); 2893 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2894 *tl = txdr_unsigned(NFSV4OP_REMOVE); 2895 } 2896 } else { 2897 ret = 0; 2898 } 2899 if (ret == 0) 2900 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp, cred); 2901 (void) nfsm_strtom(nd, name, namelen); 2902 error = nfscl_request(nd, dvp, p, cred); 2903 if (error) 2904 return (error); 2905 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 2906 /* For NFSv4, parse out any Delereturn replies. */ 2907 if (ret > 0 && nd->nd_repstat != 0 && 2908 (nd->nd_flag & ND_NOMOREDATA)) { 2909 /* 2910 * If the Delegreturn failed, try again without 2911 * it. The server will Recall, as required. 2912 */ 2913 m_freem(nd->nd_mrep); 2914 goto tryagain; 2915 } 2916 for (i = 0; i < (ret * 2); i++) { 2917 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 2918 ND_NFSV4) { 2919 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2920 if (*(tl + 1)) 2921 nd->nd_flag |= ND_NOMOREDATA; 2922 } 2923 } 2924 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 2925 } 2926 if (nd->nd_repstat && !error) 2927 error = nd->nd_repstat; 2928 nfsmout: 2929 m_freem(nd->nd_mrep); 2930 return (error); 2931 } 2932 2933 /* 2934 * Do an nfs rename rpc. 2935 */ 2936 int 2937 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen, 2938 vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred, 2939 NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap, 2940 int *fattrflagp, int *tattrflagp) 2941 { 2942 u_int32_t *tl; 2943 struct nfsrv_descript nfsd, *nd = &nfsd; 2944 struct nfsmount *nmp; 2945 struct nfsnode *np; 2946 nfsattrbit_t attrbits; 2947 nfsv4stateid_t fdstateid, tdstateid; 2948 int error = 0, ret = 0, gottd = 0, gotfd = 0, i; 2949 2950 *fattrflagp = 0; 2951 *tattrflagp = 0; 2952 nmp = VFSTONFS(fdvp->v_mount); 2953 if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN) 2954 return (ENAMETOOLONG); 2955 tryagain: 2956 if (NFSHASNFSV4(nmp) && ret == 0) { 2957 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp, 2958 &tdstateid, &gottd, p); 2959 if (gotfd && gottd) { 2960 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp, cred); 2961 } else if (gotfd) { 2962 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp, cred); 2963 } else if (gottd) { 2964 NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp, cred); 2965 } 2966 if (gotfd) { 2967 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2968 if (NFSHASNFSV4N(nmp)) 2969 *tl++ = 0; 2970 else 2971 *tl++ = fdstateid.seqid; 2972 *tl++ = fdstateid.other[0]; 2973 *tl++ = fdstateid.other[1]; 2974 *tl = fdstateid.other[2]; 2975 if (gottd) { 2976 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2977 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2978 np = VTONFS(tvp); 2979 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, 2980 np->n_fhp->nfh_len, 0); 2981 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2982 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN); 2983 } 2984 } 2985 if (gottd) { 2986 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 2987 if (NFSHASNFSV4N(nmp)) 2988 *tl++ = 0; 2989 else 2990 *tl++ = tdstateid.seqid; 2991 *tl++ = tdstateid.other[0]; 2992 *tl++ = tdstateid.other[1]; 2993 *tl = tdstateid.other[2]; 2994 } 2995 if (ret > 0) { 2996 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 2997 *tl = txdr_unsigned(NFSV4OP_PUTFH); 2998 np = VTONFS(fdvp); 2999 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, 3000 np->n_fhp->nfh_len, 0); 3001 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3002 *tl = txdr_unsigned(NFSV4OP_SAVEFH); 3003 } 3004 } else { 3005 ret = 0; 3006 } 3007 if (ret == 0) 3008 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp, cred); 3009 if (nd->nd_flag & ND_NFSV4) { 3010 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3011 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3012 NFSWCCATTR_ATTRBIT(&attrbits); 3013 (void) nfsrv_putattrbit(nd, &attrbits); 3014 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3015 *tl = txdr_unsigned(NFSV4OP_PUTFH); 3016 (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, 3017 VTONFS(tdvp)->n_fhp->nfh_len, 0); 3018 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3019 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3020 (void) nfsrv_putattrbit(nd, &attrbits); 3021 nd->nd_flag |= ND_V4WCCATTR; 3022 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3023 *tl = txdr_unsigned(NFSV4OP_RENAME); 3024 } 3025 (void) nfsm_strtom(nd, fnameptr, fnamelen); 3026 if (!(nd->nd_flag & ND_NFSV4)) 3027 (void)nfsm_fhtom(nmp, nd, VTONFS(tdvp)->n_fhp->nfh_fh, 3028 VTONFS(tdvp)->n_fhp->nfh_len, 0); 3029 (void) nfsm_strtom(nd, tnameptr, tnamelen); 3030 error = nfscl_request(nd, fdvp, p, cred); 3031 if (error) 3032 return (error); 3033 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) { 3034 /* For NFSv4, parse out any Delereturn replies. */ 3035 if (ret > 0 && nd->nd_repstat != 0 && 3036 (nd->nd_flag & ND_NOMOREDATA)) { 3037 /* 3038 * If the Delegreturn failed, try again without 3039 * it. The server will Recall, as required. 3040 */ 3041 m_freem(nd->nd_mrep); 3042 goto tryagain; 3043 } 3044 for (i = 0; i < (ret * 2); i++) { 3045 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == 3046 ND_NFSV4) { 3047 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3048 if (*(tl + 1)) { 3049 if (i == 1 && ret > 1) { 3050 /* 3051 * If the Delegreturn failed, try again 3052 * without it. The server will Recall, as 3053 * required. 3054 * If ret > 1, the second iteration of this 3055 * loop is the second DelegReturn result. 3056 */ 3057 m_freem(nd->nd_mrep); 3058 goto tryagain; 3059 } else { 3060 nd->nd_flag |= ND_NOMOREDATA; 3061 } 3062 } 3063 } 3064 } 3065 /* Now, the first wcc attribute reply. */ 3066 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 3067 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3068 if (*(tl + 1)) 3069 nd->nd_flag |= ND_NOMOREDATA; 3070 } 3071 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL, NULL); 3072 /* and the second wcc attribute reply. */ 3073 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && 3074 !error) { 3075 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3076 if (*(tl + 1)) 3077 nd->nd_flag |= ND_NOMOREDATA; 3078 } 3079 if (!error) 3080 error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp, 3081 NULL, NULL); 3082 } 3083 if (nd->nd_repstat && !error) 3084 error = nd->nd_repstat; 3085 nfsmout: 3086 m_freem(nd->nd_mrep); 3087 return (error); 3088 } 3089 3090 /* 3091 * nfs hard link create rpc 3092 */ 3093 int 3094 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen, 3095 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 3096 struct nfsvattr *nap, int *attrflagp, int *dattrflagp) 3097 { 3098 u_int32_t *tl; 3099 struct nfsrv_descript nfsd, *nd = &nfsd; 3100 nfsattrbit_t attrbits; 3101 int error = 0; 3102 3103 *attrflagp = 0; 3104 *dattrflagp = 0; 3105 if (namelen > NFS_MAXNAMLEN) 3106 return (ENAMETOOLONG); 3107 NFSCL_REQSTART(nd, NFSPROC_LINK, vp, cred); 3108 if (nd->nd_flag & ND_NFSV4) { 3109 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3110 *tl = txdr_unsigned(NFSV4OP_PUTFH); 3111 } 3112 (void)nfsm_fhtom(VFSTONFS(dvp->v_mount), nd, VTONFS(dvp)->n_fhp->nfh_fh, 3113 VTONFS(dvp)->n_fhp->nfh_len, 0); 3114 if (nd->nd_flag & ND_NFSV4) { 3115 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3116 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3117 NFSWCCATTR_ATTRBIT(&attrbits); 3118 (void) nfsrv_putattrbit(nd, &attrbits); 3119 nd->nd_flag |= ND_V4WCCATTR; 3120 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3121 *tl = txdr_unsigned(NFSV4OP_LINK); 3122 } 3123 (void) nfsm_strtom(nd, name, namelen); 3124 error = nfscl_request(nd, vp, p, cred); 3125 if (error) 3126 return (error); 3127 if (nd->nd_flag & ND_NFSV3) { 3128 error = nfscl_postop_attr(nd, nap, attrflagp); 3129 if (!error) 3130 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 3131 NULL, NULL); 3132 } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) { 3133 /* 3134 * First, parse out the PutFH and Getattr result. 3135 */ 3136 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3137 if (!(*(tl + 1))) 3138 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3139 if (*(tl + 1)) 3140 nd->nd_flag |= ND_NOMOREDATA; 3141 /* 3142 * Get the pre-op attributes. 3143 */ 3144 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3145 } 3146 if (nd->nd_repstat && !error) 3147 error = nd->nd_repstat; 3148 nfsmout: 3149 m_freem(nd->nd_mrep); 3150 return (error); 3151 } 3152 3153 /* 3154 * nfs symbolic link create rpc 3155 */ 3156 int 3157 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, const char *target, 3158 struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 3159 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 3160 int *dattrflagp) 3161 { 3162 u_int32_t *tl; 3163 struct nfsrv_descript nfsd, *nd = &nfsd; 3164 struct nfsmount *nmp; 3165 int slen, error = 0; 3166 3167 *nfhpp = NULL; 3168 *attrflagp = 0; 3169 *dattrflagp = 0; 3170 nmp = VFSTONFS(dvp->v_mount); 3171 slen = strlen(target); 3172 if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN) 3173 return (ENAMETOOLONG); 3174 NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp, cred); 3175 if (nd->nd_flag & ND_NFSV4) { 3176 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3177 *tl = txdr_unsigned(NFLNK); 3178 (void) nfsm_strtom(nd, target, slen); 3179 } 3180 (void) nfsm_strtom(nd, name, namelen); 3181 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 3182 nfscl_fillsattr(nd, vap, dvp, 0, 0); 3183 if (!(nd->nd_flag & ND_NFSV4)) 3184 (void) nfsm_strtom(nd, target, slen); 3185 if (nd->nd_flag & ND_NFSV2) 3186 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0); 3187 error = nfscl_request(nd, dvp, p, cred); 3188 if (error) 3189 return (error); 3190 if (nd->nd_flag & ND_NFSV4) 3191 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3192 if ((nd->nd_flag & ND_NFSV3) && !error) { 3193 if (!nd->nd_repstat) 3194 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 3195 if (!error) 3196 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, 3197 NULL, NULL); 3198 } 3199 if (nd->nd_repstat && !error) 3200 error = nd->nd_repstat; 3201 m_freem(nd->nd_mrep); 3202 /* 3203 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 3204 * Only do this if vfs.nfs.ignore_eexist is set. 3205 * Never do this for NFSv4.1 or later minor versions, since sessions 3206 * should guarantee "exactly once" RPC semantics. 3207 */ 3208 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 3209 nmp->nm_minorvers == 0)) 3210 error = 0; 3211 return (error); 3212 } 3213 3214 /* 3215 * nfs make dir rpc 3216 */ 3217 int 3218 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap, 3219 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 3220 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 3221 int *dattrflagp) 3222 { 3223 u_int32_t *tl; 3224 struct nfsrv_descript nfsd, *nd = &nfsd; 3225 nfsattrbit_t attrbits; 3226 int error = 0; 3227 struct nfsfh *fhp; 3228 struct nfsmount *nmp; 3229 3230 *nfhpp = NULL; 3231 *attrflagp = 0; 3232 *dattrflagp = 0; 3233 nmp = VFSTONFS(dvp->v_mount); 3234 fhp = VTONFS(dvp)->n_fhp; 3235 if (namelen > NFS_MAXNAMLEN) 3236 return (ENAMETOOLONG); 3237 NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp, cred); 3238 if (nd->nd_flag & ND_NFSV4) { 3239 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3240 *tl = txdr_unsigned(NFDIR); 3241 } 3242 (void) nfsm_strtom(nd, name, namelen); 3243 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1 | NFSSATTR_NEWFILE, 0); 3244 if (nd->nd_flag & ND_NFSV4) { 3245 NFSGETATTR_ATTRBIT(&attrbits); 3246 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3247 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3248 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3249 (void) nfsrv_putattrbit(nd, &attrbits); 3250 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3251 *tl = txdr_unsigned(NFSV4OP_PUTFH); 3252 (void)nfsm_fhtom(nmp, nd, fhp->nfh_fh, fhp->nfh_len, 0); 3253 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3254 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3255 (void) nfsrv_putattrbit(nd, &attrbits); 3256 } 3257 error = nfscl_request(nd, dvp, p, cred); 3258 if (error) 3259 return (error); 3260 if (nd->nd_flag & ND_NFSV4) 3261 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3262 if (!nd->nd_repstat && !error) { 3263 if (nd->nd_flag & ND_NFSV4) { 3264 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3265 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 3266 } 3267 if (!error) 3268 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 3269 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) { 3270 /* Get rid of the PutFH and Getattr status values. */ 3271 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); 3272 /* Load the directory attributes. */ 3273 error = nfsm_loadattr(nd, dnap); 3274 if (error == 0) 3275 *dattrflagp = 1; 3276 } 3277 } 3278 if ((nd->nd_flag & ND_NFSV3) && !error) 3279 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3280 if (nd->nd_repstat && !error) 3281 error = nd->nd_repstat; 3282 nfsmout: 3283 m_freem(nd->nd_mrep); 3284 /* 3285 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry. 3286 * Only do this if vfs.nfs.ignore_eexist is set. 3287 * Never do this for NFSv4.1 or later minor versions, since sessions 3288 * should guarantee "exactly once" RPC semantics. 3289 */ 3290 if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) || 3291 nmp->nm_minorvers == 0)) 3292 error = 0; 3293 return (error); 3294 } 3295 3296 /* 3297 * nfs remove directory call 3298 */ 3299 int 3300 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred, 3301 NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp) 3302 { 3303 struct nfsrv_descript nfsd, *nd = &nfsd; 3304 int error = 0; 3305 3306 *dattrflagp = 0; 3307 if (namelen > NFS_MAXNAMLEN) 3308 return (ENAMETOOLONG); 3309 NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp, cred); 3310 (void) nfsm_strtom(nd, name, namelen); 3311 error = nfscl_request(nd, dvp, p, cred); 3312 if (error) 3313 return (error); 3314 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) 3315 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, NULL); 3316 if (nd->nd_repstat && !error) 3317 error = nd->nd_repstat; 3318 m_freem(nd->nd_mrep); 3319 /* 3320 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry. 3321 */ 3322 if (error == ENOENT) 3323 error = 0; 3324 return (error); 3325 } 3326 3327 /* 3328 * Check to make sure the file name in a Readdir reply is valid. 3329 */ 3330 static bool 3331 nfscl_invalidfname(bool is_v4, char *name, int len) 3332 { 3333 int i; 3334 char *cp; 3335 3336 if (is_v4 && ((len == 1 && name[0] == '.') || 3337 (len == 2 && name[0] == '.' && name[1] == '.'))) { 3338 printf("Readdir NFSv4 reply has dot or dotdot in it\n"); 3339 return (true); 3340 } 3341 cp = name; 3342 for (i = 0; i < len; i++, cp++) { 3343 if (*cp == '/' || *cp == '\0') { 3344 printf("Readdir reply file name had imbedded / or nul" 3345 " byte\n"); 3346 return (true); 3347 } 3348 } 3349 return (false); 3350 } 3351 3352 /* 3353 * Readdir rpc. 3354 * Always returns with either uio_resid unchanged, if you are at the 3355 * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks 3356 * filled in. 3357 * I felt this would allow caching of directory blocks more easily 3358 * than returning a pertially filled block. 3359 * Directory offset cookies: 3360 * Oh my, what to do with them... 3361 * I can think of three ways to deal with them: 3362 * 1 - have the layer above these RPCs maintain a map between logical 3363 * directory byte offsets and the NFS directory offset cookies 3364 * 2 - pass the opaque directory offset cookies up into userland 3365 * and let the libc functions deal with them, via the system call 3366 * 3 - return them to userland in the "struct dirent", so future versions 3367 * of libc can use them and do whatever is necessary to make things work 3368 * above these rpc calls, in the meantime 3369 * For now, I do #3 by "hiding" the directory offset cookies after the 3370 * d_name field in struct dirent. This is space inside d_reclen that 3371 * will be ignored by anything that doesn't know about them. 3372 * The directory offset cookies are filled in as the last 8 bytes of 3373 * each directory entry, after d_name. Someday, the userland libc 3374 * functions may be able to use these. In the meantime, it satisfies 3375 * OpenBSD's requirements for cookies being returned. 3376 * If expects the directory offset cookie for the read to be in uio_offset 3377 * and returns the one for the next entry after this directory block in 3378 * there, as well. 3379 */ 3380 int 3381 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3382 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3383 int *eofp) 3384 { 3385 int len, left; 3386 struct dirent *dp = NULL; 3387 u_int32_t *tl; 3388 nfsquad_t cookie, ncookie; 3389 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 3390 struct nfsnode *dnp = VTONFS(vp); 3391 struct nfsvattr nfsva; 3392 struct nfsrv_descript nfsd, *nd = &nfsd; 3393 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3394 int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0; 3395 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3396 char *cp; 3397 nfsattrbit_t attrbits, dattrbits; 3398 u_int32_t rderr, *tl2 = NULL; 3399 size_t tresid; 3400 3401 KASSERT(uiop->uio_iovcnt == 1 && 3402 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 3403 ("nfs readdirrpc bad uio")); 3404 KASSERT(uiop->uio_segflg == UIO_SYSSPACE, 3405 ("nfsrpc_readdir: uio userspace")); 3406 ncookie.lval[0] = ncookie.lval[1] = 0; 3407 /* 3408 * There is no point in reading a lot more than uio_resid, however 3409 * adding one additional DIRBLKSIZ makes sense. Since uio_resid 3410 * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this 3411 * will never make readsize > nm_readdirsize. 3412 */ 3413 readsize = nmp->nm_readdirsize; 3414 if (readsize > uiop->uio_resid) 3415 readsize = uiop->uio_resid + DIRBLKSIZ; 3416 3417 *attrflagp = 0; 3418 if (eofp) 3419 *eofp = 0; 3420 tresid = uiop->uio_resid; 3421 cookie.lval[0] = cookiep->nfsuquad[0]; 3422 cookie.lval[1] = cookiep->nfsuquad[1]; 3423 nd->nd_mrep = NULL; 3424 3425 /* 3426 * For NFSv4, first create the "." and ".." entries. 3427 */ 3428 if (NFSHASNFSV4(nmp)) { 3429 reqsize = 6 * NFSX_UNSIGNED; 3430 NFSGETATTR_ATTRBIT(&dattrbits); 3431 NFSZERO_ATTRBIT(&attrbits); 3432 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3433 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE); 3434 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3435 NFSATTRBIT_MOUNTEDONFILEID)) { 3436 NFSSETBIT_ATTRBIT(&attrbits, 3437 NFSATTRBIT_MOUNTEDONFILEID); 3438 gotmnton = 1; 3439 } else { 3440 /* 3441 * Must fake it. Use the fileno, except when the 3442 * fsid is != to that of the directory. For that 3443 * case, generate a fake fileno that is not the same. 3444 */ 3445 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3446 gotmnton = 0; 3447 } 3448 3449 /* 3450 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3451 */ 3452 if (uiop->uio_offset == 0) { 3453 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred); 3454 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3455 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3456 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3457 (void) nfsrv_putattrbit(nd, &attrbits); 3458 error = nfscl_request(nd, vp, p, cred); 3459 if (error) 3460 return (error); 3461 dotfileid = 0; /* Fake out the compiler. */ 3462 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3463 error = nfsm_loadattr(nd, &nfsva); 3464 if (error != 0) 3465 goto nfsmout; 3466 dotfileid = nfsva.na_fileid; 3467 } 3468 if (nd->nd_repstat == 0) { 3469 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3470 len = fxdr_unsigned(int, *(tl + 4)); 3471 if (len > 0 && len <= NFSX_V4FHMAX) 3472 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3473 else 3474 error = EPERM; 3475 if (!error) { 3476 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3477 nfsva.na_mntonfileno = UINT64_MAX; 3478 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3479 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3480 NULL, NULL, NULL, p, cred); 3481 if (error) { 3482 dotdotfileid = dotfileid; 3483 } else if (gotmnton) { 3484 if (nfsva.na_mntonfileno != UINT64_MAX) 3485 dotdotfileid = nfsva.na_mntonfileno; 3486 else 3487 dotdotfileid = nfsva.na_fileid; 3488 } else if (nfsva.na_filesid[0] == 3489 dnp->n_vattr.na_filesid[0] && 3490 nfsva.na_filesid[1] == 3491 dnp->n_vattr.na_filesid[1]) { 3492 dotdotfileid = nfsva.na_fileid; 3493 } else { 3494 do { 3495 fakefileno--; 3496 } while (fakefileno == 3497 nfsva.na_fileid); 3498 dotdotfileid = fakefileno; 3499 } 3500 } 3501 } else if (nd->nd_repstat == NFSERR_NOENT) { 3502 /* 3503 * Lookupp returns NFSERR_NOENT when we are 3504 * at the root, so just use the current dir. 3505 */ 3506 nd->nd_repstat = 0; 3507 dotdotfileid = dotfileid; 3508 } else { 3509 error = nd->nd_repstat; 3510 } 3511 m_freem(nd->nd_mrep); 3512 if (error) 3513 return (error); 3514 nd->nd_mrep = NULL; 3515 dp = (struct dirent *)uiop->uio_iov->iov_base; 3516 dp->d_pad0 = dp->d_pad1 = 0; 3517 dp->d_off = 0; 3518 dp->d_type = DT_DIR; 3519 dp->d_fileno = dotfileid; 3520 dp->d_namlen = 1; 3521 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3522 dp->d_name[0] = '.'; 3523 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3524 /* 3525 * Just make these offset cookie 0. 3526 */ 3527 tl = (u_int32_t *)&dp->d_name[8]; 3528 *tl++ = 0; 3529 *tl = 0; 3530 blksiz += dp->d_reclen; 3531 uiop->uio_resid -= dp->d_reclen; 3532 uiop->uio_offset += dp->d_reclen; 3533 uiop->uio_iov->iov_base = 3534 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3535 uiop->uio_iov->iov_len -= dp->d_reclen; 3536 dp = (struct dirent *)uiop->uio_iov->iov_base; 3537 dp->d_pad0 = dp->d_pad1 = 0; 3538 dp->d_off = 0; 3539 dp->d_type = DT_DIR; 3540 dp->d_fileno = dotdotfileid; 3541 dp->d_namlen = 2; 3542 *((uint64_t *)dp->d_name) = 0; 3543 dp->d_name[0] = '.'; 3544 dp->d_name[1] = '.'; 3545 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3546 /* 3547 * Just make these offset cookie 0. 3548 */ 3549 tl = (u_int32_t *)&dp->d_name[8]; 3550 *tl++ = 0; 3551 *tl = 0; 3552 blksiz += dp->d_reclen; 3553 uiop->uio_resid -= dp->d_reclen; 3554 uiop->uio_offset += dp->d_reclen; 3555 uiop->uio_iov->iov_base = 3556 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 3557 uiop->uio_iov->iov_len -= dp->d_reclen; 3558 } 3559 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR); 3560 } else { 3561 reqsize = 5 * NFSX_UNSIGNED; 3562 } 3563 3564 /* 3565 * Loop around doing readdir rpc's of size readsize. 3566 * The stopping criteria is EOF or buffer full. 3567 */ 3568 while (more_dirs && bigenough) { 3569 *attrflagp = 0; 3570 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp, cred); 3571 if (nd->nd_flag & ND_NFSV2) { 3572 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3573 *tl++ = cookie.lval[1]; 3574 *tl = txdr_unsigned(readsize); 3575 } else { 3576 NFSM_BUILD(tl, u_int32_t *, reqsize); 3577 *tl++ = cookie.lval[0]; 3578 *tl++ = cookie.lval[1]; 3579 if (cookie.qval == 0) { 3580 *tl++ = 0; 3581 *tl++ = 0; 3582 } else { 3583 NFSLOCKNODE(dnp); 3584 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 3585 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 3586 NFSUNLOCKNODE(dnp); 3587 } 3588 if (nd->nd_flag & ND_NFSV4) { 3589 *tl++ = txdr_unsigned(readsize); 3590 *tl = txdr_unsigned(readsize); 3591 (void) nfsrv_putattrbit(nd, &attrbits); 3592 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 3593 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3594 (void) nfsrv_putattrbit(nd, &dattrbits); 3595 } else { 3596 *tl = txdr_unsigned(readsize); 3597 } 3598 } 3599 error = nfscl_request(nd, vp, p, cred); 3600 if (error) 3601 return (error); 3602 if (!(nd->nd_flag & ND_NFSV2)) { 3603 if (nd->nd_flag & ND_NFSV3) 3604 error = nfscl_postop_attr(nd, nap, attrflagp); 3605 if (!nd->nd_repstat && !error) { 3606 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER); 3607 NFSLOCKNODE(dnp); 3608 dnp->n_cookieverf.nfsuquad[0] = *tl++; 3609 dnp->n_cookieverf.nfsuquad[1] = *tl; 3610 NFSUNLOCKNODE(dnp); 3611 } 3612 } 3613 if (nd->nd_repstat || error) { 3614 if (!error) 3615 error = nd->nd_repstat; 3616 goto nfsmout; 3617 } 3618 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3619 more_dirs = fxdr_unsigned(int, *tl); 3620 if (!more_dirs) 3621 tryformoredirs = 0; 3622 3623 /* loop through the dir entries, doctoring them to 4bsd form */ 3624 while (more_dirs && bigenough) { 3625 if (nd->nd_flag & ND_NFSV4) { 3626 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3627 ncookie.lval[0] = *tl++; 3628 ncookie.lval[1] = *tl++; 3629 len = fxdr_unsigned(int, *tl); 3630 } else if (nd->nd_flag & ND_NFSV3) { 3631 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3632 nfsva.na_fileid = fxdr_hyper(tl); 3633 tl += 2; 3634 len = fxdr_unsigned(int, *tl); 3635 } else { 3636 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3637 nfsva.na_fileid = fxdr_unsigned(uint64_t, 3638 *tl++); 3639 len = fxdr_unsigned(int, *tl); 3640 } 3641 if (len <= 0 || len > NFS_MAXNAMLEN) { 3642 error = EBADRPC; 3643 goto nfsmout; 3644 } 3645 tlen = roundup2(len, 8); 3646 if (tlen == len) 3647 tlen += 8; /* To ensure null termination. */ 3648 left = DIRBLKSIZ - blksiz; 3649 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 3650 NFSBZERO(uiop->uio_iov->iov_base, left); 3651 dp->d_reclen += left; 3652 uiop->uio_iov->iov_base = 3653 (char *)uiop->uio_iov->iov_base + left; 3654 uiop->uio_iov->iov_len -= left; 3655 uiop->uio_resid -= left; 3656 uiop->uio_offset += left; 3657 blksiz = 0; 3658 } 3659 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 3660 uiop->uio_resid) 3661 bigenough = 0; 3662 if (bigenough) { 3663 struct iovec saviov; 3664 off_t savoff; 3665 ssize_t savresid; 3666 int savblksiz; 3667 3668 saviov.iov_base = uiop->uio_iov->iov_base; 3669 saviov.iov_len = uiop->uio_iov->iov_len; 3670 savoff = uiop->uio_offset; 3671 savresid = uiop->uio_resid; 3672 savblksiz = blksiz; 3673 3674 dp = (struct dirent *)uiop->uio_iov->iov_base; 3675 dp->d_pad0 = dp->d_pad1 = 0; 3676 dp->d_off = 0; 3677 dp->d_namlen = len; 3678 dp->d_reclen = _GENERIC_DIRLEN(len) + 3679 NFSX_HYPER; 3680 dp->d_type = DT_UNKNOWN; 3681 blksiz += dp->d_reclen; 3682 if (blksiz == DIRBLKSIZ) 3683 blksiz = 0; 3684 uiop->uio_resid -= DIRHDSIZ; 3685 uiop->uio_offset += DIRHDSIZ; 3686 uiop->uio_iov->iov_base = 3687 (char *)uiop->uio_iov->iov_base + DIRHDSIZ; 3688 uiop->uio_iov->iov_len -= DIRHDSIZ; 3689 cp = uiop->uio_iov->iov_base; 3690 error = nfsm_mbufuio(nd, uiop, len); 3691 if (error) 3692 goto nfsmout; 3693 /* Check for an invalid file name. */ 3694 if (nfscl_invalidfname( 3695 (nd->nd_flag & ND_NFSV4) != 0, cp, len)) { 3696 /* Skip over this entry. */ 3697 uiop->uio_iov->iov_base = 3698 saviov.iov_base; 3699 uiop->uio_iov->iov_len = 3700 saviov.iov_len; 3701 uiop->uio_offset = savoff; 3702 uiop->uio_resid = savresid; 3703 blksiz = savblksiz; 3704 } else { 3705 cp = uiop->uio_iov->iov_base; 3706 tlen -= len; 3707 NFSBZERO(cp, tlen); 3708 cp += tlen; /* points to cookie store */ 3709 tl2 = (u_int32_t *)cp; 3710 uiop->uio_iov->iov_base = 3711 (char *)uiop->uio_iov->iov_base + 3712 tlen + NFSX_HYPER; 3713 uiop->uio_iov->iov_len -= tlen + 3714 NFSX_HYPER; 3715 uiop->uio_resid -= tlen + NFSX_HYPER; 3716 uiop->uio_offset += (tlen + NFSX_HYPER); 3717 } 3718 } else { 3719 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3720 if (error) 3721 goto nfsmout; 3722 } 3723 if (nd->nd_flag & ND_NFSV4) { 3724 rderr = 0; 3725 nfsva.na_mntonfileno = UINT64_MAX; 3726 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3727 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3728 NULL, NULL, &rderr, p, cred); 3729 if (error) 3730 goto nfsmout; 3731 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3732 } else if (nd->nd_flag & ND_NFSV3) { 3733 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 3734 ncookie.lval[0] = *tl++; 3735 ncookie.lval[1] = *tl++; 3736 } else { 3737 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3738 ncookie.lval[0] = 0; 3739 ncookie.lval[1] = *tl++; 3740 } 3741 if (bigenough) { 3742 if (nd->nd_flag & ND_NFSV4) { 3743 if (rderr) { 3744 dp->d_fileno = 0; 3745 } else { 3746 if (gotmnton) { 3747 if (nfsva.na_mntonfileno != UINT64_MAX) 3748 dp->d_fileno = nfsva.na_mntonfileno; 3749 else 3750 dp->d_fileno = nfsva.na_fileid; 3751 } else if (nfsva.na_filesid[0] == 3752 dnp->n_vattr.na_filesid[0] && 3753 nfsva.na_filesid[1] == 3754 dnp->n_vattr.na_filesid[1]) { 3755 dp->d_fileno = nfsva.na_fileid; 3756 } else { 3757 do { 3758 fakefileno--; 3759 } while (fakefileno == 3760 nfsva.na_fileid); 3761 dp->d_fileno = fakefileno; 3762 } 3763 dp->d_type = vtonfs_dtype(nfsva.na_type); 3764 } 3765 } else { 3766 dp->d_fileno = nfsva.na_fileid; 3767 } 3768 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 3769 ncookie.lval[0]; 3770 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 3771 ncookie.lval[1]; 3772 } 3773 more_dirs = fxdr_unsigned(int, *tl); 3774 } 3775 /* 3776 * If at end of rpc data, get the eof boolean 3777 */ 3778 if (!more_dirs) { 3779 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 3780 eof = fxdr_unsigned(int, *tl); 3781 if (tryformoredirs) 3782 more_dirs = !eof; 3783 if (nd->nd_flag & ND_NFSV4) { 3784 error = nfscl_postop_attr(nd, nap, attrflagp); 3785 if (error) 3786 goto nfsmout; 3787 } 3788 } 3789 m_freem(nd->nd_mrep); 3790 nd->nd_mrep = NULL; 3791 } 3792 /* 3793 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 3794 * by increasing d_reclen for the last record. 3795 */ 3796 if (blksiz > 0) { 3797 left = DIRBLKSIZ - blksiz; 3798 NFSBZERO(uiop->uio_iov->iov_base, left); 3799 dp->d_reclen += left; 3800 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 3801 left; 3802 uiop->uio_iov->iov_len -= left; 3803 uiop->uio_resid -= left; 3804 uiop->uio_offset += left; 3805 } 3806 3807 /* 3808 * If returning no data, assume end of file. 3809 * If not bigenough, return not end of file, since you aren't 3810 * returning all the data 3811 * Otherwise, return the eof flag from the server. 3812 */ 3813 if (eofp) { 3814 if (tresid == ((size_t)(uiop->uio_resid))) 3815 *eofp = 1; 3816 else if (!bigenough) 3817 *eofp = 0; 3818 else 3819 *eofp = eof; 3820 } 3821 3822 /* 3823 * Add extra empty records to any remaining DIRBLKSIZ chunks. 3824 */ 3825 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { 3826 dp = (struct dirent *)uiop->uio_iov->iov_base; 3827 NFSBZERO(dp, DIRBLKSIZ); 3828 dp->d_type = DT_UNKNOWN; 3829 tl = (u_int32_t *)&dp->d_name[4]; 3830 *tl++ = cookie.lval[0]; 3831 *tl = cookie.lval[1]; 3832 dp->d_reclen = DIRBLKSIZ; 3833 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 3834 DIRBLKSIZ; 3835 uiop->uio_iov->iov_len -= DIRBLKSIZ; 3836 uiop->uio_resid -= DIRBLKSIZ; 3837 uiop->uio_offset += DIRBLKSIZ; 3838 } 3839 3840 nfsmout: 3841 if (nd->nd_mrep != NULL) 3842 m_freem(nd->nd_mrep); 3843 return (error); 3844 } 3845 3846 /* 3847 * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir(). 3848 * (Also used for NFS V4 when mount flag set.) 3849 * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.) 3850 */ 3851 int 3852 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep, 3853 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, 3854 int *eofp) 3855 { 3856 int len, left; 3857 struct dirent *dp = NULL; 3858 u_int32_t *tl; 3859 vnode_t newvp = NULLVP; 3860 struct nfsrv_descript nfsd, *nd = &nfsd; 3861 struct nameidata nami, *ndp = &nami; 3862 struct componentname *cnp = &ndp->ni_cnd; 3863 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 3864 struct nfsnode *dnp = VTONFS(vp), *np; 3865 struct nfsvattr nfsva; 3866 struct nfsfh *nfhp; 3867 nfsquad_t cookie, ncookie; 3868 int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1; 3869 int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0; 3870 int isdotdot = 0, unlocknewvp = 0; 3871 u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX; 3872 u_int64_t fileno = 0; 3873 char *cp; 3874 nfsattrbit_t attrbits, dattrbits; 3875 size_t tresid; 3876 u_int32_t *tl2 = NULL, rderr; 3877 struct timespec dctime, ts; 3878 bool attr_ok; 3879 3880 KASSERT(uiop->uio_iovcnt == 1 && 3881 (uiop->uio_resid & (DIRBLKSIZ - 1)) == 0, 3882 ("nfs readdirplusrpc bad uio")); 3883 KASSERT(uiop->uio_segflg == UIO_SYSSPACE, 3884 ("nfsrpc_readdirplus: uio userspace")); 3885 ncookie.lval[0] = ncookie.lval[1] = 0; 3886 timespecclear(&dctime); 3887 *attrflagp = 0; 3888 if (eofp != NULL) 3889 *eofp = 0; 3890 ndp->ni_dvp = vp; 3891 nd->nd_mrep = NULL; 3892 cookie.lval[0] = cookiep->nfsuquad[0]; 3893 cookie.lval[1] = cookiep->nfsuquad[1]; 3894 tresid = uiop->uio_resid; 3895 3896 /* 3897 * For NFSv4, first create the "." and ".." entries. 3898 */ 3899 if (NFSHASNFSV4(nmp)) { 3900 NFSGETATTR_ATTRBIT(&dattrbits); 3901 NFSZERO_ATTRBIT(&attrbits); 3902 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID); 3903 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 3904 NFSATTRBIT_MOUNTEDONFILEID)) { 3905 NFSSETBIT_ATTRBIT(&attrbits, 3906 NFSATTRBIT_MOUNTEDONFILEID); 3907 gotmnton = 1; 3908 } else { 3909 /* 3910 * Must fake it. Use the fileno, except when the 3911 * fsid is != to that of the directory. For that 3912 * case, generate a fake fileno that is not the same. 3913 */ 3914 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID); 3915 gotmnton = 0; 3916 } 3917 3918 /* 3919 * Joy, oh joy. For V4 we get to hand craft '.' and '..'. 3920 */ 3921 if (uiop->uio_offset == 0) { 3922 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp, cred); 3923 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 3924 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 3925 *tl = txdr_unsigned(NFSV4OP_GETATTR); 3926 (void) nfsrv_putattrbit(nd, &attrbits); 3927 error = nfscl_request(nd, vp, p, cred); 3928 if (error) 3929 return (error); 3930 dotfileid = 0; /* Fake out the compiler. */ 3931 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 3932 error = nfsm_loadattr(nd, &nfsva); 3933 if (error != 0) 3934 goto nfsmout; 3935 dctime = nfsva.na_ctime; 3936 dotfileid = nfsva.na_fileid; 3937 } 3938 if (nd->nd_repstat == 0) { 3939 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 3940 len = fxdr_unsigned(int, *(tl + 4)); 3941 if (len > 0 && len <= NFSX_V4FHMAX) 3942 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 3943 else 3944 error = EPERM; 3945 if (!error) { 3946 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED); 3947 nfsva.na_mntonfileno = UINT64_MAX; 3948 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 3949 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 3950 NULL, NULL, NULL, p, cred); 3951 if (error) { 3952 dotdotfileid = dotfileid; 3953 } else if (gotmnton) { 3954 if (nfsva.na_mntonfileno != UINT64_MAX) 3955 dotdotfileid = nfsva.na_mntonfileno; 3956 else 3957 dotdotfileid = nfsva.na_fileid; 3958 } else if (nfsva.na_filesid[0] == 3959 dnp->n_vattr.na_filesid[0] && 3960 nfsva.na_filesid[1] == 3961 dnp->n_vattr.na_filesid[1]) { 3962 dotdotfileid = nfsva.na_fileid; 3963 } else { 3964 do { 3965 fakefileno--; 3966 } while (fakefileno == 3967 nfsva.na_fileid); 3968 dotdotfileid = fakefileno; 3969 } 3970 } 3971 } else if (nd->nd_repstat == NFSERR_NOENT) { 3972 /* 3973 * Lookupp returns NFSERR_NOENT when we are 3974 * at the root, so just use the current dir. 3975 */ 3976 nd->nd_repstat = 0; 3977 dotdotfileid = dotfileid; 3978 } else { 3979 error = nd->nd_repstat; 3980 } 3981 m_freem(nd->nd_mrep); 3982 if (error) 3983 return (error); 3984 nd->nd_mrep = NULL; 3985 dp = (struct dirent *)uiop->uio_iov->iov_base; 3986 dp->d_pad0 = dp->d_pad1 = 0; 3987 dp->d_off = 0; 3988 dp->d_type = DT_DIR; 3989 dp->d_fileno = dotfileid; 3990 dp->d_namlen = 1; 3991 *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */ 3992 dp->d_name[0] = '.'; 3993 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 3994 /* 3995 * Just make these offset cookie 0. 3996 */ 3997 tl = (u_int32_t *)&dp->d_name[8]; 3998 *tl++ = 0; 3999 *tl = 0; 4000 blksiz += dp->d_reclen; 4001 uiop->uio_resid -= dp->d_reclen; 4002 uiop->uio_offset += dp->d_reclen; 4003 uiop->uio_iov->iov_base = 4004 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 4005 uiop->uio_iov->iov_len -= dp->d_reclen; 4006 dp = (struct dirent *)uiop->uio_iov->iov_base; 4007 dp->d_pad0 = dp->d_pad1 = 0; 4008 dp->d_off = 0; 4009 dp->d_type = DT_DIR; 4010 dp->d_fileno = dotdotfileid; 4011 dp->d_namlen = 2; 4012 *((uint64_t *)dp->d_name) = 0; 4013 dp->d_name[0] = '.'; 4014 dp->d_name[1] = '.'; 4015 dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER; 4016 /* 4017 * Just make these offset cookie 0. 4018 */ 4019 tl = (u_int32_t *)&dp->d_name[8]; 4020 *tl++ = 0; 4021 *tl = 0; 4022 blksiz += dp->d_reclen; 4023 uiop->uio_resid -= dp->d_reclen; 4024 uiop->uio_offset += dp->d_reclen; 4025 uiop->uio_iov->iov_base = 4026 (char *)uiop->uio_iov->iov_base + dp->d_reclen; 4027 uiop->uio_iov->iov_len -= dp->d_reclen; 4028 } 4029 NFSREADDIRPLUS_ATTRBIT(&attrbits); 4030 if (gotmnton) 4031 NFSSETBIT_ATTRBIT(&attrbits, 4032 NFSATTRBIT_MOUNTEDONFILEID); 4033 if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr, 4034 NFSATTRBIT_TIMECREATE)) 4035 NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE); 4036 } 4037 4038 /* 4039 * Loop around doing readdir rpc's of size nm_readdirsize. 4040 * The stopping criteria is EOF or buffer full. 4041 */ 4042 while (more_dirs && bigenough) { 4043 *attrflagp = 0; 4044 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp, cred); 4045 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED); 4046 *tl++ = cookie.lval[0]; 4047 *tl++ = cookie.lval[1]; 4048 if (cookie.qval == 0) { 4049 *tl++ = 0; 4050 *tl++ = 0; 4051 } else { 4052 NFSLOCKNODE(dnp); 4053 *tl++ = dnp->n_cookieverf.nfsuquad[0]; 4054 *tl++ = dnp->n_cookieverf.nfsuquad[1]; 4055 NFSUNLOCKNODE(dnp); 4056 } 4057 *tl++ = txdr_unsigned(nmp->nm_readdirsize); 4058 *tl = txdr_unsigned(nmp->nm_readdirsize); 4059 if (nd->nd_flag & ND_NFSV4) { 4060 (void) nfsrv_putattrbit(nd, &attrbits); 4061 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4062 *tl = txdr_unsigned(NFSV4OP_GETATTR); 4063 (void) nfsrv_putattrbit(nd, &dattrbits); 4064 } 4065 nanouptime(&ts); 4066 error = nfscl_request(nd, vp, p, cred); 4067 if (error) 4068 return (error); 4069 if (nd->nd_flag & ND_NFSV3) 4070 error = nfscl_postop_attr(nd, nap, attrflagp); 4071 if (nd->nd_repstat || error) { 4072 if (!error) 4073 error = nd->nd_repstat; 4074 goto nfsmout; 4075 } 4076 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0) 4077 dctime = nap->na_ctime; 4078 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4079 NFSLOCKNODE(dnp); 4080 dnp->n_cookieverf.nfsuquad[0] = *tl++; 4081 dnp->n_cookieverf.nfsuquad[1] = *tl++; 4082 NFSUNLOCKNODE(dnp); 4083 more_dirs = fxdr_unsigned(int, *tl); 4084 if (!more_dirs) 4085 tryformoredirs = 0; 4086 4087 /* loop through the dir entries, doctoring them to 4bsd form */ 4088 while (more_dirs && bigenough) { 4089 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4090 if (nd->nd_flag & ND_NFSV4) { 4091 ncookie.lval[0] = *tl++; 4092 ncookie.lval[1] = *tl++; 4093 } else { 4094 fileno = fxdr_hyper(tl); 4095 tl += 2; 4096 } 4097 len = fxdr_unsigned(int, *tl); 4098 if (len <= 0 || len > NFS_MAXNAMLEN) { 4099 error = EBADRPC; 4100 goto nfsmout; 4101 } 4102 tlen = roundup2(len, 8); 4103 if (tlen == len) 4104 tlen += 8; /* To ensure null termination. */ 4105 left = DIRBLKSIZ - blksiz; 4106 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) { 4107 NFSBZERO(uiop->uio_iov->iov_base, left); 4108 dp->d_reclen += left; 4109 uiop->uio_iov->iov_base = 4110 (char *)uiop->uio_iov->iov_base + left; 4111 uiop->uio_iov->iov_len -= left; 4112 uiop->uio_resid -= left; 4113 uiop->uio_offset += left; 4114 blksiz = 0; 4115 } 4116 if (_GENERIC_DIRLEN(len) + NFSX_HYPER > 4117 uiop->uio_resid) 4118 bigenough = 0; 4119 if (bigenough) { 4120 struct iovec saviov; 4121 off_t savoff; 4122 ssize_t savresid; 4123 int savblksiz; 4124 4125 saviov.iov_base = uiop->uio_iov->iov_base; 4126 saviov.iov_len = uiop->uio_iov->iov_len; 4127 savoff = uiop->uio_offset; 4128 savresid = uiop->uio_resid; 4129 savblksiz = blksiz; 4130 4131 dp = (struct dirent *)uiop->uio_iov->iov_base; 4132 dp->d_pad0 = dp->d_pad1 = 0; 4133 dp->d_off = 0; 4134 dp->d_namlen = len; 4135 dp->d_reclen = _GENERIC_DIRLEN(len) + 4136 NFSX_HYPER; 4137 dp->d_type = DT_UNKNOWN; 4138 blksiz += dp->d_reclen; 4139 if (blksiz == DIRBLKSIZ) 4140 blksiz = 0; 4141 uiop->uio_resid -= DIRHDSIZ; 4142 uiop->uio_offset += DIRHDSIZ; 4143 uiop->uio_iov->iov_base = 4144 (char *)uiop->uio_iov->iov_base + DIRHDSIZ; 4145 uiop->uio_iov->iov_len -= DIRHDSIZ; 4146 cnp->cn_nameptr = uiop->uio_iov->iov_base; 4147 cnp->cn_namelen = len; 4148 NFSCNHASHZERO(cnp); 4149 cp = uiop->uio_iov->iov_base; 4150 error = nfsm_mbufuio(nd, uiop, len); 4151 if (error) 4152 goto nfsmout; 4153 /* Check for an invalid file name. */ 4154 if (nfscl_invalidfname( 4155 (nd->nd_flag & ND_NFSV4) != 0, cp, len)) { 4156 /* Skip over this entry. */ 4157 uiop->uio_iov->iov_base = 4158 saviov.iov_base; 4159 uiop->uio_iov->iov_len = 4160 saviov.iov_len; 4161 uiop->uio_offset = savoff; 4162 uiop->uio_resid = savresid; 4163 blksiz = savblksiz; 4164 } else { 4165 cp = uiop->uio_iov->iov_base; 4166 tlen -= len; 4167 NFSBZERO(cp, tlen); 4168 cp += tlen; /* points to cookie store */ 4169 tl2 = (u_int32_t *)cp; 4170 if (len == 2 && 4171 cnp->cn_nameptr[0] == '.' && 4172 cnp->cn_nameptr[1] == '.') 4173 isdotdot = 1; 4174 else 4175 isdotdot = 0; 4176 uiop->uio_iov->iov_base = 4177 (char *)uiop->uio_iov->iov_base + 4178 tlen + NFSX_HYPER; 4179 uiop->uio_iov->iov_len -= tlen + 4180 NFSX_HYPER; 4181 uiop->uio_resid -= tlen + NFSX_HYPER; 4182 uiop->uio_offset += (tlen + NFSX_HYPER); 4183 } 4184 } else { 4185 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 4186 if (error) 4187 goto nfsmout; 4188 } 4189 nfhp = NULL; 4190 if (nd->nd_flag & ND_NFSV3) { 4191 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED); 4192 ncookie.lval[0] = *tl++; 4193 ncookie.lval[1] = *tl++; 4194 attrflag = fxdr_unsigned(int, *tl); 4195 if (attrflag) { 4196 error = nfsm_loadattr(nd, &nfsva); 4197 if (error) 4198 goto nfsmout; 4199 } 4200 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED); 4201 if (*tl) { 4202 error = nfsm_getfh(nd, &nfhp); 4203 if (error) 4204 goto nfsmout; 4205 } 4206 if (!attrflag && nfhp != NULL) { 4207 free(nfhp, M_NFSFH); 4208 nfhp = NULL; 4209 } 4210 } else { 4211 rderr = 0; 4212 nfsva.na_mntonfileno = 0xffffffff; 4213 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp, 4214 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 4215 NULL, NULL, &rderr, p, cred); 4216 if (error) 4217 goto nfsmout; 4218 } 4219 4220 if (bigenough) { 4221 if (nd->nd_flag & ND_NFSV4) { 4222 if (rderr) { 4223 dp->d_fileno = 0; 4224 } else if (gotmnton) { 4225 if (nfsva.na_mntonfileno != 0xffffffff) 4226 dp->d_fileno = nfsva.na_mntonfileno; 4227 else 4228 dp->d_fileno = nfsva.na_fileid; 4229 } else if (nfsva.na_filesid[0] == 4230 dnp->n_vattr.na_filesid[0] && 4231 nfsva.na_filesid[1] == 4232 dnp->n_vattr.na_filesid[1]) { 4233 dp->d_fileno = nfsva.na_fileid; 4234 } else { 4235 do { 4236 fakefileno--; 4237 } while (fakefileno == 4238 nfsva.na_fileid); 4239 dp->d_fileno = fakefileno; 4240 } 4241 } else { 4242 dp->d_fileno = fileno; 4243 } 4244 *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] = 4245 ncookie.lval[0]; 4246 *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] = 4247 ncookie.lval[1]; 4248 4249 if (nfhp != NULL) { 4250 attr_ok = true; 4251 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len, 4252 dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) { 4253 VREF(vp); 4254 newvp = vp; 4255 unlocknewvp = 0; 4256 free(nfhp, M_NFSFH); 4257 np = dnp; 4258 } else if (isdotdot != 0) { 4259 /* 4260 * Skip doing a nfscl_nget() call for "..". 4261 * There's a race between acquiring the nfs 4262 * node here and lookups that look for the 4263 * directory being read (in the parent). 4264 * It would try to get a lock on ".." here, 4265 * owning the lock on the directory being 4266 * read. Lookup will hold the lock on ".." 4267 * and try to acquire the lock on the 4268 * directory being read. 4269 * If the directory is unlocked/relocked, 4270 * then there is a LOR with the buflock 4271 * vp is relocked. 4272 */ 4273 free(nfhp, M_NFSFH); 4274 } else { 4275 error = nfscl_nget(vp->v_mount, vp, 4276 nfhp, cnp, p, &np, LK_EXCLUSIVE); 4277 if (!error) { 4278 newvp = NFSTOV(np); 4279 unlocknewvp = 1; 4280 /* 4281 * If n_localmodtime >= time before RPC, 4282 * then a file modification operation, 4283 * such as VOP_SETATTR() of size, has 4284 * occurred while the Lookup RPC and 4285 * acquisition of the vnode happened. As 4286 * such, the attributes might be stale, 4287 * with possibly an incorrect size. 4288 */ 4289 NFSLOCKNODE(np); 4290 if (timespecisset( 4291 &np->n_localmodtime) && 4292 timespeccmp(&np->n_localmodtime, 4293 &ts, >=)) { 4294 NFSCL_DEBUG(4, "nfsrpc_readdirplus:" 4295 " localmod stale attributes\n"); 4296 attr_ok = false; 4297 } 4298 NFSUNLOCKNODE(np); 4299 } 4300 } 4301 nfhp = NULL; 4302 if (newvp != NULLVP) { 4303 if (attr_ok) 4304 error = nfscl_loadattrcache(&newvp, 4305 &nfsva, NULL, 0, 0); 4306 if (error) { 4307 if (unlocknewvp) 4308 vput(newvp); 4309 else 4310 vrele(newvp); 4311 goto nfsmout; 4312 } 4313 dp->d_type = 4314 vtonfs_dtype(np->n_vattr.na_type); 4315 ndp->ni_vp = newvp; 4316 NFSCNHASH(cnp, HASHINIT); 4317 if (cnp->cn_namelen <= NCHNAMLEN && 4318 ndp->ni_dvp != ndp->ni_vp && 4319 (newvp->v_type != VDIR || 4320 dctime.tv_sec != 0)) { 4321 cache_enter_time_flags(ndp->ni_dvp, 4322 ndp->ni_vp, cnp, 4323 &nfsva.na_ctime, 4324 newvp->v_type != VDIR ? NULL : 4325 &dctime, VFS_CACHE_DROPOLD); 4326 } 4327 if (unlocknewvp) 4328 vput(newvp); 4329 else 4330 vrele(newvp); 4331 newvp = NULLVP; 4332 } 4333 } 4334 } else if (nfhp != NULL) { 4335 free(nfhp, M_NFSFH); 4336 } 4337 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4338 more_dirs = fxdr_unsigned(int, *tl); 4339 } 4340 /* 4341 * If at end of rpc data, get the eof boolean 4342 */ 4343 if (!more_dirs) { 4344 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 4345 eof = fxdr_unsigned(int, *tl); 4346 if (tryformoredirs) 4347 more_dirs = !eof; 4348 if (nd->nd_flag & ND_NFSV4) { 4349 error = nfscl_postop_attr(nd, nap, attrflagp); 4350 if (error) 4351 goto nfsmout; 4352 } 4353 } 4354 m_freem(nd->nd_mrep); 4355 nd->nd_mrep = NULL; 4356 } 4357 /* 4358 * Fill last record, iff any, out to a multiple of DIRBLKSIZ 4359 * by increasing d_reclen for the last record. 4360 */ 4361 if (blksiz > 0) { 4362 left = DIRBLKSIZ - blksiz; 4363 NFSBZERO(uiop->uio_iov->iov_base, left); 4364 dp->d_reclen += left; 4365 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 4366 left; 4367 uiop->uio_iov->iov_len -= left; 4368 uiop->uio_resid -= left; 4369 uiop->uio_offset += left; 4370 } 4371 4372 /* 4373 * If returning no data, assume end of file. 4374 * If not bigenough, return not end of file, since you aren't 4375 * returning all the data 4376 * Otherwise, return the eof flag from the server. 4377 */ 4378 if (eofp != NULL) { 4379 if (tresid == uiop->uio_resid) 4380 *eofp = 1; 4381 else if (!bigenough) 4382 *eofp = 0; 4383 else 4384 *eofp = eof; 4385 } 4386 4387 /* 4388 * Add extra empty records to any remaining DIRBLKSIZ chunks. 4389 */ 4390 while (uiop->uio_resid > 0 && uiop->uio_resid != tresid) { 4391 dp = (struct dirent *)uiop->uio_iov->iov_base; 4392 NFSBZERO(dp, DIRBLKSIZ); 4393 dp->d_type = DT_UNKNOWN; 4394 tl = (u_int32_t *)&dp->d_name[4]; 4395 *tl++ = cookie.lval[0]; 4396 *tl = cookie.lval[1]; 4397 dp->d_reclen = DIRBLKSIZ; 4398 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base + 4399 DIRBLKSIZ; 4400 uiop->uio_iov->iov_len -= DIRBLKSIZ; 4401 uiop->uio_resid -= DIRBLKSIZ; 4402 uiop->uio_offset += DIRBLKSIZ; 4403 } 4404 4405 nfsmout: 4406 if (nd->nd_mrep != NULL) 4407 m_freem(nd->nd_mrep); 4408 return (error); 4409 } 4410 4411 /* 4412 * Nfs commit rpc 4413 */ 4414 int 4415 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred, 4416 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 4417 { 4418 u_int32_t *tl; 4419 struct nfsrv_descript nfsd, *nd = &nfsd; 4420 nfsattrbit_t attrbits; 4421 int error; 4422 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4423 4424 *attrflagp = 0; 4425 NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp, cred); 4426 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 4427 txdr_hyper(offset, tl); 4428 tl += 2; 4429 *tl = txdr_unsigned(cnt); 4430 if (nd->nd_flag & ND_NFSV4) { 4431 /* 4432 * And do a Getattr op. 4433 */ 4434 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 4435 *tl = txdr_unsigned(NFSV4OP_GETATTR); 4436 NFSGETATTR_ATTRBIT(&attrbits); 4437 (void) nfsrv_putattrbit(nd, &attrbits); 4438 } 4439 error = nfscl_request(nd, vp, p, cred); 4440 if (error) 4441 return (error); 4442 error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, NULL); 4443 if (!error && !nd->nd_repstat) { 4444 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 4445 NFSLOCKMNT(nmp); 4446 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) { 4447 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 4448 nd->nd_repstat = NFSERR_STALEWRITEVERF; 4449 } 4450 NFSUNLOCKMNT(nmp); 4451 if (nd->nd_flag & ND_NFSV4) 4452 error = nfscl_postop_attr(nd, nap, attrflagp); 4453 } 4454 nfsmout: 4455 if (!error && nd->nd_repstat) 4456 error = nd->nd_repstat; 4457 m_freem(nd->nd_mrep); 4458 return (error); 4459 } 4460 4461 /* 4462 * NFS byte range lock rpc. 4463 * (Mostly just calls one of the three lower level RPC routines.) 4464 */ 4465 int 4466 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl, 4467 int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags) 4468 { 4469 struct nfscllockowner *lp; 4470 struct nfsclclient *clp; 4471 struct nfsfh *nfhp; 4472 struct nfsrv_descript nfsd, *nd = &nfsd; 4473 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 4474 u_int64_t off, len; 4475 off_t start, end; 4476 u_int32_t clidrev = 0; 4477 int error = 0, newone = 0, expireret = 0, retrycnt, donelocally; 4478 int callcnt, dorpc; 4479 4480 /* 4481 * Convert the flock structure into a start and end and do POSIX 4482 * bounds checking. 4483 */ 4484 switch (fl->l_whence) { 4485 case SEEK_SET: 4486 case SEEK_CUR: 4487 /* 4488 * Caller is responsible for adding any necessary offset 4489 * when SEEK_CUR is used. 4490 */ 4491 start = fl->l_start; 4492 off = fl->l_start; 4493 break; 4494 case SEEK_END: 4495 start = size + fl->l_start; 4496 off = size + fl->l_start; 4497 break; 4498 default: 4499 return (EINVAL); 4500 } 4501 if (start < 0) 4502 return (EINVAL); 4503 if (fl->l_len != 0) { 4504 end = start + fl->l_len - 1; 4505 if (end < start) 4506 return (EINVAL); 4507 } 4508 4509 len = fl->l_len; 4510 if (len == 0) 4511 len = NFS64BITSSET; 4512 retrycnt = 0; 4513 do { 4514 nd->nd_repstat = 0; 4515 if (op == F_GETLK) { 4516 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); 4517 if (error) 4518 return (error); 4519 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags); 4520 if (!error) { 4521 clidrev = clp->nfsc_clientidrev; 4522 error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred, 4523 p, id, flags); 4524 } else if (error == -1) { 4525 error = 0; 4526 } 4527 nfscl_clientrelease(clp); 4528 } else if (op == F_UNLCK && fl->l_type == F_UNLCK) { 4529 /* 4530 * We must loop around for all lockowner cases. 4531 */ 4532 callcnt = 0; 4533 error = nfscl_getcl(vp->v_mount, cred, p, false, true, &clp); 4534 if (error) 4535 return (error); 4536 do { 4537 error = nfscl_relbytelock(vp, off, len, cred, p, callcnt, 4538 clp, id, flags, &lp, &dorpc); 4539 /* 4540 * If it returns a NULL lp, we're done. 4541 */ 4542 if (lp == NULL) { 4543 if (callcnt == 0) 4544 nfscl_clientrelease(clp); 4545 else 4546 nfscl_releasealllocks(clp, vp, p, id, flags); 4547 return (error); 4548 } 4549 if (nmp->nm_clp != NULL) 4550 clidrev = nmp->nm_clp->nfsc_clientidrev; 4551 else 4552 clidrev = 0; 4553 /* 4554 * If the server doesn't support Posix lock semantics, 4555 * only allow locks on the entire file, since it won't 4556 * handle overlapping byte ranges. 4557 * There might still be a problem when a lock 4558 * upgrade/downgrade (read<->write) occurs, since the 4559 * server "might" expect an unlock first? 4560 */ 4561 if (dorpc && (lp->nfsl_open->nfso_posixlock || 4562 (off == 0 && len == NFS64BITSSET))) { 4563 /* 4564 * Since the lock records will go away, we must 4565 * wait for grace and delay here. 4566 */ 4567 do { 4568 error = nfsrpc_locku(nd, nmp, lp, off, len, 4569 NFSV4LOCKT_READ, cred, p, 0); 4570 if ((nd->nd_repstat == NFSERR_GRACE || 4571 nd->nd_repstat == NFSERR_DELAY) && 4572 error == 0) 4573 (void) nfs_catnap(PZERO, (int)nd->nd_repstat, 4574 "nfs_advlock"); 4575 } while ((nd->nd_repstat == NFSERR_GRACE || 4576 nd->nd_repstat == NFSERR_DELAY) && error == 0); 4577 } 4578 callcnt++; 4579 } while (error == 0 && nd->nd_repstat == 0); 4580 nfscl_releasealllocks(clp, vp, p, id, flags); 4581 } else if (op == F_SETLK) { 4582 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p, 4583 NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally); 4584 if (error || donelocally) { 4585 return (error); 4586 } 4587 if (nmp->nm_clp != NULL) 4588 clidrev = nmp->nm_clp->nfsc_clientidrev; 4589 else 4590 clidrev = 0; 4591 nfhp = VTONFS(vp)->n_fhp; 4592 if (!lp->nfsl_open->nfso_posixlock && 4593 (off != 0 || len != NFS64BITSSET)) { 4594 error = EINVAL; 4595 } else { 4596 error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh, 4597 nfhp->nfh_len, lp, newone, reclaim, off, 4598 len, fl->l_type, cred, p, 0); 4599 } 4600 if (!error) 4601 error = nd->nd_repstat; 4602 nfscl_lockrelease(lp, error, newone); 4603 } else { 4604 error = EINVAL; 4605 } 4606 if (!error) 4607 error = nd->nd_repstat; 4608 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 4609 error == NFSERR_STALEDONTRECOVER || 4610 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 4611 error == NFSERR_BADSESSION) { 4612 (void) nfs_catnap(PZERO, error, "nfs_advlock"); 4613 } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) 4614 && clidrev != 0) { 4615 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 4616 retrycnt++; 4617 } 4618 } while (error == NFSERR_GRACE || 4619 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY || 4620 error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID || 4621 error == NFSERR_BADSESSION || 4622 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 4623 expireret == 0 && clidrev != 0 && retrycnt < 4)); 4624 if (error && retrycnt >= 4) 4625 error = EIO; 4626 return (error); 4627 } 4628 4629 /* 4630 * The lower level routine for the LockT case. 4631 */ 4632 int 4633 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp, 4634 struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl, 4635 struct ucred *cred, NFSPROC_T *p, void *id, int flags) 4636 { 4637 u_int32_t *tl; 4638 int error, type, size; 4639 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4640 struct nfsnode *np; 4641 struct nfsmount *nmp; 4642 struct nfsclsession *tsep; 4643 4644 nmp = VFSTONFS(vp->v_mount); 4645 NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp, cred); 4646 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4647 if (fl->l_type == F_RDLCK) 4648 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4649 else 4650 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4651 txdr_hyper(off, tl); 4652 tl += 2; 4653 txdr_hyper(len, tl); 4654 tl += 2; 4655 tsep = nfsmnt_mdssession(nmp); 4656 *tl++ = tsep->nfsess_clientid.lval[0]; 4657 *tl = tsep->nfsess_clientid.lval[1]; 4658 nfscl_filllockowner(id, own, flags); 4659 np = VTONFS(vp); 4660 NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN], 4661 np->n_fhp->nfh_len); 4662 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len); 4663 error = nfscl_request(nd, vp, p, cred); 4664 if (error) 4665 return (error); 4666 if (nd->nd_repstat == 0) { 4667 fl->l_type = F_UNLCK; 4668 } else if (nd->nd_repstat == NFSERR_DENIED) { 4669 nd->nd_repstat = 0; 4670 fl->l_whence = SEEK_SET; 4671 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4672 fl->l_start = fxdr_hyper(tl); 4673 tl += 2; 4674 len = fxdr_hyper(tl); 4675 tl += 2; 4676 if (len == NFS64BITSSET) 4677 fl->l_len = 0; 4678 else 4679 fl->l_len = len; 4680 type = fxdr_unsigned(int, *tl++); 4681 if (type == NFSV4LOCKT_WRITE) 4682 fl->l_type = F_WRLCK; 4683 else 4684 fl->l_type = F_RDLCK; 4685 /* 4686 * XXX For now, I have no idea what to do with the 4687 * conflicting lock_owner, so I'll just set the pid == 0 4688 * and skip over the lock_owner. 4689 */ 4690 fl->l_pid = (pid_t)0; 4691 tl += 2; 4692 size = fxdr_unsigned(int, *tl); 4693 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4694 error = EBADRPC; 4695 if (!error) 4696 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4697 } else if (nd->nd_repstat == NFSERR_STALECLIENTID) 4698 nfscl_initiate_recovery(clp); 4699 nfsmout: 4700 m_freem(nd->nd_mrep); 4701 return (error); 4702 } 4703 4704 /* 4705 * Lower level function that performs the LockU RPC. 4706 */ 4707 static int 4708 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp, 4709 struct nfscllockowner *lp, u_int64_t off, u_int64_t len, 4710 u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred) 4711 { 4712 u_int32_t *tl; 4713 int error; 4714 4715 nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh, 4716 lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0, cred); 4717 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED); 4718 *tl++ = txdr_unsigned(type); 4719 *tl = txdr_unsigned(lp->nfsl_seqid); 4720 if (nfstest_outofseq && 4721 (arc4random() % nfstest_outofseq) == 0) 4722 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4723 tl++; 4724 if (NFSHASNFSV4N(nmp)) 4725 *tl++ = 0; 4726 else 4727 *tl++ = lp->nfsl_stateid.seqid; 4728 *tl++ = lp->nfsl_stateid.other[0]; 4729 *tl++ = lp->nfsl_stateid.other[1]; 4730 *tl++ = lp->nfsl_stateid.other[2]; 4731 txdr_hyper(off, tl); 4732 tl += 2; 4733 txdr_hyper(len, tl); 4734 if (syscred) 4735 nd->nd_flag |= ND_USEGSSNAME; 4736 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 4737 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4738 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4739 if (error) 4740 return (error); 4741 if (nd->nd_repstat == 0) { 4742 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4743 lp->nfsl_stateid.seqid = *tl++; 4744 lp->nfsl_stateid.other[0] = *tl++; 4745 lp->nfsl_stateid.other[1] = *tl++; 4746 lp->nfsl_stateid.other[2] = *tl; 4747 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4748 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4749 nfsmout: 4750 m_freem(nd->nd_mrep); 4751 return (error); 4752 } 4753 4754 /* 4755 * The actual Lock RPC. 4756 */ 4757 int 4758 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp, 4759 u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone, 4760 int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred, 4761 NFSPROC_T *p, int syscred) 4762 { 4763 u_int32_t *tl; 4764 int error, size; 4765 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 4766 struct nfsclsession *tsep; 4767 4768 nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0, 4769 cred); 4770 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED); 4771 if (type == F_RDLCK) 4772 *tl++ = txdr_unsigned(NFSV4LOCKT_READ); 4773 else 4774 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE); 4775 *tl++ = txdr_unsigned(reclaim); 4776 txdr_hyper(off, tl); 4777 tl += 2; 4778 txdr_hyper(len, tl); 4779 tl += 2; 4780 if (newone) { 4781 *tl = newnfs_true; 4782 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 4783 2 * NFSX_UNSIGNED + NFSX_HYPER); 4784 *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid); 4785 if (NFSHASNFSV4N(nmp)) 4786 *tl++ = 0; 4787 else 4788 *tl++ = lp->nfsl_open->nfso_stateid.seqid; 4789 *tl++ = lp->nfsl_open->nfso_stateid.other[0]; 4790 *tl++ = lp->nfsl_open->nfso_stateid.other[1]; 4791 *tl++ = lp->nfsl_open->nfso_stateid.other[2]; 4792 *tl++ = txdr_unsigned(lp->nfsl_seqid); 4793 tsep = nfsmnt_mdssession(nmp); 4794 *tl++ = tsep->nfsess_clientid.lval[0]; 4795 *tl = tsep->nfsess_clientid.lval[1]; 4796 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 4797 NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen); 4798 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 4799 } else { 4800 *tl = newnfs_false; 4801 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED); 4802 if (NFSHASNFSV4N(nmp)) 4803 *tl++ = 0; 4804 else 4805 *tl++ = lp->nfsl_stateid.seqid; 4806 *tl++ = lp->nfsl_stateid.other[0]; 4807 *tl++ = lp->nfsl_stateid.other[1]; 4808 *tl++ = lp->nfsl_stateid.other[2]; 4809 *tl = txdr_unsigned(lp->nfsl_seqid); 4810 if (nfstest_outofseq && 4811 (arc4random() % nfstest_outofseq) == 0) 4812 *tl = txdr_unsigned(lp->nfsl_seqid + 1); 4813 } 4814 if (syscred) 4815 nd->nd_flag |= ND_USEGSSNAME; 4816 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 4817 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 4818 if (error) 4819 return (error); 4820 if (newone) 4821 NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd); 4822 NFSCL_INCRSEQID(lp->nfsl_seqid, nd); 4823 if (nd->nd_repstat == 0) { 4824 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID); 4825 lp->nfsl_stateid.seqid = *tl++; 4826 lp->nfsl_stateid.other[0] = *tl++; 4827 lp->nfsl_stateid.other[1] = *tl++; 4828 lp->nfsl_stateid.other[2] = *tl; 4829 } else if (nd->nd_repstat == NFSERR_DENIED) { 4830 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED); 4831 size = fxdr_unsigned(int, *(tl + 7)); 4832 if (size < 0 || size > NFSV4_OPAQUELIMIT) 4833 error = EBADRPC; 4834 if (!error) 4835 error = nfsm_advance(nd, NFSM_RNDUP(size), -1); 4836 } else if (nd->nd_repstat == NFSERR_STALESTATEID) 4837 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp); 4838 nfsmout: 4839 m_freem(nd->nd_mrep); 4840 return (error); 4841 } 4842 4843 /* 4844 * nfs statfs rpc 4845 * (always called with the vp for the mount point) 4846 */ 4847 int 4848 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp, 4849 uint32_t *leasep, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, 4850 int *attrflagp) 4851 { 4852 u_int32_t *tl = NULL; 4853 struct nfsrv_descript nfsd, *nd = &nfsd; 4854 struct nfsmount *nmp; 4855 nfsattrbit_t attrbits; 4856 int error; 4857 4858 *attrflagp = 0; 4859 nmp = VFSTONFS(vp->v_mount); 4860 if (NFSHASNFSV4(nmp)) { 4861 /* 4862 * For V4, you actually do a getattr. 4863 */ 4864 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); 4865 if (leasep != NULL) 4866 NFSROOTFS_GETATTRBIT(&attrbits); 4867 else 4868 NFSSTATFS_GETATTRBIT(&attrbits); 4869 (void) nfsrv_putattrbit(nd, &attrbits); 4870 nd->nd_flag |= ND_USEGSSNAME; 4871 error = nfscl_request(nd, vp, p, cred); 4872 if (error) 4873 return (error); 4874 if (nd->nd_repstat == 0) { 4875 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4876 NULL, NULL, sbp, fsp, NULL, 0, NULL, leasep, NULL, 4877 p, cred); 4878 if (!error) { 4879 nmp->nm_fsid[0] = nap->na_filesid[0]; 4880 nmp->nm_fsid[1] = nap->na_filesid[1]; 4881 NFSSETHASSETFSID(nmp); 4882 *attrflagp = 1; 4883 } 4884 } else { 4885 error = nd->nd_repstat; 4886 } 4887 if (error) 4888 goto nfsmout; 4889 } else { 4890 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp, NULL); 4891 error = nfscl_request(nd, vp, p, cred); 4892 if (error) 4893 return (error); 4894 if (nd->nd_flag & ND_NFSV3) { 4895 error = nfscl_postop_attr(nd, nap, attrflagp); 4896 if (error) 4897 goto nfsmout; 4898 } 4899 if (nd->nd_repstat) { 4900 error = nd->nd_repstat; 4901 goto nfsmout; 4902 } 4903 NFSM_DISSECT(tl, u_int32_t *, 4904 NFSX_STATFS(nd->nd_flag & ND_NFSV3)); 4905 } 4906 if (NFSHASNFSV3(nmp)) { 4907 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2; 4908 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2; 4909 sbp->sf_abytes = fxdr_hyper(tl); tl += 2; 4910 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2; 4911 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2; 4912 sbp->sf_afiles = fxdr_hyper(tl); tl += 2; 4913 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl); 4914 } else if (NFSHASNFSV4(nmp) == 0) { 4915 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++); 4916 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++); 4917 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++); 4918 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++); 4919 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl); 4920 } 4921 nfsmout: 4922 m_freem(nd->nd_mrep); 4923 return (error); 4924 } 4925 4926 /* 4927 * nfs pathconf rpc 4928 */ 4929 int 4930 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc, 4931 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 4932 { 4933 struct nfsrv_descript nfsd, *nd = &nfsd; 4934 struct nfsmount *nmp; 4935 u_int32_t *tl; 4936 nfsattrbit_t attrbits; 4937 int error; 4938 struct nfsnode *np; 4939 4940 *attrflagp = 0; 4941 nmp = VFSTONFS(vp->v_mount); 4942 if (NFSHASNFSV4(nmp)) { 4943 np = VTONFS(vp); 4944 if ((nmp->nm_privflag & NFSMNTP_FAKEROOTFH) != 0 && 4945 nmp->nm_fhsize == 0) { 4946 /* Attempt to get the actual root file handle. */ 4947 error = nfsrpc_getdirpath(nmp, NFSMNT_DIRPATH(nmp), 4948 cred, p); 4949 if (error != 0) 4950 return (EACCES); 4951 if (np->n_fhp->nfh_len == NFSX_FHMAX + 1) 4952 nfscl_statfs(vp, cred, p); 4953 } 4954 /* 4955 * For V4, you actually do a getattr. 4956 */ 4957 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp, cred); 4958 NFSPATHCONF_GETATTRBIT(&attrbits); 4959 (void) nfsrv_putattrbit(nd, &attrbits); 4960 nd->nd_flag |= ND_USEGSSNAME; 4961 error = nfscl_request(nd, vp, p, cred); 4962 if (error) 4963 return (error); 4964 if (nd->nd_repstat == 0) { 4965 error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0, 4966 pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p, 4967 cred); 4968 if (!error) 4969 *attrflagp = 1; 4970 } else { 4971 error = nd->nd_repstat; 4972 } 4973 } else { 4974 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp, NULL); 4975 error = nfscl_request(nd, vp, p, cred); 4976 if (error) 4977 return (error); 4978 error = nfscl_postop_attr(nd, nap, attrflagp); 4979 if (nd->nd_repstat && !error) 4980 error = nd->nd_repstat; 4981 if (!error) { 4982 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF); 4983 pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++); 4984 pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++); 4985 pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++); 4986 pc->pc_chownrestricted = 4987 fxdr_unsigned(u_int32_t, *tl++); 4988 pc->pc_caseinsensitive = 4989 fxdr_unsigned(u_int32_t, *tl++); 4990 pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl); 4991 } 4992 } 4993 nfsmout: 4994 m_freem(nd->nd_mrep); 4995 return (error); 4996 } 4997 4998 /* 4999 * nfs version 3 fsinfo rpc call 5000 */ 5001 int 5002 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred, 5003 NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp) 5004 { 5005 u_int32_t *tl; 5006 struct nfsrv_descript nfsd, *nd = &nfsd; 5007 int error; 5008 5009 *attrflagp = 0; 5010 NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp, NULL); 5011 error = nfscl_request(nd, vp, p, cred); 5012 if (error) 5013 return (error); 5014 error = nfscl_postop_attr(nd, nap, attrflagp); 5015 if (nd->nd_repstat && !error) 5016 error = nd->nd_repstat; 5017 if (!error) { 5018 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO); 5019 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++); 5020 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++); 5021 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++); 5022 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++); 5023 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++); 5024 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++); 5025 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++); 5026 fsp->fs_maxfilesize = fxdr_hyper(tl); 5027 tl += 2; 5028 fxdr_nfsv3time(tl, &fsp->fs_timedelta); 5029 tl += 2; 5030 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl); 5031 } 5032 nfsmout: 5033 m_freem(nd->nd_mrep); 5034 return (error); 5035 } 5036 5037 /* 5038 * This function performs the Renew RPC. 5039 */ 5040 int 5041 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred, 5042 NFSPROC_T *p) 5043 { 5044 u_int32_t *tl; 5045 struct nfsrv_descript nfsd; 5046 struct nfsrv_descript *nd = &nfsd; 5047 struct nfsmount *nmp; 5048 int error; 5049 struct nfssockreq *nrp; 5050 struct nfsclsession *tsep; 5051 5052 nmp = clp->nfsc_nmp; 5053 if (nmp == NULL) 5054 return (0); 5055 if (dsp == NULL) 5056 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0, 5057 0, cred); 5058 else 5059 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, 5060 &dsp->nfsclds_sess, 0, 0, NULL); 5061 if (!NFSHASNFSV4N(nmp)) { 5062 /* NFSv4.1 just uses a Sequence Op and not a Renew. */ 5063 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 5064 tsep = nfsmnt_mdssession(nmp); 5065 *tl++ = tsep->nfsess_clientid.lval[0]; 5066 *tl = tsep->nfsess_clientid.lval[1]; 5067 } 5068 nrp = NULL; 5069 if (dsp != NULL) 5070 nrp = dsp->nfsclds_sockp; 5071 if (nrp == NULL) 5072 /* If NULL, use the MDS socket. */ 5073 nrp = &nmp->nm_sockreq; 5074 nd->nd_flag |= ND_USEGSSNAME; 5075 if (dsp == NULL) 5076 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 5077 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5078 else { 5079 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 5080 NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess); 5081 if (error == ENXIO) 5082 nfscl_cancelreqs(dsp); 5083 } 5084 if (error) 5085 return (error); 5086 error = nd->nd_repstat; 5087 m_freem(nd->nd_mrep); 5088 return (error); 5089 } 5090 5091 /* 5092 * This function performs the Releaselockowner RPC. 5093 */ 5094 int 5095 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp, 5096 uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p) 5097 { 5098 struct nfsrv_descript nfsd, *nd = &nfsd; 5099 u_int32_t *tl; 5100 int error; 5101 uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX]; 5102 struct nfsclsession *tsep; 5103 5104 if (NFSHASNFSV4N(nmp)) { 5105 /* For NFSv4.1, do a FreeStateID. */ 5106 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL, 5107 NULL, 0, 0, cred); 5108 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID); 5109 } else { 5110 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL, 5111 NULL, 0, 0, NULL); 5112 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 5113 tsep = nfsmnt_mdssession(nmp); 5114 *tl++ = tsep->nfsess_clientid.lval[0]; 5115 *tl = tsep->nfsess_clientid.lval[1]; 5116 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN); 5117 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen); 5118 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen); 5119 } 5120 nd->nd_flag |= ND_USEGSSNAME; 5121 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5122 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5123 if (error) 5124 return (error); 5125 error = nd->nd_repstat; 5126 m_freem(nd->nd_mrep); 5127 return (error); 5128 } 5129 5130 /* 5131 * This function performs the Compound to get the mount pt FH. 5132 */ 5133 int 5134 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred, 5135 NFSPROC_T *p) 5136 { 5137 u_int32_t *tl; 5138 struct nfsrv_descript nfsd; 5139 struct nfsrv_descript *nd = &nfsd; 5140 u_char *cp, *cp2, *fhp; 5141 int error, cnt, len, setnil; 5142 u_int32_t *opcntp; 5143 5144 nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0, 5145 0, NULL); 5146 cp = dirpath; 5147 cnt = 0; 5148 do { 5149 setnil = 0; 5150 while (*cp == '/') 5151 cp++; 5152 cp2 = cp; 5153 while (*cp2 != '\0' && *cp2 != '/') 5154 cp2++; 5155 if (*cp2 == '/') { 5156 setnil = 1; 5157 *cp2 = '\0'; 5158 } 5159 if (cp2 != cp) { 5160 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 5161 *tl = txdr_unsigned(NFSV4OP_LOOKUP); 5162 nfsm_strtom(nd, cp, strlen(cp)); 5163 cnt++; 5164 } 5165 if (setnil) 5166 *cp2++ = '/'; 5167 cp = cp2; 5168 } while (*cp != '\0'); 5169 if (NFSHASNFSV4N(nmp)) 5170 /* Has a Sequence Op done by nfscl_reqstart(). */ 5171 *opcntp = txdr_unsigned(3 + cnt); 5172 else 5173 *opcntp = txdr_unsigned(2 + cnt); 5174 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 5175 *tl = txdr_unsigned(NFSV4OP_GETFH); 5176 nd->nd_flag |= ND_USEGSSNAME; 5177 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5178 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5179 if (error) 5180 return (error); 5181 if (nd->nd_repstat == 0) { 5182 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED); 5183 tl += (2 + 2 * cnt); 5184 if ((len = fxdr_unsigned(int, *tl)) <= 0 || 5185 len > NFSX_FHMAX) { 5186 nd->nd_repstat = NFSERR_BADXDR; 5187 } else { 5188 fhp = malloc(len + 1, M_TEMP, M_WAITOK); 5189 nd->nd_repstat = nfsrv_mtostr(nd, fhp, len); 5190 if (nd->nd_repstat == 0) { 5191 NFSLOCKMNT(nmp); 5192 if (nmp->nm_fhsize == 0) { 5193 NFSBCOPY(fhp, nmp->nm_fh, len); 5194 nmp->nm_fhsize = len; 5195 } 5196 NFSUNLOCKMNT(nmp); 5197 } 5198 free(fhp, M_TEMP); 5199 } 5200 } 5201 error = nd->nd_repstat; 5202 nfsmout: 5203 m_freem(nd->nd_mrep); 5204 return (error); 5205 } 5206 5207 /* 5208 * This function performs the Delegreturn RPC. 5209 */ 5210 int 5211 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred, 5212 struct nfsmount *nmp, NFSPROC_T *p, int syscred) 5213 { 5214 u_int32_t *tl; 5215 struct nfsrv_descript nfsd; 5216 struct nfsrv_descript *nd = &nfsd; 5217 int error; 5218 5219 nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh, 5220 dp->nfsdl_fhlen, NULL, NULL, 0, 0, cred); 5221 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID); 5222 if (NFSHASNFSV4N(nmp)) 5223 *tl++ = 0; 5224 else 5225 *tl++ = dp->nfsdl_stateid.seqid; 5226 *tl++ = dp->nfsdl_stateid.other[0]; 5227 *tl++ = dp->nfsdl_stateid.other[1]; 5228 *tl = dp->nfsdl_stateid.other[2]; 5229 if (syscred) 5230 nd->nd_flag |= ND_USEGSSNAME; 5231 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5232 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5233 if (error) 5234 return (error); 5235 error = nd->nd_repstat; 5236 m_freem(nd->nd_mrep); 5237 return (error); 5238 } 5239 5240 /* 5241 * nfs getacl call. 5242 */ 5243 int 5244 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) 5245 { 5246 struct nfsrv_descript nfsd, *nd = &nfsd; 5247 int error; 5248 nfsattrbit_t attrbits; 5249 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 5250 5251 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 5252 return (EOPNOTSUPP); 5253 NFSCL_REQSTART(nd, NFSPROC_GETACL, vp, cred); 5254 NFSZERO_ATTRBIT(&attrbits); 5255 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 5256 (void) nfsrv_putattrbit(nd, &attrbits); 5257 error = nfscl_request(nd, vp, p, cred); 5258 if (error) 5259 return (error); 5260 if (!nd->nd_repstat) 5261 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL, 5262 NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred); 5263 else 5264 error = nd->nd_repstat; 5265 m_freem(nd->nd_mrep); 5266 return (error); 5267 } 5268 5269 /* 5270 * nfs setacl call. 5271 */ 5272 int 5273 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p, struct acl *aclp) 5274 { 5275 int error; 5276 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 5277 5278 if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp)) 5279 return (EOPNOTSUPP); 5280 error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL); 5281 return (error); 5282 } 5283 5284 /* 5285 * nfs setacl call. 5286 */ 5287 static int 5288 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p, 5289 struct acl *aclp, nfsv4stateid_t *stateidp) 5290 { 5291 struct nfsrv_descript nfsd, *nd = &nfsd; 5292 int error; 5293 nfsattrbit_t attrbits; 5294 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 5295 5296 if (!NFSHASNFSV4(nmp)) 5297 return (EOPNOTSUPP); 5298 NFSCL_REQSTART(nd, NFSPROC_SETACL, vp, cred); 5299 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 5300 NFSZERO_ATTRBIT(&attrbits); 5301 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL); 5302 (void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0, 5303 &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL); 5304 error = nfscl_request(nd, vp, p, cred); 5305 if (error) 5306 return (error); 5307 /* Don't care about the pre/postop attributes */ 5308 m_freem(nd->nd_mrep); 5309 return (nd->nd_repstat); 5310 } 5311 5312 /* 5313 * Do the NFSv4.1 Exchange ID. 5314 */ 5315 int 5316 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp, 5317 struct nfssockreq *nrp, int minorvers, uint32_t exchflags, 5318 struct nfsclds **dspp, struct ucred *cred, NFSPROC_T *p) 5319 { 5320 uint32_t *tl, v41flags; 5321 struct nfsrv_descript nfsd; 5322 struct nfsrv_descript *nd = &nfsd; 5323 struct nfsclds *dsp; 5324 struct timespec verstime; 5325 int error, len; 5326 5327 *dspp = NULL; 5328 if (minorvers == 0) 5329 minorvers = nmp->nm_minorvers; 5330 nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, 5331 NFS_VER4, minorvers, NULL); 5332 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5333 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* Client owner */ 5334 *tl = txdr_unsigned(clp->nfsc_rev); 5335 (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen); 5336 5337 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED); 5338 *tl++ = txdr_unsigned(exchflags); 5339 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE); 5340 5341 /* Set the implementation id4 */ 5342 *tl = txdr_unsigned(1); 5343 (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org")); 5344 (void) nfsm_strtom(nd, version, strlen(version)); 5345 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME); 5346 verstime.tv_sec = 1293840000; /* Jan 1, 2011 */ 5347 verstime.tv_nsec = 0; 5348 txdr_nfsv4time(&verstime, tl); 5349 nd->nd_flag |= ND_USEGSSNAME; 5350 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, 5351 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5352 NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error, 5353 (int)nd->nd_repstat); 5354 if (error != 0) 5355 return (error); 5356 if (nd->nd_repstat == 0) { 5357 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER); 5358 len = fxdr_unsigned(int, *(tl + 7)); 5359 if (len < 0 || len > NFSV4_OPAQUELIMIT) { 5360 error = NFSERR_BADXDR; 5361 goto nfsmout; 5362 } 5363 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS, 5364 M_WAITOK | M_ZERO); 5365 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew; 5366 dsp->nfsclds_servownlen = len; 5367 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++; 5368 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++; 5369 dsp->nfsclds_sess.nfsess_sequenceid = 5370 fxdr_unsigned(uint32_t, *tl++); 5371 v41flags = fxdr_unsigned(uint32_t, *tl); 5372 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 && 5373 NFSHASPNFSOPT(nmp)) { 5374 NFSCL_DEBUG(1, "set PNFS\n"); 5375 NFSLOCKMNT(nmp); 5376 nmp->nm_state |= NFSSTA_PNFS; 5377 NFSUNLOCKMNT(nmp); 5378 dsp->nfsclds_flags |= NFSCLDS_MDS; 5379 } 5380 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0) 5381 dsp->nfsclds_flags |= NFSCLDS_DS; 5382 if (minorvers == NFSV42_MINORVERSION) 5383 dsp->nfsclds_flags |= NFSCLDS_MINORV2; 5384 if (len > 0) 5385 nd->nd_repstat = nfsrv_mtostr(nd, 5386 dsp->nfsclds_serverown, len); 5387 if (nd->nd_repstat == 0) { 5388 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 5389 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 5390 NULL, MTX_DEF); 5391 nfscl_initsessionslots(&dsp->nfsclds_sess); 5392 *dspp = dsp; 5393 } else 5394 free(dsp, M_NFSCLDS); 5395 } 5396 error = nd->nd_repstat; 5397 nfsmout: 5398 m_freem(nd->nd_mrep); 5399 return (error); 5400 } 5401 5402 /* 5403 * Do the NFSv4.1 Create Session. 5404 */ 5405 int 5406 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep, 5407 struct nfssockreq *nrp, struct nfsclds *dsp, uint32_t sequenceid, int mds, 5408 struct ucred *cred, NFSPROC_T *p) 5409 { 5410 uint32_t crflags, maxval, *tl; 5411 struct nfsrv_descript nfsd; 5412 struct nfsrv_descript *nd = &nfsd; 5413 int error, irdcnt, minorvers; 5414 5415 /* Make sure nm_rsize, nm_wsize is set. */ 5416 if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0) 5417 nmp->nm_rsize = NFS_MAXBSIZE; 5418 if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0) 5419 nmp->nm_wsize = NFS_MAXBSIZE; 5420 if (dsp == NULL) 5421 minorvers = nmp->nm_minorvers; 5422 else if ((dsp->nfsclds_flags & NFSCLDS_MINORV2) != 0) 5423 minorvers = NFSV42_MINORVERSION; 5424 else 5425 minorvers = NFSV41_MINORVERSION; 5426 nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, 5427 NFS_VER4, minorvers, NULL); 5428 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5429 *tl++ = sep->nfsess_clientid.lval[0]; 5430 *tl++ = sep->nfsess_clientid.lval[1]; 5431 *tl++ = txdr_unsigned(sequenceid); 5432 crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST); 5433 if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0) 5434 crflags |= NFSV4CRSESS_CONNBACKCHAN; 5435 *tl = txdr_unsigned(crflags); 5436 5437 /* Fill in fore channel attributes. */ 5438 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5439 *tl++ = 0; /* Header pad size */ 5440 if ((nd->nd_flag & ND_NFSV42) != 0 && mds != 0 && sb_max_adj >= 5441 nmp->nm_wsize && sb_max_adj >= nmp->nm_rsize) { 5442 /* 5443 * NFSv4.2 Extended Attribute operations may want to do 5444 * requests/replies that are larger than nm_rsize/nm_wsize. 5445 */ 5446 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); 5447 *tl++ = txdr_unsigned(sb_max_adj - NFS_MAXXDR); 5448 } else { 5449 *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR); 5450 *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR); 5451 } 5452 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 5453 *tl++ = txdr_unsigned(20); /* Max operations */ 5454 *tl++ = txdr_unsigned(64); /* Max slots */ 5455 *tl = 0; /* No rdma ird */ 5456 5457 /* Fill in back channel attributes. */ 5458 NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5459 *tl++ = 0; /* Header pad size */ 5460 *tl++ = txdr_unsigned(10000); /* Max request size */ 5461 *tl++ = txdr_unsigned(10000); /* Max response size */ 5462 *tl++ = txdr_unsigned(4096); /* Max response size cached */ 5463 *tl++ = txdr_unsigned(4); /* Max operations */ 5464 *tl++ = txdr_unsigned(NFSV4_CBSLOTS); /* Max slots */ 5465 *tl = 0; /* No rdma ird */ 5466 5467 NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED); 5468 *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */ 5469 5470 /* Allow AUTH_SYS callbacks as uid, gid == 0. */ 5471 *tl++ = txdr_unsigned(1); /* Auth_sys only */ 5472 *tl++ = txdr_unsigned(AUTH_SYS); /* AUTH_SYS type */ 5473 *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */ 5474 *tl++ = 0; /* Null machine name */ 5475 *tl++ = 0; /* Uid == 0 */ 5476 *tl++ = 0; /* Gid == 0 */ 5477 *tl = 0; /* No additional gids */ 5478 nd->nd_flag |= ND_USEGSSNAME; 5479 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG, 5480 NFS_VER4, NULL, 1, NULL, NULL); 5481 if (error != 0) 5482 return (error); 5483 if (nd->nd_repstat == 0) { 5484 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 5485 2 * NFSX_UNSIGNED); 5486 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID); 5487 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 5488 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++); 5489 crflags = fxdr_unsigned(uint32_t, *tl); 5490 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) { 5491 NFSLOCKMNT(nmp); 5492 nmp->nm_state |= NFSSTA_SESSPERSIST; 5493 NFSUNLOCKMNT(nmp); 5494 } 5495 5496 /* Get the fore channel slot count. */ 5497 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5498 tl++; /* Skip the header pad size. */ 5499 5500 /* Make sure nm_wsize is small enough. */ 5501 maxval = fxdr_unsigned(uint32_t, *tl++); 5502 while (maxval < nmp->nm_wsize + NFS_MAXXDR) { 5503 if (nmp->nm_wsize > 8096) 5504 nmp->nm_wsize /= 2; 5505 else 5506 break; 5507 } 5508 sep->nfsess_maxreq = maxval; 5509 5510 /* Make sure nm_rsize is small enough. */ 5511 maxval = fxdr_unsigned(uint32_t, *tl++); 5512 while (maxval < nmp->nm_rsize + NFS_MAXXDR) { 5513 if (nmp->nm_rsize > 8096) 5514 nmp->nm_rsize /= 2; 5515 else 5516 break; 5517 } 5518 sep->nfsess_maxresp = maxval; 5519 5520 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++); 5521 tl++; 5522 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++); 5523 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots); 5524 irdcnt = fxdr_unsigned(int, *tl); 5525 if (irdcnt < 0 || irdcnt > 1) { 5526 error = NFSERR_BADXDR; 5527 goto nfsmout; 5528 } 5529 if (irdcnt > 0) 5530 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 5531 5532 /* and the back channel slot count. */ 5533 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5534 tl += 5; 5535 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 5536 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 5537 } 5538 error = nd->nd_repstat; 5539 nfsmout: 5540 m_freem(nd->nd_mrep); 5541 return (error); 5542 } 5543 5544 /* 5545 * Do the NFSv4.1 Destroy Client. 5546 */ 5547 int 5548 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 5549 struct ucred *cred, NFSPROC_T *p) 5550 { 5551 uint32_t *tl; 5552 struct nfsrv_descript nfsd; 5553 struct nfsrv_descript *nd = &nfsd; 5554 int error; 5555 struct nfsclsession *tsep; 5556 5557 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0, 5558 0, NULL); 5559 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5560 tsep = nfsmnt_mdssession(nmp); 5561 *tl++ = tsep->nfsess_clientid.lval[0]; 5562 *tl = tsep->nfsess_clientid.lval[1]; 5563 nd->nd_flag |= ND_USEGSSNAME; 5564 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5565 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5566 if (error != 0) 5567 return (error); 5568 error = nd->nd_repstat; 5569 m_freem(nd->nd_mrep); 5570 return (error); 5571 } 5572 5573 /* 5574 * Do the NFSv4.1 LayoutGet. 5575 */ 5576 static int 5577 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 5578 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype, 5579 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep, 5580 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p) 5581 { 5582 struct nfsrv_descript nfsd, *nd = &nfsd; 5583 int error; 5584 5585 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0, 5586 0, cred); 5587 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, 5588 layouttype, layoutlen, 0); 5589 nd->nd_flag |= ND_USEGSSNAME; 5590 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5591 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5592 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); 5593 if (error != 0) 5594 return (error); 5595 if (nd->nd_repstat == 0) 5596 error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep, 5597 flhp); 5598 if (error == 0 && nd->nd_repstat != 0) 5599 error = nd->nd_repstat; 5600 m_freem(nd->nd_mrep); 5601 return (error); 5602 } 5603 5604 /* 5605 * Do the NFSv4.1 Get Device Info. 5606 */ 5607 int 5608 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 5609 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 5610 NFSPROC_T *p) 5611 { 5612 uint32_t cnt, *tl, vers, minorvers; 5613 struct nfsrv_descript nfsd; 5614 struct nfsrv_descript *nd = &nfsd; 5615 struct sockaddr_in sin, ssin; 5616 struct sockaddr_in6 sin6, ssin6; 5617 struct nfsclds *dsp = NULL, **dspp, **gotdspp; 5618 struct nfscldevinfo *ndi; 5619 int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j; 5620 int stripecnt; 5621 uint8_t stripeindex; 5622 sa_family_t af, safilled; 5623 5624 ssin.sin_port = 0; /* To shut up compiler. */ 5625 ssin.sin_addr.s_addr = 0; /* ditto */ 5626 *ndip = NULL; 5627 ndi = NULL; 5628 gotdspp = NULL; 5629 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0, 5630 0, cred); 5631 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5632 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 5633 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5634 *tl++ = txdr_unsigned(layouttype); 5635 *tl++ = txdr_unsigned(100000); 5636 if (notifybitsp != NULL && *notifybitsp != 0) { 5637 *tl = txdr_unsigned(1); /* One word of bits. */ 5638 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5639 *tl = txdr_unsigned(*notifybitsp); 5640 } else 5641 *tl = txdr_unsigned(0); 5642 nd->nd_flag |= ND_USEGSSNAME; 5643 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5644 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5645 if (error != 0) 5646 return (error); 5647 if (nd->nd_repstat == 0) { 5648 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5649 if (layouttype != fxdr_unsigned(int, *tl)) 5650 printf("EEK! devinfo layout type not same!\n"); 5651 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) { 5652 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5653 stripecnt = fxdr_unsigned(int, *tl); 5654 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 5655 if (stripecnt < 1 || stripecnt > 4096) { 5656 printf("pNFS File layout devinfo stripecnt %d:" 5657 " out of range\n", stripecnt); 5658 error = NFSERR_BADXDR; 5659 goto nfsmout; 5660 } 5661 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * 5662 NFSX_UNSIGNED); 5663 addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 5664 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 5665 if (addrcnt < 1 || addrcnt > 128) { 5666 printf("NFS devinfo addrcnt %d: out of range\n", 5667 addrcnt); 5668 error = NFSERR_BADXDR; 5669 goto nfsmout; 5670 } 5671 5672 /* 5673 * Now we know how many stripe indices and addresses, so 5674 * we can allocate the structure the correct size. 5675 */ 5676 i = (stripecnt * sizeof(uint8_t)) / 5677 sizeof(struct nfsclds *) + 1; 5678 NFSCL_DEBUG(4, "stripeindices=%d\n", i); 5679 ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 5680 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | 5681 M_ZERO); 5682 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5683 NFSX_V4DEVICEID); 5684 ndi->nfsdi_refcnt = 0; 5685 ndi->nfsdi_flags = NFSDI_FILELAYOUT; 5686 ndi->nfsdi_stripecnt = stripecnt; 5687 ndi->nfsdi_addrcnt = addrcnt; 5688 /* Fill in the stripe indices. */ 5689 for (i = 0; i < stripecnt; i++) { 5690 stripeindex = fxdr_unsigned(uint8_t, *tl++); 5691 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 5692 if (stripeindex >= addrcnt) { 5693 printf("pNFS File Layout devinfo" 5694 " stripeindex %d: too big\n", 5695 (int)stripeindex); 5696 error = NFSERR_BADXDR; 5697 goto nfsmout; 5698 } 5699 nfsfldi_setstripeindex(ndi, i, stripeindex); 5700 } 5701 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 5702 /* For Flex File, we only get one address list. */ 5703 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *), 5704 M_NFSDEVINFO, M_WAITOK | M_ZERO); 5705 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5706 NFSX_V4DEVICEID); 5707 ndi->nfsdi_refcnt = 0; 5708 ndi->nfsdi_flags = NFSDI_FLEXFILE; 5709 addrcnt = ndi->nfsdi_addrcnt = 1; 5710 } 5711 5712 /* Now, dissect the server address(es). */ 5713 safilled = AF_UNSPEC; 5714 for (i = 0; i < addrcnt; i++) { 5715 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5716 cnt = fxdr_unsigned(uint32_t, *tl); 5717 if (cnt == 0) { 5718 printf("NFS devinfo 0 len addrlist\n"); 5719 error = NFSERR_BADXDR; 5720 goto nfsmout; 5721 } 5722 dspp = nfsfldi_addr(ndi, i); 5723 safilled = AF_UNSPEC; 5724 for (j = 0; j < cnt; j++) { 5725 error = nfsv4_getipaddr(nd, &sin, &sin6, &af, 5726 &isudp); 5727 if (error != 0 && error != EPERM) { 5728 error = NFSERR_BADXDR; 5729 goto nfsmout; 5730 } 5731 if (error == 0 && isudp == 0) { 5732 /* 5733 * The priority is: 5734 * - Same address family. 5735 * Save the address and dspp, so that 5736 * the connection can be done after 5737 * parsing is complete. 5738 */ 5739 if (safilled == AF_UNSPEC || 5740 (af == nmp->nm_nam->sa_family && 5741 safilled != nmp->nm_nam->sa_family) 5742 ) { 5743 if (af == AF_INET) 5744 ssin = sin; 5745 else 5746 ssin6 = sin6; 5747 safilled = af; 5748 gotdspp = dspp; 5749 } 5750 } 5751 } 5752 } 5753 5754 gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */ 5755 gotminor = NFSV41_MINORVERSION; 5756 /* For Flex File, we will take one of the versions to use. */ 5757 if (layouttype == NFSLAYOUT_FLEXFILE) { 5758 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5759 j = fxdr_unsigned(int, *tl); 5760 if (j < 1 || j > NFSDEV_MAXVERS) { 5761 printf("pNFS: too many versions\n"); 5762 error = NFSERR_BADXDR; 5763 goto nfsmout; 5764 } 5765 gotvers = 0; 5766 gotminor = 0; 5767 for (i = 0; i < j; i++) { 5768 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED); 5769 vers = fxdr_unsigned(uint32_t, *tl++); 5770 minorvers = fxdr_unsigned(uint32_t, *tl++); 5771 if (vers == NFS_VER3) 5772 minorvers = 0; 5773 if ((vers == NFS_VER4 && ((minorvers == 5774 NFSV41_MINORVERSION && gotminor == 0) || 5775 minorvers == NFSV42_MINORVERSION)) || 5776 (vers == NFS_VER3 && gotvers == 0)) { 5777 gotvers = vers; 5778 gotminor = minorvers; 5779 /* We'll take this one. */ 5780 ndi->nfsdi_versindex = i; 5781 ndi->nfsdi_vers = vers; 5782 ndi->nfsdi_minorvers = minorvers; 5783 ndi->nfsdi_rsize = fxdr_unsigned( 5784 uint32_t, *tl++); 5785 ndi->nfsdi_wsize = fxdr_unsigned( 5786 uint32_t, *tl++); 5787 if (*tl == newnfs_true) 5788 ndi->nfsdi_flags |= 5789 NFSDI_TIGHTCOUPLED; 5790 else 5791 ndi->nfsdi_flags &= 5792 ~NFSDI_TIGHTCOUPLED; 5793 } 5794 } 5795 if (gotvers == 0) { 5796 printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n"); 5797 error = NFSERR_BADXDR; 5798 goto nfsmout; 5799 } 5800 } 5801 5802 /* And the notify bits. */ 5803 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5804 bitcnt = fxdr_unsigned(int, *tl); 5805 if (bitcnt > 0) { 5806 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5807 if (notifybitsp != NULL) 5808 *notifybitsp = 5809 fxdr_unsigned(uint32_t, *tl); 5810 } 5811 if (safilled != AF_UNSPEC) { 5812 KASSERT(ndi != NULL, ("ndi is NULL")); 5813 *ndip = ndi; 5814 } else 5815 error = EPERM; 5816 if (error == 0) { 5817 /* 5818 * Now we can do a TCP connection for the correct 5819 * NFS version and IP address. 5820 */ 5821 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled, 5822 gotvers, gotminor, &dsp, p); 5823 } 5824 if (error == 0) { 5825 KASSERT(gotdspp != NULL, ("gotdspp is NULL")); 5826 *gotdspp = dsp; 5827 } 5828 } 5829 if (nd->nd_repstat != 0 && error == 0) 5830 error = nd->nd_repstat; 5831 nfsmout: 5832 if (error != 0 && ndi != NULL) 5833 nfscl_freedevinfo(ndi); 5834 m_freem(nd->nd_mrep); 5835 return (error); 5836 } 5837 5838 /* 5839 * Do the NFSv4.1 LayoutCommit. 5840 */ 5841 int 5842 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5843 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5844 int layouttype, struct ucred *cred, NFSPROC_T *p) 5845 { 5846 uint32_t *tl; 5847 struct nfsrv_descript nfsd, *nd = &nfsd; 5848 int error; 5849 5850 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL, 5851 0, 0, cred); 5852 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5853 NFSX_STATEID); 5854 txdr_hyper(off, tl); 5855 tl += 2; 5856 txdr_hyper(len, tl); 5857 tl += 2; 5858 if (reclaim != 0) 5859 *tl++ = newnfs_true; 5860 else 5861 *tl++ = newnfs_false; 5862 *tl++ = txdr_unsigned(stateidp->seqid); 5863 *tl++ = stateidp->other[0]; 5864 *tl++ = stateidp->other[1]; 5865 *tl++ = stateidp->other[2]; 5866 *tl++ = newnfs_true; 5867 if (lastbyte < off) 5868 lastbyte = off; 5869 else if (lastbyte >= (off + len)) 5870 lastbyte = off + len - 1; 5871 txdr_hyper(lastbyte, tl); 5872 tl += 2; 5873 *tl++ = newnfs_false; 5874 *tl++ = txdr_unsigned(layouttype); 5875 /* All supported layouts are 0 length. */ 5876 *tl = txdr_unsigned(0); 5877 nd->nd_flag |= ND_USEGSSNAME; 5878 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5879 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5880 if (error != 0) 5881 return (error); 5882 error = nd->nd_repstat; 5883 m_freem(nd->nd_mrep); 5884 return (error); 5885 } 5886 5887 /* 5888 * Do the NFSv4.1 LayoutReturn. 5889 */ 5890 int 5891 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5892 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5893 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5894 uint32_t stat, uint32_t op, char *devid) 5895 { 5896 uint32_t *tl; 5897 struct nfsrv_descript nfsd, *nd = &nfsd; 5898 uint64_t tu64; 5899 int error; 5900 5901 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL, 5902 0, 0, cred); 5903 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5904 if (reclaim != 0) 5905 *tl++ = newnfs_true; 5906 else 5907 *tl++ = newnfs_false; 5908 *tl++ = txdr_unsigned(layouttype); 5909 *tl++ = txdr_unsigned(iomode); 5910 *tl = txdr_unsigned(layoutreturn); 5911 if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5912 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5913 NFSX_UNSIGNED); 5914 txdr_hyper(offset, tl); 5915 tl += 2; 5916 txdr_hyper(len, tl); 5917 tl += 2; 5918 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5919 *tl++ = txdr_unsigned(stateidp->seqid); 5920 *tl++ = stateidp->other[0]; 5921 *tl++ = stateidp->other[1]; 5922 *tl++ = stateidp->other[2]; 5923 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) 5924 *tl = txdr_unsigned(0); 5925 else if (layouttype == NFSLAYOUT_FLEXFILE) { 5926 if (stat != 0) { 5927 *tl = txdr_unsigned(2 * NFSX_HYPER + 5928 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5929 NFSX_UNSIGNED); 5930 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 5931 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5932 NFSX_UNSIGNED); 5933 *tl++ = txdr_unsigned(1); /* One error. */ 5934 tu64 = 0; /* Offset. */ 5935 txdr_hyper(tu64, tl); tl += 2; 5936 tu64 = UINT64_MAX; /* Length. */ 5937 txdr_hyper(tu64, tl); tl += 2; 5938 NFSBCOPY(stateidp, tl, NFSX_STATEID); 5939 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5940 *tl++ = txdr_unsigned(1); /* One error. */ 5941 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5942 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5943 *tl++ = txdr_unsigned(stat); 5944 *tl++ = txdr_unsigned(op); 5945 } else { 5946 *tl = txdr_unsigned(2 * NFSX_UNSIGNED); 5947 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5948 /* No ioerrs. */ 5949 *tl++ = 0; 5950 } 5951 *tl = 0; /* No stats yet. */ 5952 } 5953 } 5954 nd->nd_flag |= ND_USEGSSNAME; 5955 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5956 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5957 if (error != 0) 5958 return (error); 5959 if (nd->nd_repstat == 0) { 5960 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5961 if (*tl != 0) { 5962 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5963 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5964 stateidp->other[0] = *tl++; 5965 stateidp->other[1] = *tl++; 5966 stateidp->other[2] = *tl; 5967 } 5968 } else 5969 error = nd->nd_repstat; 5970 nfsmout: 5971 m_freem(nd->nd_mrep); 5972 return (error); 5973 } 5974 5975 /* 5976 * Do the NFSv4.2 LayoutError. 5977 */ 5978 static int 5979 nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset, 5980 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5981 uint32_t stat, uint32_t op, char *devid) 5982 { 5983 uint32_t *tl; 5984 struct nfsrv_descript nfsd, *nd = &nfsd; 5985 int error; 5986 5987 nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL, 5988 0, 0, cred); 5989 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5990 NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5991 txdr_hyper(offset, tl); tl += 2; 5992 txdr_hyper(len, tl); tl += 2; 5993 *tl++ = txdr_unsigned(stateidp->seqid); 5994 *tl++ = stateidp->other[0]; 5995 *tl++ = stateidp->other[1]; 5996 *tl++ = stateidp->other[2]; 5997 *tl++ = txdr_unsigned(1); 5998 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5999 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 6000 *tl++ = txdr_unsigned(stat); 6001 *tl = txdr_unsigned(op); 6002 nd->nd_flag |= ND_USEGSSNAME; 6003 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 6004 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 6005 if (error != 0) 6006 return (error); 6007 if (nd->nd_repstat != 0) 6008 error = nd->nd_repstat; 6009 m_freem(nd->nd_mrep); 6010 return (error); 6011 } 6012 6013 /* 6014 * Acquire a layout and devinfo, if possible. The caller must have acquired 6015 * a reference count on the nfsclclient structure before calling this. 6016 * Return the layout in lypp with a reference count on it, if successful. 6017 */ 6018 static int 6019 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 6020 int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, 6021 uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 6022 { 6023 struct nfscllayout *lyp; 6024 struct nfsclflayout *flp; 6025 struct nfsclflayouthead flh; 6026 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose; 6027 nfsv4stateid_t stateid; 6028 struct nfsclsession *tsep; 6029 6030 *lypp = NULL; 6031 if (NFSHASFLEXFILE(nmp)) 6032 layouttype = NFSLAYOUT_FLEXFILE; 6033 else 6034 layouttype = NFSLAYOUT_NFSV4_1_FILES; 6035 /* 6036 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 6037 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 6038 * flp == NULL. 6039 */ 6040 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 6041 off, rw, &flp, &recalled); 6042 islocked = 0; 6043 if (lyp == NULL || flp == NULL) { 6044 if (recalled != 0) 6045 return (EIO); 6046 LIST_INIT(&flh); 6047 tsep = nfsmnt_mdssession(nmp); 6048 layoutlen = tsep->nfsess_maxcache - 6049 (NFSX_STATEID + 3 * NFSX_UNSIGNED); 6050 if (lyp == NULL) { 6051 stateid.seqid = 0; 6052 stateid.other[0] = stateidp->other[0]; 6053 stateid.other[1] = stateidp->other[1]; 6054 stateid.other[2] = stateidp->other[2]; 6055 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 6056 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, 6057 (uint64_t)0, layouttype, layoutlen, &stateid, 6058 &retonclose, &flh, cred, p); 6059 } else { 6060 islocked = 1; 6061 stateid.seqid = lyp->nfsly_stateid.seqid; 6062 stateid.other[0] = lyp->nfsly_stateid.other[0]; 6063 stateid.other[1] = lyp->nfsly_stateid.other[1]; 6064 stateid.other[2] = lyp->nfsly_stateid.other[2]; 6065 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 6066 nfhp->nfh_len, iomode, off, UINT64_MAX, 6067 (uint64_t)0, layouttype, layoutlen, &stateid, 6068 &retonclose, &flh, cred, p); 6069 } 6070 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, 6071 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, 6072 &flh, layouttype, error, NULL, cred, p); 6073 if (error == 0) 6074 *lypp = lyp; 6075 else if (islocked != 0) 6076 nfscl_rellayout(lyp, 1); 6077 } else 6078 *lypp = lyp; 6079 return (error); 6080 } 6081 6082 /* 6083 * Do a TCP connection plus exchange id and create session. 6084 * If successful, a "struct nfsclds" is linked into the list for the 6085 * mount point and a pointer to it is returned. 6086 */ 6087 static int 6088 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin, 6089 struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers, 6090 struct nfsclds **dspp, NFSPROC_T *p) 6091 { 6092 struct sockaddr_in *msad, *sad; 6093 struct sockaddr_in6 *msad6, *sad6; 6094 struct nfsclclient *clp; 6095 struct nfssockreq *nrp; 6096 struct nfsclds *dsp, *tdsp; 6097 int error, firsttry; 6098 enum nfsclds_state retv; 6099 uint32_t sequenceid = 0; 6100 6101 KASSERT(nmp->nm_sockreq.nr_cred != NULL, 6102 ("nfsrpc_fillsa: NULL nr_cred")); 6103 NFSLOCKCLSTATE(); 6104 clp = nmp->nm_clp; 6105 NFSUNLOCKCLSTATE(); 6106 if (clp == NULL) 6107 return (EPERM); 6108 if (af == AF_INET) { 6109 NFSLOCKMNT(nmp); 6110 /* 6111 * Check to see if we already have a session for this 6112 * address that is usable for a DS. 6113 * Note that the MDS's address is in a different place 6114 * than the sessions already acquired for DS's. 6115 */ 6116 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 6117 tdsp = TAILQ_FIRST(&nmp->nm_sess); 6118 while (tdsp != NULL) { 6119 if (msad != NULL && msad->sin_family == AF_INET && 6120 sin->sin_addr.s_addr == msad->sin_addr.s_addr && 6121 sin->sin_port == msad->sin_port && 6122 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 6123 tdsp->nfsclds_sess.nfsess_defunct == 0) { 6124 *dspp = tdsp; 6125 NFSUNLOCKMNT(nmp); 6126 NFSCL_DEBUG(4, "fnd same addr\n"); 6127 return (0); 6128 } 6129 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 6130 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 6131 msad = (struct sockaddr_in *) 6132 tdsp->nfsclds_sockp->nr_nam; 6133 else 6134 msad = NULL; 6135 } 6136 NFSUNLOCKMNT(nmp); 6137 6138 /* No IP address match, so look for new/trunked one. */ 6139 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 6140 sad->sin_len = sizeof(*sad); 6141 sad->sin_family = AF_INET; 6142 sad->sin_port = sin->sin_port; 6143 sad->sin_addr.s_addr = sin->sin_addr.s_addr; 6144 if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) { 6145 /* For pNFS, a separate server principal is needed. */ 6146 nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST, 6147 M_NFSSOCKREQ, M_WAITOK | M_ZERO); 6148 /* 6149 * Use the latter part of nr_srvprinc as a temporary 6150 * buffer for the IP address. 6151 */ 6152 inet_ntoa_r(sad->sin_addr, 6153 &nrp->nr_srvprinc[NI_MAXSERV]); 6154 NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n", 6155 &nrp->nr_srvprinc[NI_MAXSERV]); 6156 if (!rpc_gss_ip_to_srv_principal_call( 6157 &nrp->nr_srvprinc[NI_MAXSERV], "nfs", 6158 nrp->nr_srvprinc)) 6159 nrp->nr_srvprinc[0] = '\0'; 6160 NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n", 6161 nrp->nr_srvprinc); 6162 } else 6163 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, 6164 M_WAITOK | M_ZERO); 6165 nrp->nr_nam = (struct sockaddr *)sad; 6166 } else if (af == AF_INET6) { 6167 NFSLOCKMNT(nmp); 6168 /* 6169 * Check to see if we already have a session for this 6170 * address that is usable for a DS. 6171 * Note that the MDS's address is in a different place 6172 * than the sessions already acquired for DS's. 6173 */ 6174 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 6175 tdsp = TAILQ_FIRST(&nmp->nm_sess); 6176 while (tdsp != NULL) { 6177 if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 6178 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 6179 &msad6->sin6_addr) && 6180 sin6->sin6_port == msad6->sin6_port && 6181 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 6182 tdsp->nfsclds_sess.nfsess_defunct == 0) { 6183 *dspp = tdsp; 6184 NFSUNLOCKMNT(nmp); 6185 return (0); 6186 } 6187 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 6188 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 6189 msad6 = (struct sockaddr_in6 *) 6190 tdsp->nfsclds_sockp->nr_nam; 6191 else 6192 msad6 = NULL; 6193 } 6194 NFSUNLOCKMNT(nmp); 6195 6196 /* No IP address match, so look for new/trunked one. */ 6197 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 6198 sad6->sin6_len = sizeof(*sad6); 6199 sad6->sin6_family = AF_INET6; 6200 sad6->sin6_port = sin6->sin6_port; 6201 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr, 6202 sizeof(struct in6_addr)); 6203 if (NFSHASPNFS(nmp) && NFSHASKERB(nmp)) { 6204 /* For pNFS, a separate server principal is needed. */ 6205 nrp = malloc(sizeof(*nrp) + NI_MAXSERV + NI_MAXHOST, 6206 M_NFSSOCKREQ, M_WAITOK | M_ZERO); 6207 /* 6208 * Use the latter part of nr_srvprinc as a temporary 6209 * buffer for the IP address. 6210 */ 6211 inet_ntop(AF_INET6, &sad6->sin6_addr, 6212 &nrp->nr_srvprinc[NI_MAXSERV], NI_MAXHOST); 6213 NFSCL_DEBUG(1, "nfsrpc_fillsa: DS IP=%s\n", 6214 &nrp->nr_srvprinc[NI_MAXSERV]); 6215 if (!rpc_gss_ip_to_srv_principal_call( 6216 &nrp->nr_srvprinc[NI_MAXSERV], "nfs", 6217 nrp->nr_srvprinc)) 6218 nrp->nr_srvprinc[0] = '\0'; 6219 NFSCL_DEBUG(1, "nfsrpc_fillsa: srv principal=%s\n", 6220 nrp->nr_srvprinc); 6221 } else 6222 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, 6223 M_WAITOK | M_ZERO); 6224 nrp->nr_nam = (struct sockaddr *)sad6; 6225 } else 6226 return (EPERM); 6227 6228 nrp->nr_sotype = SOCK_STREAM; 6229 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 6230 nrp->nr_prog = NFS_PROG; 6231 nrp->nr_vers = vers; 6232 6233 /* 6234 * Use the credentials that were used for the mount, which are 6235 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 6236 * Ref. counting the credentials with crhold() is probably not 6237 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 6238 * unmount, but I did it anyhow. 6239 */ 6240 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 6241 error = newnfs_connect(nmp, nrp, NULL, p, 0, false, &nrp->nr_client); 6242 NFSCL_DEBUG(3, "DS connect=%d\n", error); 6243 6244 dsp = NULL; 6245 /* Now, do the exchangeid and create session. */ 6246 if (error == 0) { 6247 if (vers == NFS_VER4) { 6248 firsttry = 0; 6249 do { 6250 error = nfsrpc_exchangeid(nmp, clp, nrp, 6251 minorvers, NFSV4EXCH_USEPNFSDS, &dsp, 6252 nrp->nr_cred, p); 6253 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 6254 if (error == NFSERR_MINORVERMISMATCH) 6255 minorvers = NFSV42_MINORVERSION; 6256 } while (error == NFSERR_MINORVERMISMATCH && 6257 firsttry++ == 0); 6258 if (error != 0) 6259 newnfs_disconnect(NULL, nrp); 6260 } else { 6261 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, 6262 M_WAITOK | M_ZERO); 6263 dsp->nfsclds_flags |= NFSCLDS_DS; 6264 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */ 6265 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 6266 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 6267 NULL, MTX_DEF); 6268 } 6269 } 6270 if (error == 0) { 6271 dsp->nfsclds_sockp = nrp; 6272 if (vers == NFS_VER4) { 6273 NFSLOCKMNT(nmp); 6274 retv = nfscl_getsameserver(nmp, dsp, &tdsp, 6275 &sequenceid); 6276 NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 6277 if (retv == NFSDSP_USETHISSESSION && 6278 nfscl_dssameconn != 0) { 6279 NFSLOCKDS(tdsp); 6280 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN; 6281 NFSUNLOCKDS(tdsp); 6282 NFSUNLOCKMNT(nmp); 6283 /* 6284 * If there is already a session for this 6285 * server, use it. 6286 */ 6287 newnfs_disconnect(NULL, nrp); 6288 nfscl_freenfsclds(dsp); 6289 *dspp = tdsp; 6290 return (0); 6291 } 6292 if (retv == NFSDSP_NOTFOUND) 6293 sequenceid = 6294 dsp->nfsclds_sess.nfsess_sequenceid; 6295 NFSUNLOCKMNT(nmp); 6296 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 6297 nrp, dsp, sequenceid, 0, nrp->nr_cred, p); 6298 NFSCL_DEBUG(3, "DS createsess=%d\n", error); 6299 } 6300 } else { 6301 NFSFREECRED(nrp->nr_cred); 6302 NFSFREEMUTEX(&nrp->nr_mtx); 6303 free(nrp->nr_nam, M_SONAME); 6304 free(nrp, M_NFSSOCKREQ); 6305 } 6306 if (error == 0) { 6307 NFSCL_DEBUG(3, "add DS session\n"); 6308 /* 6309 * Put it at the end of the list. That way the list 6310 * is ordered by when the entry was added. This matters 6311 * since the one done first is the one that should be 6312 * used for sequencid'ing any subsequent create sessions. 6313 */ 6314 NFSLOCKMNT(nmp); 6315 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 6316 NFSUNLOCKMNT(nmp); 6317 *dspp = dsp; 6318 } else if (dsp != NULL) { 6319 newnfs_disconnect(NULL, nrp); 6320 nfscl_freenfsclds(dsp); 6321 } 6322 return (error); 6323 } 6324 6325 /* 6326 * Do the NFSv4.1 Reclaim Complete. 6327 */ 6328 int 6329 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 6330 { 6331 uint32_t *tl; 6332 struct nfsrv_descript nfsd; 6333 struct nfsrv_descript *nd = &nfsd; 6334 int error; 6335 6336 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0, 6337 0, cred); 6338 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6339 *tl = newnfs_false; 6340 nd->nd_flag |= ND_USEGSSNAME; 6341 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 6342 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 6343 if (error != 0) 6344 return (error); 6345 error = nd->nd_repstat; 6346 m_freem(nd->nd_mrep); 6347 return (error); 6348 } 6349 6350 /* 6351 * Initialize the slot tables for a session. 6352 */ 6353 static void 6354 nfscl_initsessionslots(struct nfsclsession *sep) 6355 { 6356 int i; 6357 6358 for (i = 0; i < NFSV4_CBSLOTS; i++) { 6359 if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 6360 m_freem(sep->nfsess_cbslots[i].nfssl_reply); 6361 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 6362 } 6363 for (i = 0; i < 64; i++) 6364 sep->nfsess_slotseq[i] = 0; 6365 sep->nfsess_slots = 0; 6366 sep->nfsess_badslots = 0; 6367 } 6368 6369 /* 6370 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 6371 */ 6372 int 6373 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6374 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) 6375 { 6376 struct nfsnode *np = VTONFS(vp); 6377 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6378 struct nfscllayout *layp; 6379 struct nfscldevinfo *dip; 6380 struct nfsclflayout *rflp; 6381 struct mbuf *m, *m2; 6382 struct nfsclwritedsdorpc *drpc, *tdrpc; 6383 nfsv4stateid_t stateid; 6384 struct ucred *newcred; 6385 uint64_t lastbyte, len, off, oresid, xfer; 6386 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo; 6387 void *lckp; 6388 uint8_t *dev; 6389 void *iovbase = NULL; 6390 size_t iovlen = 0; 6391 off_t offs = 0; 6392 ssize_t resid = 0; 6393 uint32_t op; 6394 6395 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 6396 (np->n_flag & NNOLAYOUT) != 0) 6397 return (EIO); 6398 /* Now, get a reference cnt on the clientid for this mount. */ 6399 if (nfscl_getref(nmp) == 0) 6400 return (EIO); 6401 6402 /* Find an appropriate stateid. */ 6403 newcred = NFSNEWCRED(cred); 6404 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 6405 rwaccess, 1, newcred, p, &stateid, &lckp); 6406 if (error != 0) { 6407 NFSFREECRED(newcred); 6408 nfscl_relref(nmp); 6409 return (error); 6410 } 6411 /* Search for a layout for this file. */ 6412 off = uiop->uio_offset; 6413 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 6414 np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled); 6415 if (layp == NULL || rflp == NULL) { 6416 if (recalled != 0) { 6417 NFSFREECRED(newcred); 6418 if (lckp != NULL) 6419 nfscl_lockderef(lckp); 6420 nfscl_relref(nmp); 6421 return (EIO); 6422 } 6423 if (layp != NULL) { 6424 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 6425 layp = NULL; 6426 } 6427 /* Try and get a Layout, if it is supported. */ 6428 if (rwaccess == NFSV4OPEN_ACCESSWRITE || 6429 (np->n_flag & NWRITEOPENED) != 0) 6430 iolaymode = NFSLAYOUTIOMODE_RW; 6431 else 6432 iolaymode = NFSLAYOUTIOMODE_READ; 6433 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 6434 rwaccess, NULL, &stateid, off, &layp, newcred, p); 6435 if (error != 0) { 6436 NFSLOCKNODE(np); 6437 np->n_flag |= NNOLAYOUT; 6438 NFSUNLOCKNODE(np); 6439 if (lckp != NULL) 6440 nfscl_lockderef(lckp); 6441 NFSFREECRED(newcred); 6442 if (layp != NULL) 6443 nfscl_rellayout(layp, 0); 6444 nfscl_relref(nmp); 6445 return (error); 6446 } 6447 } 6448 6449 /* 6450 * Loop around finding a layout that works for the first part of 6451 * this I/O operation, and then call the function that actually 6452 * does the RPC. 6453 */ 6454 eof = 0; 6455 len = (uint64_t)uiop->uio_resid; 6456 while (len > 0 && error == 0 && eof == 0) { 6457 off = uiop->uio_offset; 6458 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 6459 if (error == 0) { 6460 oresid = xfer = (uint64_t)uiop->uio_resid; 6461 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 6462 xfer = rflp->nfsfl_end - rflp->nfsfl_off; 6463 /* 6464 * For Flex File layout with mirrored DSs, select one 6465 * of them at random for reads. For writes and commits, 6466 * do all mirrors. 6467 */ 6468 m = NULL; 6469 tdrpc = drpc = NULL; 6470 firstmirror = 0; 6471 mirrorcnt = 1; 6472 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 && 6473 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) { 6474 if (rwaccess == NFSV4OPEN_ACCESSREAD) { 6475 firstmirror = arc4random() % mirrorcnt; 6476 mirrorcnt = firstmirror + 1; 6477 } else { 6478 if (docommit == 0) { 6479 /* 6480 * Save values, so uiop can be 6481 * rolled back upon a write 6482 * error. 6483 */ 6484 offs = uiop->uio_offset; 6485 resid = uiop->uio_resid; 6486 iovbase = 6487 uiop->uio_iov->iov_base; 6488 iovlen = uiop->uio_iov->iov_len; 6489 m = nfsm_uiombuflist(uiop, len, 6490 0); 6491 if (m == NULL) { 6492 error = EFAULT; 6493 break; 6494 } 6495 } 6496 tdrpc = drpc = malloc(sizeof(*drpc) * 6497 (mirrorcnt - 1), M_TEMP, M_WAITOK | 6498 M_ZERO); 6499 } 6500 } 6501 for (i = firstmirror; i < mirrorcnt && error == 0; i++){ 6502 m2 = NULL; 6503 if (m != NULL && i < mirrorcnt - 1) 6504 m2 = m_copym(m, 0, M_COPYALL, M_WAITOK); 6505 else { 6506 m2 = m; 6507 m = NULL; 6508 } 6509 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { 6510 dev = rflp->nfsfl_ffm[i].dev; 6511 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6512 rflp->nfsfl_ffm[i].devp); 6513 } else { 6514 dev = rflp->nfsfl_dev; 6515 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6516 rflp->nfsfl_devp); 6517 } 6518 if (dip != NULL) { 6519 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE) 6520 != 0) 6521 error = nfscl_dofflayoutio(vp, 6522 uiop, iomode, must_commit, 6523 &eof, &stateid, rwaccess, 6524 dip, layp, rflp, off, xfer, 6525 i, docommit, m2, tdrpc, 6526 newcred, p); 6527 else 6528 error = nfscl_doflayoutio(vp, 6529 uiop, iomode, must_commit, 6530 &eof, &stateid, rwaccess, 6531 dip, layp, rflp, off, xfer, 6532 docommit, newcred, p); 6533 nfscl_reldevinfo(dip); 6534 } else { 6535 if (m2 != NULL) 6536 m_freem(m2); 6537 error = EIO; 6538 } 6539 tdrpc++; 6540 } 6541 if (m != NULL) 6542 m_freem(m); 6543 tdrpc = drpc; 6544 timo = hz / 50; /* Wait for 20msec. */ 6545 if (timo < 1) 6546 timo = 1; 6547 for (i = firstmirror; i < mirrorcnt - 1 && 6548 tdrpc != NULL; i++, tdrpc++) { 6549 /* 6550 * For the unused drpc entries, both inprog and 6551 * err == 0, so this loop won't break. 6552 */ 6553 while (tdrpc->inprog != 0 && tdrpc->done == 0) 6554 tsleep(&tdrpc->tsk, PVFS, "clrpcio", 6555 timo); 6556 if (error == 0 && tdrpc->err != 0) 6557 error = tdrpc->err; 6558 if (rwaccess != NFSV4OPEN_ACCESSREAD && 6559 docommit == 0 && *must_commit == 0 && 6560 tdrpc->must_commit == 1) 6561 *must_commit = 1; 6562 } 6563 free(drpc, M_TEMP); 6564 if (error == 0) { 6565 if (mirrorcnt > 1 && rwaccess == 6566 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6567 NFSLOCKCLSTATE(); 6568 layp->nfsly_flags |= NFSLY_WRITTEN; 6569 NFSUNLOCKCLSTATE(); 6570 } 6571 lastbyte = off + xfer - 1; 6572 NFSLOCKCLSTATE(); 6573 if (lastbyte > layp->nfsly_lastbyte) 6574 layp->nfsly_lastbyte = lastbyte; 6575 NFSUNLOCKCLSTATE(); 6576 } else if (error == NFSERR_OPENMODE && 6577 rwaccess == NFSV4OPEN_ACCESSREAD) { 6578 NFSLOCKMNT(nmp); 6579 nmp->nm_state |= NFSSTA_OPENMODE; 6580 NFSUNLOCKMNT(nmp); 6581 } else if ((error == NFSERR_NOSPC || 6582 error == NFSERR_IO || error == NFSERR_NXIO) && 6583 nmp->nm_minorvers == NFSV42_MINORVERSION) { 6584 if (docommit != 0) 6585 op = NFSV4OP_COMMIT; 6586 else if (rwaccess == NFSV4OPEN_ACCESSREAD) 6587 op = NFSV4OP_READ; 6588 else 6589 op = NFSV4OP_WRITE; 6590 nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh, 6591 np->n_fhp->nfh_len, off, xfer, 6592 &layp->nfsly_stateid, newcred, p, error, op, 6593 dip->nfsdi_deviceid); 6594 error = EIO; 6595 } else 6596 error = EIO; 6597 if (error == 0) 6598 len -= (oresid - (uint64_t)uiop->uio_resid); 6599 else if (mirrorcnt > 1 && rwaccess == 6600 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6601 /* 6602 * In case the rpc gets retried, roll the 6603 * uio fields changed by nfsm_uiombuflist() 6604 * back. 6605 */ 6606 uiop->uio_offset = offs; 6607 uiop->uio_resid = resid; 6608 uiop->uio_iov->iov_base = iovbase; 6609 uiop->uio_iov->iov_len = iovlen; 6610 } 6611 } 6612 } 6613 if (lckp != NULL) 6614 nfscl_lockderef(lckp); 6615 NFSFREECRED(newcred); 6616 nfscl_rellayout(layp, 0); 6617 nfscl_relref(nmp); 6618 return (error); 6619 } 6620 6621 /* 6622 * Find a file layout that will handle the first bytes of the requested 6623 * range and return the information from it needed to the I/O operation. 6624 */ 6625 int 6626 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 6627 struct nfsclflayout **retflpp) 6628 { 6629 struct nfsclflayout *flp, *nflp, *rflp; 6630 uint32_t rw; 6631 6632 rflp = NULL; 6633 rw = rwaccess; 6634 /* For reading, do the Read list first and then the Write list. */ 6635 do { 6636 if (rw == NFSV4OPEN_ACCESSREAD) 6637 flp = LIST_FIRST(&lyp->nfsly_flayread); 6638 else 6639 flp = LIST_FIRST(&lyp->nfsly_flayrw); 6640 while (flp != NULL) { 6641 nflp = LIST_NEXT(flp, nfsfl_list); 6642 if (flp->nfsfl_off > off) 6643 break; 6644 if (flp->nfsfl_end > off && 6645 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 6646 rflp = flp; 6647 flp = nflp; 6648 } 6649 if (rw == NFSV4OPEN_ACCESSREAD) 6650 rw = NFSV4OPEN_ACCESSWRITE; 6651 else 6652 rw = 0; 6653 } while (rw != 0); 6654 if (rflp != NULL) { 6655 /* This one covers the most bytes starting at off. */ 6656 *retflpp = rflp; 6657 return (0); 6658 } 6659 return (EIO); 6660 } 6661 6662 /* 6663 * Do I/O using an NFSv4.1 or NFSv4.2 file layout. 6664 */ 6665 static int 6666 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6667 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6668 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6669 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) 6670 { 6671 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 6672 int commit_thru_mds, error, stripe_index, stripe_pos, minorvers; 6673 struct nfsnode *np; 6674 struct nfsfh *fhp; 6675 struct nfsclds **dspp; 6676 6677 np = VTONFS(vp); 6678 rel_off = off - flp->nfsfl_patoff; 6679 stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK; 6680 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 6681 dp->nfsdi_stripecnt; 6682 transfer = stripe_unit_size - (rel_off % stripe_unit_size); 6683 error = 0; 6684 6685 /* Loop around, doing I/O for each stripe unit. */ 6686 while (len > 0 && error == 0) { 6687 stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 6688 dspp = nfsfldi_addr(dp, stripe_index); 6689 if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0) 6690 minorvers = NFSV42_MINORVERSION; 6691 else 6692 minorvers = NFSV41_MINORVERSION; 6693 if (len > transfer && docommit == 0) 6694 xfer = transfer; 6695 else 6696 xfer = len; 6697 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 6698 /* Dense layout. */ 6699 if (stripe_pos >= flp->nfsfl_fhcnt) 6700 return (EIO); 6701 fhp = flp->nfsfl_fh[stripe_pos]; 6702 io_off = (rel_off / (stripe_unit_size * 6703 dp->nfsdi_stripecnt)) * stripe_unit_size + 6704 rel_off % stripe_unit_size; 6705 } else { 6706 /* Sparse layout. */ 6707 if (flp->nfsfl_fhcnt > 1) { 6708 if (stripe_index >= flp->nfsfl_fhcnt) 6709 return (EIO); 6710 fhp = flp->nfsfl_fh[stripe_index]; 6711 } else if (flp->nfsfl_fhcnt == 1) 6712 fhp = flp->nfsfl_fh[0]; 6713 else 6714 fhp = np->n_fhp; 6715 io_off = off; 6716 } 6717 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { 6718 commit_thru_mds = 1; 6719 if (docommit != 0) 6720 error = EIO; 6721 } else { 6722 commit_thru_mds = 0; 6723 NFSLOCKNODE(np); 6724 np->n_flag |= NDSCOMMIT; 6725 NFSUNLOCKNODE(np); 6726 } 6727 if (docommit != 0) { 6728 if (error == 0) 6729 error = nfsrpc_commitds(vp, io_off, xfer, 6730 *dspp, fhp, NFS_VER4, minorvers, cred, p); 6731 if (error == 0) { 6732 /* 6733 * Set both eof and uio_resid = 0 to end any 6734 * loops. 6735 */ 6736 *eofp = 1; 6737 uiop->uio_resid = 0; 6738 } else { 6739 NFSLOCKNODE(np); 6740 np->n_flag &= ~NDSCOMMIT; 6741 NFSUNLOCKNODE(np); 6742 } 6743 } else if (rwflag == NFSV4OPEN_ACCESSREAD) 6744 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6745 io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p); 6746 else { 6747 error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 6748 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 6749 0, NFS_VER4, minorvers, cred, p); 6750 if (error == 0) { 6751 NFSLOCKCLSTATE(); 6752 lyp->nfsly_flags |= NFSLY_WRITTEN; 6753 NFSUNLOCKCLSTATE(); 6754 } 6755 } 6756 if (error == 0) { 6757 transfer = stripe_unit_size; 6758 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 6759 len -= xfer; 6760 off += xfer; 6761 } 6762 } 6763 return (error); 6764 } 6765 6766 /* 6767 * Do I/O using an NFSv4.1 flex file layout. 6768 */ 6769 static int 6770 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6771 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6772 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6773 uint64_t len, int mirror, int docommit, struct mbuf *mp, 6774 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6775 { 6776 uint64_t xfer; 6777 int error; 6778 struct nfsnode *np; 6779 struct nfsfh *fhp; 6780 struct nfsclds **dspp; 6781 struct ucred *tcred; 6782 struct mbuf *m, *m2; 6783 uint32_t copylen; 6784 6785 np = VTONFS(vp); 6786 error = 0; 6787 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, 6788 (uintmax_t)len); 6789 /* Loop around, doing I/O for each stripe unit. */ 6790 while (len > 0 && error == 0) { 6791 dspp = nfsfldi_addr(dp, 0); 6792 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex]; 6793 stateidp = &flp->nfsfl_ffm[mirror].st; 6794 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n", 6795 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid); 6796 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) { 6797 tcred = NFSNEWCRED(cred); 6798 tcred->cr_uid = flp->nfsfl_ffm[mirror].user; 6799 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group; 6800 tcred->cr_ngroups = 1; 6801 } else 6802 tcred = cred; 6803 if (rwflag == NFSV4OPEN_ACCESSREAD) 6804 copylen = dp->nfsdi_rsize; 6805 else { 6806 copylen = dp->nfsdi_wsize; 6807 if (len > copylen && mp != NULL) { 6808 /* 6809 * When a mirrored configuration needs to do 6810 * multiple writes to each mirror, all writes 6811 * except the last one must be a multiple of 6812 * 4 bytes. This is required so that the XDR 6813 * does not need padding. 6814 * If possible, clip the size to an exact 6815 * multiple of the mbuf length, so that the 6816 * split will be on an mbuf boundary. 6817 */ 6818 copylen &= 0xfffffffc; 6819 if (copylen > mp->m_len) 6820 copylen = copylen / mp->m_len * 6821 mp->m_len; 6822 } 6823 } 6824 NFSLOCKNODE(np); 6825 np->n_flag |= NDSCOMMIT; 6826 NFSUNLOCKNODE(np); 6827 if (len > copylen && docommit == 0) 6828 xfer = copylen; 6829 else 6830 xfer = len; 6831 if (docommit != 0) { 6832 if (error == 0) { 6833 /* 6834 * Do last mirrored DS commit with this thread. 6835 */ 6836 if (mirror < flp->nfsfl_mirrorcnt - 1) 6837 error = nfsio_commitds(vp, off, xfer, 6838 *dspp, fhp, dp->nfsdi_vers, 6839 dp->nfsdi_minorvers, drpc, tcred, 6840 p); 6841 else 6842 error = nfsrpc_commitds(vp, off, xfer, 6843 *dspp, fhp, dp->nfsdi_vers, 6844 dp->nfsdi_minorvers, tcred, p); 6845 NFSCL_DEBUG(4, "commitds=%d\n", error); 6846 if (error != 0 && error != EACCES && error != 6847 ESTALE) { 6848 NFSCL_DEBUG(4, 6849 "DS layreterr for commit\n"); 6850 nfscl_dserr(NFSV4OP_COMMIT, error, dp, 6851 lyp, *dspp); 6852 } 6853 } 6854 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error); 6855 if (error == 0) { 6856 /* 6857 * Set both eof and uio_resid = 0 to end any 6858 * loops. 6859 */ 6860 *eofp = 1; 6861 uiop->uio_resid = 0; 6862 } else { 6863 NFSLOCKNODE(np); 6864 np->n_flag &= ~NDSCOMMIT; 6865 NFSUNLOCKNODE(np); 6866 } 6867 } else if (rwflag == NFSV4OPEN_ACCESSREAD) { 6868 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6869 off, xfer, fhp, 1, dp->nfsdi_vers, 6870 dp->nfsdi_minorvers, tcred, p); 6871 NFSCL_DEBUG(4, "readds=%d\n", error); 6872 if (error != 0 && error != EACCES && error != ESTALE) { 6873 NFSCL_DEBUG(4, "DS layreterr for read\n"); 6874 nfscl_dserr(NFSV4OP_READ, error, dp, lyp, 6875 *dspp); 6876 } 6877 } else { 6878 if (flp->nfsfl_mirrorcnt == 1) { 6879 error = nfsrpc_writeds(vp, uiop, iomode, 6880 must_commit, stateidp, *dspp, off, xfer, 6881 fhp, 0, 1, dp->nfsdi_vers, 6882 dp->nfsdi_minorvers, tcred, p); 6883 if (error == 0) { 6884 NFSLOCKCLSTATE(); 6885 lyp->nfsly_flags |= NFSLY_WRITTEN; 6886 NFSUNLOCKCLSTATE(); 6887 } 6888 } else { 6889 m = mp; 6890 if (xfer < len) { 6891 /* The mbuf list must be split. */ 6892 m2 = nfsm_split(mp, xfer); 6893 if (m2 != NULL) 6894 mp = m2; 6895 else { 6896 m_freem(mp); 6897 error = EIO; 6898 } 6899 } 6900 NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n", 6901 (uintmax_t)len, (uintmax_t)xfer); 6902 /* 6903 * Do last write to a mirrored DS with this 6904 * thread. 6905 */ 6906 if (error == 0) { 6907 if (mirror < flp->nfsfl_mirrorcnt - 1) 6908 error = nfsio_writedsmir(vp, 6909 iomode, must_commit, 6910 stateidp, *dspp, off, 6911 xfer, fhp, m, 6912 dp->nfsdi_vers, 6913 dp->nfsdi_minorvers, drpc, 6914 tcred, p); 6915 else 6916 error = nfsrpc_writedsmir(vp, 6917 iomode, must_commit, 6918 stateidp, *dspp, off, 6919 xfer, fhp, m, 6920 dp->nfsdi_vers, 6921 dp->nfsdi_minorvers, tcred, 6922 p); 6923 } 6924 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); 6925 if (error != 0 && error != EACCES && error != 6926 ESTALE) { 6927 NFSCL_DEBUG(4, 6928 "DS layreterr for write\n"); 6929 nfscl_dserr(NFSV4OP_WRITE, error, dp, 6930 lyp, *dspp); 6931 } 6932 } 6933 } 6934 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error); 6935 if (error == 0) { 6936 len -= xfer; 6937 off += xfer; 6938 } 6939 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) 6940 NFSFREECRED(tcred); 6941 } 6942 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error); 6943 return (error); 6944 } 6945 6946 /* 6947 * The actual read RPC done to a DS. 6948 */ 6949 static int 6950 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 6951 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex, 6952 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) 6953 { 6954 uint32_t *tl; 6955 int attrflag, error, retlen; 6956 struct nfsrv_descript nfsd; 6957 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6958 struct nfsrv_descript *nd = &nfsd; 6959 struct nfssockreq *nrp; 6960 struct nfsvattr na; 6961 6962 nd->nd_mrep = NULL; 6963 if (vers == 0 || vers == NFS_VER4) { 6964 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, 6965 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 6966 NULL); 6967 vers = NFS_VER4; 6968 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers); 6969 if (flex != 0) 6970 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6971 else 6972 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6973 } else { 6974 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh, 6975 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 6976 NULL); 6977 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]); 6978 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]); 6979 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n"); 6980 } 6981 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 6982 txdr_hyper(io_off, tl); 6983 *(tl + 2) = txdr_unsigned(len); 6984 nrp = dsp->nfsclds_sockp; 6985 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp); 6986 if (nrp == NULL) 6987 /* If NULL, use the MDS socket. */ 6988 nrp = &nmp->nm_sockreq; 6989 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6990 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6991 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat, 6992 error); 6993 if (error != 0) 6994 return (error); 6995 if (vers == NFS_VER3) { 6996 error = nfscl_postop_attr(nd, &na, &attrflag); 6997 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error); 6998 if (error != 0) 6999 goto nfsmout; 7000 } 7001 if (nd->nd_repstat != 0) { 7002 error = nd->nd_repstat; 7003 goto nfsmout; 7004 } 7005 if (vers == NFS_VER3) { 7006 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7007 *eofp = fxdr_unsigned(int, *(tl + 1)); 7008 } else { 7009 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7010 *eofp = fxdr_unsigned(int, *tl); 7011 } 7012 NFSM_STRSIZ(retlen, len); 7013 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp); 7014 error = nfsm_mbufuio(nd, uiop, retlen); 7015 nfsmout: 7016 if (nd->nd_mrep != NULL) 7017 m_freem(nd->nd_mrep); 7018 return (error); 7019 } 7020 7021 /* 7022 * The actual write RPC done to a DS. 7023 */ 7024 static int 7025 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 7026 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 7027 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers, 7028 struct ucred *cred, NFSPROC_T *p) 7029 { 7030 uint32_t *tl; 7031 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7032 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC; 7033 int32_t backup; 7034 struct nfsrv_descript nfsd; 7035 struct nfsrv_descript *nd = &nfsd; 7036 struct nfssockreq *nrp; 7037 struct nfsvattr na; 7038 7039 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 7040 nd->nd_mrep = NULL; 7041 if (vers == 0 || vers == NFS_VER4) { 7042 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 7043 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7044 NULL); 7045 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers); 7046 vers = NFS_VER4; 7047 if (flex != 0) 7048 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 7049 else 7050 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 7051 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 7052 } else { 7053 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 7054 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7055 NULL); 7056 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 7057 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 7058 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n"); 7059 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 7060 } 7061 txdr_hyper(io_off, tl); 7062 tl += 2; 7063 if (vers == NFS_VER3) 7064 *tl++ = txdr_unsigned(len); 7065 *tl++ = txdr_unsigned(*iomode); 7066 *tl = txdr_unsigned(len); 7067 error = nfsm_uiombuf(nd, uiop, len); 7068 if (error != 0) { 7069 m_freem(nd->nd_mreq); 7070 return (error); 7071 } 7072 nrp = dsp->nfsclds_sockp; 7073 if (nrp == NULL) 7074 /* If NULL, use the MDS socket. */ 7075 nrp = &nmp->nm_sockreq; 7076 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7077 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7078 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error, 7079 nd->nd_repstat); 7080 if (error != 0) 7081 return (error); 7082 if (nd->nd_repstat != 0) { 7083 /* 7084 * In case the rpc gets retried, roll 7085 * the uio fields changed by nfsm_uiombuf() 7086 * back. 7087 */ 7088 uiop->uio_offset -= len; 7089 uiop->uio_resid += len; 7090 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len; 7091 uiop->uio_iov->iov_len += len; 7092 error = nd->nd_repstat; 7093 } else { 7094 if (vers == NFS_VER3) { 7095 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 7096 NULL); 7097 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error); 7098 if (error != 0) 7099 goto nfsmout; 7100 } 7101 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 7102 rlen = fxdr_unsigned(int, *tl++); 7103 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen); 7104 if (rlen == 0) { 7105 error = NFSERR_IO; 7106 goto nfsmout; 7107 } else if (rlen < len) { 7108 backup = len - rlen; 7109 uiop->uio_iov->iov_base = 7110 (char *)uiop->uio_iov->iov_base - backup; 7111 uiop->uio_iov->iov_len += backup; 7112 uiop->uio_offset -= backup; 7113 uiop->uio_resid += backup; 7114 len = rlen; 7115 } 7116 commit = fxdr_unsigned(int, *tl++); 7117 7118 /* 7119 * Return the lowest commitment level 7120 * obtained by any of the RPCs. 7121 */ 7122 if (committed == NFSWRITE_FILESYNC) 7123 committed = commit; 7124 else if (committed == NFSWRITE_DATASYNC && 7125 commit == NFSWRITE_UNSTABLE) 7126 committed = commit; 7127 if (commit_thru_mds != 0) { 7128 NFSLOCKMNT(nmp); 7129 if (!NFSHASWRITEVERF(nmp)) { 7130 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 7131 NFSSETWRITEVERF(nmp); 7132 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) && 7133 *must_commit != 2) { 7134 *must_commit = 1; 7135 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 7136 } 7137 NFSUNLOCKMNT(nmp); 7138 } else { 7139 NFSLOCKDS(dsp); 7140 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 7141 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7142 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 7143 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && 7144 *must_commit != 2) { 7145 *must_commit = 1; 7146 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7147 } 7148 NFSUNLOCKDS(dsp); 7149 } 7150 } 7151 nfsmout: 7152 if (nd->nd_mrep != NULL) 7153 m_freem(nd->nd_mrep); 7154 *iomode = committed; 7155 if (nd->nd_repstat != 0 && error == 0) 7156 error = nd->nd_repstat; 7157 return (error); 7158 } 7159 7160 /* 7161 * The actual write RPC done to a DS. 7162 * This variant is called from a separate kernel process for mirrors. 7163 * Any short write is considered an IO error. 7164 */ 7165 static int 7166 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, 7167 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 7168 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 7169 struct ucred *cred, NFSPROC_T *p) 7170 { 7171 uint32_t *tl; 7172 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7173 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen; 7174 struct nfsrv_descript nfsd; 7175 struct nfsrv_descript *nd = &nfsd; 7176 struct nfssockreq *nrp; 7177 struct nfsvattr na; 7178 7179 nd->nd_mrep = NULL; 7180 if (vers == 0 || vers == NFS_VER4) { 7181 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 7182 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7183 NULL); 7184 vers = NFS_VER4; 7185 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n", 7186 minorvers); 7187 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 7188 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 7189 } else { 7190 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 7191 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7192 NULL); 7193 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 7194 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 7195 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n"); 7196 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 7197 } 7198 txdr_hyper(io_off, tl); 7199 tl += 2; 7200 if (vers == NFS_VER3) 7201 *tl++ = txdr_unsigned(len); 7202 *tl++ = txdr_unsigned(*iomode); 7203 *tl = txdr_unsigned(len); 7204 if (len > 0) { 7205 /* Put data in mbuf chain. */ 7206 nd->nd_mb->m_next = m; 7207 } 7208 nrp = dsp->nfsclds_sockp; 7209 if (nrp == NULL) 7210 /* If NULL, use the MDS socket. */ 7211 nrp = &nmp->nm_sockreq; 7212 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7213 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7214 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error, 7215 nd->nd_repstat); 7216 if (error != 0) 7217 return (error); 7218 if (nd->nd_repstat != 0) 7219 error = nd->nd_repstat; 7220 else { 7221 if (vers == NFS_VER3) { 7222 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 7223 NULL); 7224 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n", 7225 error); 7226 if (error != 0) 7227 goto nfsmout; 7228 } 7229 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 7230 rlen = fxdr_unsigned(int, *tl++); 7231 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, 7232 rlen); 7233 if (rlen != len) { 7234 error = NFSERR_IO; 7235 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", 7236 len, rlen); 7237 goto nfsmout; 7238 } 7239 commit = fxdr_unsigned(int, *tl++); 7240 7241 /* 7242 * Return the lowest commitment level 7243 * obtained by any of the RPCs. 7244 */ 7245 if (committed == NFSWRITE_FILESYNC) 7246 committed = commit; 7247 else if (committed == NFSWRITE_DATASYNC && 7248 commit == NFSWRITE_UNSTABLE) 7249 committed = commit; 7250 NFSLOCKDS(dsp); 7251 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 7252 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7253 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 7254 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) && 7255 *must_commit != 2) { 7256 *must_commit = 1; 7257 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7258 } 7259 NFSUNLOCKDS(dsp); 7260 } 7261 nfsmout: 7262 if (nd->nd_mrep != NULL) 7263 m_freem(nd->nd_mrep); 7264 *iomode = committed; 7265 if (nd->nd_repstat != 0 && error == 0) 7266 error = nd->nd_repstat; 7267 return (error); 7268 } 7269 7270 /* 7271 * Start up the thread that will execute nfsrpc_writedsmir(). 7272 */ 7273 static void 7274 start_writedsmir(void *arg, int pending) 7275 { 7276 struct nfsclwritedsdorpc *drpc; 7277 7278 drpc = (struct nfsclwritedsdorpc *)arg; 7279 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode, 7280 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len, 7281 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred, 7282 drpc->p); 7283 drpc->done = 1; 7284 crfree(drpc->cred); 7285 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err); 7286 } 7287 7288 /* 7289 * Set up the write DS mirror call for the pNFS I/O thread. 7290 */ 7291 static int 7292 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit, 7293 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len, 7294 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 7295 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7296 { 7297 int error, ret; 7298 7299 error = 0; 7300 drpc->done = 0; 7301 drpc->vp = vp; 7302 drpc->iomode = *iomode; 7303 drpc->must_commit = *must_commit; 7304 drpc->stateidp = stateidp; 7305 drpc->dsp = dsp; 7306 drpc->off = off; 7307 drpc->len = len; 7308 drpc->fhp = fhp; 7309 drpc->m = m; 7310 drpc->vers = vers; 7311 drpc->minorvers = minorvers; 7312 drpc->cred = crhold(cred); 7313 drpc->p = p; 7314 drpc->inprog = 0; 7315 ret = EIO; 7316 if (nfs_pnfsiothreads != 0) { 7317 ret = nfs_pnfsio(start_writedsmir, drpc); 7318 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret); 7319 } 7320 if (ret != 0) { 7321 error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit, 7322 stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p); 7323 crfree(drpc->cred); 7324 } 7325 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error); 7326 return (error); 7327 } 7328 7329 /* 7330 * Free up the nfsclds structure. 7331 */ 7332 void 7333 nfscl_freenfsclds(struct nfsclds *dsp) 7334 { 7335 int i; 7336 7337 if (dsp == NULL) 7338 return; 7339 if (dsp->nfsclds_sockp != NULL) { 7340 NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 7341 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 7342 free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 7343 free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 7344 } 7345 NFSFREEMUTEX(&dsp->nfsclds_mtx); 7346 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 7347 for (i = 0; i < NFSV4_CBSLOTS; i++) { 7348 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 7349 m_freem( 7350 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 7351 } 7352 free(dsp, M_NFSCLDS); 7353 } 7354 7355 static enum nfsclds_state 7356 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 7357 struct nfsclds **retdspp, uint32_t *sequencep) 7358 { 7359 struct nfsclds *dsp; 7360 int fndseq; 7361 7362 /* 7363 * Search the list of nfsclds structures for one with the same 7364 * server. 7365 */ 7366 fndseq = 0; 7367 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 7368 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 7369 dsp->nfsclds_servownlen != 0 && 7370 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 7371 dsp->nfsclds_servownlen) && 7372 dsp->nfsclds_sess.nfsess_defunct == 0) { 7373 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 7374 TAILQ_FIRST(&nmp->nm_sess), dsp, 7375 dsp->nfsclds_flags); 7376 if (fndseq == 0) { 7377 /* Get sequenceid# from first entry. */ 7378 *sequencep = 7379 dsp->nfsclds_sess.nfsess_sequenceid; 7380 fndseq = 1; 7381 } 7382 /* Server major id matches. */ 7383 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 7384 *retdspp = dsp; 7385 return (NFSDSP_USETHISSESSION); 7386 } 7387 } 7388 } 7389 if (fndseq != 0) 7390 return (NFSDSP_SEQTHISSESSION); 7391 return (NFSDSP_NOTFOUND); 7392 } 7393 7394 /* 7395 * NFS commit rpc to a NFSv4.1 DS. 7396 */ 7397 static int 7398 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7399 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, 7400 NFSPROC_T *p) 7401 { 7402 uint32_t *tl; 7403 struct nfsrv_descript nfsd, *nd = &nfsd; 7404 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7405 struct nfssockreq *nrp; 7406 struct nfsvattr na; 7407 int attrflag, error; 7408 7409 nd->nd_mrep = NULL; 7410 if (vers == 0 || vers == NFS_VER4) { 7411 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, 7412 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7413 NULL); 7414 vers = NFS_VER4; 7415 } else { 7416 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh, 7417 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, 7418 NULL); 7419 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]); 7420 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]); 7421 } 7422 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers, 7423 minorvers); 7424 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7425 txdr_hyper(offset, tl); 7426 tl += 2; 7427 *tl = txdr_unsigned(cnt); 7428 nrp = dsp->nfsclds_sockp; 7429 if (nrp == NULL) 7430 /* If NULL, use the MDS socket. */ 7431 nrp = &nmp->nm_sockreq; 7432 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7433 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7434 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error, 7435 nd->nd_repstat); 7436 if (error != 0) 7437 return (error); 7438 if (nd->nd_repstat == 0) { 7439 if (vers == NFS_VER3) { 7440 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 7441 NULL); 7442 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error); 7443 if (error != 0) 7444 goto nfsmout; 7445 } 7446 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 7447 NFSLOCKDS(dsp); 7448 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 7449 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7450 error = NFSERR_STALEWRITEVERF; 7451 } 7452 NFSUNLOCKDS(dsp); 7453 } 7454 nfsmout: 7455 if (error == 0 && nd->nd_repstat != 0) 7456 error = nd->nd_repstat; 7457 m_freem(nd->nd_mrep); 7458 return (error); 7459 } 7460 7461 /* 7462 * Start up the thread that will execute nfsrpc_commitds(). 7463 */ 7464 static void 7465 start_commitds(void *arg, int pending) 7466 { 7467 struct nfsclwritedsdorpc *drpc; 7468 7469 drpc = (struct nfsclwritedsdorpc *)arg; 7470 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len, 7471 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, 7472 drpc->p); 7473 drpc->done = 1; 7474 crfree(drpc->cred); 7475 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err); 7476 } 7477 7478 /* 7479 * Set up the commit DS mirror call for the pNFS I/O thread. 7480 */ 7481 static int 7482 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7483 struct nfsfh *fhp, int vers, int minorvers, 7484 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7485 { 7486 int error, ret; 7487 7488 error = 0; 7489 drpc->done = 0; 7490 drpc->vp = vp; 7491 drpc->off = offset; 7492 drpc->len = cnt; 7493 drpc->dsp = dsp; 7494 drpc->fhp = fhp; 7495 drpc->vers = vers; 7496 drpc->minorvers = minorvers; 7497 drpc->cred = crhold(cred); 7498 drpc->p = p; 7499 drpc->inprog = 0; 7500 ret = EIO; 7501 if (nfs_pnfsiothreads != 0) { 7502 ret = nfs_pnfsio(start_commitds, drpc); 7503 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret); 7504 } 7505 if (ret != 0) { 7506 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers, 7507 minorvers, cred, p); 7508 crfree(drpc->cred); 7509 } 7510 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error); 7511 return (error); 7512 } 7513 7514 /* 7515 * NFS Advise rpc 7516 */ 7517 int 7518 nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise, 7519 struct ucred *cred, NFSPROC_T *p) 7520 { 7521 u_int32_t *tl; 7522 struct nfsrv_descript nfsd, *nd = &nfsd; 7523 nfsattrbit_t hints; 7524 int error; 7525 7526 NFSZERO_ATTRBIT(&hints); 7527 if (advise == POSIX_FADV_WILLNEED) 7528 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7529 else if (advise == POSIX_FADV_DONTNEED) 7530 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7531 else 7532 return (0); 7533 NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp, cred); 7534 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7535 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER); 7536 txdr_hyper(offset, tl); 7537 tl += 2; 7538 txdr_hyper(cnt, tl); 7539 nfsrv_putattrbit(nd, &hints); 7540 error = nfscl_request(nd, vp, p, cred); 7541 if (error != 0) 7542 return (error); 7543 if (nd->nd_repstat != 0) 7544 error = nd->nd_repstat; 7545 m_freem(nd->nd_mrep); 7546 return (error); 7547 } 7548 7549 #ifdef notyet 7550 /* 7551 * NFS advise rpc to a NFSv4.2 DS. 7552 */ 7553 static int 7554 nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7555 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7556 struct ucred *cred, NFSPROC_T *p) 7557 { 7558 uint32_t *tl; 7559 struct nfsrv_descript nfsd, *nd = &nfsd; 7560 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7561 struct nfssockreq *nrp; 7562 nfsattrbit_t hints; 7563 int error; 7564 7565 /* For NFS DSs prior to NFSv4.2, just return OK. */ 7566 if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION) 7567 return (0); 7568 NFSZERO_ATTRBIT(&hints); 7569 if (advise == POSIX_FADV_WILLNEED) 7570 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7571 else if (advise == POSIX_FADV_DONTNEED) 7572 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7573 else 7574 return (0); 7575 nd->nd_mrep = NULL; 7576 nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh, 7577 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers, NULL); 7578 vers = NFS_VER4; 7579 NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers, 7580 minorvers); 7581 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7582 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7583 txdr_hyper(offset, tl); 7584 tl += 2; 7585 *tl = txdr_unsigned(cnt); 7586 nfsrv_putattrbit(nd, &hints); 7587 nrp = dsp->nfsclds_sockp; 7588 if (nrp == NULL) 7589 /* If NULL, use the MDS socket. */ 7590 nrp = &nmp->nm_sockreq; 7591 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7592 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7593 NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error, 7594 nd->nd_repstat); 7595 if (error != 0) 7596 return (error); 7597 if (nd->nd_repstat != 0) 7598 error = nd->nd_repstat; 7599 m_freem(nd->nd_mrep); 7600 return (error); 7601 } 7602 7603 /* 7604 * Start up the thread that will execute nfsrpc_commitds(). 7605 */ 7606 static void 7607 start_adviseds(void *arg, int pending) 7608 { 7609 struct nfsclwritedsdorpc *drpc; 7610 7611 drpc = (struct nfsclwritedsdorpc *)arg; 7612 drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len, 7613 drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, 7614 drpc->cred, drpc->p); 7615 drpc->done = 1; 7616 crfree(drpc->cred); 7617 NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err); 7618 } 7619 7620 /* 7621 * Set up the advise DS mirror call for the pNFS I/O thread. 7622 */ 7623 static int 7624 nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7625 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7626 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7627 { 7628 int error, ret; 7629 7630 error = 0; 7631 drpc->done = 0; 7632 drpc->vp = vp; 7633 drpc->off = offset; 7634 drpc->len = cnt; 7635 drpc->advise = advise; 7636 drpc->dsp = dsp; 7637 drpc->fhp = fhp; 7638 drpc->vers = vers; 7639 drpc->minorvers = minorvers; 7640 drpc->cred = crhold(cred); 7641 drpc->p = p; 7642 drpc->inprog = 0; 7643 ret = EIO; 7644 if (nfs_pnfsiothreads != 0) { 7645 ret = nfs_pnfsio(start_adviseds, drpc); 7646 NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret); 7647 } 7648 if (ret != 0) { 7649 error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers, 7650 minorvers, cred, p); 7651 crfree(drpc->cred); 7652 } 7653 NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error); 7654 return (error); 7655 } 7656 #endif /* notyet */ 7657 7658 /* 7659 * Do the Allocate operation, retrying for recovery. 7660 */ 7661 int 7662 nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap, 7663 int *attrflagp, struct ucred *cred, NFSPROC_T *p) 7664 { 7665 int error, expireret = 0, retrycnt, nostateid; 7666 uint32_t clidrev = 0; 7667 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7668 struct nfsfh *nfhp = NULL; 7669 nfsv4stateid_t stateid; 7670 off_t tmp_off; 7671 void *lckp; 7672 7673 if (len < 0) 7674 return (EINVAL); 7675 if (len == 0) 7676 return (0); 7677 tmp_off = off + len; 7678 NFSLOCKMNT(nmp); 7679 if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) { 7680 NFSUNLOCKMNT(nmp); 7681 return (EFBIG); 7682 } 7683 if (nmp->nm_clp != NULL) 7684 clidrev = nmp->nm_clp->nfsc_clientidrev; 7685 NFSUNLOCKMNT(nmp); 7686 nfhp = VTONFS(vp)->n_fhp; 7687 retrycnt = 0; 7688 do { 7689 lckp = NULL; 7690 nostateid = 0; 7691 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 7692 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); 7693 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 7694 stateid.other[2] == 0) { 7695 nostateid = 1; 7696 NFSCL_DEBUG(1, "stateid0 in allocate\n"); 7697 } 7698 7699 /* 7700 * Not finding a stateid should probably never happen, 7701 * but just return an error for this case. 7702 */ 7703 if (nostateid != 0) 7704 error = EIO; 7705 else 7706 error = nfsrpc_allocaterpc(vp, off, len, &stateid, 7707 nap, attrflagp, cred, p); 7708 if (error == NFSERR_STALESTATEID) 7709 nfscl_initiate_recovery(nmp->nm_clp); 7710 if (lckp != NULL) 7711 nfscl_lockderef(lckp); 7712 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 7713 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 7714 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 7715 (void) nfs_catnap(PZERO, error, "nfs_allocate"); 7716 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && 7717 error == NFSERR_BADSTATEID)) && clidrev != 0) { 7718 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 7719 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { 7720 error = EIO; 7721 } 7722 retrycnt++; 7723 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 7724 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 7725 error == NFSERR_STALEDONTRECOVER || 7726 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 7727 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 7728 expireret == 0 && clidrev != 0 && retrycnt < 4)); 7729 if (error != 0 && retrycnt >= 4) 7730 error = EIO; 7731 return (error); 7732 } 7733 7734 /* 7735 * The allocate RPC. 7736 */ 7737 static int 7738 nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp, 7739 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 7740 { 7741 uint32_t *tl; 7742 int error; 7743 struct nfsrv_descript nfsd; 7744 struct nfsrv_descript *nd = &nfsd; 7745 nfsattrbit_t attrbits; 7746 7747 *attrflagp = 0; 7748 NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp, cred); 7749 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 7750 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 7751 txdr_hyper(off, tl); tl += 2; 7752 txdr_hyper(len, tl); tl += 2; 7753 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7754 NFSGETATTR_ATTRBIT(&attrbits); 7755 nfsrv_putattrbit(nd, &attrbits); 7756 error = nfscl_request(nd, vp, p, cred); 7757 if (error != 0) 7758 return (error); 7759 if (nd->nd_repstat == 0) { 7760 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7761 error = nfsm_loadattr(nd, nap); 7762 if (error == 0) 7763 *attrflagp = NFS_LATTR_NOSHRINK; 7764 } else 7765 error = nd->nd_repstat; 7766 nfsmout: 7767 m_freem(nd->nd_mrep); 7768 return (error); 7769 } 7770 7771 /* 7772 * Set up the XDR arguments for the LayoutGet operation. 7773 */ 7774 static void 7775 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, 7776 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype, 7777 int layoutlen, int usecurstateid) 7778 { 7779 uint32_t *tl; 7780 7781 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 7782 NFSX_STATEID); 7783 *tl++ = newnfs_false; /* Don't signal availability. */ 7784 *tl++ = txdr_unsigned(layouttype); 7785 *tl++ = txdr_unsigned(iomode); 7786 txdr_hyper(offset, tl); 7787 tl += 2; 7788 txdr_hyper(len, tl); 7789 tl += 2; 7790 txdr_hyper(minlen, tl); 7791 tl += 2; 7792 if (usecurstateid != 0) { 7793 /* Special stateid for Current stateid. */ 7794 *tl++ = txdr_unsigned(1); 7795 *tl++ = 0; 7796 *tl++ = 0; 7797 *tl++ = 0; 7798 } else { 7799 *tl++ = txdr_unsigned(stateidp->seqid); 7800 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 7801 *tl++ = stateidp->other[0]; 7802 *tl++ = stateidp->other[1]; 7803 *tl++ = stateidp->other[2]; 7804 } 7805 *tl = txdr_unsigned(layoutlen); 7806 } 7807 7808 /* 7809 * Parse the reply for a successful LayoutGet operation. 7810 */ 7811 static int 7812 nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd, 7813 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp) 7814 { 7815 uint32_t *tl; 7816 struct nfsclflayout *flp, *prevflp, *tflp; 7817 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen; 7818 int m, mirrorcnt; 7819 uint64_t retlen, off; 7820 struct nfsfh *nfhp; 7821 uint8_t *cp; 7822 uid_t user; 7823 gid_t grp; 7824 7825 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n"); 7826 error = 0; 7827 flp = NULL; 7828 gotiomode = -1; 7829 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 7830 if (*tl++ != 0) 7831 *retonclosep = 1; 7832 else 7833 *retonclosep = 0; 7834 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 7835 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 7836 (int)stateidp->seqid); 7837 stateidp->other[0] = *tl++; 7838 stateidp->other[1] = *tl++; 7839 stateidp->other[2] = *tl++; 7840 cnt = fxdr_unsigned(int, *tl); 7841 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 7842 if (cnt <= 0 || cnt > 10000) { 7843 /* Don't accept more than 10000 layouts in reply. */ 7844 error = NFSERR_BADXDR; 7845 goto nfsmout; 7846 } 7847 for (i = 0; i < cnt; i++) { 7848 /* Dissect to the layout type. */ 7849 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 7850 3 * NFSX_UNSIGNED); 7851 off = fxdr_hyper(tl); tl += 2; 7852 retlen = fxdr_hyper(tl); tl += 2; 7853 iomode = fxdr_unsigned(int, *tl++); 7854 laytype = fxdr_unsigned(int, *tl); 7855 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype, 7856 (uintmax_t)off, (uintmax_t)retlen, iomode); 7857 /* Ignore length of layout body for now. */ 7858 if (laytype == NFSLAYOUT_NFSV4_1_FILES) { 7859 /* Parse the File layout up to fhcnt. */ 7860 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + 7861 NFSX_HYPER + NFSX_V4DEVICEID); 7862 fhcnt = fxdr_unsigned(int, *(tl + 4 + 7863 NFSX_V4DEVICEID / NFSX_UNSIGNED)); 7864 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7865 if (fhcnt < 0 || fhcnt > 100) { 7866 /* Don't accept more than 100 file handles. */ 7867 error = NFSERR_BADXDR; 7868 goto nfsmout; 7869 } 7870 if (fhcnt > 0) 7871 flp = malloc(sizeof(*flp) + fhcnt * 7872 sizeof(struct nfsfh *), M_NFSFLAYOUT, 7873 M_WAITOK); 7874 else 7875 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, 7876 M_WAITOK); 7877 flp->nfsfl_flags = NFSFL_FILE; 7878 flp->nfsfl_fhcnt = 0; 7879 flp->nfsfl_devp = NULL; 7880 flp->nfsfl_off = off; 7881 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7882 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7883 else 7884 flp->nfsfl_end = flp->nfsfl_off + retlen; 7885 flp->nfsfl_iomode = iomode; 7886 if (gotiomode == -1) 7887 gotiomode = flp->nfsfl_iomode; 7888 /* Ignore layout body length for now. */ 7889 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 7890 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 7891 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 7892 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 7893 mtx_lock(&nmp->nm_mtx); 7894 if (nmp->nm_minorvers > 1 && (flp->nfsfl_util & 7895 NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0) 7896 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 7897 mtx_unlock(&nmp->nm_mtx); 7898 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 7899 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 7900 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n", 7901 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff); 7902 for (j = 0; j < fhcnt; j++) { 7903 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7904 nfhlen = fxdr_unsigned(int, *tl); 7905 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 7906 error = NFSERR_BADXDR; 7907 goto nfsmout; 7908 } 7909 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, 7910 M_NFSFH, M_WAITOK); 7911 flp->nfsfl_fh[j] = nfhp; 7912 flp->nfsfl_fhcnt++; 7913 nfhp->nfh_len = nfhlen; 7914 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 7915 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 7916 } 7917 } else if (laytype == NFSLAYOUT_FLEXFILE) { 7918 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 7919 NFSX_HYPER); 7920 mirrorcnt = fxdr_unsigned(int, *(tl + 2)); 7921 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt); 7922 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) { 7923 error = NFSERR_BADXDR; 7924 goto nfsmout; 7925 } 7926 flp = malloc(sizeof(*flp) + mirrorcnt * 7927 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK); 7928 flp->nfsfl_flags = NFSFL_FLEXFILE; 7929 flp->nfsfl_mirrorcnt = mirrorcnt; 7930 for (j = 0; j < mirrorcnt; j++) 7931 flp->nfsfl_ffm[j].devp = NULL; 7932 flp->nfsfl_off = off; 7933 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7934 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7935 else 7936 flp->nfsfl_end = flp->nfsfl_off + retlen; 7937 flp->nfsfl_iomode = iomode; 7938 if (gotiomode == -1) 7939 gotiomode = flp->nfsfl_iomode; 7940 flp->nfsfl_stripeunit = fxdr_hyper(tl); 7941 NFSCL_DEBUG(4, "stripeunit=%ju\n", 7942 (uintmax_t)flp->nfsfl_stripeunit); 7943 for (j = 0; j < mirrorcnt; j++) { 7944 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7945 k = fxdr_unsigned(int, *tl); 7946 if (k < 1 || k > 128) { 7947 error = NFSERR_BADXDR; 7948 goto nfsmout; 7949 } 7950 NFSCL_DEBUG(4, "servercnt=%d\n", k); 7951 for (l = 0; l < k; l++) { 7952 NFSM_DISSECT(tl, uint32_t *, 7953 NFSX_V4DEVICEID + NFSX_STATEID + 7954 2 * NFSX_UNSIGNED); 7955 if (l == 0) { 7956 /* Just use the first server. */ 7957 NFSBCOPY(tl, 7958 flp->nfsfl_ffm[j].dev, 7959 NFSX_V4DEVICEID); 7960 tl += (NFSX_V4DEVICEID / 7961 NFSX_UNSIGNED); 7962 tl++; 7963 flp->nfsfl_ffm[j].st.seqid = 7964 *tl++; 7965 flp->nfsfl_ffm[j].st.other[0] = 7966 *tl++; 7967 flp->nfsfl_ffm[j].st.other[1] = 7968 *tl++; 7969 flp->nfsfl_ffm[j].st.other[2] = 7970 *tl++; 7971 NFSCL_DEBUG(4, "st.seqid=%u " 7972 "st.o0=0x%x st.o1=0x%x " 7973 "st.o2=0x%x\n", 7974 flp->nfsfl_ffm[j].st.seqid, 7975 flp->nfsfl_ffm[j].st.other[0], 7976 flp->nfsfl_ffm[j].st.other[1], 7977 flp->nfsfl_ffm[j].st.other[2]); 7978 } else 7979 tl += ((NFSX_V4DEVICEID + 7980 NFSX_STATEID + 7981 NFSX_UNSIGNED) / 7982 NFSX_UNSIGNED); 7983 fhcnt = fxdr_unsigned(int, *tl); 7984 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7985 if (fhcnt < 1 || 7986 fhcnt > NFSDEV_MAXVERS) { 7987 error = NFSERR_BADXDR; 7988 goto nfsmout; 7989 } 7990 for (m = 0; m < fhcnt; m++) { 7991 NFSM_DISSECT(tl, uint32_t *, 7992 NFSX_UNSIGNED); 7993 nfhlen = fxdr_unsigned(int, 7994 *tl); 7995 NFSCL_DEBUG(4, "nfhlen=%d\n", 7996 nfhlen); 7997 if (nfhlen <= 0 || nfhlen > 7998 NFSX_V4FHMAX) { 7999 error = NFSERR_BADXDR; 8000 goto nfsmout; 8001 } 8002 NFSM_DISSECT(cp, uint8_t *, 8003 NFSM_RNDUP(nfhlen)); 8004 if (l == 0) { 8005 flp->nfsfl_ffm[j].fhcnt 8006 = fhcnt; 8007 nfhp = malloc( 8008 sizeof(*nfhp) + 8009 nfhlen - 1, M_NFSFH, 8010 M_WAITOK); 8011 flp->nfsfl_ffm[j].fh[m] 8012 = nfhp; 8013 nfhp->nfh_len = nfhlen; 8014 NFSBCOPY(cp, 8015 nfhp->nfh_fh, 8016 nfhlen); 8017 NFSCL_DEBUG(4, 8018 "got fh\n"); 8019 } 8020 } 8021 /* Now, get the ffsd_user/ffds_group. */ 8022 error = nfsrv_parseug(nd, 0, &user, 8023 &grp, curthread); 8024 NFSCL_DEBUG(4, "after parseu=%d\n", 8025 error); 8026 if (error == 0) 8027 error = nfsrv_parseug(nd, 1, 8028 &user, &grp, curthread); 8029 NFSCL_DEBUG(4, "aft parseg=%d\n", 8030 grp); 8031 if (error != 0) 8032 goto nfsmout; 8033 NFSCL_DEBUG(4, "user=%d group=%d\n", 8034 user, grp); 8035 if (l == 0) { 8036 flp->nfsfl_ffm[j].user = user; 8037 flp->nfsfl_ffm[j].group = grp; 8038 NFSCL_DEBUG(4, 8039 "usr=%d grp=%d\n", user, 8040 grp); 8041 } 8042 } 8043 } 8044 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8045 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++); 8046 #ifdef notnow 8047 /* 8048 * At this time, there is no flag. 8049 * NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be 8050 * added, or it may never exist? 8051 */ 8052 mtx_lock(&nmp->nm_mtx); 8053 if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags & 8054 NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0) 8055 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 8056 mtx_unlock(&nmp->nm_mtx); 8057 #endif 8058 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl); 8059 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n", 8060 flp->nfsfl_fflags, flp->nfsfl_statshint); 8061 } else { 8062 error = NFSERR_BADXDR; 8063 goto nfsmout; 8064 } 8065 if (flp->nfsfl_iomode == gotiomode) { 8066 /* Keep the list in increasing offset order. */ 8067 tflp = LIST_FIRST(flhp); 8068 prevflp = NULL; 8069 while (tflp != NULL && 8070 tflp->nfsfl_off < flp->nfsfl_off) { 8071 prevflp = tflp; 8072 tflp = LIST_NEXT(tflp, nfsfl_list); 8073 } 8074 if (prevflp == NULL) 8075 LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 8076 else 8077 LIST_INSERT_AFTER(prevflp, flp, 8078 nfsfl_list); 8079 NFSCL_DEBUG(4, "flp inserted\n"); 8080 } else { 8081 printf("nfscl_layoutget(): got wrong iomode\n"); 8082 nfscl_freeflayout(flp); 8083 } 8084 flp = NULL; 8085 } 8086 nfsmout: 8087 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error); 8088 if (error != 0 && flp != NULL) 8089 nfscl_freeflayout(flp); 8090 return (error); 8091 } 8092 8093 /* 8094 * Parse a user/group digit string. 8095 */ 8096 static int 8097 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp, 8098 NFSPROC_T *p) 8099 { 8100 uint32_t *tl; 8101 char *cp, *str, str0[NFSV4_SMALLSTR + 1]; 8102 uint32_t len = 0; 8103 int error = 0; 8104 8105 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8106 len = fxdr_unsigned(uint32_t, *tl); 8107 str = NULL; 8108 if (len > NFSV4_OPAQUELIMIT) { 8109 error = NFSERR_BADXDR; 8110 goto nfsmout; 8111 } 8112 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len); 8113 if (len == 0) { 8114 if (dogrp != 0) 8115 *gidp = GID_NOGROUP; 8116 else 8117 *uidp = UID_NOBODY; 8118 return (0); 8119 } 8120 if (len > NFSV4_SMALLSTR) 8121 str = malloc(len + 1, M_TEMP, M_WAITOK); 8122 else 8123 str = str0; 8124 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len)); 8125 NFSBCOPY(cp, str, len); 8126 str[len] = '\0'; 8127 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str); 8128 if (dogrp != 0) 8129 error = nfsv4_strtogid(nd, str, len, gidp); 8130 else 8131 error = nfsv4_strtouid(nd, str, len, uidp); 8132 nfsmout: 8133 if (len > NFSV4_SMALLSTR) 8134 free(str, M_TEMP); 8135 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error); 8136 return (error); 8137 } 8138 8139 /* 8140 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), 8141 * so that it does both an Open and a Layoutget. 8142 */ 8143 static int 8144 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 8145 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 8146 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 8147 struct ucred *cred, NFSPROC_T *p) 8148 { 8149 struct nfscllayout *lyp; 8150 struct nfsclflayout *flp; 8151 struct nfsclflayouthead flh; 8152 int error, islocked, layoutlen, recalled, retonclose, usecurstateid; 8153 int layouttype, laystat; 8154 nfsv4stateid_t stateid; 8155 struct nfsclsession *tsep; 8156 8157 error = 0; 8158 if (NFSHASFLEXFILE(nmp)) 8159 layouttype = NFSLAYOUT_FLEXFILE; 8160 else 8161 layouttype = NFSLAYOUT_NFSV4_1_FILES; 8162 /* 8163 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 8164 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 8165 * flp == NULL. 8166 */ 8167 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp, 8168 &recalled); 8169 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); 8170 if (lyp == NULL) 8171 islocked = 0; 8172 else if (flp != NULL) 8173 islocked = 1; 8174 else 8175 islocked = 2; 8176 if ((lyp == NULL || flp == NULL) && recalled == 0) { 8177 LIST_INIT(&flh); 8178 tsep = nfsmnt_mdssession(nmp); 8179 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 8180 3 * NFSX_UNSIGNED); 8181 if (lyp == NULL) 8182 usecurstateid = 1; 8183 else { 8184 usecurstateid = 0; 8185 stateid.seqid = lyp->nfsly_stateid.seqid; 8186 stateid.other[0] = lyp->nfsly_stateid.other[0]; 8187 stateid.other[1] = lyp->nfsly_stateid.other[1]; 8188 stateid.other[2] = lyp->nfsly_stateid.other[2]; 8189 } 8190 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, 8191 newfhp, newfhlen, mode, op, name, namelen, 8192 dpp, &stateid, usecurstateid, layouttype, layoutlen, 8193 &retonclose, &flh, &laystat, cred, p); 8194 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", 8195 laystat, error); 8196 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, 8197 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, 8198 &islocked, cred, p); 8199 } else 8200 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, 8201 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); 8202 if (islocked == 2) 8203 nfscl_rellayout(lyp, 1); 8204 else if (islocked == 1) 8205 nfscl_rellayout(lyp, 0); 8206 return (error); 8207 } 8208 8209 /* 8210 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS 8211 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are 8212 * handled by nfsrpc_openrpc(). 8213 * For the case where op == NULL, dvp is the directory. When op != NULL, it 8214 * can be NULL. 8215 */ 8216 static int 8217 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 8218 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 8219 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 8220 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, 8221 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, 8222 int *laystatp, struct ucred *cred, NFSPROC_T *p) 8223 { 8224 uint32_t *tl; 8225 struct nfsrv_descript nfsd, *nd = &nfsd; 8226 struct nfscldeleg *ndp = NULL; 8227 struct nfsvattr nfsva; 8228 struct nfsclsession *tsep; 8229 uint32_t rflags, deleg; 8230 nfsattrbit_t attrbits; 8231 int error, ret, acesize, limitby, iomode; 8232 8233 *dpp = NULL; 8234 *laystatp = ENXIO; 8235 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL, 8236 0, 0, cred); 8237 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 8238 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 8239 *tl++ = txdr_unsigned(mode & (NFSV4OPEN_ACCESSBOTH | 8240 NFSV4OPEN_WANTDELEGMASK)); 8241 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 8242 tsep = nfsmnt_mdssession(nmp); 8243 *tl++ = tsep->nfsess_clientid.lval[0]; 8244 *tl = tsep->nfsess_clientid.lval[1]; 8245 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 8246 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8247 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 8248 if (NFSHASNFSV4N(nmp)) { 8249 *tl = txdr_unsigned(NFSV4OPEN_CLAIMFH); 8250 } else { 8251 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 8252 nfsm_strtom(nd, name, namelen); 8253 } 8254 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8255 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8256 NFSZERO_ATTRBIT(&attrbits); 8257 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 8258 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 8259 nfsrv_putattrbit(nd, &attrbits); 8260 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8261 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 8262 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) 8263 iomode = NFSLAYOUTIOMODE_RW; 8264 else 8265 iomode = NFSLAYOUTIOMODE_READ; 8266 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, 8267 layouttype, layoutlen, usecurstateid); 8268 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 8269 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 8270 if (error != 0) 8271 return (error); 8272 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 8273 if (nd->nd_repstat != 0) 8274 *laystatp = nd->nd_repstat; 8275 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8276 /* ND_NOMOREDATA will be set if the Open operation failed. */ 8277 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8278 6 * NFSX_UNSIGNED); 8279 op->nfso_stateid.seqid = *tl++; 8280 op->nfso_stateid.other[0] = *tl++; 8281 op->nfso_stateid.other[1] = *tl++; 8282 op->nfso_stateid.other[2] = *tl; 8283 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 8284 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8285 if (error != 0) 8286 goto nfsmout; 8287 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 8288 deleg = fxdr_unsigned(u_int32_t, *tl); 8289 if (deleg == NFSV4OPEN_DELEGATEREAD || 8290 deleg == NFSV4OPEN_DELEGATEWRITE) { 8291 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 8292 NFSCLFLAGS_FIRSTDELEG)) 8293 op->nfso_own->nfsow_clp->nfsc_flags |= 8294 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 8295 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, 8296 M_NFSCLDELEG, M_WAITOK); 8297 LIST_INIT(&ndp->nfsdl_owner); 8298 LIST_INIT(&ndp->nfsdl_lock); 8299 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 8300 ndp->nfsdl_fhlen = newfhlen; 8301 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 8302 newnfs_copyincred(cred, &ndp->nfsdl_cred); 8303 nfscl_lockinit(&ndp->nfsdl_rwlock); 8304 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8305 NFSX_UNSIGNED); 8306 ndp->nfsdl_stateid.seqid = *tl++; 8307 ndp->nfsdl_stateid.other[0] = *tl++; 8308 ndp->nfsdl_stateid.other[1] = *tl++; 8309 ndp->nfsdl_stateid.other[2] = *tl++; 8310 ret = fxdr_unsigned(int, *tl); 8311 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 8312 ndp->nfsdl_flags = NFSCLDL_WRITE; 8313 /* 8314 * Indicates how much the file can grow. 8315 */ 8316 NFSM_DISSECT(tl, u_int32_t *, 8317 3 * NFSX_UNSIGNED); 8318 limitby = fxdr_unsigned(int, *tl++); 8319 switch (limitby) { 8320 case NFSV4OPEN_LIMITSIZE: 8321 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 8322 break; 8323 case NFSV4OPEN_LIMITBLOCKS: 8324 ndp->nfsdl_sizelimit = 8325 fxdr_unsigned(u_int64_t, *tl++); 8326 ndp->nfsdl_sizelimit *= 8327 fxdr_unsigned(u_int64_t, *tl); 8328 break; 8329 default: 8330 error = NFSERR_BADXDR; 8331 goto nfsmout; 8332 }; 8333 } else 8334 ndp->nfsdl_flags = NFSCLDL_READ; 8335 if (ret != 0) 8336 ndp->nfsdl_flags |= NFSCLDL_RECALL; 8337 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, false, 8338 &ret, &acesize, p); 8339 if (error != 0) 8340 goto nfsmout; 8341 } else if (deleg == NFSV4OPEN_DELEGATENONEEXT && 8342 NFSHASNFSV4N(nmp)) { 8343 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8344 deleg = fxdr_unsigned(uint32_t, *tl); 8345 if (deleg == NFSV4OPEN_CONTENTION || 8346 deleg == NFSV4OPEN_RESOURCE) 8347 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8348 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 8349 error = NFSERR_BADXDR; 8350 goto nfsmout; 8351 } 8352 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || 8353 nfscl_assumeposixlocks) 8354 op->nfso_posixlock = 1; 8355 else 8356 op->nfso_posixlock = 0; 8357 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8358 /* If the 2nd element == NFS_OK, the Getattr succeeded. */ 8359 if (*++tl == 0) { 8360 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 8361 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 8362 NULL, NULL, NULL, p, cred); 8363 if (error != 0) 8364 goto nfsmout; 8365 if (ndp != NULL) { 8366 ndp->nfsdl_change = nfsva.na_filerev; 8367 ndp->nfsdl_modtime = nfsva.na_mtime; 8368 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8369 *dpp = ndp; 8370 ndp = NULL; 8371 } 8372 /* 8373 * At this point, the Open has succeeded, so set 8374 * nd_repstat = NFS_OK. If the Layoutget failed, 8375 * this function just won't return a layout. 8376 */ 8377 if (nd->nd_repstat == 0) { 8378 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8379 *laystatp = fxdr_unsigned(int, *++tl); 8380 if (*laystatp == 0) { 8381 error = nfsrv_parselayoutget(nmp, nd, 8382 stateidp, retonclosep, flhp); 8383 if (error != 0) 8384 *laystatp = error; 8385 } 8386 } else 8387 nd->nd_repstat = 0; /* Return 0 for Open. */ 8388 } 8389 } 8390 if (nd->nd_repstat != 0 && error == 0) 8391 error = nd->nd_repstat; 8392 nfsmout: 8393 free(ndp, M_NFSCLDELEG); 8394 m_freem(nd->nd_mrep); 8395 return (error); 8396 } 8397 8398 /* 8399 * Similar nfsrpc_createv4(), but also does the LayoutGet operation. 8400 * Used only for mounts with pNFS enabled. 8401 */ 8402 static int 8403 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8404 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8405 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8406 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8407 int *dattrflagp, int *unlockedp, nfsv4stateid_t *stateidp, 8408 int usecurstateid, int layouttype, int layoutlen, int *retonclosep, 8409 struct nfsclflayouthead *flhp, int *laystatp) 8410 { 8411 uint32_t *tl; 8412 int error = 0, deleg, newone, ret, acesize, limitby; 8413 struct nfsrv_descript nfsd, *nd = &nfsd; 8414 struct nfsclopen *op; 8415 struct nfscldeleg *dp = NULL; 8416 struct nfsnode *np; 8417 struct nfsfh *nfhp; 8418 struct nfsclsession *tsep; 8419 nfsattrbit_t attrbits; 8420 nfsv4stateid_t stateid; 8421 struct nfsmount *nmp; 8422 8423 nmp = VFSTONFS(dvp->v_mount); 8424 np = VTONFS(dvp); 8425 *laystatp = ENXIO; 8426 *unlockedp = 0; 8427 *nfhpp = NULL; 8428 *dpp = NULL; 8429 *attrflagp = 0; 8430 *dattrflagp = 0; 8431 if (namelen > NFS_MAXNAMLEN) 8432 return (ENAMETOOLONG); 8433 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp, cred); 8434 /* 8435 * For V4, this is actually an Open op. 8436 */ 8437 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 8438 *tl++ = txdr_unsigned(owp->nfsow_seqid); 8439 if (NFSHASNFSV4N(nmp)) { 8440 if (!NFSHASPNFS(nmp) && nfscl_enablecallb != 0 && 8441 nfs_numnfscbd > 0) 8442 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 8443 NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTWRITEDELEG); 8444 else 8445 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 8446 NFSV4OPEN_ACCESSREAD | NFSV4OPEN_WANTNODELEG); 8447 } else 8448 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 8449 NFSV4OPEN_ACCESSREAD); 8450 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 8451 tsep = nfsmnt_mdssession(nmp); 8452 *tl++ = tsep->nfsess_clientid.lval[0]; 8453 *tl = tsep->nfsess_clientid.lval[1]; 8454 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 8455 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8456 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 8457 if ((fmode & O_EXCL) != 0) { 8458 if (NFSHASSESSPERSIST(nmp)) { 8459 /* Use GUARDED for persistent sessions. */ 8460 *tl = txdr_unsigned(NFSCREATE_GUARDED); 8461 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); 8462 } else { 8463 /* Otherwise, use EXCLUSIVE4_1. */ 8464 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 8465 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 8466 *tl++ = cverf.lval[0]; 8467 *tl = cverf.lval[1]; 8468 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); 8469 } 8470 } else { 8471 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 8472 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_NEWFILE, 0); 8473 } 8474 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8475 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 8476 nfsm_strtom(nd, name, namelen); 8477 /* Get the new file's handle and attributes, plus save the FH. */ 8478 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 8479 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); 8480 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 8481 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8482 NFSGETATTR_ATTRBIT(&attrbits); 8483 nfsrv_putattrbit(nd, &attrbits); 8484 /* Get the directory's post-op attributes. */ 8485 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8486 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8487 (void)nfsm_fhtom(nmp, nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 8488 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8489 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8490 nfsrv_putattrbit(nd, &attrbits); 8491 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8492 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); 8493 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 8494 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, 8495 layouttype, layoutlen, usecurstateid); 8496 error = nfscl_request(nd, dvp, p, cred); 8497 if (error != 0) 8498 return (error); 8499 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, 8500 error); 8501 if (nd->nd_repstat != 0) 8502 *laystatp = nd->nd_repstat; 8503 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 8504 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8505 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); 8506 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8507 6 * NFSX_UNSIGNED); 8508 stateid.seqid = *tl++; 8509 stateid.other[0] = *tl++; 8510 stateid.other[1] = *tl++; 8511 stateid.other[2] = *tl; 8512 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8513 if (error != 0) 8514 goto nfsmout; 8515 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 8516 deleg = fxdr_unsigned(int, *tl); 8517 if (deleg == NFSV4OPEN_DELEGATEREAD || 8518 deleg == NFSV4OPEN_DELEGATEWRITE) { 8519 if (!(owp->nfsow_clp->nfsc_flags & 8520 NFSCLFLAGS_FIRSTDELEG)) 8521 owp->nfsow_clp->nfsc_flags |= 8522 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 8523 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, 8524 M_NFSCLDELEG, M_WAITOK); 8525 LIST_INIT(&dp->nfsdl_owner); 8526 LIST_INIT(&dp->nfsdl_lock); 8527 dp->nfsdl_clp = owp->nfsow_clp; 8528 newnfs_copyincred(cred, &dp->nfsdl_cred); 8529 nfscl_lockinit(&dp->nfsdl_rwlock); 8530 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8531 NFSX_UNSIGNED); 8532 dp->nfsdl_stateid.seqid = *tl++; 8533 dp->nfsdl_stateid.other[0] = *tl++; 8534 dp->nfsdl_stateid.other[1] = *tl++; 8535 dp->nfsdl_stateid.other[2] = *tl++; 8536 ret = fxdr_unsigned(int, *tl); 8537 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 8538 dp->nfsdl_flags = NFSCLDL_WRITE; 8539 /* 8540 * Indicates how much the file can grow. 8541 */ 8542 NFSM_DISSECT(tl, u_int32_t *, 8543 3 * NFSX_UNSIGNED); 8544 limitby = fxdr_unsigned(int, *tl++); 8545 switch (limitby) { 8546 case NFSV4OPEN_LIMITSIZE: 8547 dp->nfsdl_sizelimit = fxdr_hyper(tl); 8548 break; 8549 case NFSV4OPEN_LIMITBLOCKS: 8550 dp->nfsdl_sizelimit = 8551 fxdr_unsigned(u_int64_t, *tl++); 8552 dp->nfsdl_sizelimit *= 8553 fxdr_unsigned(u_int64_t, *tl); 8554 break; 8555 default: 8556 error = NFSERR_BADXDR; 8557 goto nfsmout; 8558 }; 8559 } else { 8560 dp->nfsdl_flags = NFSCLDL_READ; 8561 } 8562 if (ret != 0) 8563 dp->nfsdl_flags |= NFSCLDL_RECALL; 8564 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, false, 8565 &ret, &acesize, p); 8566 if (error != 0) 8567 goto nfsmout; 8568 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 8569 error = NFSERR_BADXDR; 8570 goto nfsmout; 8571 } 8572 8573 /* Now, we should have the status for the SaveFH. */ 8574 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8575 if (*++tl == 0) { 8576 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); 8577 /* 8578 * Now, process the GetFH and Getattr for the newly 8579 * created file. nfscl_mtofh() will set 8580 * ND_NOMOREDATA if these weren't successful. 8581 */ 8582 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 8583 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); 8584 if (error != 0) 8585 goto nfsmout; 8586 } else 8587 nd->nd_flag |= ND_NOMOREDATA; 8588 /* Now we have the PutFH and Getattr for the directory. */ 8589 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8590 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8591 if (*++tl != 0) 8592 nd->nd_flag |= ND_NOMOREDATA; 8593 else { 8594 NFSM_DISSECT(tl, uint32_t *, 2 * 8595 NFSX_UNSIGNED); 8596 if (*++tl != 0) 8597 nd->nd_flag |= ND_NOMOREDATA; 8598 } 8599 } 8600 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8601 /* Load the directory attributes. */ 8602 error = nfsm_loadattr(nd, dnap); 8603 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); 8604 if (error != 0) 8605 goto nfsmout; 8606 *dattrflagp = 1; 8607 if (dp != NULL && *attrflagp != 0) { 8608 dp->nfsdl_change = nnap->na_filerev; 8609 dp->nfsdl_modtime = nnap->na_mtime; 8610 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8611 } 8612 /* 8613 * We can now complete the Open state. 8614 */ 8615 nfhp = *nfhpp; 8616 if (dp != NULL) { 8617 dp->nfsdl_fhlen = nfhp->nfh_len; 8618 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, 8619 nfhp->nfh_len); 8620 } 8621 /* 8622 * Get an Open structure that will be 8623 * attached to the OpenOwner, acquired already. 8624 */ 8625 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 8626 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 8627 cred, p, NULL, &op, &newone, NULL, 0, false); 8628 if (error != 0) 8629 goto nfsmout; 8630 op->nfso_stateid = stateid; 8631 newnfs_copyincred(cred, &op->nfso_cred); 8632 8633 nfscl_openrelease(nmp, op, error, newone); 8634 *unlockedp = 1; 8635 8636 /* Now, handle the RestoreFH and LayoutGet. */ 8637 if (nd->nd_repstat == 0) { 8638 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 8639 *laystatp = fxdr_unsigned(int, *(tl + 3)); 8640 if (*laystatp == 0) { 8641 error = nfsrv_parselayoutget(nmp, nd, 8642 stateidp, retonclosep, flhp); 8643 if (error != 0) 8644 *laystatp = error; 8645 } 8646 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", 8647 error); 8648 } else 8649 nd->nd_repstat = 0; 8650 } 8651 } 8652 if (nd->nd_repstat != 0 && error == 0) 8653 error = nd->nd_repstat; 8654 if (error == NFSERR_STALECLIENTID) 8655 nfscl_initiate_recovery(owp->nfsow_clp); 8656 nfsmout: 8657 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); 8658 if (error == 0) 8659 *dpp = dp; 8660 else 8661 free(dp, M_NFSCLDELEG); 8662 m_freem(nd->nd_mrep); 8663 return (error); 8664 } 8665 8666 /* 8667 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. 8668 */ 8669 static int 8670 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8671 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8672 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8673 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8674 int *dattrflagp, int *unlockedp) 8675 { 8676 struct nfscllayout *lyp; 8677 struct nfsclflayouthead flh; 8678 struct nfsfh *nfhp; 8679 struct nfsclsession *tsep; 8680 struct nfsmount *nmp; 8681 nfsv4stateid_t stateid; 8682 int error, layoutlen, layouttype, retonclose, laystat; 8683 8684 error = 0; 8685 nmp = VFSTONFS(dvp->v_mount); 8686 if (NFSHASFLEXFILE(nmp)) 8687 layouttype = NFSLAYOUT_FLEXFILE; 8688 else 8689 layouttype = NFSLAYOUT_NFSV4_1_FILES; 8690 LIST_INIT(&flh); 8691 tsep = nfsmnt_mdssession(nmp); 8692 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); 8693 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, 8694 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 8695 unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose, 8696 &flh, &laystat); 8697 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", 8698 laystat, error); 8699 lyp = NULL; 8700 if (laystat == 0) { 8701 nfhp = *nfhpp; 8702 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, 8703 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, 8704 layouttype, laystat, NULL, cred, p); 8705 } else 8706 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, 8707 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, 8708 cred, p); 8709 if (laystat == 0) 8710 nfscl_rellayout(lyp, 0); 8711 return (error); 8712 } 8713 8714 /* 8715 * Process the results of a layoutget() operation. 8716 */ 8717 static int 8718 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, 8719 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, 8720 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype, 8721 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) 8722 { 8723 struct nfsclflayout *tflp; 8724 struct nfscldevinfo *dip; 8725 uint8_t *dev; 8726 int i, mirrorcnt; 8727 8728 if (laystat == NFSERR_UNKNLAYOUTTYPE) { 8729 NFSLOCKMNT(nmp); 8730 if (!NFSHASFLEXFILE(nmp)) { 8731 /* Switch to using Flex File Layout. */ 8732 nmp->nm_state |= NFSSTA_FLEXFILE; 8733 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 8734 /* Disable pNFS. */ 8735 NFSCL_DEBUG(1, "disable PNFS\n"); 8736 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE); 8737 } 8738 NFSUNLOCKMNT(nmp); 8739 } 8740 if (laystat == 0) { 8741 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); 8742 LIST_FOREACH(tflp, flhp, nfsfl_list) { 8743 if (layouttype == NFSLAYOUT_FLEXFILE) 8744 mirrorcnt = tflp->nfsfl_mirrorcnt; 8745 else 8746 mirrorcnt = 1; 8747 for (i = 0; i < mirrorcnt; i++) { 8748 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp); 8749 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); 8750 if (laystat != 0) { 8751 if (layouttype == NFSLAYOUT_FLEXFILE) 8752 dev = tflp->nfsfl_ffm[i].dev; 8753 else 8754 dev = tflp->nfsfl_dev; 8755 laystat = nfsrpc_getdeviceinfo(nmp, dev, 8756 layouttype, notifybit, &dip, cred, 8757 p); 8758 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", 8759 laystat); 8760 if (laystat != 0) 8761 goto out; 8762 laystat = nfscl_adddevinfo(nmp, dip, i, 8763 tflp); 8764 if (laystat != 0) 8765 printf("nfsrpc_layoutgetresout" 8766 ": cannot add\n"); 8767 } 8768 } 8769 } 8770 } 8771 out: 8772 if (laystat == 0) { 8773 /* 8774 * nfscl_layout() always returns with the nfsly_lock 8775 * set to a refcnt (shared lock). 8776 * Passing in dvp is sufficient, since it is only used to 8777 * get the fsid for the file system. 8778 */ 8779 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, 8780 layouttype, retonclose, flhp, lypp, cred, p); 8781 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", 8782 laystat); 8783 if (laystat == 0 && islockedp != NULL) 8784 *islockedp = 1; 8785 } 8786 return (laystat); 8787 } 8788 8789 /* 8790 * nfs copy_file_range operation. 8791 */ 8792 int 8793 nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp, 8794 off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp, 8795 struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap, 8796 struct ucred *cred, bool consecutive, bool *must_commitp) 8797 { 8798 int commit, error, expireret = 0, retrycnt; 8799 u_int32_t clidrev = 0; 8800 struct nfsmount *nmp = VFSTONFS(invp->v_mount); 8801 struct nfsfh *innfhp = NULL, *outnfhp = NULL; 8802 nfsv4stateid_t instateid, outstateid; 8803 void *inlckp, *outlckp; 8804 8805 if (nmp->nm_clp != NULL) 8806 clidrev = nmp->nm_clp->nfsc_clientidrev; 8807 innfhp = VTONFS(invp)->n_fhp; 8808 outnfhp = VTONFS(outvp)->n_fhp; 8809 retrycnt = 0; 8810 do { 8811 /* Get both stateids. */ 8812 inlckp = NULL; 8813 nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len, 8814 NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid, 8815 &inlckp); 8816 outlckp = NULL; 8817 nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len, 8818 NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid, 8819 &outlckp); 8820 8821 error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp, 8822 &instateid, &outstateid, innap, inattrflagp, outnap, 8823 outattrflagp, consecutive, &commit, cred, curthread); 8824 if (error == 0) { 8825 if (commit != NFSWRITE_FILESYNC) 8826 *must_commitp = true; 8827 *inoffp += *lenp; 8828 *outoffp += *lenp; 8829 } else if (error == NFSERR_STALESTATEID) 8830 nfscl_initiate_recovery(nmp->nm_clp); 8831 if (inlckp != NULL) 8832 nfscl_lockderef(inlckp); 8833 if (outlckp != NULL) 8834 nfscl_lockderef(outlckp); 8835 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8836 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8837 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 8838 (void) nfs_catnap(PZERO, error, "nfs_cfr"); 8839 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && 8840 error == NFSERR_BADSTATEID)) && clidrev != 0) { 8841 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 8842 curthread); 8843 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { 8844 error = EIO; 8845 } 8846 retrycnt++; 8847 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 8848 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8849 error == NFSERR_STALEDONTRECOVER || 8850 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 8851 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 8852 expireret == 0 && clidrev != 0 && retrycnt < 4)); 8853 if (error != 0 && (retrycnt >= 4 || 8854 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8855 error == NFSERR_STALEDONTRECOVER)) 8856 error = EIO; 8857 return (error); 8858 } 8859 8860 /* 8861 * The copy RPC. 8862 */ 8863 static int 8864 nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff, 8865 size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp, 8866 struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap, 8867 int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred, 8868 NFSPROC_T *p) 8869 { 8870 uint32_t *tl, *opcntp; 8871 int error; 8872 struct nfsrv_descript nfsd; 8873 struct nfsrv_descript *nd = &nfsd; 8874 struct nfsmount *nmp; 8875 nfsattrbit_t attrbits; 8876 struct vattr va; 8877 uint64_t len; 8878 8879 nmp = VFSTONFS(invp->v_mount); 8880 *inattrflagp = *outattrflagp = 0; 8881 *commitp = NFSWRITE_UNSTABLE; 8882 len = *lenp; 8883 *lenp = 0; 8884 if (len > nfs_maxcopyrange) 8885 len = nfs_maxcopyrange; 8886 nfscl_reqstart(nd, NFSPROC_COPY, nmp, VTONFS(invp)->n_fhp->nfh_fh, 8887 VTONFS(invp)->n_fhp->nfh_len, &opcntp, NULL, 0, 0, cred); 8888 /* 8889 * First do a Setattr of atime to the server's clock 8890 * time. The FreeBSD "collective" was of the opinion 8891 * that setting atime was necessary for this syscall. 8892 * Do the Setattr before the Copy, so that it can be 8893 * handled well if the server replies NFSERR_DELAY to 8894 * the Setattr operation. 8895 */ 8896 if ((nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) { 8897 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8898 *tl = txdr_unsigned(NFSV4OP_SETATTR); 8899 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); 8900 VATTR_NULL(&va); 8901 va.va_atime.tv_sec = va.va_atime.tv_nsec = 0; 8902 va.va_vaflags = VA_UTIMES_NULL; 8903 nfscl_fillsattr(nd, &va, invp, 0, 0); 8904 /* Bump opcnt from 7 to 8. */ 8905 *opcntp = txdr_unsigned(8); 8906 } 8907 8908 /* Now Getattr the invp attributes. */ 8909 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8910 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8911 NFSGETATTR_ATTRBIT(&attrbits); 8912 nfsrv_putattrbit(nd, &attrbits); 8913 8914 /* Set outvp. */ 8915 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8916 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8917 (void)nfsm_fhtom(nmp, nd, VTONFS(outvp)->n_fhp->nfh_fh, 8918 VTONFS(outvp)->n_fhp->nfh_len, 0); 8919 8920 /* Do the Copy. */ 8921 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8922 *tl = txdr_unsigned(NFSV4OP_COPY); 8923 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); 8924 nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID); 8925 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED); 8926 txdr_hyper(inoff, tl); tl += 2; 8927 txdr_hyper(outoff, tl); tl += 2; 8928 txdr_hyper(len, tl); tl += 2; 8929 if (consecutive) 8930 *tl++ = newnfs_true; 8931 else 8932 *tl++ = newnfs_false; 8933 *tl++ = newnfs_true; 8934 *tl++ = 0; 8935 8936 /* Get the outvp attributes. */ 8937 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8938 NFSWRITEGETATTR_ATTRBIT(&attrbits); 8939 nfsrv_putattrbit(nd, &attrbits); 8940 8941 error = nfscl_request(nd, invp, p, cred); 8942 if (error != 0) 8943 return (error); 8944 /* Skip over the Setattr reply. */ 8945 if ((nd->nd_flag & ND_NOMOREDATA) == 0 && 8946 (nmp->nm_mountp->mnt_flag & MNT_NOATIME) == 0) { 8947 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8948 if (*(tl + 1) == 0) { 8949 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8950 if (error != 0) 8951 goto nfsmout; 8952 } else 8953 nd->nd_flag |= ND_NOMOREDATA; 8954 } 8955 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8956 /* Get the input file's attributes. */ 8957 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8958 if (*(tl + 1) == 0) { 8959 error = nfsm_loadattr(nd, innap); 8960 if (error != 0) 8961 goto nfsmout; 8962 *inattrflagp = 1; 8963 } else 8964 nd->nd_flag |= ND_NOMOREDATA; 8965 } 8966 /* Skip over return stat for PutFH. */ 8967 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8968 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8969 if (*++tl != 0) 8970 nd->nd_flag |= ND_NOMOREDATA; 8971 } 8972 /* Skip over return stat for Copy. */ 8973 if ((nd->nd_flag & ND_NOMOREDATA) == 0) 8974 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8975 if (nd->nd_repstat == 0) { 8976 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8977 if (*tl != 0) { 8978 /* There should be no callback ids. */ 8979 error = NFSERR_BADXDR; 8980 goto nfsmout; 8981 } 8982 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED + 8983 NFSX_VERF); 8984 len = fxdr_hyper(tl); tl += 2; 8985 *commitp = fxdr_unsigned(int, *tl++); 8986 NFSLOCKMNT(nmp); 8987 if (!NFSHASWRITEVERF(nmp)) { 8988 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8989 NFSSETWRITEVERF(nmp); 8990 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 8991 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8992 nd->nd_repstat = NFSERR_STALEWRITEVERF; 8993 } 8994 NFSUNLOCKMNT(nmp); 8995 tl += (NFSX_VERF / NFSX_UNSIGNED); 8996 if (nd->nd_repstat == 0 && *++tl != newnfs_true) 8997 /* Must be a synchronous copy. */ 8998 nd->nd_repstat = NFSERR_NOTSUPP; 8999 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9000 error = nfsm_loadattr(nd, outnap); 9001 if (error == 0) 9002 *outattrflagp = NFS_LATTR_NOSHRINK; 9003 if (nd->nd_repstat == 0) 9004 *lenp = len; 9005 } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) { 9006 /* 9007 * For the case where consecutive is not supported, but 9008 * synchronous is supported, we can try consecutive == false 9009 * by returning this error. Otherwise, return NFSERR_NOTSUPP, 9010 * since Copy cannot be done. 9011 */ 9012 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 9013 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9014 if (!consecutive || *++tl == newnfs_false) 9015 nd->nd_repstat = NFSERR_NOTSUPP; 9016 } else 9017 nd->nd_repstat = NFSERR_BADXDR; 9018 } 9019 if (error == 0) 9020 error = nd->nd_repstat; 9021 nfsmout: 9022 m_freem(nd->nd_mrep); 9023 return (error); 9024 } 9025 9026 /* 9027 * Seek operation. 9028 */ 9029 int 9030 nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content, 9031 struct ucred *cred, struct nfsvattr *nap, int *attrflagp) 9032 { 9033 int error, expireret = 0, retrycnt; 9034 u_int32_t clidrev = 0; 9035 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 9036 struct nfsnode *np = VTONFS(vp); 9037 struct nfsfh *nfhp = NULL; 9038 nfsv4stateid_t stateid; 9039 void *lckp; 9040 9041 if (nmp->nm_clp != NULL) 9042 clidrev = nmp->nm_clp->nfsc_clientidrev; 9043 nfhp = np->n_fhp; 9044 retrycnt = 0; 9045 do { 9046 lckp = NULL; 9047 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 9048 NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp); 9049 error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content, 9050 nap, attrflagp, cred); 9051 if (error == NFSERR_STALESTATEID) 9052 nfscl_initiate_recovery(nmp->nm_clp); 9053 if (lckp != NULL) 9054 nfscl_lockderef(lckp); 9055 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 9056 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 9057 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 9058 (void) nfs_catnap(PZERO, error, "nfs_seek"); 9059 } else if ((error == NFSERR_EXPIRED || (!NFSHASINT(nmp) && 9060 error == NFSERR_BADSTATEID)) && clidrev != 0) { 9061 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 9062 curthread); 9063 } else if (error == NFSERR_BADSTATEID && NFSHASINT(nmp)) { 9064 error = EIO; 9065 } 9066 retrycnt++; 9067 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 9068 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 9069 error == NFSERR_BADSESSION || 9070 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 9071 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 9072 expireret == 0 && clidrev != 0 && retrycnt < 4) || 9073 (error == NFSERR_OPENMODE && retrycnt < 4)); 9074 if (error && retrycnt >= 4) 9075 error = EIO; 9076 return (error); 9077 } 9078 9079 /* 9080 * The seek RPC. 9081 */ 9082 static int 9083 nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp, 9084 int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred) 9085 { 9086 uint32_t *tl; 9087 int error; 9088 struct nfsrv_descript nfsd; 9089 struct nfsrv_descript *nd = &nfsd; 9090 nfsattrbit_t attrbits; 9091 9092 *attrflagp = 0; 9093 NFSCL_REQSTART(nd, NFSPROC_SEEK, vp, cred); 9094 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 9095 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 9096 txdr_hyper(*offp, tl); tl += 2; 9097 *tl++ = txdr_unsigned(content); 9098 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9099 NFSGETATTR_ATTRBIT(&attrbits); 9100 nfsrv_putattrbit(nd, &attrbits); 9101 error = nfscl_request(nd, vp, curthread, cred); 9102 if (error != 0) 9103 return (error); 9104 if (nd->nd_repstat == 0) { 9105 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER); 9106 if (*tl++ == newnfs_true) 9107 *eofp = true; 9108 else 9109 *eofp = false; 9110 *offp = fxdr_hyper(tl); 9111 /* Just skip over Getattr op status. */ 9112 error = nfsm_loadattr(nd, nap); 9113 if (error == 0) 9114 *attrflagp = 1; 9115 } 9116 error = nd->nd_repstat; 9117 nfsmout: 9118 m_freem(nd->nd_mrep); 9119 return (error); 9120 } 9121 9122 /* 9123 * The getextattr RPC. 9124 */ 9125 int 9126 nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp, 9127 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 9128 { 9129 uint32_t *tl; 9130 int error; 9131 struct nfsrv_descript nfsd; 9132 struct nfsrv_descript *nd = &nfsd; 9133 nfsattrbit_t attrbits; 9134 uint32_t len, len2; 9135 9136 *attrflagp = 0; 9137 NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp, cred); 9138 nfsm_strtom(nd, name, strlen(name)); 9139 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9140 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9141 NFSGETATTR_ATTRBIT(&attrbits); 9142 nfsrv_putattrbit(nd, &attrbits); 9143 error = nfscl_request(nd, vp, p, cred); 9144 if (error != 0) 9145 return (error); 9146 if (nd->nd_repstat == 0) { 9147 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 9148 len = fxdr_unsigned(uint32_t, *tl); 9149 /* Sanity check lengths. */ 9150 if (uiop != NULL && len > 0 && len <= IOSIZE_MAX && 9151 uiop->uio_resid <= UINT32_MAX) { 9152 len2 = uiop->uio_resid; 9153 if (len2 >= len) 9154 error = nfsm_mbufuio(nd, uiop, len); 9155 else { 9156 error = nfsm_mbufuio(nd, uiop, len2); 9157 if (error == 0) { 9158 /* 9159 * nfsm_mbufuio() advances to a multiple 9160 * of 4, so round up len2 as well. Then 9161 * we need to advance over the rest of 9162 * the data, rounding up the remaining 9163 * length. 9164 */ 9165 len2 = NFSM_RNDUP(len2); 9166 len2 = NFSM_RNDUP(len - len2); 9167 if (len2 > 0) 9168 error = nfsm_advance(nd, len2, 9169 -1); 9170 } 9171 } 9172 } else if (uiop == NULL && len > 0) { 9173 /* Just wants the length and not the data. */ 9174 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 9175 } else if (len > 0) 9176 error = ENOATTR; 9177 if (error != 0) 9178 goto nfsmout; 9179 *lenp = len; 9180 /* Just skip over Getattr op status. */ 9181 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9182 error = nfsm_loadattr(nd, nap); 9183 if (error == 0) 9184 *attrflagp = 1; 9185 } 9186 if (error == 0) 9187 error = nd->nd_repstat; 9188 nfsmout: 9189 m_freem(nd->nd_mrep); 9190 return (error); 9191 } 9192 9193 /* 9194 * The setextattr RPC. 9195 */ 9196 int 9197 nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop, 9198 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 9199 { 9200 uint32_t *tl; 9201 int error; 9202 struct nfsrv_descript nfsd; 9203 struct nfsrv_descript *nd = &nfsd; 9204 nfsattrbit_t attrbits; 9205 9206 *attrflagp = 0; 9207 NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp, cred); 9208 if (uiop->uio_resid > nd->nd_maxreq) { 9209 /* nd_maxreq is set by NFSCL_REQSTART(). */ 9210 m_freem(nd->nd_mreq); 9211 return (EINVAL); 9212 } 9213 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9214 *tl = txdr_unsigned(NFSV4SXATTR_EITHER); 9215 nfsm_strtom(nd, name, strlen(name)); 9216 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9217 *tl = txdr_unsigned(uiop->uio_resid); 9218 error = nfsm_uiombuf(nd, uiop, uiop->uio_resid); 9219 if (error != 0) { 9220 m_freem(nd->nd_mreq); 9221 return (error); 9222 } 9223 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9224 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9225 NFSGETATTR_ATTRBIT(&attrbits); 9226 nfsrv_putattrbit(nd, &attrbits); 9227 error = nfscl_request(nd, vp, p, cred); 9228 if (error != 0) 9229 return (error); 9230 if (nd->nd_repstat == 0) { 9231 /* Just skip over the reply and Getattr op status. */ 9232 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 9233 NFSX_UNSIGNED); 9234 error = nfsm_loadattr(nd, nap); 9235 if (error == 0) 9236 *attrflagp = 1; 9237 } 9238 if (error == 0) 9239 error = nd->nd_repstat; 9240 nfsmout: 9241 m_freem(nd->nd_mrep); 9242 return (error); 9243 } 9244 9245 /* 9246 * The removeextattr RPC. 9247 */ 9248 int 9249 nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap, 9250 int *attrflagp, struct ucred *cred, NFSPROC_T *p) 9251 { 9252 uint32_t *tl; 9253 int error; 9254 struct nfsrv_descript nfsd; 9255 struct nfsrv_descript *nd = &nfsd; 9256 nfsattrbit_t attrbits; 9257 9258 *attrflagp = 0; 9259 NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp, cred); 9260 nfsm_strtom(nd, name, strlen(name)); 9261 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 9262 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9263 NFSGETATTR_ATTRBIT(&attrbits); 9264 nfsrv_putattrbit(nd, &attrbits); 9265 error = nfscl_request(nd, vp, p, cred); 9266 if (error != 0) 9267 return (error); 9268 if (nd->nd_repstat == 0) { 9269 /* Just skip over the reply and Getattr op status. */ 9270 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 9271 NFSX_UNSIGNED); 9272 error = nfsm_loadattr(nd, nap); 9273 if (error == 0) 9274 *attrflagp = 1; 9275 } 9276 if (error == 0) 9277 error = nd->nd_repstat; 9278 nfsmout: 9279 m_freem(nd->nd_mrep); 9280 return (error); 9281 } 9282 9283 /* 9284 * The listextattr RPC. 9285 */ 9286 int 9287 nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop, 9288 size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp, 9289 struct ucred *cred, NFSPROC_T *p) 9290 { 9291 uint32_t *tl; 9292 int cnt, error, i, len; 9293 struct nfsrv_descript nfsd; 9294 struct nfsrv_descript *nd = &nfsd; 9295 nfsattrbit_t attrbits; 9296 u_char c; 9297 9298 *attrflagp = 0; 9299 NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp, cred); 9300 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 9301 txdr_hyper(*cookiep, tl); tl += 2; 9302 *tl++ = txdr_unsigned(*lenp); 9303 *tl = txdr_unsigned(NFSV4OP_GETATTR); 9304 NFSGETATTR_ATTRBIT(&attrbits); 9305 nfsrv_putattrbit(nd, &attrbits); 9306 error = nfscl_request(nd, vp, p, cred); 9307 if (error != 0) 9308 return (error); 9309 *eofp = true; 9310 *lenp = 0; 9311 if (nd->nd_repstat == 0) { 9312 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 9313 *cookiep = fxdr_hyper(tl); tl += 2; 9314 cnt = fxdr_unsigned(int, *tl); 9315 if (cnt < 0) { 9316 error = EBADRPC; 9317 goto nfsmout; 9318 } 9319 for (i = 0; i < cnt; i++) { 9320 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 9321 len = fxdr_unsigned(int, *tl); 9322 if (len <= 0 || len > EXTATTR_MAXNAMELEN) { 9323 error = EBADRPC; 9324 goto nfsmout; 9325 } 9326 if (uiop == NULL) 9327 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 9328 else if (uiop->uio_resid >= len + 1) { 9329 c = len; 9330 error = uiomove(&c, sizeof(c), uiop); 9331 if (error == 0) 9332 error = nfsm_mbufuio(nd, uiop, len); 9333 } else { 9334 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 9335 *eofp = false; 9336 } 9337 if (error != 0) 9338 goto nfsmout; 9339 *lenp += (len + 1); 9340 } 9341 /* Get the eof and skip over the Getattr op status. */ 9342 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); 9343 /* 9344 * *eofp is set false above, because it wasn't able to copy 9345 * all of the reply. 9346 */ 9347 if (*eofp && *tl == 0) 9348 *eofp = false; 9349 error = nfsm_loadattr(nd, nap); 9350 if (error == 0) 9351 *attrflagp = 1; 9352 } 9353 if (error == 0) 9354 error = nd->nd_repstat; 9355 nfsmout: 9356 m_freem(nd->nd_mrep); 9357 return (error); 9358 } 9359 9360 /* 9361 * Split an mbuf list. For non-M_EXTPG mbufs, just use m_split(). 9362 */ 9363 static struct mbuf * 9364 nfsm_split(struct mbuf *mp, uint64_t xfer) 9365 { 9366 struct mbuf *m, *m2; 9367 vm_page_t pg; 9368 int i, j, left, pgno, plen, trim; 9369 char *cp, *cp2; 9370 9371 if ((mp->m_flags & M_EXTPG) == 0) { 9372 m = m_split(mp, xfer, M_WAITOK); 9373 return (m); 9374 } 9375 9376 /* Find the correct mbuf to split at. */ 9377 for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next) 9378 xfer -= m->m_len; 9379 if (m == NULL) 9380 return (NULL); 9381 9382 /* If xfer == m->m_len, we can just split the mbuf list. */ 9383 if (xfer == m->m_len) { 9384 m2 = m->m_next; 9385 m->m_next = NULL; 9386 return (m2); 9387 } 9388 9389 /* Find the page to split at. */ 9390 pgno = 0; 9391 left = xfer; 9392 do { 9393 if (pgno == 0) 9394 plen = m_epg_pagelen(m, 0, m->m_epg_1st_off); 9395 else 9396 plen = m_epg_pagelen(m, pgno, 0); 9397 if (left <= plen) 9398 break; 9399 left -= plen; 9400 pgno++; 9401 } while (pgno < m->m_epg_npgs); 9402 if (pgno == m->m_epg_npgs) 9403 panic("nfsm_split: eroneous ext_pgs mbuf"); 9404 9405 m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs, 0); 9406 m2->m_epg_flags |= EPG_FLAG_ANON; 9407 9408 /* 9409 * If left < plen, allocate a new page for the new mbuf 9410 * and copy the data after left in the page to this new 9411 * page. 9412 */ 9413 if (left < plen) { 9414 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP | 9415 VM_ALLOC_WIRED); 9416 m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg); 9417 m2->m_epg_npgs = 1; 9418 9419 /* Copy the data after left to the new page. */ 9420 trim = plen - left; 9421 cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); 9422 if (pgno == 0) 9423 cp += m->m_epg_1st_off; 9424 cp += left; 9425 cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]); 9426 if (pgno == m->m_epg_npgs - 1) 9427 m2->m_epg_last_len = trim; 9428 else { 9429 cp2 += PAGE_SIZE - trim; 9430 m2->m_epg_1st_off = PAGE_SIZE - trim; 9431 m2->m_epg_last_len = m->m_epg_last_len; 9432 } 9433 memcpy(cp2, cp, trim); 9434 m2->m_len = trim; 9435 } else { 9436 m2->m_len = 0; 9437 m2->m_epg_last_len = m->m_epg_last_len; 9438 } 9439 9440 /* Move the pages beyond pgno to the new mbuf. */ 9441 for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) { 9442 m2->m_epg_pa[j] = m->m_epg_pa[i]; 9443 /* Never moves page 0. */ 9444 m2->m_len += m_epg_pagelen(m, i, 0); 9445 } 9446 m2->m_epg_npgs = j; 9447 m->m_epg_npgs = pgno + 1; 9448 m->m_epg_last_len = left; 9449 m->m_len = xfer; 9450 9451 m2->m_next = m->m_next; 9452 m->m_next = NULL; 9453 return (m2); 9454 } 9455 9456 /* 9457 * Do the NFSv4.1 Bind Connection to Session. 9458 * Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c). 9459 */ 9460 void 9461 nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr) 9462 { 9463 struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg; 9464 uint32_t res, *tl; 9465 struct nfsrv_descript nfsd; 9466 struct nfsrv_descript *nd = &nfsd; 9467 struct rpc_callextra ext; 9468 struct timeval utimeout; 9469 enum clnt_stat stat; 9470 int error; 9471 9472 nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL, 9473 NFS_VER4, rcp->minorvers, NULL); 9474 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 9475 memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID); 9476 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9477 *tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH); 9478 *tl = newnfs_false; 9479 9480 memset(&ext, 0, sizeof(ext)); 9481 utimeout.tv_sec = 30; 9482 utimeout.tv_usec = 0; 9483 ext.rc_auth = authunix_create(cr); 9484 nd->nd_mrep = NULL; 9485 stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq, 9486 &nd->nd_mrep, utimeout); 9487 AUTH_DESTROY(ext.rc_auth); 9488 if (stat != RPC_SUCCESS) { 9489 printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat); 9490 return; 9491 } 9492 if (nd->nd_mrep == NULL) { 9493 printf("nfsrpc_bindconnsess: no reply args\n"); 9494 return; 9495 } 9496 error = 0; 9497 newnfs_realign(&nd->nd_mrep, M_WAITOK); 9498 nd->nd_md = nd->nd_mrep; 9499 nd->nd_dpos = mtod(nd->nd_md, char *); 9500 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9501 nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++); 9502 if (nd->nd_repstat == NFSERR_OK) { 9503 res = fxdr_unsigned(uint32_t, *tl); 9504 if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res), 9505 -1)) != 0) 9506 goto nfsmout; 9507 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 9508 4 * NFSX_UNSIGNED); 9509 tl += 3; 9510 if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) { 9511 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9512 res = fxdr_unsigned(uint32_t, *tl); 9513 if (res != NFSCDFS4_BOTH) 9514 printf("nfsrpc_bindconnsess: did not " 9515 "return FS4_BOTH\n"); 9516 } else 9517 printf("nfsrpc_bindconnsess: not same " 9518 "sessionid\n"); 9519 } else if (nd->nd_repstat != NFSERR_BADSESSION) 9520 printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat); 9521 nfsmout: 9522 if (error != 0) 9523 printf("nfsrpc_bindconnsess: reply bad xdr\n"); 9524 m_freem(nd->nd_mrep); 9525 } 9526 9527 /* 9528 * Do roughly what nfs_statfs() does for NFSv4, but when called with a shared 9529 * locked vnode. 9530 */ 9531 static void 9532 nfscl_statfs(struct vnode *vp, struct ucred *cred, NFSPROC_T *td) 9533 { 9534 struct nfsvattr nfsva; 9535 struct nfsfsinfo fs; 9536 struct nfsstatfs sb; 9537 struct mount *mp; 9538 struct nfsmount *nmp; 9539 uint32_t lease; 9540 int attrflag, error; 9541 9542 mp = vp->v_mount; 9543 nmp = VFSTONFS(mp); 9544 error = nfsrpc_statfs(vp, &sb, &fs, &lease, cred, td, &nfsva, 9545 &attrflag); 9546 if (attrflag != 0) 9547 (void) nfscl_loadattrcache(&vp, &nfsva, NULL, 0, 1); 9548 if (error == 0) { 9549 NFSLOCKCLSTATE(); 9550 if (nmp->nm_clp != NULL) 9551 nmp->nm_clp->nfsc_renew = NFSCL_RENEW(lease); 9552 NFSUNLOCKCLSTATE(); 9553 mtx_lock(&nmp->nm_mtx); 9554 nfscl_loadfsinfo(nmp, &fs); 9555 nfscl_loadsbinfo(nmp, &sb, &mp->mnt_stat); 9556 mp->mnt_stat.f_iosize = newnfs_iosize(nmp); 9557 mtx_unlock(&nmp->nm_mtx); 9558 } 9559 } 9560