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) 5237 NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED); 5238 5239 /* and the back channel slot count. */ 5240 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED); 5241 tl += 5; 5242 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl); 5243 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots); 5244 } 5245 error = nd->nd_repstat; 5246 nfsmout: 5247 m_freem(nd->nd_mrep); 5248 return (error); 5249 } 5250 5251 /* 5252 * Do the NFSv4.1 Destroy Session. 5253 */ 5254 int 5255 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp, 5256 struct ucred *cred, NFSPROC_T *p) 5257 { 5258 uint32_t *tl; 5259 struct nfsrv_descript nfsd; 5260 struct nfsrv_descript *nd = &nfsd; 5261 int error; 5262 struct nfsclsession *tsep; 5263 5264 nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0, 5265 0); 5266 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID); 5267 tsep = nfsmnt_mdssession(nmp); 5268 bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID); 5269 nd->nd_flag |= ND_USEGSSNAME; 5270 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5271 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5272 if (error != 0) 5273 return (error); 5274 error = nd->nd_repstat; 5275 m_freem(nd->nd_mrep); 5276 return (error); 5277 } 5278 5279 /* 5280 * Do the NFSv4.1 Destroy Client. 5281 */ 5282 int 5283 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp, 5284 struct ucred *cred, NFSPROC_T *p) 5285 { 5286 uint32_t *tl; 5287 struct nfsrv_descript nfsd; 5288 struct nfsrv_descript *nd = &nfsd; 5289 int error; 5290 struct nfsclsession *tsep; 5291 5292 nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0, 5293 0); 5294 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5295 tsep = nfsmnt_mdssession(nmp); 5296 *tl++ = tsep->nfsess_clientid.lval[0]; 5297 *tl = tsep->nfsess_clientid.lval[1]; 5298 nd->nd_flag |= ND_USEGSSNAME; 5299 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5300 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5301 if (error != 0) 5302 return (error); 5303 error = nd->nd_repstat; 5304 m_freem(nd->nd_mrep); 5305 return (error); 5306 } 5307 5308 /* 5309 * Do the NFSv4.1 LayoutGet. 5310 */ 5311 static int 5312 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode, 5313 uint64_t offset, uint64_t len, uint64_t minlen, int layouttype, 5314 int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep, 5315 struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p, 5316 void *stuff) 5317 { 5318 struct nfsrv_descript nfsd, *nd = &nfsd; 5319 int error; 5320 5321 nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0, 5322 0); 5323 nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp, 5324 layouttype, layoutlen, 0); 5325 nd->nd_flag |= ND_USEGSSNAME; 5326 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5327 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5328 NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat); 5329 if (error != 0) 5330 return (error); 5331 if (nd->nd_repstat == 0) 5332 error = nfsrv_parselayoutget(nmp, nd, stateidp, retonclosep, 5333 flhp); 5334 if (error == 0 && nd->nd_repstat != 0) 5335 error = nd->nd_repstat; 5336 m_freem(nd->nd_mrep); 5337 return (error); 5338 } 5339 5340 /* 5341 * Do the NFSv4.1 Get Device Info. 5342 */ 5343 int 5344 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype, 5345 uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred, 5346 NFSPROC_T *p) 5347 { 5348 uint32_t cnt, *tl, vers, minorvers; 5349 struct nfsrv_descript nfsd; 5350 struct nfsrv_descript *nd = &nfsd; 5351 struct sockaddr_in sin, ssin; 5352 struct sockaddr_in6 sin6, ssin6; 5353 struct nfsclds *dsp = NULL, **dspp, **gotdspp; 5354 struct nfscldevinfo *ndi; 5355 int addrcnt = 0, bitcnt, error, gotminor, gotvers, i, isudp, j; 5356 int stripecnt; 5357 uint8_t stripeindex; 5358 sa_family_t af, safilled; 5359 5360 ssin.sin_port = 0; /* To shut up compiler. */ 5361 ssin.sin_addr.s_addr = 0; /* ditto */ 5362 *ndip = NULL; 5363 ndi = NULL; 5364 gotdspp = NULL; 5365 nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0, 5366 0); 5367 NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5368 NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID); 5369 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5370 *tl++ = txdr_unsigned(layouttype); 5371 *tl++ = txdr_unsigned(100000); 5372 if (notifybitsp != NULL && *notifybitsp != 0) { 5373 *tl = txdr_unsigned(1); /* One word of bits. */ 5374 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 5375 *tl = txdr_unsigned(*notifybitsp); 5376 } else 5377 *tl = txdr_unsigned(0); 5378 nd->nd_flag |= ND_USEGSSNAME; 5379 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5380 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5381 if (error != 0) 5382 return (error); 5383 if (nd->nd_repstat == 0) { 5384 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5385 if (layouttype != fxdr_unsigned(int, *tl)) 5386 printf("EEK! devinfo layout type not same!\n"); 5387 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) { 5388 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5389 stripecnt = fxdr_unsigned(int, *tl); 5390 NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt); 5391 if (stripecnt < 1 || stripecnt > 4096) { 5392 printf("pNFS File layout devinfo stripecnt %d:" 5393 " out of range\n", stripecnt); 5394 error = NFSERR_BADXDR; 5395 goto nfsmout; 5396 } 5397 NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) * 5398 NFSX_UNSIGNED); 5399 addrcnt = fxdr_unsigned(int, *(tl + stripecnt)); 5400 NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt); 5401 if (addrcnt < 1 || addrcnt > 128) { 5402 printf("NFS devinfo addrcnt %d: out of range\n", 5403 addrcnt); 5404 error = NFSERR_BADXDR; 5405 goto nfsmout; 5406 } 5407 5408 /* 5409 * Now we know how many stripe indices and addresses, so 5410 * we can allocate the structure the correct size. 5411 */ 5412 i = (stripecnt * sizeof(uint8_t)) / 5413 sizeof(struct nfsclds *) + 1; 5414 NFSCL_DEBUG(4, "stripeindices=%d\n", i); 5415 ndi = malloc(sizeof(*ndi) + (addrcnt + i) * 5416 sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK | 5417 M_ZERO); 5418 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5419 NFSX_V4DEVICEID); 5420 ndi->nfsdi_refcnt = 0; 5421 ndi->nfsdi_flags = NFSDI_FILELAYOUT; 5422 ndi->nfsdi_stripecnt = stripecnt; 5423 ndi->nfsdi_addrcnt = addrcnt; 5424 /* Fill in the stripe indices. */ 5425 for (i = 0; i < stripecnt; i++) { 5426 stripeindex = fxdr_unsigned(uint8_t, *tl++); 5427 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex); 5428 if (stripeindex >= addrcnt) { 5429 printf("pNFS File Layout devinfo" 5430 " stripeindex %d: too big\n", 5431 (int)stripeindex); 5432 error = NFSERR_BADXDR; 5433 goto nfsmout; 5434 } 5435 nfsfldi_setstripeindex(ndi, i, stripeindex); 5436 } 5437 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 5438 /* For Flex File, we only get one address list. */ 5439 ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *), 5440 M_NFSDEVINFO, M_WAITOK | M_ZERO); 5441 NFSBCOPY(deviceid, ndi->nfsdi_deviceid, 5442 NFSX_V4DEVICEID); 5443 ndi->nfsdi_refcnt = 0; 5444 ndi->nfsdi_flags = NFSDI_FLEXFILE; 5445 addrcnt = ndi->nfsdi_addrcnt = 1; 5446 } 5447 5448 /* Now, dissect the server address(es). */ 5449 safilled = AF_UNSPEC; 5450 for (i = 0; i < addrcnt; i++) { 5451 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5452 cnt = fxdr_unsigned(uint32_t, *tl); 5453 if (cnt == 0) { 5454 printf("NFS devinfo 0 len addrlist\n"); 5455 error = NFSERR_BADXDR; 5456 goto nfsmout; 5457 } 5458 dspp = nfsfldi_addr(ndi, i); 5459 safilled = AF_UNSPEC; 5460 for (j = 0; j < cnt; j++) { 5461 error = nfsv4_getipaddr(nd, &sin, &sin6, &af, 5462 &isudp); 5463 if (error != 0 && error != EPERM) { 5464 error = NFSERR_BADXDR; 5465 goto nfsmout; 5466 } 5467 if (error == 0 && isudp == 0) { 5468 /* 5469 * The priority is: 5470 * - Same address family. 5471 * Save the address and dspp, so that 5472 * the connection can be done after 5473 * parsing is complete. 5474 */ 5475 if (safilled == AF_UNSPEC || 5476 (af == nmp->nm_nam->sa_family && 5477 safilled != nmp->nm_nam->sa_family) 5478 ) { 5479 if (af == AF_INET) 5480 ssin = sin; 5481 else 5482 ssin6 = sin6; 5483 safilled = af; 5484 gotdspp = dspp; 5485 } 5486 } 5487 } 5488 } 5489 5490 gotvers = NFS_VER4; /* Default NFSv4.1 for File Layout. */ 5491 gotminor = NFSV41_MINORVERSION; 5492 /* For Flex File, we will take one of the versions to use. */ 5493 if (layouttype == NFSLAYOUT_FLEXFILE) { 5494 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5495 j = fxdr_unsigned(int, *tl); 5496 if (j < 1 || j > NFSDEV_MAXVERS) { 5497 printf("pNFS: too many versions\n"); 5498 error = NFSERR_BADXDR; 5499 goto nfsmout; 5500 } 5501 gotvers = 0; 5502 gotminor = 0; 5503 for (i = 0; i < j; i++) { 5504 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED); 5505 vers = fxdr_unsigned(uint32_t, *tl++); 5506 minorvers = fxdr_unsigned(uint32_t, *tl++); 5507 if (vers == NFS_VER3) 5508 minorvers = 0; 5509 if ((vers == NFS_VER4 && ((minorvers == 5510 NFSV41_MINORVERSION && gotminor == 0) || 5511 minorvers == NFSV42_MINORVERSION)) || 5512 (vers == NFS_VER3 && gotvers == 0)) { 5513 gotvers = vers; 5514 gotminor = minorvers; 5515 /* We'll take this one. */ 5516 ndi->nfsdi_versindex = i; 5517 ndi->nfsdi_vers = vers; 5518 ndi->nfsdi_minorvers = minorvers; 5519 ndi->nfsdi_rsize = fxdr_unsigned( 5520 uint32_t, *tl++); 5521 ndi->nfsdi_wsize = fxdr_unsigned( 5522 uint32_t, *tl++); 5523 if (*tl == newnfs_true) 5524 ndi->nfsdi_flags |= 5525 NFSDI_TIGHTCOUPLED; 5526 else 5527 ndi->nfsdi_flags &= 5528 ~NFSDI_TIGHTCOUPLED; 5529 } 5530 } 5531 if (gotvers == 0) { 5532 printf("pNFS: no NFSv3, NFSv4.1 or NFSv4.2\n"); 5533 error = NFSERR_BADXDR; 5534 goto nfsmout; 5535 } 5536 } 5537 5538 /* And the notify bits. */ 5539 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5540 bitcnt = fxdr_unsigned(int, *tl); 5541 if (bitcnt > 0) { 5542 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5543 if (notifybitsp != NULL) 5544 *notifybitsp = 5545 fxdr_unsigned(uint32_t, *tl); 5546 } 5547 if (safilled != AF_UNSPEC) { 5548 KASSERT(ndi != NULL, ("ndi is NULL")); 5549 *ndip = ndi; 5550 } else 5551 error = EPERM; 5552 if (error == 0) { 5553 /* 5554 * Now we can do a TCP connection for the correct 5555 * NFS version and IP address. 5556 */ 5557 error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled, 5558 gotvers, gotminor, &dsp, p); 5559 } 5560 if (error == 0) { 5561 KASSERT(gotdspp != NULL, ("gotdspp is NULL")); 5562 *gotdspp = dsp; 5563 } 5564 } 5565 if (nd->nd_repstat != 0 && error == 0) 5566 error = nd->nd_repstat; 5567 nfsmout: 5568 if (error != 0 && ndi != NULL) 5569 nfscl_freedevinfo(ndi); 5570 m_freem(nd->nd_mrep); 5571 return (error); 5572 } 5573 5574 /* 5575 * Do the NFSv4.1 LayoutCommit. 5576 */ 5577 int 5578 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5579 uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp, 5580 int layouttype, struct ucred *cred, NFSPROC_T *p, void *stuff) 5581 { 5582 uint32_t *tl; 5583 struct nfsrv_descript nfsd, *nd = &nfsd; 5584 int error; 5585 5586 nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL, 5587 0, 0); 5588 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 5589 NFSX_STATEID); 5590 txdr_hyper(off, tl); 5591 tl += 2; 5592 txdr_hyper(len, tl); 5593 tl += 2; 5594 if (reclaim != 0) 5595 *tl++ = newnfs_true; 5596 else 5597 *tl++ = newnfs_false; 5598 *tl++ = txdr_unsigned(stateidp->seqid); 5599 *tl++ = stateidp->other[0]; 5600 *tl++ = stateidp->other[1]; 5601 *tl++ = stateidp->other[2]; 5602 *tl++ = newnfs_true; 5603 if (lastbyte < off) 5604 lastbyte = off; 5605 else if (lastbyte >= (off + len)) 5606 lastbyte = off + len - 1; 5607 txdr_hyper(lastbyte, tl); 5608 tl += 2; 5609 *tl++ = newnfs_false; 5610 *tl++ = txdr_unsigned(layouttype); 5611 /* All supported layouts are 0 length. */ 5612 *tl = txdr_unsigned(0); 5613 nd->nd_flag |= ND_USEGSSNAME; 5614 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5615 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5616 if (error != 0) 5617 return (error); 5618 error = nd->nd_repstat; 5619 m_freem(nd->nd_mrep); 5620 return (error); 5621 } 5622 5623 /* 5624 * Do the NFSv4.1 LayoutReturn. 5625 */ 5626 int 5627 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim, 5628 int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset, 5629 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5630 uint32_t stat, uint32_t op, char *devid) 5631 { 5632 uint32_t *tl; 5633 struct nfsrv_descript nfsd, *nd = &nfsd; 5634 uint64_t tu64; 5635 int error; 5636 5637 nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL, 5638 0, 0); 5639 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED); 5640 if (reclaim != 0) 5641 *tl++ = newnfs_true; 5642 else 5643 *tl++ = newnfs_false; 5644 *tl++ = txdr_unsigned(layouttype); 5645 *tl++ = txdr_unsigned(iomode); 5646 *tl = txdr_unsigned(layoutreturn); 5647 if (layoutreturn == NFSLAYOUTRETURN_FILE) { 5648 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5649 NFSX_UNSIGNED); 5650 txdr_hyper(offset, tl); 5651 tl += 2; 5652 txdr_hyper(len, tl); 5653 tl += 2; 5654 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid); 5655 *tl++ = txdr_unsigned(stateidp->seqid); 5656 *tl++ = stateidp->other[0]; 5657 *tl++ = stateidp->other[1]; 5658 *tl++ = stateidp->other[2]; 5659 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) 5660 *tl = txdr_unsigned(0); 5661 else if (layouttype == NFSLAYOUT_FLEXFILE) { 5662 if (stat != 0) { 5663 *tl = txdr_unsigned(2 * NFSX_HYPER + 5664 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5665 NFSX_UNSIGNED); 5666 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 5667 NFSX_STATEID + NFSX_V4DEVICEID + 5 * 5668 NFSX_UNSIGNED); 5669 *tl++ = txdr_unsigned(1); /* One error. */ 5670 tu64 = 0; /* Offset. */ 5671 txdr_hyper(tu64, tl); tl += 2; 5672 tu64 = UINT64_MAX; /* Length. */ 5673 txdr_hyper(tu64, tl); tl += 2; 5674 NFSBCOPY(stateidp, tl, NFSX_STATEID); 5675 tl += (NFSX_STATEID / NFSX_UNSIGNED); 5676 *tl++ = txdr_unsigned(1); /* One error. */ 5677 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5678 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5679 *tl++ = txdr_unsigned(stat); 5680 *tl++ = txdr_unsigned(op); 5681 } else { 5682 *tl = txdr_unsigned(2 * NFSX_UNSIGNED); 5683 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 5684 /* No ioerrs. */ 5685 *tl++ = 0; 5686 } 5687 *tl = 0; /* No stats yet. */ 5688 } 5689 } 5690 nd->nd_flag |= ND_USEGSSNAME; 5691 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5692 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5693 if (error != 0) 5694 return (error); 5695 if (nd->nd_repstat == 0) { 5696 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 5697 if (*tl != 0) { 5698 NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID); 5699 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 5700 stateidp->other[0] = *tl++; 5701 stateidp->other[1] = *tl++; 5702 stateidp->other[2] = *tl; 5703 } 5704 } else 5705 error = nd->nd_repstat; 5706 nfsmout: 5707 m_freem(nd->nd_mrep); 5708 return (error); 5709 } 5710 5711 /* 5712 * Do the NFSv4.2 LayoutError. 5713 */ 5714 static int 5715 nfsrpc_layouterror(struct nfsmount *nmp, uint8_t *fh, int fhlen, uint64_t offset, 5716 uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p, 5717 uint32_t stat, uint32_t op, char *devid) 5718 { 5719 uint32_t *tl; 5720 struct nfsrv_descript nfsd, *nd = &nfsd; 5721 int error; 5722 5723 nfscl_reqstart(nd, NFSPROC_LAYOUTERROR, nmp, fh, fhlen, NULL, NULL, 5724 0, 0); 5725 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID + 5726 NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED); 5727 txdr_hyper(offset, tl); tl += 2; 5728 txdr_hyper(len, tl); tl += 2; 5729 *tl++ = txdr_unsigned(stateidp->seqid); 5730 *tl++ = stateidp->other[0]; 5731 *tl++ = stateidp->other[1]; 5732 *tl++ = stateidp->other[2]; 5733 *tl++ = txdr_unsigned(1); 5734 NFSBCOPY(devid, tl, NFSX_V4DEVICEID); 5735 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 5736 *tl++ = txdr_unsigned(stat); 5737 *tl = txdr_unsigned(op); 5738 nd->nd_flag |= ND_USEGSSNAME; 5739 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 5740 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 5741 if (error != 0) 5742 return (error); 5743 if (nd->nd_repstat != 0) 5744 error = nd->nd_repstat; 5745 m_freem(nd->nd_mrep); 5746 return (error); 5747 } 5748 5749 /* 5750 * Acquire a layout and devinfo, if possible. The caller must have acquired 5751 * a reference count on the nfsclclient structure before calling this. 5752 * Return the layout in lypp with a reference count on it, if successful. 5753 */ 5754 static int 5755 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp, 5756 int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp, 5757 uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p) 5758 { 5759 struct nfscllayout *lyp; 5760 struct nfsclflayout *flp; 5761 struct nfsclflayouthead flh; 5762 int error = 0, islocked, layoutlen, layouttype, recalled, retonclose; 5763 nfsv4stateid_t stateid; 5764 struct nfsclsession *tsep; 5765 5766 *lypp = NULL; 5767 if (NFSHASFLEXFILE(nmp)) 5768 layouttype = NFSLAYOUT_FLEXFILE; 5769 else 5770 layouttype = NFSLAYOUT_NFSV4_1_FILES; 5771 /* 5772 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 5773 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 5774 * flp == NULL. 5775 */ 5776 lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len, 5777 off, rw, &flp, &recalled); 5778 islocked = 0; 5779 if (lyp == NULL || flp == NULL) { 5780 if (recalled != 0) 5781 return (EIO); 5782 LIST_INIT(&flh); 5783 tsep = nfsmnt_mdssession(nmp); 5784 layoutlen = tsep->nfsess_maxcache - 5785 (NFSX_STATEID + 3 * NFSX_UNSIGNED); 5786 if (lyp == NULL) { 5787 stateid.seqid = 0; 5788 stateid.other[0] = stateidp->other[0]; 5789 stateid.other[1] = stateidp->other[1]; 5790 stateid.other[2] = stateidp->other[2]; 5791 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5792 nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX, 5793 (uint64_t)0, layouttype, layoutlen, &stateid, 5794 &retonclose, &flh, cred, p, NULL); 5795 } else { 5796 islocked = 1; 5797 stateid.seqid = lyp->nfsly_stateid.seqid; 5798 stateid.other[0] = lyp->nfsly_stateid.other[0]; 5799 stateid.other[1] = lyp->nfsly_stateid.other[1]; 5800 stateid.other[2] = lyp->nfsly_stateid.other[2]; 5801 error = nfsrpc_layoutget(nmp, nfhp->nfh_fh, 5802 nfhp->nfh_len, iomode, off, UINT64_MAX, 5803 (uint64_t)0, layouttype, layoutlen, &stateid, 5804 &retonclose, &flh, cred, p, NULL); 5805 } 5806 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh, 5807 nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp, 5808 &flh, layouttype, error, NULL, cred, p); 5809 if (error == 0) 5810 *lypp = lyp; 5811 else if (islocked != 0) 5812 nfscl_rellayout(lyp, 1); 5813 } else 5814 *lypp = lyp; 5815 return (error); 5816 } 5817 5818 /* 5819 * Do a TCP connection plus exchange id and create session. 5820 * If successful, a "struct nfsclds" is linked into the list for the 5821 * mount point and a pointer to it is returned. 5822 */ 5823 static int 5824 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin, 5825 struct sockaddr_in6 *sin6, sa_family_t af, int vers, int minorvers, 5826 struct nfsclds **dspp, NFSPROC_T *p) 5827 { 5828 struct sockaddr_in *msad, *sad; 5829 struct sockaddr_in6 *msad6, *sad6; 5830 struct nfsclclient *clp; 5831 struct nfssockreq *nrp; 5832 struct nfsclds *dsp, *tdsp; 5833 int error, firsttry; 5834 enum nfsclds_state retv; 5835 uint32_t sequenceid = 0; 5836 5837 KASSERT(nmp->nm_sockreq.nr_cred != NULL, 5838 ("nfsrpc_fillsa: NULL nr_cred")); 5839 NFSLOCKCLSTATE(); 5840 clp = nmp->nm_clp; 5841 NFSUNLOCKCLSTATE(); 5842 if (clp == NULL) 5843 return (EPERM); 5844 if (af == AF_INET) { 5845 NFSLOCKMNT(nmp); 5846 /* 5847 * Check to see if we already have a session for this 5848 * address that is usable for a DS. 5849 * Note that the MDS's address is in a different place 5850 * than the sessions already acquired for DS's. 5851 */ 5852 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam; 5853 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5854 while (tdsp != NULL) { 5855 if (msad != NULL && msad->sin_family == AF_INET && 5856 sin->sin_addr.s_addr == msad->sin_addr.s_addr && 5857 sin->sin_port == msad->sin_port && 5858 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5859 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5860 *dspp = tdsp; 5861 NFSUNLOCKMNT(nmp); 5862 NFSCL_DEBUG(4, "fnd same addr\n"); 5863 return (0); 5864 } 5865 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5866 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5867 msad = (struct sockaddr_in *) 5868 tdsp->nfsclds_sockp->nr_nam; 5869 else 5870 msad = NULL; 5871 } 5872 NFSUNLOCKMNT(nmp); 5873 5874 /* No IP address match, so look for new/trunked one. */ 5875 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO); 5876 sad->sin_len = sizeof(*sad); 5877 sad->sin_family = AF_INET; 5878 sad->sin_port = sin->sin_port; 5879 sad->sin_addr.s_addr = sin->sin_addr.s_addr; 5880 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5881 nrp->nr_nam = (struct sockaddr *)sad; 5882 } else if (af == AF_INET6) { 5883 NFSLOCKMNT(nmp); 5884 /* 5885 * Check to see if we already have a session for this 5886 * address that is usable for a DS. 5887 * Note that the MDS's address is in a different place 5888 * than the sessions already acquired for DS's. 5889 */ 5890 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam; 5891 tdsp = TAILQ_FIRST(&nmp->nm_sess); 5892 while (tdsp != NULL) { 5893 if (msad6 != NULL && msad6->sin6_family == AF_INET6 && 5894 IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, 5895 &msad6->sin6_addr) && 5896 sin6->sin6_port == msad6->sin6_port && 5897 (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 && 5898 tdsp->nfsclds_sess.nfsess_defunct == 0) { 5899 *dspp = tdsp; 5900 NFSUNLOCKMNT(nmp); 5901 return (0); 5902 } 5903 tdsp = TAILQ_NEXT(tdsp, nfsclds_list); 5904 if (tdsp != NULL && tdsp->nfsclds_sockp != NULL) 5905 msad6 = (struct sockaddr_in6 *) 5906 tdsp->nfsclds_sockp->nr_nam; 5907 else 5908 msad6 = NULL; 5909 } 5910 NFSUNLOCKMNT(nmp); 5911 5912 /* No IP address match, so look for new/trunked one. */ 5913 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO); 5914 sad6->sin6_len = sizeof(*sad6); 5915 sad6->sin6_family = AF_INET6; 5916 sad6->sin6_port = sin6->sin6_port; 5917 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr, 5918 sizeof(struct in6_addr)); 5919 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO); 5920 nrp->nr_nam = (struct sockaddr *)sad6; 5921 } else 5922 return (EPERM); 5923 5924 nrp->nr_sotype = SOCK_STREAM; 5925 mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF); 5926 nrp->nr_prog = NFS_PROG; 5927 nrp->nr_vers = vers; 5928 5929 /* 5930 * Use the credentials that were used for the mount, which are 5931 * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc. 5932 * Ref. counting the credentials with crhold() is probably not 5933 * necessary, since nm_sockreq.nr_cred won't be crfree()'d until 5934 * unmount, but I did it anyhow. 5935 */ 5936 nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred); 5937 error = newnfs_connect(nmp, nrp, NULL, p, 0, false, &nrp->nr_client); 5938 NFSCL_DEBUG(3, "DS connect=%d\n", error); 5939 5940 dsp = NULL; 5941 /* Now, do the exchangeid and create session. */ 5942 if (error == 0) { 5943 if (vers == NFS_VER4) { 5944 firsttry = 0; 5945 do { 5946 error = nfsrpc_exchangeid(nmp, clp, nrp, 5947 minorvers, NFSV4EXCH_USEPNFSDS, &dsp, 5948 nrp->nr_cred, p); 5949 NFSCL_DEBUG(3, "DS exchangeid=%d\n", error); 5950 if (error == NFSERR_MINORVERMISMATCH) 5951 minorvers = NFSV42_MINORVERSION; 5952 } while (error == NFSERR_MINORVERMISMATCH && 5953 firsttry++ == 0); 5954 if (error != 0) 5955 newnfs_disconnect(NULL, nrp); 5956 } else { 5957 dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, 5958 M_WAITOK | M_ZERO); 5959 dsp->nfsclds_flags |= NFSCLDS_DS; 5960 dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */ 5961 mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF); 5962 mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", 5963 NULL, MTX_DEF); 5964 } 5965 } 5966 if (error == 0) { 5967 dsp->nfsclds_sockp = nrp; 5968 if (vers == NFS_VER4) { 5969 NFSLOCKMNT(nmp); 5970 retv = nfscl_getsameserver(nmp, dsp, &tdsp, 5971 &sequenceid); 5972 NFSCL_DEBUG(3, "getsame ret=%d\n", retv); 5973 if (retv == NFSDSP_USETHISSESSION && 5974 nfscl_dssameconn != 0) { 5975 NFSLOCKDS(tdsp); 5976 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN; 5977 NFSUNLOCKDS(tdsp); 5978 NFSUNLOCKMNT(nmp); 5979 /* 5980 * If there is already a session for this 5981 * server, use it. 5982 */ 5983 newnfs_disconnect(NULL, nrp); 5984 nfscl_freenfsclds(dsp); 5985 *dspp = tdsp; 5986 return (0); 5987 } 5988 if (retv == NFSDSP_NOTFOUND) 5989 sequenceid = 5990 dsp->nfsclds_sess.nfsess_sequenceid; 5991 NFSUNLOCKMNT(nmp); 5992 error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess, 5993 nrp, dsp, sequenceid, 0, nrp->nr_cred, p); 5994 NFSCL_DEBUG(3, "DS createsess=%d\n", error); 5995 } 5996 } else { 5997 NFSFREECRED(nrp->nr_cred); 5998 NFSFREEMUTEX(&nrp->nr_mtx); 5999 free(nrp->nr_nam, M_SONAME); 6000 free(nrp, M_NFSSOCKREQ); 6001 } 6002 if (error == 0) { 6003 NFSCL_DEBUG(3, "add DS session\n"); 6004 /* 6005 * Put it at the end of the list. That way the list 6006 * is ordered by when the entry was added. This matters 6007 * since the one done first is the one that should be 6008 * used for sequencid'ing any subsequent create sessions. 6009 */ 6010 NFSLOCKMNT(nmp); 6011 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list); 6012 NFSUNLOCKMNT(nmp); 6013 *dspp = dsp; 6014 } else if (dsp != NULL) { 6015 newnfs_disconnect(NULL, nrp); 6016 nfscl_freenfsclds(dsp); 6017 } 6018 return (error); 6019 } 6020 6021 /* 6022 * Do the NFSv4.1 Reclaim Complete. 6023 */ 6024 int 6025 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p) 6026 { 6027 uint32_t *tl; 6028 struct nfsrv_descript nfsd; 6029 struct nfsrv_descript *nd = &nfsd; 6030 int error; 6031 6032 nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0, 6033 0); 6034 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 6035 *tl = newnfs_false; 6036 nd->nd_flag |= ND_USEGSSNAME; 6037 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred, 6038 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 6039 if (error != 0) 6040 return (error); 6041 error = nd->nd_repstat; 6042 m_freem(nd->nd_mrep); 6043 return (error); 6044 } 6045 6046 /* 6047 * Initialize the slot tables for a session. 6048 */ 6049 static void 6050 nfscl_initsessionslots(struct nfsclsession *sep) 6051 { 6052 int i; 6053 6054 for (i = 0; i < NFSV4_CBSLOTS; i++) { 6055 if (sep->nfsess_cbslots[i].nfssl_reply != NULL) 6056 m_freem(sep->nfsess_cbslots[i].nfssl_reply); 6057 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot)); 6058 } 6059 for (i = 0; i < 64; i++) 6060 sep->nfsess_slotseq[i] = 0; 6061 sep->nfsess_slots = 0; 6062 } 6063 6064 /* 6065 * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS). 6066 */ 6067 int 6068 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6069 uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p) 6070 { 6071 struct nfsnode *np = VTONFS(vp); 6072 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6073 struct nfscllayout *layp; 6074 struct nfscldevinfo *dip; 6075 struct nfsclflayout *rflp; 6076 struct mbuf *m, *m2; 6077 struct nfsclwritedsdorpc *drpc, *tdrpc; 6078 nfsv4stateid_t stateid; 6079 struct ucred *newcred; 6080 uint64_t lastbyte, len, off, oresid, xfer; 6081 int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo; 6082 void *lckp; 6083 uint8_t *dev; 6084 void *iovbase = NULL; 6085 size_t iovlen = 0; 6086 off_t offs = 0; 6087 ssize_t resid = 0; 6088 uint32_t op; 6089 6090 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 || 6091 (np->n_flag & NNOLAYOUT) != 0) 6092 return (EIO); 6093 /* Now, get a reference cnt on the clientid for this mount. */ 6094 if (nfscl_getref(nmp) == 0) 6095 return (EIO); 6096 6097 /* Find an appropriate stateid. */ 6098 newcred = NFSNEWCRED(cred); 6099 error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 6100 rwaccess, 1, newcred, p, &stateid, &lckp); 6101 if (error != 0) { 6102 NFSFREECRED(newcred); 6103 nfscl_relref(nmp); 6104 return (error); 6105 } 6106 /* Search for a layout for this file. */ 6107 off = uiop->uio_offset; 6108 layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh, 6109 np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled); 6110 if (layp == NULL || rflp == NULL) { 6111 if (recalled != 0) { 6112 NFSFREECRED(newcred); 6113 if (lckp != NULL) 6114 nfscl_lockderef(lckp); 6115 nfscl_relref(nmp); 6116 return (EIO); 6117 } 6118 if (layp != NULL) { 6119 nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0); 6120 layp = NULL; 6121 } 6122 /* Try and get a Layout, if it is supported. */ 6123 if (rwaccess == NFSV4OPEN_ACCESSWRITE || 6124 (np->n_flag & NWRITEOPENED) != 0) 6125 iolaymode = NFSLAYOUTIOMODE_RW; 6126 else 6127 iolaymode = NFSLAYOUTIOMODE_READ; 6128 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode, 6129 rwaccess, NULL, &stateid, off, &layp, newcred, p); 6130 if (error != 0) { 6131 NFSLOCKNODE(np); 6132 np->n_flag |= NNOLAYOUT; 6133 NFSUNLOCKNODE(np); 6134 if (lckp != NULL) 6135 nfscl_lockderef(lckp); 6136 NFSFREECRED(newcred); 6137 if (layp != NULL) 6138 nfscl_rellayout(layp, 0); 6139 nfscl_relref(nmp); 6140 return (error); 6141 } 6142 } 6143 6144 /* 6145 * Loop around finding a layout that works for the first part of 6146 * this I/O operation, and then call the function that actually 6147 * does the RPC. 6148 */ 6149 eof = 0; 6150 len = (uint64_t)uiop->uio_resid; 6151 while (len > 0 && error == 0 && eof == 0) { 6152 off = uiop->uio_offset; 6153 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp); 6154 if (error == 0) { 6155 oresid = xfer = (uint64_t)uiop->uio_resid; 6156 if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off)) 6157 xfer = rflp->nfsfl_end - rflp->nfsfl_off; 6158 /* 6159 * For Flex File layout with mirrored DSs, select one 6160 * of them at random for reads. For writes and commits, 6161 * do all mirrors. 6162 */ 6163 m = NULL; 6164 tdrpc = drpc = NULL; 6165 firstmirror = 0; 6166 mirrorcnt = 1; 6167 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 && 6168 (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) { 6169 if (rwaccess == NFSV4OPEN_ACCESSREAD) { 6170 firstmirror = arc4random() % mirrorcnt; 6171 mirrorcnt = firstmirror + 1; 6172 } else { 6173 if (docommit == 0) { 6174 /* 6175 * Save values, so uiop can be 6176 * rolled back upon a write 6177 * error. 6178 */ 6179 offs = uiop->uio_offset; 6180 resid = uiop->uio_resid; 6181 iovbase = 6182 uiop->uio_iov->iov_base; 6183 iovlen = uiop->uio_iov->iov_len; 6184 m = nfsm_uiombuflist(uiop, len, 6185 0); 6186 } 6187 tdrpc = drpc = malloc(sizeof(*drpc) * 6188 (mirrorcnt - 1), M_TEMP, M_WAITOK | 6189 M_ZERO); 6190 } 6191 } 6192 for (i = firstmirror; i < mirrorcnt && error == 0; i++){ 6193 m2 = NULL; 6194 if (m != NULL && i < mirrorcnt - 1) 6195 m2 = m_copym(m, 0, M_COPYALL, M_WAITOK); 6196 else { 6197 m2 = m; 6198 m = NULL; 6199 } 6200 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) { 6201 dev = rflp->nfsfl_ffm[i].dev; 6202 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6203 rflp->nfsfl_ffm[i].devp); 6204 } else { 6205 dev = rflp->nfsfl_dev; 6206 dip = nfscl_getdevinfo(nmp->nm_clp, dev, 6207 rflp->nfsfl_devp); 6208 } 6209 if (dip != NULL) { 6210 if ((rflp->nfsfl_flags & NFSFL_FLEXFILE) 6211 != 0) 6212 error = nfscl_dofflayoutio(vp, 6213 uiop, iomode, must_commit, 6214 &eof, &stateid, rwaccess, 6215 dip, layp, rflp, off, xfer, 6216 i, docommit, m2, tdrpc, 6217 newcred, p); 6218 else 6219 error = nfscl_doflayoutio(vp, 6220 uiop, iomode, must_commit, 6221 &eof, &stateid, rwaccess, 6222 dip, layp, rflp, off, xfer, 6223 docommit, newcred, p); 6224 nfscl_reldevinfo(dip); 6225 } else { 6226 if (m2 != NULL) 6227 m_freem(m2); 6228 error = EIO; 6229 } 6230 tdrpc++; 6231 } 6232 if (m != NULL) 6233 m_freem(m); 6234 tdrpc = drpc; 6235 timo = hz / 50; /* Wait for 20msec. */ 6236 if (timo < 1) 6237 timo = 1; 6238 for (i = firstmirror; i < mirrorcnt - 1 && 6239 tdrpc != NULL; i++, tdrpc++) { 6240 /* 6241 * For the unused drpc entries, both inprog and 6242 * err == 0, so this loop won't break. 6243 */ 6244 while (tdrpc->inprog != 0 && tdrpc->done == 0) 6245 tsleep(&tdrpc->tsk, PVFS, "clrpcio", 6246 timo); 6247 if (error == 0 && tdrpc->err != 0) 6248 error = tdrpc->err; 6249 } 6250 free(drpc, M_TEMP); 6251 if (error == 0) { 6252 if (mirrorcnt > 1 && rwaccess == 6253 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6254 NFSLOCKCLSTATE(); 6255 layp->nfsly_flags |= NFSLY_WRITTEN; 6256 NFSUNLOCKCLSTATE(); 6257 } 6258 lastbyte = off + xfer - 1; 6259 NFSLOCKCLSTATE(); 6260 if (lastbyte > layp->nfsly_lastbyte) 6261 layp->nfsly_lastbyte = lastbyte; 6262 NFSUNLOCKCLSTATE(); 6263 } else if (error == NFSERR_OPENMODE && 6264 rwaccess == NFSV4OPEN_ACCESSREAD) { 6265 NFSLOCKMNT(nmp); 6266 nmp->nm_state |= NFSSTA_OPENMODE; 6267 NFSUNLOCKMNT(nmp); 6268 } else if ((error == NFSERR_NOSPC || 6269 error == NFSERR_IO || error == NFSERR_NXIO) && 6270 nmp->nm_minorvers == NFSV42_MINORVERSION) { 6271 if (docommit != 0) 6272 op = NFSV4OP_COMMIT; 6273 else if (rwaccess == NFSV4OPEN_ACCESSREAD) 6274 op = NFSV4OP_READ; 6275 else 6276 op = NFSV4OP_WRITE; 6277 nfsrpc_layouterror(nmp, np->n_fhp->nfh_fh, 6278 np->n_fhp->nfh_len, off, xfer, 6279 &layp->nfsly_stateid, newcred, p, error, op, 6280 dip->nfsdi_deviceid); 6281 error = EIO; 6282 } else 6283 error = EIO; 6284 if (error == 0) 6285 len -= (oresid - (uint64_t)uiop->uio_resid); 6286 else if (mirrorcnt > 1 && rwaccess == 6287 NFSV4OPEN_ACCESSWRITE && docommit == 0) { 6288 /* 6289 * In case the rpc gets retried, roll the 6290 * uio fields changed by nfsm_uiombuflist() 6291 * back. 6292 */ 6293 uiop->uio_offset = offs; 6294 uiop->uio_resid = resid; 6295 uiop->uio_iov->iov_base = iovbase; 6296 uiop->uio_iov->iov_len = iovlen; 6297 } 6298 } 6299 } 6300 if (lckp != NULL) 6301 nfscl_lockderef(lckp); 6302 NFSFREECRED(newcred); 6303 nfscl_rellayout(layp, 0); 6304 nfscl_relref(nmp); 6305 return (error); 6306 } 6307 6308 /* 6309 * Find a file layout that will handle the first bytes of the requested 6310 * range and return the information from it needed to the I/O operation. 6311 */ 6312 int 6313 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess, 6314 struct nfsclflayout **retflpp) 6315 { 6316 struct nfsclflayout *flp, *nflp, *rflp; 6317 uint32_t rw; 6318 6319 rflp = NULL; 6320 rw = rwaccess; 6321 /* For reading, do the Read list first and then the Write list. */ 6322 do { 6323 if (rw == NFSV4OPEN_ACCESSREAD) 6324 flp = LIST_FIRST(&lyp->nfsly_flayread); 6325 else 6326 flp = LIST_FIRST(&lyp->nfsly_flayrw); 6327 while (flp != NULL) { 6328 nflp = LIST_NEXT(flp, nfsfl_list); 6329 if (flp->nfsfl_off > off) 6330 break; 6331 if (flp->nfsfl_end > off && 6332 (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end)) 6333 rflp = flp; 6334 flp = nflp; 6335 } 6336 if (rw == NFSV4OPEN_ACCESSREAD) 6337 rw = NFSV4OPEN_ACCESSWRITE; 6338 else 6339 rw = 0; 6340 } while (rw != 0); 6341 if (rflp != NULL) { 6342 /* This one covers the most bytes starting at off. */ 6343 *retflpp = rflp; 6344 return (0); 6345 } 6346 return (EIO); 6347 } 6348 6349 /* 6350 * Do I/O using an NFSv4.1 or NFSv4.2 file layout. 6351 */ 6352 static int 6353 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6354 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6355 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6356 uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p) 6357 { 6358 uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer; 6359 int commit_thru_mds, error, stripe_index, stripe_pos, minorvers; 6360 struct nfsnode *np; 6361 struct nfsfh *fhp; 6362 struct nfsclds **dspp; 6363 6364 np = VTONFS(vp); 6365 rel_off = off - flp->nfsfl_patoff; 6366 stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK; 6367 stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) % 6368 dp->nfsdi_stripecnt; 6369 transfer = stripe_unit_size - (rel_off % stripe_unit_size); 6370 error = 0; 6371 6372 /* Loop around, doing I/O for each stripe unit. */ 6373 while (len > 0 && error == 0) { 6374 stripe_index = nfsfldi_stripeindex(dp, stripe_pos); 6375 dspp = nfsfldi_addr(dp, stripe_index); 6376 if (((*dspp)->nfsclds_flags & NFSCLDS_MINORV2) != 0) 6377 minorvers = NFSV42_MINORVERSION; 6378 else 6379 minorvers = NFSV41_MINORVERSION; 6380 if (len > transfer && docommit == 0) 6381 xfer = transfer; 6382 else 6383 xfer = len; 6384 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) { 6385 /* Dense layout. */ 6386 if (stripe_pos >= flp->nfsfl_fhcnt) 6387 return (EIO); 6388 fhp = flp->nfsfl_fh[stripe_pos]; 6389 io_off = (rel_off / (stripe_unit_size * 6390 dp->nfsdi_stripecnt)) * stripe_unit_size + 6391 rel_off % stripe_unit_size; 6392 } else { 6393 /* Sparse layout. */ 6394 if (flp->nfsfl_fhcnt > 1) { 6395 if (stripe_index >= flp->nfsfl_fhcnt) 6396 return (EIO); 6397 fhp = flp->nfsfl_fh[stripe_index]; 6398 } else if (flp->nfsfl_fhcnt == 1) 6399 fhp = flp->nfsfl_fh[0]; 6400 else 6401 fhp = np->n_fhp; 6402 io_off = off; 6403 } 6404 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) { 6405 commit_thru_mds = 1; 6406 if (docommit != 0) 6407 error = EIO; 6408 } else { 6409 commit_thru_mds = 0; 6410 NFSLOCKNODE(np); 6411 np->n_flag |= NDSCOMMIT; 6412 NFSUNLOCKNODE(np); 6413 } 6414 if (docommit != 0) { 6415 if (error == 0) 6416 error = nfsrpc_commitds(vp, io_off, xfer, 6417 *dspp, fhp, NFS_VER4, minorvers, cred, p); 6418 if (error == 0) { 6419 /* 6420 * Set both eof and uio_resid = 0 to end any 6421 * loops. 6422 */ 6423 *eofp = 1; 6424 uiop->uio_resid = 0; 6425 } else { 6426 NFSLOCKNODE(np); 6427 np->n_flag &= ~NDSCOMMIT; 6428 NFSUNLOCKNODE(np); 6429 } 6430 } else if (rwflag == NFSV4OPEN_ACCESSREAD) 6431 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6432 io_off, xfer, fhp, 0, NFS_VER4, minorvers, cred, p); 6433 else { 6434 error = nfsrpc_writeds(vp, uiop, iomode, must_commit, 6435 stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds, 6436 0, NFS_VER4, minorvers, cred, p); 6437 if (error == 0) { 6438 NFSLOCKCLSTATE(); 6439 lyp->nfsly_flags |= NFSLY_WRITTEN; 6440 NFSUNLOCKCLSTATE(); 6441 } 6442 } 6443 if (error == 0) { 6444 transfer = stripe_unit_size; 6445 stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt; 6446 len -= xfer; 6447 off += xfer; 6448 } 6449 } 6450 return (error); 6451 } 6452 6453 /* 6454 * Do I/O using an NFSv4.1 flex file layout. 6455 */ 6456 static int 6457 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6458 int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp, 6459 struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off, 6460 uint64_t len, int mirror, int docommit, struct mbuf *mp, 6461 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6462 { 6463 uint64_t xfer; 6464 int error; 6465 struct nfsnode *np; 6466 struct nfsfh *fhp; 6467 struct nfsclds **dspp; 6468 struct ucred *tcred; 6469 struct mbuf *m, *m2; 6470 uint32_t copylen; 6471 6472 np = VTONFS(vp); 6473 error = 0; 6474 NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off, 6475 (uintmax_t)len); 6476 /* Loop around, doing I/O for each stripe unit. */ 6477 while (len > 0 && error == 0) { 6478 dspp = nfsfldi_addr(dp, 0); 6479 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex]; 6480 stateidp = &flp->nfsfl_ffm[mirror].st; 6481 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n", 6482 mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid); 6483 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) { 6484 tcred = NFSNEWCRED(cred); 6485 tcred->cr_uid = flp->nfsfl_ffm[mirror].user; 6486 tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group; 6487 tcred->cr_ngroups = 1; 6488 } else 6489 tcred = cred; 6490 if (rwflag == NFSV4OPEN_ACCESSREAD) 6491 copylen = dp->nfsdi_rsize; 6492 else { 6493 copylen = dp->nfsdi_wsize; 6494 if (len > copylen && mp != NULL) { 6495 /* 6496 * When a mirrored configuration needs to do 6497 * multiple writes to each mirror, all writes 6498 * except the last one must be a multiple of 6499 * 4 bytes. This is required so that the XDR 6500 * does not need padding. 6501 * If possible, clip the size to an exact 6502 * multiple of the mbuf length, so that the 6503 * split will be on an mbuf boundary. 6504 */ 6505 copylen &= 0xfffffffc; 6506 if (copylen > mp->m_len) 6507 copylen = copylen / mp->m_len * 6508 mp->m_len; 6509 } 6510 } 6511 NFSLOCKNODE(np); 6512 np->n_flag |= NDSCOMMIT; 6513 NFSUNLOCKNODE(np); 6514 if (len > copylen && docommit == 0) 6515 xfer = copylen; 6516 else 6517 xfer = len; 6518 if (docommit != 0) { 6519 if (error == 0) { 6520 /* 6521 * Do last mirrored DS commit with this thread. 6522 */ 6523 if (mirror < flp->nfsfl_mirrorcnt - 1) 6524 error = nfsio_commitds(vp, off, xfer, 6525 *dspp, fhp, dp->nfsdi_vers, 6526 dp->nfsdi_minorvers, drpc, tcred, 6527 p); 6528 else 6529 error = nfsrpc_commitds(vp, off, xfer, 6530 *dspp, fhp, dp->nfsdi_vers, 6531 dp->nfsdi_minorvers, tcred, p); 6532 NFSCL_DEBUG(4, "commitds=%d\n", error); 6533 if (error != 0 && error != EACCES && error != 6534 ESTALE) { 6535 NFSCL_DEBUG(4, 6536 "DS layreterr for commit\n"); 6537 nfscl_dserr(NFSV4OP_COMMIT, error, dp, 6538 lyp, *dspp); 6539 } 6540 } 6541 NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error); 6542 if (error == 0) { 6543 /* 6544 * Set both eof and uio_resid = 0 to end any 6545 * loops. 6546 */ 6547 *eofp = 1; 6548 uiop->uio_resid = 0; 6549 } else { 6550 NFSLOCKNODE(np); 6551 np->n_flag &= ~NDSCOMMIT; 6552 NFSUNLOCKNODE(np); 6553 } 6554 } else if (rwflag == NFSV4OPEN_ACCESSREAD) { 6555 error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp, 6556 off, xfer, fhp, 1, dp->nfsdi_vers, 6557 dp->nfsdi_minorvers, tcred, p); 6558 NFSCL_DEBUG(4, "readds=%d\n", error); 6559 if (error != 0 && error != EACCES && error != ESTALE) { 6560 NFSCL_DEBUG(4, "DS layreterr for read\n"); 6561 nfscl_dserr(NFSV4OP_READ, error, dp, lyp, 6562 *dspp); 6563 } 6564 } else { 6565 if (flp->nfsfl_mirrorcnt == 1) { 6566 error = nfsrpc_writeds(vp, uiop, iomode, 6567 must_commit, stateidp, *dspp, off, xfer, 6568 fhp, 0, 1, dp->nfsdi_vers, 6569 dp->nfsdi_minorvers, tcred, p); 6570 if (error == 0) { 6571 NFSLOCKCLSTATE(); 6572 lyp->nfsly_flags |= NFSLY_WRITTEN; 6573 NFSUNLOCKCLSTATE(); 6574 } 6575 } else { 6576 m = mp; 6577 if (xfer < len) { 6578 /* The mbuf list must be split. */ 6579 m2 = nfsm_split(mp, xfer); 6580 if (m2 != NULL) 6581 mp = m2; 6582 else { 6583 m_freem(mp); 6584 error = EIO; 6585 } 6586 } 6587 NFSCL_DEBUG(4, "mcopy len=%jd xfer=%jd\n", 6588 (uintmax_t)len, (uintmax_t)xfer); 6589 /* 6590 * Do last write to a mirrored DS with this 6591 * thread. 6592 */ 6593 if (error == 0) { 6594 if (mirror < flp->nfsfl_mirrorcnt - 1) 6595 error = nfsio_writedsmir(vp, 6596 iomode, must_commit, 6597 stateidp, *dspp, off, 6598 xfer, fhp, m, 6599 dp->nfsdi_vers, 6600 dp->nfsdi_minorvers, drpc, 6601 tcred, p); 6602 else 6603 error = nfsrpc_writedsmir(vp, 6604 iomode, must_commit, 6605 stateidp, *dspp, off, 6606 xfer, fhp, m, 6607 dp->nfsdi_vers, 6608 dp->nfsdi_minorvers, tcred, 6609 p); 6610 } 6611 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error); 6612 if (error != 0 && error != EACCES && error != 6613 ESTALE) { 6614 NFSCL_DEBUG(4, 6615 "DS layreterr for write\n"); 6616 nfscl_dserr(NFSV4OP_WRITE, error, dp, 6617 lyp, *dspp); 6618 } 6619 } 6620 } 6621 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error); 6622 if (error == 0) { 6623 len -= xfer; 6624 off += xfer; 6625 } 6626 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) 6627 NFSFREECRED(tcred); 6628 } 6629 NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error); 6630 return (error); 6631 } 6632 6633 /* 6634 * The actual read RPC done to a DS. 6635 */ 6636 static int 6637 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp, 6638 struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex, 6639 int vers, int minorvers, struct ucred *cred, NFSPROC_T *p) 6640 { 6641 uint32_t *tl; 6642 int attrflag, error, retlen; 6643 struct nfsrv_descript nfsd; 6644 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6645 struct nfsrv_descript *nd = &nfsd; 6646 struct nfssockreq *nrp; 6647 struct nfsvattr na; 6648 6649 nd->nd_mrep = NULL; 6650 if (vers == 0 || vers == NFS_VER4) { 6651 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh, 6652 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6653 vers = NFS_VER4; 6654 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers); 6655 if (flex != 0) 6656 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6657 else 6658 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6659 } else { 6660 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh, 6661 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6662 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]); 6663 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]); 6664 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n"); 6665 } 6666 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3); 6667 txdr_hyper(io_off, tl); 6668 *(tl + 2) = txdr_unsigned(len); 6669 nrp = dsp->nfsclds_sockp; 6670 NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp); 6671 if (nrp == NULL) 6672 /* If NULL, use the MDS socket. */ 6673 nrp = &nmp->nm_sockreq; 6674 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6675 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6676 NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat, 6677 error); 6678 if (error != 0) 6679 return (error); 6680 if (vers == NFS_VER3) { 6681 error = nfscl_postop_attr(nd, &na, &attrflag, NULL); 6682 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error); 6683 if (error != 0) 6684 goto nfsmout; 6685 } 6686 if (nd->nd_repstat != 0) { 6687 error = nd->nd_repstat; 6688 goto nfsmout; 6689 } 6690 if (vers == NFS_VER3) { 6691 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 6692 *eofp = fxdr_unsigned(int, *(tl + 1)); 6693 } else { 6694 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 6695 *eofp = fxdr_unsigned(int, *tl); 6696 } 6697 NFSM_STRSIZ(retlen, len); 6698 NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp); 6699 error = nfsm_mbufuio(nd, uiop, retlen); 6700 nfsmout: 6701 if (nd->nd_mrep != NULL) 6702 m_freem(nd->nd_mrep); 6703 return (error); 6704 } 6705 6706 /* 6707 * The actual write RPC done to a DS. 6708 */ 6709 static int 6710 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit, 6711 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6712 struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers, 6713 struct ucred *cred, NFSPROC_T *p) 6714 { 6715 uint32_t *tl; 6716 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6717 int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC; 6718 int32_t backup; 6719 struct nfsrv_descript nfsd; 6720 struct nfsrv_descript *nd = &nfsd; 6721 struct nfssockreq *nrp; 6722 struct nfsvattr na; 6723 6724 KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1")); 6725 nd->nd_mrep = NULL; 6726 if (vers == 0 || vers == NFS_VER4) { 6727 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6728 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6729 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers); 6730 vers = NFS_VER4; 6731 if (flex != 0) 6732 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6733 else 6734 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO); 6735 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6736 } else { 6737 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6738 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6739 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 6740 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 6741 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n"); 6742 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6743 } 6744 txdr_hyper(io_off, tl); 6745 tl += 2; 6746 if (vers == NFS_VER3) 6747 *tl++ = txdr_unsigned(len); 6748 *tl++ = txdr_unsigned(*iomode); 6749 *tl = txdr_unsigned(len); 6750 nfsm_uiombuf(nd, uiop, len); 6751 nrp = dsp->nfsclds_sockp; 6752 if (nrp == NULL) 6753 /* If NULL, use the MDS socket. */ 6754 nrp = &nmp->nm_sockreq; 6755 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6756 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6757 NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error, 6758 nd->nd_repstat); 6759 if (error != 0) 6760 return (error); 6761 if (nd->nd_repstat != 0) { 6762 /* 6763 * In case the rpc gets retried, roll 6764 * the uio fields changed by nfsm_uiombuf() 6765 * back. 6766 */ 6767 uiop->uio_offset -= len; 6768 uiop->uio_resid += len; 6769 uiop->uio_iov->iov_base = (char *)uiop->uio_iov->iov_base - len; 6770 uiop->uio_iov->iov_len += len; 6771 error = nd->nd_repstat; 6772 } else { 6773 if (vers == NFS_VER3) { 6774 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6775 NULL); 6776 NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error); 6777 if (error != 0) 6778 goto nfsmout; 6779 } 6780 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6781 rlen = fxdr_unsigned(int, *tl++); 6782 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen); 6783 if (rlen == 0) { 6784 error = NFSERR_IO; 6785 goto nfsmout; 6786 } else if (rlen < len) { 6787 backup = len - rlen; 6788 uiop->uio_iov->iov_base = 6789 (char *)uiop->uio_iov->iov_base - backup; 6790 uiop->uio_iov->iov_len += backup; 6791 uiop->uio_offset -= backup; 6792 uiop->uio_resid += backup; 6793 len = rlen; 6794 } 6795 commit = fxdr_unsigned(int, *tl++); 6796 6797 /* 6798 * Return the lowest commitment level 6799 * obtained by any of the RPCs. 6800 */ 6801 if (committed == NFSWRITE_FILESYNC) 6802 committed = commit; 6803 else if (committed == NFSWRITE_DATASYNC && 6804 commit == NFSWRITE_UNSTABLE) 6805 committed = commit; 6806 if (commit_thru_mds != 0) { 6807 NFSLOCKMNT(nmp); 6808 if (!NFSHASWRITEVERF(nmp)) { 6809 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6810 NFSSETWRITEVERF(nmp); 6811 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 6812 *must_commit = 1; 6813 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 6814 } 6815 NFSUNLOCKMNT(nmp); 6816 } else { 6817 NFSLOCKDS(dsp); 6818 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6819 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6820 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6821 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6822 *must_commit = 1; 6823 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6824 } 6825 NFSUNLOCKDS(dsp); 6826 } 6827 } 6828 nfsmout: 6829 if (nd->nd_mrep != NULL) 6830 m_freem(nd->nd_mrep); 6831 *iomode = committed; 6832 if (nd->nd_repstat != 0 && error == 0) 6833 error = nd->nd_repstat; 6834 return (error); 6835 } 6836 6837 /* 6838 * The actual write RPC done to a DS. 6839 * This variant is called from a separate kernel process for mirrors. 6840 * Any short write is considered an IO error. 6841 */ 6842 static int 6843 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6844 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len, 6845 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6846 struct ucred *cred, NFSPROC_T *p) 6847 { 6848 uint32_t *tl; 6849 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 6850 int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen; 6851 struct nfsrv_descript nfsd; 6852 struct nfsrv_descript *nd = &nfsd; 6853 struct nfssockreq *nrp; 6854 struct nfsvattr na; 6855 6856 nd->nd_mrep = NULL; 6857 if (vers == 0 || vers == NFS_VER4) { 6858 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh, 6859 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6860 vers = NFS_VER4; 6861 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n", 6862 minorvers); 6863 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 6864 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 6865 } else { 6866 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh, 6867 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 6868 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]); 6869 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]); 6870 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n"); 6871 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED); 6872 } 6873 txdr_hyper(io_off, tl); 6874 tl += 2; 6875 if (vers == NFS_VER3) 6876 *tl++ = txdr_unsigned(len); 6877 *tl++ = txdr_unsigned(*iomode); 6878 *tl = txdr_unsigned(len); 6879 if (len > 0) { 6880 /* Put data in mbuf chain. */ 6881 nd->nd_mb->m_next = m; 6882 } 6883 nrp = dsp->nfsclds_sockp; 6884 if (nrp == NULL) 6885 /* If NULL, use the MDS socket. */ 6886 nrp = &nmp->nm_sockreq; 6887 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 6888 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 6889 NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error, 6890 nd->nd_repstat); 6891 if (error != 0) 6892 return (error); 6893 if (nd->nd_repstat != 0) 6894 error = nd->nd_repstat; 6895 else { 6896 if (vers == NFS_VER3) { 6897 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 6898 NULL); 6899 NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n", 6900 error); 6901 if (error != 0) 6902 goto nfsmout; 6903 } 6904 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF); 6905 rlen = fxdr_unsigned(int, *tl++); 6906 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len, 6907 rlen); 6908 if (rlen != len) { 6909 error = NFSERR_IO; 6910 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", 6911 len, rlen); 6912 goto nfsmout; 6913 } 6914 commit = fxdr_unsigned(int, *tl++); 6915 6916 /* 6917 * Return the lowest commitment level 6918 * obtained by any of the RPCs. 6919 */ 6920 if (committed == NFSWRITE_FILESYNC) 6921 committed = commit; 6922 else if (committed == NFSWRITE_DATASYNC && 6923 commit == NFSWRITE_UNSTABLE) 6924 committed = commit; 6925 NFSLOCKDS(dsp); 6926 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) { 6927 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6928 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF; 6929 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 6930 *must_commit = 1; 6931 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 6932 } 6933 NFSUNLOCKDS(dsp); 6934 } 6935 nfsmout: 6936 if (nd->nd_mrep != NULL) 6937 m_freem(nd->nd_mrep); 6938 *iomode = committed; 6939 if (nd->nd_repstat != 0 && error == 0) 6940 error = nd->nd_repstat; 6941 return (error); 6942 } 6943 6944 /* 6945 * Start up the thread that will execute nfsrpc_writedsmir(). 6946 */ 6947 static void 6948 start_writedsmir(void *arg, int pending) 6949 { 6950 struct nfsclwritedsdorpc *drpc; 6951 6952 drpc = (struct nfsclwritedsdorpc *)arg; 6953 drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode, 6954 &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len, 6955 drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred, 6956 drpc->p); 6957 drpc->done = 1; 6958 NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err); 6959 } 6960 6961 /* 6962 * Set up the write DS mirror call for the pNFS I/O thread. 6963 */ 6964 static int 6965 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit, 6966 nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len, 6967 struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers, 6968 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 6969 { 6970 int error, ret; 6971 6972 error = 0; 6973 drpc->done = 0; 6974 drpc->vp = vp; 6975 drpc->iomode = *iomode; 6976 drpc->must_commit = *must_commit; 6977 drpc->stateidp = stateidp; 6978 drpc->dsp = dsp; 6979 drpc->off = off; 6980 drpc->len = len; 6981 drpc->fhp = fhp; 6982 drpc->m = m; 6983 drpc->vers = vers; 6984 drpc->minorvers = minorvers; 6985 drpc->cred = cred; 6986 drpc->p = p; 6987 drpc->inprog = 0; 6988 ret = EIO; 6989 if (nfs_pnfsiothreads != 0) { 6990 ret = nfs_pnfsio(start_writedsmir, drpc); 6991 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret); 6992 } 6993 if (ret != 0) 6994 error = nfsrpc_writedsmir(vp, iomode, must_commit, stateidp, 6995 dsp, off, len, fhp, m, vers, minorvers, cred, p); 6996 NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error); 6997 return (error); 6998 } 6999 7000 /* 7001 * Free up the nfsclds structure. 7002 */ 7003 void 7004 nfscl_freenfsclds(struct nfsclds *dsp) 7005 { 7006 int i; 7007 7008 if (dsp == NULL) 7009 return; 7010 if (dsp->nfsclds_sockp != NULL) { 7011 NFSFREECRED(dsp->nfsclds_sockp->nr_cred); 7012 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx); 7013 free(dsp->nfsclds_sockp->nr_nam, M_SONAME); 7014 free(dsp->nfsclds_sockp, M_NFSSOCKREQ); 7015 } 7016 NFSFREEMUTEX(&dsp->nfsclds_mtx); 7017 NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx); 7018 for (i = 0; i < NFSV4_CBSLOTS; i++) { 7019 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL) 7020 m_freem( 7021 dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply); 7022 } 7023 free(dsp, M_NFSCLDS); 7024 } 7025 7026 static enum nfsclds_state 7027 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp, 7028 struct nfsclds **retdspp, uint32_t *sequencep) 7029 { 7030 struct nfsclds *dsp; 7031 int fndseq; 7032 7033 /* 7034 * Search the list of nfsclds structures for one with the same 7035 * server. 7036 */ 7037 fndseq = 0; 7038 TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) { 7039 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen && 7040 dsp->nfsclds_servownlen != 0 && 7041 !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown, 7042 dsp->nfsclds_servownlen) && 7043 dsp->nfsclds_sess.nfsess_defunct == 0) { 7044 NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n", 7045 TAILQ_FIRST(&nmp->nm_sess), dsp, 7046 dsp->nfsclds_flags); 7047 if (fndseq == 0) { 7048 /* Get sequenceid# from first entry. */ 7049 *sequencep = 7050 dsp->nfsclds_sess.nfsess_sequenceid; 7051 fndseq = 1; 7052 } 7053 /* Server major id matches. */ 7054 if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) { 7055 *retdspp = dsp; 7056 return (NFSDSP_USETHISSESSION); 7057 } 7058 } 7059 } 7060 if (fndseq != 0) 7061 return (NFSDSP_SEQTHISSESSION); 7062 return (NFSDSP_NOTFOUND); 7063 } 7064 7065 /* 7066 * NFS commit rpc to a NFSv4.1 DS. 7067 */ 7068 static int 7069 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7070 struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred, 7071 NFSPROC_T *p) 7072 { 7073 uint32_t *tl; 7074 struct nfsrv_descript nfsd, *nd = &nfsd; 7075 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7076 struct nfssockreq *nrp; 7077 struct nfsvattr na; 7078 int attrflag, error; 7079 7080 nd->nd_mrep = NULL; 7081 if (vers == 0 || vers == NFS_VER4) { 7082 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh, 7083 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 7084 vers = NFS_VER4; 7085 } else { 7086 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh, 7087 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 7088 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]); 7089 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]); 7090 } 7091 NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers, 7092 minorvers); 7093 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7094 txdr_hyper(offset, tl); 7095 tl += 2; 7096 *tl = txdr_unsigned(cnt); 7097 nrp = dsp->nfsclds_sockp; 7098 if (nrp == NULL) 7099 /* If NULL, use the MDS socket. */ 7100 nrp = &nmp->nm_sockreq; 7101 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7102 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7103 NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error, 7104 nd->nd_repstat); 7105 if (error != 0) 7106 return (error); 7107 if (nd->nd_repstat == 0) { 7108 if (vers == NFS_VER3) { 7109 error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL, 7110 NULL); 7111 NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error); 7112 if (error != 0) 7113 goto nfsmout; 7114 } 7115 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF); 7116 NFSLOCKDS(dsp); 7117 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) { 7118 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF); 7119 error = NFSERR_STALEWRITEVERF; 7120 } 7121 NFSUNLOCKDS(dsp); 7122 } 7123 nfsmout: 7124 if (error == 0 && nd->nd_repstat != 0) 7125 error = nd->nd_repstat; 7126 m_freem(nd->nd_mrep); 7127 return (error); 7128 } 7129 7130 /* 7131 * Start up the thread that will execute nfsrpc_commitds(). 7132 */ 7133 static void 7134 start_commitds(void *arg, int pending) 7135 { 7136 struct nfsclwritedsdorpc *drpc; 7137 7138 drpc = (struct nfsclwritedsdorpc *)arg; 7139 drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len, 7140 drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred, 7141 drpc->p); 7142 drpc->done = 1; 7143 NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err); 7144 } 7145 7146 /* 7147 * Set up the commit DS mirror call for the pNFS I/O thread. 7148 */ 7149 static int 7150 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp, 7151 struct nfsfh *fhp, int vers, int minorvers, 7152 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7153 { 7154 int error, ret; 7155 7156 error = 0; 7157 drpc->done = 0; 7158 drpc->vp = vp; 7159 drpc->off = offset; 7160 drpc->len = cnt; 7161 drpc->dsp = dsp; 7162 drpc->fhp = fhp; 7163 drpc->vers = vers; 7164 drpc->minorvers = minorvers; 7165 drpc->cred = cred; 7166 drpc->p = p; 7167 drpc->inprog = 0; 7168 ret = EIO; 7169 if (nfs_pnfsiothreads != 0) { 7170 ret = nfs_pnfsio(start_commitds, drpc); 7171 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret); 7172 } 7173 if (ret != 0) 7174 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers, 7175 minorvers, cred, p); 7176 NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error); 7177 return (error); 7178 } 7179 7180 /* 7181 * NFS Advise rpc 7182 */ 7183 int 7184 nfsrpc_advise(vnode_t vp, off_t offset, uint64_t cnt, int advise, 7185 struct ucred *cred, NFSPROC_T *p) 7186 { 7187 u_int32_t *tl; 7188 struct nfsrv_descript nfsd, *nd = &nfsd; 7189 nfsattrbit_t hints; 7190 int error; 7191 7192 NFSZERO_ATTRBIT(&hints); 7193 if (advise == POSIX_FADV_WILLNEED) 7194 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7195 else if (advise == POSIX_FADV_DONTNEED) 7196 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7197 else 7198 return (0); 7199 NFSCL_REQSTART(nd, NFSPROC_IOADVISE, vp); 7200 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7201 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER); 7202 txdr_hyper(offset, tl); 7203 tl += 2; 7204 txdr_hyper(cnt, tl); 7205 nfsrv_putattrbit(nd, &hints); 7206 error = nfscl_request(nd, vp, p, cred, NULL); 7207 if (error != 0) 7208 return (error); 7209 if (nd->nd_repstat != 0) 7210 error = nd->nd_repstat; 7211 m_freem(nd->nd_mrep); 7212 return (error); 7213 } 7214 7215 #ifdef notyet 7216 /* 7217 * NFS advise rpc to a NFSv4.2 DS. 7218 */ 7219 static int 7220 nfsrpc_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7221 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7222 struct ucred *cred, NFSPROC_T *p) 7223 { 7224 uint32_t *tl; 7225 struct nfsrv_descript nfsd, *nd = &nfsd; 7226 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7227 struct nfssockreq *nrp; 7228 nfsattrbit_t hints; 7229 int error; 7230 7231 /* For NFS DSs prior to NFSv4.2, just return OK. */ 7232 if (vers == NFS_VER3 || minorversion < NFSV42_MINORVERSION) 7233 return (0); 7234 NFSZERO_ATTRBIT(&hints); 7235 if (advise == POSIX_FADV_WILLNEED) 7236 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_WILLNEED); 7237 else if (advise == POSIX_FADV_DONTNEED) 7238 NFSSETBIT_ATTRBIT(&hints, NFSV4IOHINT_DONTNEED); 7239 else 7240 return (0); 7241 nd->nd_mrep = NULL; 7242 nfscl_reqstart(nd, NFSPROC_IOADVISEDS, nmp, fhp->nfh_fh, 7243 fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers); 7244 vers = NFS_VER4; 7245 NFSCL_DEBUG(4, "nfsrpc_adviseds: vers=%d minvers=%d\n", vers, 7246 minorvers); 7247 nfsm_stateidtom(nd, NULL, NFSSTATEID_PUTALLZERO); 7248 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 7249 txdr_hyper(offset, tl); 7250 tl += 2; 7251 *tl = txdr_unsigned(cnt); 7252 nfsrv_putattrbit(nd, &hints); 7253 nrp = dsp->nfsclds_sockp; 7254 if (nrp == NULL) 7255 /* If NULL, use the MDS socket. */ 7256 nrp = &nmp->nm_sockreq; 7257 error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred, 7258 NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess); 7259 NFSCL_DEBUG(4, "nfsrpc_adviseds: err=%d stat=%d\n", error, 7260 nd->nd_repstat); 7261 if (error != 0) 7262 return (error); 7263 if (nd->nd_repstat != 0) 7264 error = nd->nd_repstat; 7265 m_freem(nd->nd_mrep); 7266 return (error); 7267 } 7268 7269 /* 7270 * Start up the thread that will execute nfsrpc_commitds(). 7271 */ 7272 static void 7273 start_adviseds(void *arg, int pending) 7274 { 7275 struct nfsclwritedsdorpc *drpc; 7276 7277 drpc = (struct nfsclwritedsdorpc *)arg; 7278 drpc->err = nfsrpc_adviseds(drpc->vp, drpc->off, drpc->len, 7279 drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, 7280 drpc->cred, drpc->p); 7281 drpc->done = 1; 7282 NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err); 7283 } 7284 7285 /* 7286 * Set up the commit DS mirror call for the pNFS I/O thread. 7287 */ 7288 static int 7289 nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise, 7290 struct nfsclds *dsp, struct nfsfh *fhp, int vers, int minorvers, 7291 struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p) 7292 { 7293 int error, ret; 7294 7295 error = 0; 7296 drpc->done = 0; 7297 drpc->vp = vp; 7298 drpc->off = offset; 7299 drpc->len = cnt; 7300 drpc->advise = advise; 7301 drpc->dsp = dsp; 7302 drpc->fhp = fhp; 7303 drpc->vers = vers; 7304 drpc->minorvers = minorvers; 7305 drpc->cred = cred; 7306 drpc->p = p; 7307 drpc->inprog = 0; 7308 ret = EIO; 7309 if (nfs_pnfsiothreads != 0) { 7310 ret = nfs_pnfsio(start_adviseds, drpc); 7311 NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret); 7312 } 7313 if (ret != 0) 7314 error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers, 7315 minorvers, cred, p); 7316 NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error); 7317 return (error); 7318 } 7319 #endif /* notyet */ 7320 7321 /* 7322 * Do the Allocate operation, retrying for recovery. 7323 */ 7324 int 7325 nfsrpc_allocate(vnode_t vp, off_t off, off_t len, struct nfsvattr *nap, 7326 int *attrflagp, struct ucred *cred, NFSPROC_T *p, void *stuff) 7327 { 7328 int error, expireret = 0, retrycnt, nostateid; 7329 uint32_t clidrev = 0; 7330 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 7331 struct nfsfh *nfhp = NULL; 7332 nfsv4stateid_t stateid; 7333 off_t tmp_off; 7334 void *lckp; 7335 7336 if (len < 0) 7337 return (EINVAL); 7338 if (len == 0) 7339 return (0); 7340 tmp_off = off + len; 7341 NFSLOCKMNT(nmp); 7342 if (tmp_off > nmp->nm_maxfilesize || tmp_off < off) { 7343 NFSUNLOCKMNT(nmp); 7344 return (EFBIG); 7345 } 7346 if (nmp->nm_clp != NULL) 7347 clidrev = nmp->nm_clp->nfsc_clientidrev; 7348 NFSUNLOCKMNT(nmp); 7349 nfhp = VTONFS(vp)->n_fhp; 7350 retrycnt = 0; 7351 do { 7352 lckp = NULL; 7353 nostateid = 0; 7354 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 7355 NFSV4OPEN_ACCESSWRITE, 0, cred, p, &stateid, &lckp); 7356 if (stateid.other[0] == 0 && stateid.other[1] == 0 && 7357 stateid.other[2] == 0) { 7358 nostateid = 1; 7359 NFSCL_DEBUG(1, "stateid0 in allocate\n"); 7360 } 7361 7362 /* 7363 * Not finding a stateid should probably never happen, 7364 * but just return an error for this case. 7365 */ 7366 if (nostateid != 0) 7367 error = EIO; 7368 else 7369 error = nfsrpc_allocaterpc(vp, off, len, &stateid, 7370 nap, attrflagp, cred, p, stuff); 7371 if (error == NFSERR_STALESTATEID) 7372 nfscl_initiate_recovery(nmp->nm_clp); 7373 if (lckp != NULL) 7374 nfscl_lockderef(lckp); 7375 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 7376 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 7377 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 7378 (void) nfs_catnap(PZERO, error, "nfs_allocate"); 7379 } else if ((error == NFSERR_EXPIRED || 7380 error == NFSERR_BADSTATEID) && clidrev != 0) { 7381 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p); 7382 } 7383 retrycnt++; 7384 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 7385 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 7386 error == NFSERR_STALEDONTRECOVER || 7387 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 7388 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 7389 expireret == 0 && clidrev != 0 && retrycnt < 4)); 7390 if (error != 0 && retrycnt >= 4) 7391 error = EIO; 7392 return (error); 7393 } 7394 7395 /* 7396 * The allocate RPC. 7397 */ 7398 static int 7399 nfsrpc_allocaterpc(vnode_t vp, off_t off, off_t len, nfsv4stateid_t *stateidp, 7400 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p, 7401 void *stuff) 7402 { 7403 uint32_t *tl; 7404 int error; 7405 struct nfsrv_descript nfsd; 7406 struct nfsrv_descript *nd = &nfsd; 7407 nfsattrbit_t attrbits; 7408 7409 *attrflagp = 0; 7410 NFSCL_REQSTART(nd, NFSPROC_ALLOCATE, vp); 7411 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 7412 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_UNSIGNED); 7413 txdr_hyper(off, tl); tl += 2; 7414 txdr_hyper(len, tl); tl += 2; 7415 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7416 NFSGETATTR_ATTRBIT(&attrbits); 7417 nfsrv_putattrbit(nd, &attrbits); 7418 error = nfscl_request(nd, vp, p, cred, stuff); 7419 if (error != 0) 7420 return (error); 7421 if (nd->nd_repstat == 0) { 7422 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 7423 error = nfsm_loadattr(nd, nap); 7424 if (error == 0) 7425 *attrflagp = NFS_LATTR_NOSHRINK; 7426 } else 7427 error = nd->nd_repstat; 7428 nfsmout: 7429 m_freem(nd->nd_mrep); 7430 return (error); 7431 } 7432 7433 /* 7434 * Set up the XDR arguments for the LayoutGet operation. 7435 */ 7436 static void 7437 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset, 7438 uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype, 7439 int layoutlen, int usecurstateid) 7440 { 7441 uint32_t *tl; 7442 7443 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER + 7444 NFSX_STATEID); 7445 *tl++ = newnfs_false; /* Don't signal availability. */ 7446 *tl++ = txdr_unsigned(layouttype); 7447 *tl++ = txdr_unsigned(iomode); 7448 txdr_hyper(offset, tl); 7449 tl += 2; 7450 txdr_hyper(len, tl); 7451 tl += 2; 7452 txdr_hyper(minlen, tl); 7453 tl += 2; 7454 if (usecurstateid != 0) { 7455 /* Special stateid for Current stateid. */ 7456 *tl++ = txdr_unsigned(1); 7457 *tl++ = 0; 7458 *tl++ = 0; 7459 *tl++ = 0; 7460 } else { 7461 *tl++ = txdr_unsigned(stateidp->seqid); 7462 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid); 7463 *tl++ = stateidp->other[0]; 7464 *tl++ = stateidp->other[1]; 7465 *tl++ = stateidp->other[2]; 7466 } 7467 *tl = txdr_unsigned(layoutlen); 7468 } 7469 7470 /* 7471 * Parse the reply for a successful LayoutGet operation. 7472 */ 7473 static int 7474 nfsrv_parselayoutget(struct nfsmount *nmp, struct nfsrv_descript *nd, 7475 nfsv4stateid_t *stateidp, int *retonclosep, struct nfsclflayouthead *flhp) 7476 { 7477 uint32_t *tl; 7478 struct nfsclflayout *flp, *prevflp, *tflp; 7479 int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen; 7480 int m, mirrorcnt; 7481 uint64_t retlen, off; 7482 struct nfsfh *nfhp; 7483 uint8_t *cp; 7484 uid_t user; 7485 gid_t grp; 7486 7487 NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n"); 7488 error = 0; 7489 flp = NULL; 7490 gotiomode = -1; 7491 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID); 7492 if (*tl++ != 0) 7493 *retonclosep = 1; 7494 else 7495 *retonclosep = 0; 7496 stateidp->seqid = fxdr_unsigned(uint32_t, *tl++); 7497 NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep, 7498 (int)stateidp->seqid); 7499 stateidp->other[0] = *tl++; 7500 stateidp->other[1] = *tl++; 7501 stateidp->other[2] = *tl++; 7502 cnt = fxdr_unsigned(int, *tl); 7503 NFSCL_DEBUG(4, "layg cnt=%d\n", cnt); 7504 if (cnt <= 0 || cnt > 10000) { 7505 /* Don't accept more than 10000 layouts in reply. */ 7506 error = NFSERR_BADXDR; 7507 goto nfsmout; 7508 } 7509 for (i = 0; i < cnt; i++) { 7510 /* Dissect to the layout type. */ 7511 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 7512 3 * NFSX_UNSIGNED); 7513 off = fxdr_hyper(tl); tl += 2; 7514 retlen = fxdr_hyper(tl); tl += 2; 7515 iomode = fxdr_unsigned(int, *tl++); 7516 laytype = fxdr_unsigned(int, *tl); 7517 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype, 7518 (uintmax_t)off, (uintmax_t)retlen, iomode); 7519 /* Ignore length of layout body for now. */ 7520 if (laytype == NFSLAYOUT_NFSV4_1_FILES) { 7521 /* Parse the File layout up to fhcnt. */ 7522 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + 7523 NFSX_HYPER + NFSX_V4DEVICEID); 7524 fhcnt = fxdr_unsigned(int, *(tl + 4 + 7525 NFSX_V4DEVICEID / NFSX_UNSIGNED)); 7526 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7527 if (fhcnt < 0 || fhcnt > 100) { 7528 /* Don't accept more than 100 file handles. */ 7529 error = NFSERR_BADXDR; 7530 goto nfsmout; 7531 } 7532 if (fhcnt > 0) 7533 flp = malloc(sizeof(*flp) + fhcnt * 7534 sizeof(struct nfsfh *), M_NFSFLAYOUT, 7535 M_WAITOK); 7536 else 7537 flp = malloc(sizeof(*flp), M_NFSFLAYOUT, 7538 M_WAITOK); 7539 flp->nfsfl_flags = NFSFL_FILE; 7540 flp->nfsfl_fhcnt = 0; 7541 flp->nfsfl_devp = NULL; 7542 flp->nfsfl_off = off; 7543 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7544 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7545 else 7546 flp->nfsfl_end = flp->nfsfl_off + retlen; 7547 flp->nfsfl_iomode = iomode; 7548 if (gotiomode == -1) 7549 gotiomode = flp->nfsfl_iomode; 7550 /* Ignore layout body length for now. */ 7551 NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID); 7552 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED); 7553 flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++); 7554 NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util); 7555 mtx_lock(&nmp->nm_mtx); 7556 if (nmp->nm_minorvers > 1 && (flp->nfsfl_util & 7557 NFSFLAYUTIL_IOADVISE_THRU_MDS) != 0) 7558 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 7559 mtx_unlock(&nmp->nm_mtx); 7560 flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++); 7561 flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2; 7562 NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n", 7563 flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff); 7564 for (j = 0; j < fhcnt; j++) { 7565 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7566 nfhlen = fxdr_unsigned(int, *tl); 7567 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) { 7568 error = NFSERR_BADXDR; 7569 goto nfsmout; 7570 } 7571 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1, 7572 M_NFSFH, M_WAITOK); 7573 flp->nfsfl_fh[j] = nfhp; 7574 flp->nfsfl_fhcnt++; 7575 nfhp->nfh_len = nfhlen; 7576 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen)); 7577 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen); 7578 } 7579 } else if (laytype == NFSLAYOUT_FLEXFILE) { 7580 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED + 7581 NFSX_HYPER); 7582 mirrorcnt = fxdr_unsigned(int, *(tl + 2)); 7583 NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt); 7584 if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) { 7585 error = NFSERR_BADXDR; 7586 goto nfsmout; 7587 } 7588 flp = malloc(sizeof(*flp) + mirrorcnt * 7589 sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK); 7590 flp->nfsfl_flags = NFSFL_FLEXFILE; 7591 flp->nfsfl_mirrorcnt = mirrorcnt; 7592 for (j = 0; j < mirrorcnt; j++) 7593 flp->nfsfl_ffm[j].devp = NULL; 7594 flp->nfsfl_off = off; 7595 if (flp->nfsfl_off + retlen < flp->nfsfl_off) 7596 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off; 7597 else 7598 flp->nfsfl_end = flp->nfsfl_off + retlen; 7599 flp->nfsfl_iomode = iomode; 7600 if (gotiomode == -1) 7601 gotiomode = flp->nfsfl_iomode; 7602 flp->nfsfl_stripeunit = fxdr_hyper(tl); 7603 NFSCL_DEBUG(4, "stripeunit=%ju\n", 7604 (uintmax_t)flp->nfsfl_stripeunit); 7605 for (j = 0; j < mirrorcnt; j++) { 7606 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7607 k = fxdr_unsigned(int, *tl); 7608 if (k < 1 || k > 128) { 7609 error = NFSERR_BADXDR; 7610 goto nfsmout; 7611 } 7612 NFSCL_DEBUG(4, "servercnt=%d\n", k); 7613 for (l = 0; l < k; l++) { 7614 NFSM_DISSECT(tl, uint32_t *, 7615 NFSX_V4DEVICEID + NFSX_STATEID + 7616 2 * NFSX_UNSIGNED); 7617 if (l == 0) { 7618 /* Just use the first server. */ 7619 NFSBCOPY(tl, 7620 flp->nfsfl_ffm[j].dev, 7621 NFSX_V4DEVICEID); 7622 tl += (NFSX_V4DEVICEID / 7623 NFSX_UNSIGNED); 7624 tl++; 7625 flp->nfsfl_ffm[j].st.seqid = 7626 *tl++; 7627 flp->nfsfl_ffm[j].st.other[0] = 7628 *tl++; 7629 flp->nfsfl_ffm[j].st.other[1] = 7630 *tl++; 7631 flp->nfsfl_ffm[j].st.other[2] = 7632 *tl++; 7633 NFSCL_DEBUG(4, "st.seqid=%u " 7634 "st.o0=0x%x st.o1=0x%x " 7635 "st.o2=0x%x\n", 7636 flp->nfsfl_ffm[j].st.seqid, 7637 flp->nfsfl_ffm[j].st.other[0], 7638 flp->nfsfl_ffm[j].st.other[1], 7639 flp->nfsfl_ffm[j].st.other[2]); 7640 } else 7641 tl += ((NFSX_V4DEVICEID + 7642 NFSX_STATEID + 7643 NFSX_UNSIGNED) / 7644 NFSX_UNSIGNED); 7645 fhcnt = fxdr_unsigned(int, *tl); 7646 NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt); 7647 if (fhcnt < 1 || 7648 fhcnt > NFSDEV_MAXVERS) { 7649 error = NFSERR_BADXDR; 7650 goto nfsmout; 7651 } 7652 for (m = 0; m < fhcnt; m++) { 7653 NFSM_DISSECT(tl, uint32_t *, 7654 NFSX_UNSIGNED); 7655 nfhlen = fxdr_unsigned(int, 7656 *tl); 7657 NFSCL_DEBUG(4, "nfhlen=%d\n", 7658 nfhlen); 7659 if (nfhlen <= 0 || nfhlen > 7660 NFSX_V4FHMAX) { 7661 error = NFSERR_BADXDR; 7662 goto nfsmout; 7663 } 7664 NFSM_DISSECT(cp, uint8_t *, 7665 NFSM_RNDUP(nfhlen)); 7666 if (l == 0) { 7667 flp->nfsfl_ffm[j].fhcnt 7668 = fhcnt; 7669 nfhp = malloc( 7670 sizeof(*nfhp) + 7671 nfhlen - 1, M_NFSFH, 7672 M_WAITOK); 7673 flp->nfsfl_ffm[j].fh[m] 7674 = nfhp; 7675 nfhp->nfh_len = nfhlen; 7676 NFSBCOPY(cp, 7677 nfhp->nfh_fh, 7678 nfhlen); 7679 NFSCL_DEBUG(4, 7680 "got fh\n"); 7681 } 7682 } 7683 /* Now, get the ffsd_user/ffds_group. */ 7684 error = nfsrv_parseug(nd, 0, &user, 7685 &grp, curthread); 7686 NFSCL_DEBUG(4, "after parseu=%d\n", 7687 error); 7688 if (error == 0) 7689 error = nfsrv_parseug(nd, 1, 7690 &user, &grp, curthread); 7691 NFSCL_DEBUG(4, "aft parseg=%d\n", 7692 grp); 7693 if (error != 0) 7694 goto nfsmout; 7695 NFSCL_DEBUG(4, "user=%d group=%d\n", 7696 user, grp); 7697 if (l == 0) { 7698 flp->nfsfl_ffm[j].user = user; 7699 flp->nfsfl_ffm[j].group = grp; 7700 NFSCL_DEBUG(4, 7701 "usr=%d grp=%d\n", user, 7702 grp); 7703 } 7704 } 7705 } 7706 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7707 flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++); 7708 #ifdef notnow 7709 /* 7710 * At this time, there is no flag. 7711 * NFSFLEXFLAG_IOADVISE_THRU_MDS might need to be 7712 * added, or it may never exist? 7713 */ 7714 mtx_lock(&nmp->nm_mtx); 7715 if (nmp->nm_minorvers > 1 && (flp->nfsfl_fflags & 7716 NFSFLEXFLAG_IOADVISE_THRU_MDS) != 0) 7717 nmp->nm_privflag |= NFSMNTP_IOADVISETHRUMDS; 7718 mtx_unlock(&nmp->nm_mtx); 7719 #endif 7720 flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl); 7721 NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n", 7722 flp->nfsfl_fflags, flp->nfsfl_statshint); 7723 } else { 7724 error = NFSERR_BADXDR; 7725 goto nfsmout; 7726 } 7727 if (flp->nfsfl_iomode == gotiomode) { 7728 /* Keep the list in increasing offset order. */ 7729 tflp = LIST_FIRST(flhp); 7730 prevflp = NULL; 7731 while (tflp != NULL && 7732 tflp->nfsfl_off < flp->nfsfl_off) { 7733 prevflp = tflp; 7734 tflp = LIST_NEXT(tflp, nfsfl_list); 7735 } 7736 if (prevflp == NULL) 7737 LIST_INSERT_HEAD(flhp, flp, nfsfl_list); 7738 else 7739 LIST_INSERT_AFTER(prevflp, flp, 7740 nfsfl_list); 7741 NFSCL_DEBUG(4, "flp inserted\n"); 7742 } else { 7743 printf("nfscl_layoutget(): got wrong iomode\n"); 7744 nfscl_freeflayout(flp); 7745 } 7746 flp = NULL; 7747 } 7748 nfsmout: 7749 NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error); 7750 if (error != 0 && flp != NULL) 7751 nfscl_freeflayout(flp); 7752 return (error); 7753 } 7754 7755 /* 7756 * Parse a user/group digit string. 7757 */ 7758 static int 7759 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp, 7760 NFSPROC_T *p) 7761 { 7762 uint32_t *tl; 7763 char *cp, *str, str0[NFSV4_SMALLSTR + 1]; 7764 uint32_t len = 0; 7765 int error = 0; 7766 7767 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 7768 len = fxdr_unsigned(uint32_t, *tl); 7769 str = NULL; 7770 if (len > NFSV4_OPAQUELIMIT) { 7771 error = NFSERR_BADXDR; 7772 goto nfsmout; 7773 } 7774 NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len); 7775 if (len == 0) { 7776 if (dogrp != 0) 7777 *gidp = GID_NOGROUP; 7778 else 7779 *uidp = UID_NOBODY; 7780 return (0); 7781 } 7782 if (len > NFSV4_SMALLSTR) 7783 str = malloc(len + 1, M_TEMP, M_WAITOK); 7784 else 7785 str = str0; 7786 NFSM_DISSECT(cp, char *, NFSM_RNDUP(len)); 7787 NFSBCOPY(cp, str, len); 7788 str[len] = '\0'; 7789 NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str); 7790 if (dogrp != 0) 7791 error = nfsv4_strtogid(nd, str, len, gidp); 7792 else 7793 error = nfsv4_strtouid(nd, str, len, uidp); 7794 nfsmout: 7795 if (len > NFSV4_SMALLSTR) 7796 free(str, M_TEMP); 7797 NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error); 7798 return (error); 7799 } 7800 7801 /* 7802 * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(), 7803 * so that it does both an Open and a Layoutget. 7804 */ 7805 static int 7806 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7807 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7808 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7809 struct ucred *cred, NFSPROC_T *p) 7810 { 7811 struct nfscllayout *lyp; 7812 struct nfsclflayout *flp; 7813 struct nfsclflayouthead flh; 7814 int error, islocked, layoutlen, recalled, retonclose, usecurstateid; 7815 int layouttype, laystat; 7816 nfsv4stateid_t stateid; 7817 struct nfsclsession *tsep; 7818 7819 error = 0; 7820 if (NFSHASFLEXFILE(nmp)) 7821 layouttype = NFSLAYOUT_FLEXFILE; 7822 else 7823 layouttype = NFSLAYOUT_NFSV4_1_FILES; 7824 /* 7825 * If lyp is returned non-NULL, there will be a refcnt (shared lock) 7826 * on it, iff flp != NULL or a lock (exclusive lock) on it iff 7827 * flp == NULL. 7828 */ 7829 lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp, 7830 &recalled); 7831 NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp); 7832 if (lyp == NULL) 7833 islocked = 0; 7834 else if (flp != NULL) 7835 islocked = 1; 7836 else 7837 islocked = 2; 7838 if ((lyp == NULL || flp == NULL) && recalled == 0) { 7839 LIST_INIT(&flh); 7840 tsep = nfsmnt_mdssession(nmp); 7841 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 7842 3 * NFSX_UNSIGNED); 7843 if (lyp == NULL) 7844 usecurstateid = 1; 7845 else { 7846 usecurstateid = 0; 7847 stateid.seqid = lyp->nfsly_stateid.seqid; 7848 stateid.other[0] = lyp->nfsly_stateid.other[0]; 7849 stateid.other[1] = lyp->nfsly_stateid.other[1]; 7850 stateid.other[2] = lyp->nfsly_stateid.other[2]; 7851 } 7852 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen, 7853 newfhp, newfhlen, mode, op, name, namelen, 7854 dpp, &stateid, usecurstateid, layouttype, layoutlen, 7855 &retonclose, &flh, &laystat, cred, p); 7856 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n", 7857 laystat, error); 7858 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen, 7859 &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat, 7860 &islocked, cred, p); 7861 } else 7862 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen, 7863 mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0); 7864 if (islocked == 2) 7865 nfscl_rellayout(lyp, 1); 7866 else if (islocked == 1) 7867 nfscl_rellayout(lyp, 0); 7868 return (error); 7869 } 7870 7871 /* 7872 * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS 7873 * enabled, only for the CLAIM_NULL case. All other NFSv4 Opens are 7874 * handled by nfsrpc_openrpc(). 7875 * For the case where op == NULL, dvp is the directory. When op != NULL, it 7876 * can be NULL. 7877 */ 7878 static int 7879 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, 7880 int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode, 7881 struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp, 7882 nfsv4stateid_t *stateidp, int usecurstateid, int layouttype, 7883 int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp, 7884 int *laystatp, struct ucred *cred, NFSPROC_T *p) 7885 { 7886 uint32_t *tl; 7887 struct nfsrv_descript nfsd, *nd = &nfsd; 7888 struct nfscldeleg *ndp = NULL; 7889 struct nfsvattr nfsva; 7890 struct nfsclsession *tsep; 7891 uint32_t rflags, deleg; 7892 nfsattrbit_t attrbits; 7893 int error, ret, acesize, limitby, iomode; 7894 7895 *dpp = NULL; 7896 *laystatp = ENXIO; 7897 nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL, 7898 0, 0); 7899 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED); 7900 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid); 7901 *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH); 7902 *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH); 7903 tsep = nfsmnt_mdssession(nmp); 7904 *tl++ = tsep->nfsess_clientid.lval[0]; 7905 *tl = tsep->nfsess_clientid.lval[1]; 7906 nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN); 7907 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED); 7908 *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE); 7909 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 7910 nfsm_strtom(nd, name, namelen); 7911 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7912 *tl = txdr_unsigned(NFSV4OP_GETATTR); 7913 NFSZERO_ATTRBIT(&attrbits); 7914 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE); 7915 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY); 7916 nfsrv_putattrbit(nd, &attrbits); 7917 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 7918 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 7919 if ((mode & NFSV4OPEN_ACCESSWRITE) != 0) 7920 iomode = NFSLAYOUTIOMODE_RW; 7921 else 7922 iomode = NFSLAYOUTIOMODE_READ; 7923 nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp, 7924 layouttype, layoutlen, usecurstateid); 7925 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred, 7926 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL); 7927 if (error != 0) 7928 return (error); 7929 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd); 7930 if (nd->nd_repstat != 0) 7931 *laystatp = nd->nd_repstat; 7932 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 7933 /* ND_NOMOREDATA will be set if the Open operation failed. */ 7934 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7935 6 * NFSX_UNSIGNED); 7936 op->nfso_stateid.seqid = *tl++; 7937 op->nfso_stateid.other[0] = *tl++; 7938 op->nfso_stateid.other[1] = *tl++; 7939 op->nfso_stateid.other[2] = *tl; 7940 rflags = fxdr_unsigned(u_int32_t, *(tl + 6)); 7941 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 7942 if (error != 0) 7943 goto nfsmout; 7944 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 7945 deleg = fxdr_unsigned(u_int32_t, *tl); 7946 if (deleg == NFSV4OPEN_DELEGATEREAD || 7947 deleg == NFSV4OPEN_DELEGATEWRITE) { 7948 if (!(op->nfso_own->nfsow_clp->nfsc_flags & 7949 NFSCLFLAGS_FIRSTDELEG)) 7950 op->nfso_own->nfsow_clp->nfsc_flags |= 7951 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 7952 ndp = malloc(sizeof(struct nfscldeleg) + newfhlen, 7953 M_NFSCLDELEG, M_WAITOK); 7954 LIST_INIT(&ndp->nfsdl_owner); 7955 LIST_INIT(&ndp->nfsdl_lock); 7956 ndp->nfsdl_clp = op->nfso_own->nfsow_clp; 7957 ndp->nfsdl_fhlen = newfhlen; 7958 NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen); 7959 newnfs_copyincred(cred, &ndp->nfsdl_cred); 7960 nfscl_lockinit(&ndp->nfsdl_rwlock); 7961 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 7962 NFSX_UNSIGNED); 7963 ndp->nfsdl_stateid.seqid = *tl++; 7964 ndp->nfsdl_stateid.other[0] = *tl++; 7965 ndp->nfsdl_stateid.other[1] = *tl++; 7966 ndp->nfsdl_stateid.other[2] = *tl++; 7967 ret = fxdr_unsigned(int, *tl); 7968 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 7969 ndp->nfsdl_flags = NFSCLDL_WRITE; 7970 /* 7971 * Indicates how much the file can grow. 7972 */ 7973 NFSM_DISSECT(tl, u_int32_t *, 7974 3 * NFSX_UNSIGNED); 7975 limitby = fxdr_unsigned(int, *tl++); 7976 switch (limitby) { 7977 case NFSV4OPEN_LIMITSIZE: 7978 ndp->nfsdl_sizelimit = fxdr_hyper(tl); 7979 break; 7980 case NFSV4OPEN_LIMITBLOCKS: 7981 ndp->nfsdl_sizelimit = 7982 fxdr_unsigned(u_int64_t, *tl++); 7983 ndp->nfsdl_sizelimit *= 7984 fxdr_unsigned(u_int64_t, *tl); 7985 break; 7986 default: 7987 error = NFSERR_BADXDR; 7988 goto nfsmout; 7989 }; 7990 } else 7991 ndp->nfsdl_flags = NFSCLDL_READ; 7992 if (ret != 0) 7993 ndp->nfsdl_flags |= NFSCLDL_RECALL; 7994 error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret, 7995 &acesize, p); 7996 if (error != 0) 7997 goto nfsmout; 7998 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 7999 error = NFSERR_BADXDR; 8000 goto nfsmout; 8001 } 8002 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 || 8003 nfscl_assumeposixlocks) 8004 op->nfso_posixlock = 1; 8005 else 8006 op->nfso_posixlock = 0; 8007 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8008 /* If the 2nd element == NFS_OK, the Getattr succeeded. */ 8009 if (*++tl == 0) { 8010 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL, 8011 NULL, 0, NULL, NULL, NULL, NULL, NULL, 0, 8012 NULL, NULL, NULL, p, cred); 8013 if (error != 0) 8014 goto nfsmout; 8015 if (ndp != NULL) { 8016 ndp->nfsdl_change = nfsva.na_filerev; 8017 ndp->nfsdl_modtime = nfsva.na_mtime; 8018 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8019 *dpp = ndp; 8020 ndp = NULL; 8021 } 8022 /* 8023 * At this point, the Open has succeeded, so set 8024 * nd_repstat = NFS_OK. If the Layoutget failed, 8025 * this function just won't return a layout. 8026 */ 8027 if (nd->nd_repstat == 0) { 8028 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8029 *laystatp = fxdr_unsigned(int, *++tl); 8030 if (*laystatp == 0) { 8031 error = nfsrv_parselayoutget(nmp, nd, 8032 stateidp, retonclosep, flhp); 8033 if (error != 0) 8034 *laystatp = error; 8035 } 8036 } else 8037 nd->nd_repstat = 0; /* Return 0 for Open. */ 8038 } 8039 } 8040 if (nd->nd_repstat != 0 && error == 0) 8041 error = nd->nd_repstat; 8042 nfsmout: 8043 free(ndp, M_NFSCLDELEG); 8044 m_freem(nd->nd_mrep); 8045 return (error); 8046 } 8047 8048 /* 8049 * Similar nfsrpc_createv4(), but also does the LayoutGet operation. 8050 * Used only for mounts with pNFS enabled. 8051 */ 8052 static int 8053 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8054 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8055 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8056 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8057 int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp, 8058 int usecurstateid, int layouttype, int layoutlen, int *retonclosep, 8059 struct nfsclflayouthead *flhp, int *laystatp) 8060 { 8061 uint32_t *tl; 8062 int error = 0, deleg, newone, ret, acesize, limitby; 8063 struct nfsrv_descript nfsd, *nd = &nfsd; 8064 struct nfsclopen *op; 8065 struct nfscldeleg *dp = NULL; 8066 struct nfsnode *np; 8067 struct nfsfh *nfhp; 8068 struct nfsclsession *tsep; 8069 nfsattrbit_t attrbits; 8070 nfsv4stateid_t stateid; 8071 struct nfsmount *nmp; 8072 8073 nmp = VFSTONFS(dvp->v_mount); 8074 np = VTONFS(dvp); 8075 *laystatp = ENXIO; 8076 *unlockedp = 0; 8077 *nfhpp = NULL; 8078 *dpp = NULL; 8079 *attrflagp = 0; 8080 *dattrflagp = 0; 8081 if (namelen > NFS_MAXNAMLEN) 8082 return (ENAMETOOLONG); 8083 NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp); 8084 /* 8085 * For V4, this is actually an Open op. 8086 */ 8087 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED); 8088 *tl++ = txdr_unsigned(owp->nfsow_seqid); 8089 *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE | 8090 NFSV4OPEN_ACCESSREAD); 8091 *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE); 8092 tsep = nfsmnt_mdssession(nmp); 8093 *tl++ = tsep->nfsess_clientid.lval[0]; 8094 *tl = tsep->nfsess_clientid.lval[1]; 8095 nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN); 8096 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8097 *tl++ = txdr_unsigned(NFSV4OPEN_CREATE); 8098 if ((fmode & O_EXCL) != 0) { 8099 if (NFSHASSESSPERSIST(nmp)) { 8100 /* Use GUARDED for persistent sessions. */ 8101 *tl = txdr_unsigned(NFSCREATE_GUARDED); 8102 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8103 } else { 8104 /* Otherwise, use EXCLUSIVE4_1. */ 8105 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41); 8106 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF); 8107 *tl++ = cverf.lval[0]; 8108 *tl = cverf.lval[1]; 8109 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8110 } 8111 } else { 8112 *tl = txdr_unsigned(NFSCREATE_UNCHECKED); 8113 nfscl_fillsattr(nd, vap, dvp, 0, 0); 8114 } 8115 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8116 *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL); 8117 nfsm_strtom(nd, name, namelen); 8118 /* Get the new file's handle and attributes, plus save the FH. */ 8119 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED); 8120 *tl++ = txdr_unsigned(NFSV4OP_SAVEFH); 8121 *tl++ = txdr_unsigned(NFSV4OP_GETFH); 8122 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8123 NFSGETATTR_ATTRBIT(&attrbits); 8124 nfsrv_putattrbit(nd, &attrbits); 8125 /* Get the directory's post-op attributes. */ 8126 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8127 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8128 nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0); 8129 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED); 8130 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8131 nfsrv_putattrbit(nd, &attrbits); 8132 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 8133 *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH); 8134 *tl = txdr_unsigned(NFSV4OP_LAYOUTGET); 8135 nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp, 8136 layouttype, layoutlen, usecurstateid); 8137 error = nfscl_request(nd, dvp, p, cred, dstuff); 8138 if (error != 0) 8139 return (error); 8140 NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat, 8141 error); 8142 if (nd->nd_repstat != 0) 8143 *laystatp = nd->nd_repstat; 8144 NFSCL_INCRSEQID(owp->nfsow_seqid, nd); 8145 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8146 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n"); 8147 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8148 6 * NFSX_UNSIGNED); 8149 stateid.seqid = *tl++; 8150 stateid.other[0] = *tl++; 8151 stateid.other[1] = *tl++; 8152 stateid.other[2] = *tl; 8153 nfsrv_getattrbits(nd, &attrbits, NULL, NULL); 8154 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); 8155 deleg = fxdr_unsigned(int, *tl); 8156 if (deleg == NFSV4OPEN_DELEGATEREAD || 8157 deleg == NFSV4OPEN_DELEGATEWRITE) { 8158 if (!(owp->nfsow_clp->nfsc_flags & 8159 NFSCLFLAGS_FIRSTDELEG)) 8160 owp->nfsow_clp->nfsc_flags |= 8161 (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG); 8162 dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX, 8163 M_NFSCLDELEG, M_WAITOK); 8164 LIST_INIT(&dp->nfsdl_owner); 8165 LIST_INIT(&dp->nfsdl_lock); 8166 dp->nfsdl_clp = owp->nfsow_clp; 8167 newnfs_copyincred(cred, &dp->nfsdl_cred); 8168 nfscl_lockinit(&dp->nfsdl_rwlock); 8169 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 8170 NFSX_UNSIGNED); 8171 dp->nfsdl_stateid.seqid = *tl++; 8172 dp->nfsdl_stateid.other[0] = *tl++; 8173 dp->nfsdl_stateid.other[1] = *tl++; 8174 dp->nfsdl_stateid.other[2] = *tl++; 8175 ret = fxdr_unsigned(int, *tl); 8176 if (deleg == NFSV4OPEN_DELEGATEWRITE) { 8177 dp->nfsdl_flags = NFSCLDL_WRITE; 8178 /* 8179 * Indicates how much the file can grow. 8180 */ 8181 NFSM_DISSECT(tl, u_int32_t *, 8182 3 * NFSX_UNSIGNED); 8183 limitby = fxdr_unsigned(int, *tl++); 8184 switch (limitby) { 8185 case NFSV4OPEN_LIMITSIZE: 8186 dp->nfsdl_sizelimit = fxdr_hyper(tl); 8187 break; 8188 case NFSV4OPEN_LIMITBLOCKS: 8189 dp->nfsdl_sizelimit = 8190 fxdr_unsigned(u_int64_t, *tl++); 8191 dp->nfsdl_sizelimit *= 8192 fxdr_unsigned(u_int64_t, *tl); 8193 break; 8194 default: 8195 error = NFSERR_BADXDR; 8196 goto nfsmout; 8197 }; 8198 } else { 8199 dp->nfsdl_flags = NFSCLDL_READ; 8200 } 8201 if (ret != 0) 8202 dp->nfsdl_flags |= NFSCLDL_RECALL; 8203 error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret, 8204 &acesize, p); 8205 if (error != 0) 8206 goto nfsmout; 8207 } else if (deleg != NFSV4OPEN_DELEGATENONE) { 8208 error = NFSERR_BADXDR; 8209 goto nfsmout; 8210 } 8211 8212 /* Now, we should have the status for the SaveFH. */ 8213 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8214 if (*++tl == 0) { 8215 NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n"); 8216 /* 8217 * Now, process the GetFH and Getattr for the newly 8218 * created file. nfscl_mtofh() will set 8219 * ND_NOMOREDATA if these weren't successful. 8220 */ 8221 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp); 8222 NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error); 8223 if (error != 0) 8224 goto nfsmout; 8225 } else 8226 nd->nd_flag |= ND_NOMOREDATA; 8227 /* Now we have the PutFH and Getattr for the directory. */ 8228 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8229 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8230 if (*++tl != 0) 8231 nd->nd_flag |= ND_NOMOREDATA; 8232 else { 8233 NFSM_DISSECT(tl, uint32_t *, 2 * 8234 NFSX_UNSIGNED); 8235 if (*++tl != 0) 8236 nd->nd_flag |= ND_NOMOREDATA; 8237 } 8238 } 8239 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8240 /* Load the directory attributes. */ 8241 error = nfsm_loadattr(nd, dnap); 8242 NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error); 8243 if (error != 0) 8244 goto nfsmout; 8245 *dattrflagp = 1; 8246 if (dp != NULL && *attrflagp != 0) { 8247 dp->nfsdl_change = nnap->na_filerev; 8248 dp->nfsdl_modtime = nnap->na_mtime; 8249 dp->nfsdl_flags |= NFSCLDL_MODTIMESET; 8250 } 8251 /* 8252 * We can now complete the Open state. 8253 */ 8254 nfhp = *nfhpp; 8255 if (dp != NULL) { 8256 dp->nfsdl_fhlen = nfhp->nfh_len; 8257 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, 8258 nfhp->nfh_len); 8259 } 8260 /* 8261 * Get an Open structure that will be 8262 * attached to the OpenOwner, acquired already. 8263 */ 8264 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 8265 (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0, 8266 cred, p, NULL, &op, &newone, NULL, 0, false); 8267 if (error != 0) 8268 goto nfsmout; 8269 op->nfso_stateid = stateid; 8270 newnfs_copyincred(cred, &op->nfso_cred); 8271 8272 nfscl_openrelease(nmp, op, error, newone); 8273 *unlockedp = 1; 8274 8275 /* Now, handle the RestoreFH and LayoutGet. */ 8276 if (nd->nd_repstat == 0) { 8277 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); 8278 *laystatp = fxdr_unsigned(int, *(tl + 3)); 8279 if (*laystatp == 0) { 8280 error = nfsrv_parselayoutget(nmp, nd, 8281 stateidp, retonclosep, flhp); 8282 if (error != 0) 8283 *laystatp = error; 8284 } 8285 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n", 8286 error); 8287 } else 8288 nd->nd_repstat = 0; 8289 } 8290 } 8291 if (nd->nd_repstat != 0 && error == 0) 8292 error = nd->nd_repstat; 8293 if (error == NFSERR_STALECLIENTID || error == NFSERR_BADSESSION) 8294 nfscl_initiate_recovery(owp->nfsow_clp); 8295 nfsmout: 8296 NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error); 8297 if (error == 0) 8298 *dpp = dp; 8299 else 8300 free(dp, M_NFSCLDELEG); 8301 m_freem(nd->nd_mrep); 8302 return (error); 8303 } 8304 8305 /* 8306 * Similar to nfsrpc_getopenlayout(), except that it used for the Create case. 8307 */ 8308 static int 8309 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap, 8310 nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp, 8311 struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, 8312 struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp, 8313 int *dattrflagp, void *dstuff, int *unlockedp) 8314 { 8315 struct nfscllayout *lyp; 8316 struct nfsclflayouthead flh; 8317 struct nfsfh *nfhp; 8318 struct nfsclsession *tsep; 8319 struct nfsmount *nmp; 8320 nfsv4stateid_t stateid; 8321 int error, layoutlen, layouttype, retonclose, laystat; 8322 8323 error = 0; 8324 nmp = VFSTONFS(dvp->v_mount); 8325 if (NFSHASFLEXFILE(nmp)) 8326 layouttype = NFSLAYOUT_FLEXFILE; 8327 else 8328 layouttype = NFSLAYOUT_NFSV4_1_FILES; 8329 LIST_INIT(&flh); 8330 tsep = nfsmnt_mdssession(nmp); 8331 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED); 8332 error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode, 8333 owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp, 8334 dstuff, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose, 8335 &flh, &laystat); 8336 NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n", 8337 laystat, error); 8338 lyp = NULL; 8339 if (laystat == 0) { 8340 nfhp = *nfhpp; 8341 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh, 8342 nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh, 8343 layouttype, laystat, NULL, cred, p); 8344 } else 8345 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid, 8346 retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL, 8347 cred, p); 8348 if (laystat == 0) 8349 nfscl_rellayout(lyp, 0); 8350 return (error); 8351 } 8352 8353 /* 8354 * Process the results of a layoutget() operation. 8355 */ 8356 static int 8357 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp, 8358 int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit, 8359 struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype, 8360 int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p) 8361 { 8362 struct nfsclflayout *tflp; 8363 struct nfscldevinfo *dip; 8364 uint8_t *dev; 8365 int i, mirrorcnt; 8366 8367 if (laystat == NFSERR_UNKNLAYOUTTYPE) { 8368 NFSLOCKMNT(nmp); 8369 if (!NFSHASFLEXFILE(nmp)) { 8370 /* Switch to using Flex File Layout. */ 8371 nmp->nm_state |= NFSSTA_FLEXFILE; 8372 } else if (layouttype == NFSLAYOUT_FLEXFILE) { 8373 /* Disable pNFS. */ 8374 NFSCL_DEBUG(1, "disable PNFS\n"); 8375 nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE); 8376 } 8377 NFSUNLOCKMNT(nmp); 8378 } 8379 if (laystat == 0) { 8380 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n"); 8381 LIST_FOREACH(tflp, flhp, nfsfl_list) { 8382 if (layouttype == NFSLAYOUT_FLEXFILE) 8383 mirrorcnt = tflp->nfsfl_mirrorcnt; 8384 else 8385 mirrorcnt = 1; 8386 for (i = 0; i < mirrorcnt; i++) { 8387 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp); 8388 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat); 8389 if (laystat != 0) { 8390 if (layouttype == NFSLAYOUT_FLEXFILE) 8391 dev = tflp->nfsfl_ffm[i].dev; 8392 else 8393 dev = tflp->nfsfl_dev; 8394 laystat = nfsrpc_getdeviceinfo(nmp, dev, 8395 layouttype, notifybit, &dip, cred, 8396 p); 8397 NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n", 8398 laystat); 8399 if (laystat != 0) 8400 goto out; 8401 laystat = nfscl_adddevinfo(nmp, dip, i, 8402 tflp); 8403 if (laystat != 0) 8404 printf("nfsrpc_layoutgetresout" 8405 ": cannot add\n"); 8406 } 8407 } 8408 } 8409 } 8410 out: 8411 if (laystat == 0) { 8412 /* 8413 * nfscl_layout() always returns with the nfsly_lock 8414 * set to a refcnt (shared lock). 8415 * Passing in dvp is sufficient, since it is only used to 8416 * get the fsid for the file system. 8417 */ 8418 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp, 8419 layouttype, retonclose, flhp, lypp, cred, p); 8420 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n", 8421 laystat); 8422 if (laystat == 0 && islockedp != NULL) 8423 *islockedp = 1; 8424 } 8425 return (laystat); 8426 } 8427 8428 /* 8429 * nfs copy_file_range operation. 8430 */ 8431 int 8432 nfsrpc_copy_file_range(vnode_t invp, off_t *inoffp, vnode_t outvp, 8433 off_t *outoffp, size_t *lenp, unsigned int flags, int *inattrflagp, 8434 struct nfsvattr *innap, int *outattrflagp, struct nfsvattr *outnap, 8435 struct ucred *cred, bool consecutive, bool *must_commitp) 8436 { 8437 int commit, error, expireret = 0, retrycnt; 8438 u_int32_t clidrev = 0; 8439 struct nfsmount *nmp = VFSTONFS(invp->v_mount); 8440 struct nfsfh *innfhp = NULL, *outnfhp = NULL; 8441 nfsv4stateid_t instateid, outstateid; 8442 void *inlckp, *outlckp; 8443 8444 if (nmp->nm_clp != NULL) 8445 clidrev = nmp->nm_clp->nfsc_clientidrev; 8446 innfhp = VTONFS(invp)->n_fhp; 8447 outnfhp = VTONFS(outvp)->n_fhp; 8448 retrycnt = 0; 8449 do { 8450 /* Get both stateids. */ 8451 inlckp = NULL; 8452 nfscl_getstateid(invp, innfhp->nfh_fh, innfhp->nfh_len, 8453 NFSV4OPEN_ACCESSREAD, 0, NULL, curthread, &instateid, 8454 &inlckp); 8455 outlckp = NULL; 8456 nfscl_getstateid(outvp, outnfhp->nfh_fh, outnfhp->nfh_len, 8457 NFSV4OPEN_ACCESSWRITE, 0, NULL, curthread, &outstateid, 8458 &outlckp); 8459 8460 error = nfsrpc_copyrpc(invp, *inoffp, outvp, *outoffp, lenp, 8461 &instateid, &outstateid, innap, inattrflagp, outnap, 8462 outattrflagp, consecutive, &commit, cred, curthread); 8463 if (error == 0) { 8464 if (commit != NFSWRITE_FILESYNC) 8465 *must_commitp = true; 8466 *inoffp += *lenp; 8467 *outoffp += *lenp; 8468 } else if (error == NFSERR_STALESTATEID) 8469 nfscl_initiate_recovery(nmp->nm_clp); 8470 if (inlckp != NULL) 8471 nfscl_lockderef(inlckp); 8472 if (outlckp != NULL) 8473 nfscl_lockderef(outlckp); 8474 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8475 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8476 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 8477 (void) nfs_catnap(PZERO, error, "nfs_cfr"); 8478 } else if ((error == NFSERR_EXPIRED || 8479 error == NFSERR_BADSTATEID) && clidrev != 0) { 8480 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 8481 curthread); 8482 } 8483 retrycnt++; 8484 } while (error == NFSERR_GRACE || error == NFSERR_DELAY || 8485 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8486 error == NFSERR_STALEDONTRECOVER || 8487 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 8488 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 8489 expireret == 0 && clidrev != 0 && retrycnt < 4)); 8490 if (error != 0 && (retrycnt >= 4 || 8491 error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION || 8492 error == NFSERR_STALEDONTRECOVER)) 8493 error = EIO; 8494 return (error); 8495 } 8496 8497 /* 8498 * The copy RPC. 8499 */ 8500 static int 8501 nfsrpc_copyrpc(vnode_t invp, off_t inoff, vnode_t outvp, off_t outoff, 8502 size_t *lenp, nfsv4stateid_t *instateidp, nfsv4stateid_t *outstateidp, 8503 struct nfsvattr *innap, int *inattrflagp, struct nfsvattr *outnap, 8504 int *outattrflagp, bool consecutive, int *commitp, struct ucred *cred, 8505 NFSPROC_T *p) 8506 { 8507 uint32_t *tl; 8508 int error; 8509 struct nfsrv_descript nfsd; 8510 struct nfsrv_descript *nd = &nfsd; 8511 struct nfsmount *nmp; 8512 nfsattrbit_t attrbits; 8513 uint64_t len; 8514 8515 nmp = VFSTONFS(outvp->v_mount); 8516 *inattrflagp = *outattrflagp = 0; 8517 *commitp = NFSWRITE_UNSTABLE; 8518 len = *lenp; 8519 *lenp = 0; 8520 if (len > nfs_maxcopyrange) 8521 len = nfs_maxcopyrange; 8522 NFSCL_REQSTART(nd, NFSPROC_COPY, invp); 8523 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8524 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8525 NFSGETATTR_ATTRBIT(&attrbits); 8526 nfsrv_putattrbit(nd, &attrbits); 8527 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8528 *tl = txdr_unsigned(NFSV4OP_PUTFH); 8529 nfsm_fhtom(nd, VTONFS(outvp)->n_fhp->nfh_fh, 8530 VTONFS(outvp)->n_fhp->nfh_len, 0); 8531 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8532 *tl = txdr_unsigned(NFSV4OP_COPY); 8533 nfsm_stateidtom(nd, instateidp, NFSSTATEID_PUTSTATEID); 8534 nfsm_stateidtom(nd, outstateidp, NFSSTATEID_PUTSTATEID); 8535 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_HYPER + 4 * NFSX_UNSIGNED); 8536 txdr_hyper(inoff, tl); tl += 2; 8537 txdr_hyper(outoff, tl); tl += 2; 8538 txdr_hyper(len, tl); tl += 2; 8539 if (consecutive) 8540 *tl++ = newnfs_true; 8541 else 8542 *tl++ = newnfs_false; 8543 *tl++ = newnfs_true; 8544 *tl++ = 0; 8545 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8546 NFSWRITEGETATTR_ATTRBIT(&attrbits); 8547 nfsrv_putattrbit(nd, &attrbits); 8548 error = nfscl_request(nd, invp, p, cred, NULL); 8549 if (error != 0) 8550 return (error); 8551 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8552 /* Get the input file's attributes. */ 8553 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8554 if (*(tl + 1) == 0) { 8555 error = nfsm_loadattr(nd, innap); 8556 if (error != 0) 8557 goto nfsmout; 8558 *inattrflagp = 1; 8559 } else 8560 nd->nd_flag |= ND_NOMOREDATA; 8561 } 8562 /* Skip over return stat for PutFH. */ 8563 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8564 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8565 if (*++tl != 0) 8566 nd->nd_flag |= ND_NOMOREDATA; 8567 } 8568 /* Skip over return stat for Copy. */ 8569 if ((nd->nd_flag & ND_NOMOREDATA) == 0) 8570 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8571 if (nd->nd_repstat == 0) { 8572 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8573 if (*tl != 0) { 8574 /* There should be no callback ids. */ 8575 error = NFSERR_BADXDR; 8576 goto nfsmout; 8577 } 8578 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED + 8579 NFSX_VERF); 8580 len = fxdr_hyper(tl); tl += 2; 8581 *commitp = fxdr_unsigned(int, *tl++); 8582 NFSLOCKMNT(nmp); 8583 if (!NFSHASWRITEVERF(nmp)) { 8584 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8585 NFSSETWRITEVERF(nmp); 8586 } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF)) { 8587 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF); 8588 nd->nd_repstat = NFSERR_STALEWRITEVERF; 8589 } 8590 NFSUNLOCKMNT(nmp); 8591 tl += (NFSX_VERF / NFSX_UNSIGNED); 8592 if (nd->nd_repstat == 0 && *++tl != newnfs_true) 8593 /* Must be a synchronous copy. */ 8594 nd->nd_repstat = NFSERR_NOTSUPP; 8595 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8596 error = nfsm_loadattr(nd, outnap); 8597 if (error == 0) 8598 *outattrflagp = NFS_LATTR_NOSHRINK; 8599 if (nd->nd_repstat == 0) 8600 *lenp = len; 8601 } else if (nd->nd_repstat == NFSERR_OFFLOADNOREQS) { 8602 /* 8603 * For the case where consecutive is not supported, but 8604 * synchronous is supported, we can try consecutive == false 8605 * by returning this error. Otherwise, return NFSERR_NOTSUPP, 8606 * since Copy cannot be done. 8607 */ 8608 if ((nd->nd_flag & ND_NOMOREDATA) == 0) { 8609 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8610 if (!consecutive || *++tl == newnfs_false) 8611 nd->nd_repstat = NFSERR_NOTSUPP; 8612 } else 8613 nd->nd_repstat = NFSERR_BADXDR; 8614 } 8615 if (error == 0) 8616 error = nd->nd_repstat; 8617 nfsmout: 8618 m_freem(nd->nd_mrep); 8619 return (error); 8620 } 8621 8622 /* 8623 * Seek operation. 8624 */ 8625 int 8626 nfsrpc_seek(vnode_t vp, off_t *offp, bool *eofp, int content, 8627 struct ucred *cred, struct nfsvattr *nap, int *attrflagp) 8628 { 8629 int error, expireret = 0, retrycnt; 8630 u_int32_t clidrev = 0; 8631 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 8632 struct nfsnode *np = VTONFS(vp); 8633 struct nfsfh *nfhp = NULL; 8634 nfsv4stateid_t stateid; 8635 void *lckp; 8636 8637 if (nmp->nm_clp != NULL) 8638 clidrev = nmp->nm_clp->nfsc_clientidrev; 8639 nfhp = np->n_fhp; 8640 retrycnt = 0; 8641 do { 8642 lckp = NULL; 8643 nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len, 8644 NFSV4OPEN_ACCESSREAD, 0, cred, curthread, &stateid, &lckp); 8645 error = nfsrpc_seekrpc(vp, offp, &stateid, eofp, content, 8646 nap, attrflagp, cred); 8647 if (error == NFSERR_STALESTATEID) 8648 nfscl_initiate_recovery(nmp->nm_clp); 8649 if (lckp != NULL) 8650 nfscl_lockderef(lckp); 8651 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8652 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8653 error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) { 8654 (void) nfs_catnap(PZERO, error, "nfs_seek"); 8655 } else if ((error == NFSERR_EXPIRED || 8656 error == NFSERR_BADSTATEID) && clidrev != 0) { 8657 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, 8658 curthread); 8659 } 8660 retrycnt++; 8661 } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID || 8662 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY || 8663 error == NFSERR_BADSESSION || 8664 (error == NFSERR_OLDSTATEID && retrycnt < 20) || 8665 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) && 8666 expireret == 0 && clidrev != 0 && retrycnt < 4) || 8667 (error == NFSERR_OPENMODE && retrycnt < 4)); 8668 if (error && retrycnt >= 4) 8669 error = EIO; 8670 return (error); 8671 } 8672 8673 /* 8674 * The seek RPC. 8675 */ 8676 static int 8677 nfsrpc_seekrpc(vnode_t vp, off_t *offp, nfsv4stateid_t *stateidp, bool *eofp, 8678 int content, struct nfsvattr *nap, int *attrflagp, struct ucred *cred) 8679 { 8680 uint32_t *tl; 8681 int error; 8682 struct nfsrv_descript nfsd; 8683 struct nfsrv_descript *nd = &nfsd; 8684 nfsattrbit_t attrbits; 8685 8686 *attrflagp = 0; 8687 NFSCL_REQSTART(nd, NFSPROC_SEEK, vp); 8688 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID); 8689 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 8690 txdr_hyper(*offp, tl); tl += 2; 8691 *tl++ = txdr_unsigned(content); 8692 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8693 NFSGETATTR_ATTRBIT(&attrbits); 8694 nfsrv_putattrbit(nd, &attrbits); 8695 error = nfscl_request(nd, vp, curthread, cred, NULL); 8696 if (error != 0) 8697 return (error); 8698 if (nd->nd_repstat == 0) { 8699 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED + NFSX_HYPER); 8700 if (*tl++ == newnfs_true) 8701 *eofp = true; 8702 else 8703 *eofp = false; 8704 *offp = fxdr_hyper(tl); 8705 /* Just skip over Getattr op status. */ 8706 error = nfsm_loadattr(nd, nap); 8707 if (error == 0) 8708 *attrflagp = 1; 8709 } 8710 error = nd->nd_repstat; 8711 nfsmout: 8712 m_freem(nd->nd_mrep); 8713 return (error); 8714 } 8715 8716 /* 8717 * The getextattr RPC. 8718 */ 8719 int 8720 nfsrpc_getextattr(vnode_t vp, const char *name, struct uio *uiop, ssize_t *lenp, 8721 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 8722 { 8723 uint32_t *tl; 8724 int error; 8725 struct nfsrv_descript nfsd; 8726 struct nfsrv_descript *nd = &nfsd; 8727 nfsattrbit_t attrbits; 8728 uint32_t len, len2; 8729 8730 *attrflagp = 0; 8731 NFSCL_REQSTART(nd, NFSPROC_GETEXTATTR, vp); 8732 nfsm_strtom(nd, name, strlen(name)); 8733 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8734 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8735 NFSGETATTR_ATTRBIT(&attrbits); 8736 nfsrv_putattrbit(nd, &attrbits); 8737 error = nfscl_request(nd, vp, p, cred, NULL); 8738 if (error != 0) 8739 return (error); 8740 if (nd->nd_repstat == 0) { 8741 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8742 len = fxdr_unsigned(uint32_t, *tl); 8743 /* Sanity check lengths. */ 8744 if (uiop != NULL && len > 0 && len <= IOSIZE_MAX && 8745 uiop->uio_resid <= UINT32_MAX) { 8746 len2 = uiop->uio_resid; 8747 if (len2 >= len) 8748 error = nfsm_mbufuio(nd, uiop, len); 8749 else { 8750 error = nfsm_mbufuio(nd, uiop, len2); 8751 if (error == 0) { 8752 /* 8753 * nfsm_mbufuio() advances to a multiple 8754 * of 4, so round up len2 as well. Then 8755 * we need to advance over the rest of 8756 * the data, rounding up the remaining 8757 * length. 8758 */ 8759 len2 = NFSM_RNDUP(len2); 8760 len2 = NFSM_RNDUP(len - len2); 8761 if (len2 > 0) 8762 error = nfsm_advance(nd, len2, 8763 -1); 8764 } 8765 } 8766 } else if (uiop == NULL && len > 0) { 8767 /* Just wants the length and not the data. */ 8768 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 8769 } else if (len > 0) 8770 error = ENOATTR; 8771 if (error != 0) 8772 goto nfsmout; 8773 *lenp = len; 8774 /* Just skip over Getattr op status. */ 8775 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 8776 error = nfsm_loadattr(nd, nap); 8777 if (error == 0) 8778 *attrflagp = 1; 8779 } 8780 if (error == 0) 8781 error = nd->nd_repstat; 8782 nfsmout: 8783 m_freem(nd->nd_mrep); 8784 return (error); 8785 } 8786 8787 /* 8788 * The setextattr RPC. 8789 */ 8790 int 8791 nfsrpc_setextattr(vnode_t vp, const char *name, struct uio *uiop, 8792 struct nfsvattr *nap, int *attrflagp, struct ucred *cred, NFSPROC_T *p) 8793 { 8794 uint32_t *tl; 8795 int error; 8796 struct nfsrv_descript nfsd; 8797 struct nfsrv_descript *nd = &nfsd; 8798 nfsattrbit_t attrbits; 8799 8800 *attrflagp = 0; 8801 NFSCL_REQSTART(nd, NFSPROC_SETEXTATTR, vp); 8802 if (uiop->uio_resid > nd->nd_maxreq) { 8803 /* nd_maxreq is set by NFSCL_REQSTART(). */ 8804 m_freem(nd->nd_mreq); 8805 return (EINVAL); 8806 } 8807 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8808 *tl = txdr_unsigned(NFSV4SXATTR_EITHER); 8809 nfsm_strtom(nd, name, strlen(name)); 8810 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8811 *tl = txdr_unsigned(uiop->uio_resid); 8812 nfsm_uiombuf(nd, uiop, uiop->uio_resid); 8813 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8814 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8815 NFSGETATTR_ATTRBIT(&attrbits); 8816 nfsrv_putattrbit(nd, &attrbits); 8817 error = nfscl_request(nd, vp, p, cred, NULL); 8818 if (error != 0) 8819 return (error); 8820 if (nd->nd_repstat == 0) { 8821 /* Just skip over the reply and Getattr op status. */ 8822 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 8823 NFSX_UNSIGNED); 8824 error = nfsm_loadattr(nd, nap); 8825 if (error == 0) 8826 *attrflagp = 1; 8827 } 8828 if (error == 0) 8829 error = nd->nd_repstat; 8830 nfsmout: 8831 m_freem(nd->nd_mrep); 8832 return (error); 8833 } 8834 8835 /* 8836 * The removeextattr RPC. 8837 */ 8838 int 8839 nfsrpc_rmextattr(vnode_t vp, const char *name, struct nfsvattr *nap, 8840 int *attrflagp, struct ucred *cred, NFSPROC_T *p) 8841 { 8842 uint32_t *tl; 8843 int error; 8844 struct nfsrv_descript nfsd; 8845 struct nfsrv_descript *nd = &nfsd; 8846 nfsattrbit_t attrbits; 8847 8848 *attrflagp = 0; 8849 NFSCL_REQSTART(nd, NFSPROC_RMEXTATTR, vp); 8850 nfsm_strtom(nd, name, strlen(name)); 8851 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); 8852 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8853 NFSGETATTR_ATTRBIT(&attrbits); 8854 nfsrv_putattrbit(nd, &attrbits); 8855 error = nfscl_request(nd, vp, p, cred, NULL); 8856 if (error != 0) 8857 return (error); 8858 if (nd->nd_repstat == 0) { 8859 /* Just skip over the reply and Getattr op status. */ 8860 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + 3 * 8861 NFSX_UNSIGNED); 8862 error = nfsm_loadattr(nd, nap); 8863 if (error == 0) 8864 *attrflagp = 1; 8865 } 8866 if (error == 0) 8867 error = nd->nd_repstat; 8868 nfsmout: 8869 m_freem(nd->nd_mrep); 8870 return (error); 8871 } 8872 8873 /* 8874 * The listextattr RPC. 8875 */ 8876 int 8877 nfsrpc_listextattr(vnode_t vp, uint64_t *cookiep, struct uio *uiop, 8878 size_t *lenp, bool *eofp, struct nfsvattr *nap, int *attrflagp, 8879 struct ucred *cred, NFSPROC_T *p) 8880 { 8881 uint32_t *tl; 8882 int cnt, error, i, len; 8883 struct nfsrv_descript nfsd; 8884 struct nfsrv_descript *nd = &nfsd; 8885 nfsattrbit_t attrbits; 8886 u_char c; 8887 8888 *attrflagp = 0; 8889 NFSCL_REQSTART(nd, NFSPROC_LISTEXTATTR, vp); 8890 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED); 8891 txdr_hyper(*cookiep, tl); tl += 2; 8892 *tl++ = txdr_unsigned(*lenp); 8893 *tl = txdr_unsigned(NFSV4OP_GETATTR); 8894 NFSGETATTR_ATTRBIT(&attrbits); 8895 nfsrv_putattrbit(nd, &attrbits); 8896 error = nfscl_request(nd, vp, p, cred, NULL); 8897 if (error != 0) 8898 return (error); 8899 *eofp = true; 8900 *lenp = 0; 8901 if (nd->nd_repstat == 0) { 8902 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED); 8903 *cookiep = fxdr_hyper(tl); tl += 2; 8904 cnt = fxdr_unsigned(int, *tl); 8905 if (cnt < 0) { 8906 error = EBADRPC; 8907 goto nfsmout; 8908 } 8909 for (i = 0; i < cnt; i++) { 8910 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); 8911 len = fxdr_unsigned(int, *tl); 8912 if (len <= 0 || len > EXTATTR_MAXNAMELEN) { 8913 error = EBADRPC; 8914 goto nfsmout; 8915 } 8916 if (uiop == NULL) 8917 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 8918 else if (uiop->uio_resid >= len + 1) { 8919 c = len; 8920 error = uiomove(&c, sizeof(c), uiop); 8921 if (error == 0) 8922 error = nfsm_mbufuio(nd, uiop, len); 8923 } else { 8924 error = nfsm_advance(nd, NFSM_RNDUP(len), -1); 8925 *eofp = false; 8926 } 8927 if (error != 0) 8928 goto nfsmout; 8929 *lenp += (len + 1); 8930 } 8931 /* Get the eof and skip over the Getattr op status. */ 8932 NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); 8933 /* 8934 * *eofp is set false above, because it wasn't able to copy 8935 * all of the reply. 8936 */ 8937 if (*eofp && *tl == 0) 8938 *eofp = false; 8939 error = nfsm_loadattr(nd, nap); 8940 if (error == 0) 8941 *attrflagp = 1; 8942 } 8943 if (error == 0) 8944 error = nd->nd_repstat; 8945 nfsmout: 8946 m_freem(nd->nd_mrep); 8947 return (error); 8948 } 8949 8950 /* 8951 * Split an mbuf list. For non-M_EXTPG mbufs, just use m_split(). 8952 */ 8953 static struct mbuf * 8954 nfsm_split(struct mbuf *mp, uint64_t xfer) 8955 { 8956 struct mbuf *m, *m2; 8957 vm_page_t pg; 8958 int i, j, left, pgno, plen, trim; 8959 char *cp, *cp2; 8960 8961 if ((mp->m_flags & M_EXTPG) == 0) { 8962 m = m_split(mp, xfer, M_WAITOK); 8963 return (m); 8964 } 8965 8966 /* Find the correct mbuf to split at. */ 8967 for (m = mp; m != NULL && xfer > m->m_len; m = m->m_next) 8968 xfer -= m->m_len; 8969 if (m == NULL) 8970 return (NULL); 8971 8972 /* If xfer == m->m_len, we can just split the mbuf list. */ 8973 if (xfer == m->m_len) { 8974 m2 = m->m_next; 8975 m->m_next = NULL; 8976 return (m2); 8977 } 8978 8979 /* Find the page to split at. */ 8980 pgno = 0; 8981 left = xfer; 8982 do { 8983 if (pgno == 0) 8984 plen = m_epg_pagelen(m, 0, m->m_epg_1st_off); 8985 else 8986 plen = m_epg_pagelen(m, pgno, 0); 8987 if (left <= plen) 8988 break; 8989 left -= plen; 8990 pgno++; 8991 } while (pgno < m->m_epg_npgs); 8992 if (pgno == m->m_epg_npgs) 8993 panic("nfsm_split: eroneous ext_pgs mbuf"); 8994 8995 m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs); 8996 m2->m_epg_flags |= EPG_FLAG_ANON; 8997 8998 /* 8999 * If left < plen, allocate a new page for the new mbuf 9000 * and copy the data after left in the page to this new 9001 * page. 9002 */ 9003 if (left < plen) { 9004 pg = vm_page_alloc_noobj(VM_ALLOC_WAITOK | VM_ALLOC_NODUMP | 9005 VM_ALLOC_WIRED); 9006 m2->m_epg_pa[0] = VM_PAGE_TO_PHYS(pg); 9007 m2->m_epg_npgs = 1; 9008 9009 /* Copy the data after left to the new page. */ 9010 trim = plen - left; 9011 cp = (char *)(void *)PHYS_TO_DMAP(m->m_epg_pa[pgno]); 9012 if (pgno == 0) 9013 cp += m->m_epg_1st_off; 9014 cp += left; 9015 cp2 = (char *)(void *)PHYS_TO_DMAP(m2->m_epg_pa[0]); 9016 if (pgno == m->m_epg_npgs - 1) 9017 m2->m_epg_last_len = trim; 9018 else { 9019 cp2 += PAGE_SIZE - trim; 9020 m2->m_epg_1st_off = PAGE_SIZE - trim; 9021 m2->m_epg_last_len = m->m_epg_last_len; 9022 } 9023 memcpy(cp2, cp, trim); 9024 m2->m_len = trim; 9025 } else { 9026 m2->m_len = 0; 9027 m2->m_epg_last_len = m->m_epg_last_len; 9028 } 9029 9030 /* Move the pages beyond pgno to the new mbuf. */ 9031 for (i = pgno + 1, j = m2->m_epg_npgs; i < m->m_epg_npgs; i++, j++) { 9032 m2->m_epg_pa[j] = m->m_epg_pa[i]; 9033 /* Never moves page 0. */ 9034 m2->m_len += m_epg_pagelen(m, i, 0); 9035 } 9036 m2->m_epg_npgs = j; 9037 m->m_epg_npgs = pgno + 1; 9038 m->m_epg_last_len = left; 9039 m->m_len = xfer; 9040 9041 m2->m_next = m->m_next; 9042 m->m_next = NULL; 9043 return (m2); 9044 } 9045 9046 /* 9047 * Do the NFSv4.1 Bind Connection to Session. 9048 * Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c). 9049 */ 9050 void 9051 nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr) 9052 { 9053 struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg; 9054 uint32_t res, *tl; 9055 struct nfsrv_descript nfsd; 9056 struct nfsrv_descript *nd = &nfsd; 9057 struct rpc_callextra ext; 9058 struct timeval utimeout; 9059 enum clnt_stat stat; 9060 int error; 9061 9062 nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL, 9063 NFS_VER4, rcp->minorvers); 9064 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED); 9065 memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID); 9066 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9067 *tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH); 9068 *tl = newnfs_false; 9069 9070 memset(&ext, 0, sizeof(ext)); 9071 utimeout.tv_sec = 30; 9072 utimeout.tv_usec = 0; 9073 ext.rc_auth = authunix_create(cr); 9074 nd->nd_mrep = NULL; 9075 stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq, 9076 &nd->nd_mrep, utimeout); 9077 AUTH_DESTROY(ext.rc_auth); 9078 if (stat != RPC_SUCCESS) { 9079 printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat); 9080 return; 9081 } 9082 if (nd->nd_mrep == NULL) { 9083 printf("nfsrpc_bindconnsess: no reply args\n"); 9084 return; 9085 } 9086 error = 0; 9087 newnfs_realign(&nd->nd_mrep, M_WAITOK); 9088 nd->nd_md = nd->nd_mrep; 9089 nd->nd_dpos = mtod(nd->nd_md, char *); 9090 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED); 9091 nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++); 9092 if (nd->nd_repstat == NFSERR_OK) { 9093 res = fxdr_unsigned(uint32_t, *tl); 9094 if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res), 9095 -1)) != 0) 9096 goto nfsmout; 9097 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 9098 4 * NFSX_UNSIGNED); 9099 tl += 3; 9100 if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) { 9101 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED; 9102 res = fxdr_unsigned(uint32_t, *tl); 9103 if (res != NFSCDFS4_BOTH) 9104 printf("nfsrpc_bindconnsess: did not " 9105 "return FS4_BOTH\n"); 9106 } else 9107 printf("nfsrpc_bindconnsess: not same " 9108 "sessionid\n"); 9109 } else if (nd->nd_repstat != NFSERR_BADSESSION) 9110 printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat); 9111 nfsmout: 9112 if (error != 0) 9113 printf("nfsrpc_bindconnsess: reply bad xdr\n"); 9114 m_freem(nd->nd_mrep); 9115 } 9116