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