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