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