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