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