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