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