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