1 /* $OpenBSD: nfs_subs.c,v 1.93 2009/03/30 19:58:50 blambert Exp $ */ 2 /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 36 */ 37 38 39 /* 40 * These functions support the macros and help fiddle mbuf chains for 41 * the nfs op functions. They do things like create the rpc header and 42 * copy data between mbuf chains and uio lists. 43 */ 44 #include <sys/param.h> 45 #include <sys/proc.h> 46 #include <sys/systm.h> 47 #include <sys/kernel.h> 48 #include <sys/mount.h> 49 #include <sys/vnode.h> 50 #include <sys/namei.h> 51 #include <sys/mbuf.h> 52 #include <sys/socket.h> 53 #include <sys/socketvar.h> 54 #include <sys/stat.h> 55 #include <sys/pool.h> 56 #include <sys/time.h> 57 58 #include <uvm/uvm_extern.h> 59 60 #include <nfs/rpcv2.h> 61 #include <nfs/nfsproto.h> 62 #include <nfs/nfsnode.h> 63 #include <nfs/nfs.h> 64 #include <nfs/xdr_subs.h> 65 #include <nfs/nfsm_subs.h> 66 #include <nfs/nfsmount.h> 67 #include <nfs/nfsrtt.h> 68 #include <nfs/nfs_var.h> 69 70 #include <miscfs/specfs/specdev.h> 71 72 #include <netinet/in.h> 73 74 #include <dev/rndvar.h> 75 #include <crypto/idgen.h> 76 77 int nfs_attrtimeo(struct nfsnode *np); 78 79 /* 80 * Data items converted to xdr at startup, since they are constant 81 * This is kinda hokey, but may save a little time doing byte swaps 82 */ 83 u_int32_t nfs_xdrneg1; 84 u_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 85 rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 86 u_int32_t nfs_prog, nfs_true, nfs_false; 87 88 /* And other global data */ 89 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON, 90 NFCHR, NFNON }; 91 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK, 92 NFFIFO, NFNON }; 93 enum vtype nv2tov_type[8] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON }; 94 enum vtype nv3tov_type[8]={ VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO }; 95 int nfs_ticks; 96 struct nfsstats nfsstats; 97 98 /* 99 * Mapping of old NFS Version 2 RPC numbers to generic numbers. 100 */ 101 int nfsv3_procid[NFS_NPROCS] = { 102 NFSPROC_NULL, 103 NFSPROC_GETATTR, 104 NFSPROC_SETATTR, 105 NFSPROC_NOOP, 106 NFSPROC_LOOKUP, 107 NFSPROC_READLINK, 108 NFSPROC_READ, 109 NFSPROC_NOOP, 110 NFSPROC_WRITE, 111 NFSPROC_CREATE, 112 NFSPROC_REMOVE, 113 NFSPROC_RENAME, 114 NFSPROC_LINK, 115 NFSPROC_SYMLINK, 116 NFSPROC_MKDIR, 117 NFSPROC_RMDIR, 118 NFSPROC_READDIR, 119 NFSPROC_FSSTAT, 120 NFSPROC_NOOP, 121 NFSPROC_NOOP, 122 NFSPROC_NOOP, 123 NFSPROC_NOOP, 124 NFSPROC_NOOP, 125 NFSPROC_NOOP, 126 NFSPROC_NOOP, 127 NFSPROC_NOOP 128 }; 129 130 /* 131 * and the reverse mapping from generic to Version 2 procedure numbers 132 */ 133 int nfsv2_procid[NFS_NPROCS] = { 134 NFSV2PROC_NULL, 135 NFSV2PROC_GETATTR, 136 NFSV2PROC_SETATTR, 137 NFSV2PROC_LOOKUP, 138 NFSV2PROC_NOOP, 139 NFSV2PROC_READLINK, 140 NFSV2PROC_READ, 141 NFSV2PROC_WRITE, 142 NFSV2PROC_CREATE, 143 NFSV2PROC_MKDIR, 144 NFSV2PROC_SYMLINK, 145 NFSV2PROC_CREATE, 146 NFSV2PROC_REMOVE, 147 NFSV2PROC_RMDIR, 148 NFSV2PROC_RENAME, 149 NFSV2PROC_LINK, 150 NFSV2PROC_READDIR, 151 NFSV2PROC_NOOP, 152 NFSV2PROC_STATFS, 153 NFSV2PROC_NOOP, 154 NFSV2PROC_NOOP, 155 NFSV2PROC_NOOP, 156 NFSV2PROC_NOOP, 157 NFSV2PROC_NOOP, 158 NFSV2PROC_NOOP, 159 NFSV2PROC_NOOP, 160 }; 161 162 /* 163 * Maps errno values to nfs error numbers. 164 * Use NFSERR_IO as the catch all for ones not specifically defined in 165 * RFC 1094. 166 */ 167 static u_char nfsrv_v2errmap[] = { 168 NFSERR_PERM, NFSERR_NOENT, NFSERR_IO, NFSERR_IO, NFSERR_IO, 169 NFSERR_NXIO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 170 NFSERR_IO, NFSERR_IO, NFSERR_ACCES, NFSERR_IO, NFSERR_IO, 171 NFSERR_IO, NFSERR_EXIST, NFSERR_IO, NFSERR_NODEV, NFSERR_NOTDIR, 172 NFSERR_ISDIR, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 173 NFSERR_IO, NFSERR_FBIG, NFSERR_NOSPC, NFSERR_IO, NFSERR_ROFS, 174 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 175 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 176 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 177 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 178 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 179 NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, NFSERR_IO, 180 NFSERR_IO, NFSERR_IO, NFSERR_NAMETOL, NFSERR_IO, NFSERR_IO, 181 NFSERR_NOTEMPTY, NFSERR_IO, NFSERR_IO, NFSERR_DQUOT, NFSERR_STALE 182 /* Everything after this maps to NFSERR_IO, so far */ 183 }; 184 185 /* 186 * Maps errno values to nfs error numbers. 187 * Although it is not obvious whether or not NFS clients really care if 188 * a returned error value is in the specified list for the procedure, the 189 * safest thing to do is filter them appropriately. For Version 2, the 190 * X/Open XNFS document is the only specification that defines error values 191 * for each RPC (The RFC simply lists all possible error values for all RPCs), 192 * so I have decided to not do this for Version 2. 193 * The first entry is the default error return and the rest are the valid 194 * errors for that RPC in increasing numeric order. 195 */ 196 static short nfsv3err_null[] = { 197 0, 198 0, 199 }; 200 201 static short nfsv3err_getattr[] = { 202 NFSERR_IO, 203 NFSERR_IO, 204 NFSERR_STALE, 205 NFSERR_BADHANDLE, 206 NFSERR_SERVERFAULT, 207 0, 208 }; 209 210 static short nfsv3err_setattr[] = { 211 NFSERR_IO, 212 NFSERR_PERM, 213 NFSERR_IO, 214 NFSERR_ACCES, 215 NFSERR_INVAL, 216 NFSERR_NOSPC, 217 NFSERR_ROFS, 218 NFSERR_DQUOT, 219 NFSERR_STALE, 220 NFSERR_BADHANDLE, 221 NFSERR_NOT_SYNC, 222 NFSERR_SERVERFAULT, 223 0, 224 }; 225 226 static short nfsv3err_lookup[] = { 227 NFSERR_IO, 228 NFSERR_NOENT, 229 NFSERR_IO, 230 NFSERR_ACCES, 231 NFSERR_NOTDIR, 232 NFSERR_NAMETOL, 233 NFSERR_STALE, 234 NFSERR_BADHANDLE, 235 NFSERR_SERVERFAULT, 236 0, 237 }; 238 239 static short nfsv3err_access[] = { 240 NFSERR_IO, 241 NFSERR_IO, 242 NFSERR_STALE, 243 NFSERR_BADHANDLE, 244 NFSERR_SERVERFAULT, 245 0, 246 }; 247 248 static short nfsv3err_readlink[] = { 249 NFSERR_IO, 250 NFSERR_IO, 251 NFSERR_ACCES, 252 NFSERR_INVAL, 253 NFSERR_STALE, 254 NFSERR_BADHANDLE, 255 NFSERR_NOTSUPP, 256 NFSERR_SERVERFAULT, 257 0, 258 }; 259 260 static short nfsv3err_read[] = { 261 NFSERR_IO, 262 NFSERR_IO, 263 NFSERR_NXIO, 264 NFSERR_ACCES, 265 NFSERR_INVAL, 266 NFSERR_STALE, 267 NFSERR_BADHANDLE, 268 NFSERR_SERVERFAULT, 269 0, 270 }; 271 272 static short nfsv3err_write[] = { 273 NFSERR_IO, 274 NFSERR_IO, 275 NFSERR_ACCES, 276 NFSERR_INVAL, 277 NFSERR_FBIG, 278 NFSERR_NOSPC, 279 NFSERR_ROFS, 280 NFSERR_DQUOT, 281 NFSERR_STALE, 282 NFSERR_BADHANDLE, 283 NFSERR_SERVERFAULT, 284 0, 285 }; 286 287 static short nfsv3err_create[] = { 288 NFSERR_IO, 289 NFSERR_IO, 290 NFSERR_ACCES, 291 NFSERR_EXIST, 292 NFSERR_NOTDIR, 293 NFSERR_NOSPC, 294 NFSERR_ROFS, 295 NFSERR_NAMETOL, 296 NFSERR_DQUOT, 297 NFSERR_STALE, 298 NFSERR_BADHANDLE, 299 NFSERR_NOTSUPP, 300 NFSERR_SERVERFAULT, 301 0, 302 }; 303 304 static short nfsv3err_mkdir[] = { 305 NFSERR_IO, 306 NFSERR_IO, 307 NFSERR_ACCES, 308 NFSERR_EXIST, 309 NFSERR_NOTDIR, 310 NFSERR_NOSPC, 311 NFSERR_ROFS, 312 NFSERR_NAMETOL, 313 NFSERR_DQUOT, 314 NFSERR_STALE, 315 NFSERR_BADHANDLE, 316 NFSERR_NOTSUPP, 317 NFSERR_SERVERFAULT, 318 0, 319 }; 320 321 static short nfsv3err_symlink[] = { 322 NFSERR_IO, 323 NFSERR_IO, 324 NFSERR_ACCES, 325 NFSERR_EXIST, 326 NFSERR_NOTDIR, 327 NFSERR_NOSPC, 328 NFSERR_ROFS, 329 NFSERR_NAMETOL, 330 NFSERR_DQUOT, 331 NFSERR_STALE, 332 NFSERR_BADHANDLE, 333 NFSERR_NOTSUPP, 334 NFSERR_SERVERFAULT, 335 0, 336 }; 337 338 static short nfsv3err_mknod[] = { 339 NFSERR_IO, 340 NFSERR_IO, 341 NFSERR_ACCES, 342 NFSERR_EXIST, 343 NFSERR_NOTDIR, 344 NFSERR_NOSPC, 345 NFSERR_ROFS, 346 NFSERR_NAMETOL, 347 NFSERR_DQUOT, 348 NFSERR_STALE, 349 NFSERR_BADHANDLE, 350 NFSERR_NOTSUPP, 351 NFSERR_SERVERFAULT, 352 NFSERR_BADTYPE, 353 0, 354 }; 355 356 static short nfsv3err_remove[] = { 357 NFSERR_IO, 358 NFSERR_NOENT, 359 NFSERR_IO, 360 NFSERR_ACCES, 361 NFSERR_NOTDIR, 362 NFSERR_ROFS, 363 NFSERR_NAMETOL, 364 NFSERR_STALE, 365 NFSERR_BADHANDLE, 366 NFSERR_SERVERFAULT, 367 0, 368 }; 369 370 static short nfsv3err_rmdir[] = { 371 NFSERR_IO, 372 NFSERR_NOENT, 373 NFSERR_IO, 374 NFSERR_ACCES, 375 NFSERR_EXIST, 376 NFSERR_NOTDIR, 377 NFSERR_INVAL, 378 NFSERR_ROFS, 379 NFSERR_NAMETOL, 380 NFSERR_NOTEMPTY, 381 NFSERR_STALE, 382 NFSERR_BADHANDLE, 383 NFSERR_NOTSUPP, 384 NFSERR_SERVERFAULT, 385 0, 386 }; 387 388 static short nfsv3err_rename[] = { 389 NFSERR_IO, 390 NFSERR_NOENT, 391 NFSERR_IO, 392 NFSERR_ACCES, 393 NFSERR_EXIST, 394 NFSERR_XDEV, 395 NFSERR_NOTDIR, 396 NFSERR_ISDIR, 397 NFSERR_INVAL, 398 NFSERR_NOSPC, 399 NFSERR_ROFS, 400 NFSERR_MLINK, 401 NFSERR_NAMETOL, 402 NFSERR_NOTEMPTY, 403 NFSERR_DQUOT, 404 NFSERR_STALE, 405 NFSERR_BADHANDLE, 406 NFSERR_NOTSUPP, 407 NFSERR_SERVERFAULT, 408 0, 409 }; 410 411 static short nfsv3err_link[] = { 412 NFSERR_IO, 413 NFSERR_IO, 414 NFSERR_ACCES, 415 NFSERR_EXIST, 416 NFSERR_XDEV, 417 NFSERR_NOTDIR, 418 NFSERR_INVAL, 419 NFSERR_NOSPC, 420 NFSERR_ROFS, 421 NFSERR_MLINK, 422 NFSERR_NAMETOL, 423 NFSERR_DQUOT, 424 NFSERR_STALE, 425 NFSERR_BADHANDLE, 426 NFSERR_NOTSUPP, 427 NFSERR_SERVERFAULT, 428 0, 429 }; 430 431 static short nfsv3err_readdir[] = { 432 NFSERR_IO, 433 NFSERR_IO, 434 NFSERR_ACCES, 435 NFSERR_NOTDIR, 436 NFSERR_STALE, 437 NFSERR_BADHANDLE, 438 NFSERR_BAD_COOKIE, 439 NFSERR_TOOSMALL, 440 NFSERR_SERVERFAULT, 441 0, 442 }; 443 444 static short nfsv3err_readdirplus[] = { 445 NFSERR_IO, 446 NFSERR_IO, 447 NFSERR_ACCES, 448 NFSERR_NOTDIR, 449 NFSERR_STALE, 450 NFSERR_BADHANDLE, 451 NFSERR_BAD_COOKIE, 452 NFSERR_NOTSUPP, 453 NFSERR_TOOSMALL, 454 NFSERR_SERVERFAULT, 455 0, 456 }; 457 458 static short nfsv3err_fsstat[] = { 459 NFSERR_IO, 460 NFSERR_IO, 461 NFSERR_STALE, 462 NFSERR_BADHANDLE, 463 NFSERR_SERVERFAULT, 464 0, 465 }; 466 467 static short nfsv3err_fsinfo[] = { 468 NFSERR_STALE, 469 NFSERR_STALE, 470 NFSERR_BADHANDLE, 471 NFSERR_SERVERFAULT, 472 0, 473 }; 474 475 static short nfsv3err_pathconf[] = { 476 NFSERR_STALE, 477 NFSERR_STALE, 478 NFSERR_BADHANDLE, 479 NFSERR_SERVERFAULT, 480 0, 481 }; 482 483 static short nfsv3err_commit[] = { 484 NFSERR_IO, 485 NFSERR_IO, 486 NFSERR_STALE, 487 NFSERR_BADHANDLE, 488 NFSERR_SERVERFAULT, 489 0, 490 }; 491 492 static short *nfsrv_v3errmap[] = { 493 nfsv3err_null, 494 nfsv3err_getattr, 495 nfsv3err_setattr, 496 nfsv3err_lookup, 497 nfsv3err_access, 498 nfsv3err_readlink, 499 nfsv3err_read, 500 nfsv3err_write, 501 nfsv3err_create, 502 nfsv3err_mkdir, 503 nfsv3err_symlink, 504 nfsv3err_mknod, 505 nfsv3err_remove, 506 nfsv3err_rmdir, 507 nfsv3err_rename, 508 nfsv3err_link, 509 nfsv3err_readdir, 510 nfsv3err_readdirplus, 511 nfsv3err_fsstat, 512 nfsv3err_fsinfo, 513 nfsv3err_pathconf, 514 nfsv3err_commit, 515 }; 516 517 extern struct nfsrtt nfsrtt; 518 519 struct pool nfsreqpl; 520 521 /* 522 * Create the header for an rpc request packet 523 * The hsiz is the size of the rest of the nfs request header. 524 * (just used to decide if a cluster is a good idea) 525 */ 526 struct mbuf * 527 nfsm_reqhead(hsiz) 528 int hsiz; 529 { 530 struct mbuf *mb; 531 532 MGET(mb, M_WAIT, MT_DATA); 533 if (hsiz > MLEN) 534 MCLGET(mb, M_WAIT); 535 mb->m_len = 0; 536 537 /* Finally, return values */ 538 return (mb); 539 } 540 541 /* 542 * Return an unpredictable XID in XDR form. 543 */ 544 u_int32_t 545 nfs_get_xid(void) 546 { 547 static struct idgen32_ctx nfs_xid_ctx; 548 static int called = 0; 549 550 if (!called) { 551 called = 1; 552 idgen32_init(&nfs_xid_ctx); 553 } 554 return (txdr_unsigned(idgen32(&nfs_xid_ctx))); 555 } 556 557 /* 558 * Build the RPC header and fill in the authorization info. 559 * Right now we are pretty centric around RPCAUTH_UNIX, in the 560 * future, this function will need some love to be able to handle 561 * other authorization methods, such as Kerberos. 562 */ 563 void 564 nfsm_rpchead(struct nfsreq *req, struct ucred *cr, int auth_type) 565 { 566 struct mbuf *mb; 567 u_int32_t *tl; 568 int i, authsiz, auth_len, ngroups; 569 570 KASSERT(auth_type == RPCAUTH_UNIX); 571 572 /* 573 * RPCAUTH_UNIX fits in an hdr mbuf, in the future other 574 * authorization methods need to figure out their own sizes 575 * and allocate and chain mbuf's accorindgly. 576 */ 577 mb = req->r_mreq; 578 579 /* 580 * We need to start out by finding how big the authorization cred 581 * and verifer are for the auth_type, to be able to correctly 582 * align the mbuf header/chain. 583 */ 584 switch (auth_type) { 585 case RPCAUTH_UNIX: 586 /* 587 * In the RPCAUTH_UNIX case, the size is the static 588 * part as shown in RFC1831 + the number of groups, 589 * RPCAUTH_UNIX has a zero verifer. 590 */ 591 if (cr->cr_ngroups > req->r_nmp->nm_numgrps) 592 ngroups = req->r_nmp->nm_numgrps; 593 else 594 ngroups = cr->cr_ngroups; 595 596 auth_len = (ngroups << 2) + 5 * NFSX_UNSIGNED; 597 authsiz = nfsm_rndup(auth_len); 598 /* The authorization size + the size of the static part */ 599 MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 600 break; 601 } 602 603 mb->m_len = 0; 604 605 /* First the RPC header. */ 606 tl = nfsm_build(&mb, 6 * NFSX_UNSIGNED); 607 608 /* Get a new (non-zero) xid */ 609 *tl++ = req->r_xid = nfs_get_xid(); 610 *tl++ = rpc_call; 611 *tl++ = rpc_vers; 612 *tl++ = nfs_prog; 613 if (ISSET(req->r_nmp->nm_flag, NFSMNT_NFSV3)) { 614 *tl++ = txdr_unsigned(NFS_VER3); 615 *tl = txdr_unsigned(req->r_procnum); 616 } else { 617 *tl++ = txdr_unsigned(NFS_VER2); 618 *tl = txdr_unsigned(nfsv2_procid[req->r_procnum]); 619 } 620 621 /* The Authorization cred and its verifier */ 622 switch (auth_type) { 623 case RPCAUTH_UNIX: 624 tl = nfsm_build(&mb, auth_len + 4 * NFSX_UNSIGNED); 625 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 626 *tl++ = txdr_unsigned(authsiz); 627 628 /* The authorization cred */ 629 *tl++ = 0; /* stamp */ 630 *tl++ = 0; /* NULL hostname */ 631 *tl++ = txdr_unsigned(cr->cr_uid); 632 *tl++ = txdr_unsigned(cr->cr_gid); 633 *tl++ = txdr_unsigned(ngroups); 634 for (i = 0; i < ngroups; i++) 635 *tl++ = txdr_unsigned(cr->cr_groups[i]); 636 /* The authorization verifier */ 637 *tl++ = txdr_unsigned(RPCAUTH_NULL); 638 *tl = 0; 639 break; 640 } 641 642 mb->m_pkthdr.len += authsiz + 10 * NFSX_UNSIGNED; 643 mb->m_pkthdr.rcvif = NULL; 644 } 645 646 /* 647 * copies mbuf chain to the uio scatter/gather list 648 */ 649 int 650 nfsm_mbuftouio(mrep, uiop, siz, dpos) 651 struct mbuf **mrep; 652 struct uio *uiop; 653 int siz; 654 caddr_t *dpos; 655 { 656 char *mbufcp, *uiocp; 657 int xfer, left, len; 658 struct mbuf *mp; 659 long uiosiz, rem; 660 int error = 0; 661 662 mp = *mrep; 663 mbufcp = *dpos; 664 len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 665 rem = nfsm_padlen(siz); 666 while (siz > 0) { 667 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 668 return (EFBIG); 669 left = uiop->uio_iov->iov_len; 670 uiocp = uiop->uio_iov->iov_base; 671 if (left > siz) 672 left = siz; 673 uiosiz = left; 674 while (left > 0) { 675 while (len == 0) { 676 mp = mp->m_next; 677 if (mp == NULL) 678 return (EBADRPC); 679 mbufcp = mtod(mp, caddr_t); 680 len = mp->m_len; 681 } 682 xfer = (left > len) ? len : left; 683 #ifdef notdef 684 /* Not Yet.. */ 685 if (uiop->uio_iov->iov_op != NULL) 686 (*(uiop->uio_iov->iov_op)) 687 (mbufcp, uiocp, xfer); 688 else 689 #endif 690 if (uiop->uio_segflg == UIO_SYSSPACE) 691 bcopy(mbufcp, uiocp, xfer); 692 else 693 copyout(mbufcp, uiocp, xfer); 694 left -= xfer; 695 len -= xfer; 696 mbufcp += xfer; 697 uiocp += xfer; 698 uiop->uio_offset += xfer; 699 uiop->uio_resid -= xfer; 700 } 701 if (uiop->uio_iov->iov_len <= siz) { 702 uiop->uio_iovcnt--; 703 uiop->uio_iov++; 704 } else { 705 uiop->uio_iov->iov_base = 706 (char *)uiop->uio_iov->iov_base + uiosiz; 707 uiop->uio_iov->iov_len -= uiosiz; 708 } 709 siz -= uiosiz; 710 } 711 *dpos = mbufcp; 712 *mrep = mp; 713 if (rem > 0) { 714 if (len < rem) 715 error = nfs_adv(mrep, dpos, rem, len); 716 else 717 *dpos += rem; 718 } 719 return (error); 720 } 721 722 /* 723 * Copy a uio scatter/gather list to an mbuf chain. 724 */ 725 void 726 nfsm_uiotombuf(struct mbuf **mp, struct uio *uiop, size_t len) 727 { 728 struct mbuf *mb, *mb2; 729 size_t xfer, pad; 730 731 mb = *mp; 732 733 pad = nfsm_padlen(len); 734 735 /* XXX -- the following should be done by the caller */ 736 uiop->uio_resid = len; 737 uiop->uio_rw = UIO_WRITE; 738 739 while (len) { 740 xfer = min(len, M_TRAILINGSPACE(mb)); 741 uiomove(mb_offset(mb), xfer, uiop); 742 mb->m_len += xfer; 743 len -= xfer; 744 if (len > 0) { 745 MGET(mb2, M_WAIT, MT_DATA); 746 if (len > MLEN) 747 MCLGET(mb2, M_WAIT); 748 mb2->m_len = 0; 749 mb->m_next = mb2; 750 mb = mb2; 751 } 752 } 753 754 if (pad > 0) { 755 if (pad > M_TRAILINGSPACE(mb)) { 756 MGET(mb2, M_WAIT, MT_DATA); 757 mb2->m_len = 0; 758 mb->m_next = mb2; 759 mb = mb2; 760 } 761 bzero(mb_offset(mb), pad); 762 mb->m_len += pad; 763 } 764 765 *mp = mb; 766 } 767 768 /* 769 * Copy a buffer to an mbuf chain 770 */ 771 void 772 nfsm_buftombuf(struct mbuf **mp, void *buf, size_t len) 773 { 774 struct iovec iov; 775 struct uio io; 776 777 iov.iov_base = buf; 778 iov.iov_len = len; 779 780 io.uio_iov = &iov; 781 io.uio_iovcnt = 1; 782 io.uio_resid = len; 783 io.uio_segflg = UIO_SYSSPACE; 784 io.uio_rw = UIO_WRITE; 785 786 nfsm_uiotombuf(mp, &io, len); 787 } 788 789 /* 790 * Copy a string to an mbuf chain 791 */ 792 void 793 nfsm_strtombuf(struct mbuf **mp, void *str, size_t len) 794 { 795 struct iovec iov[2]; 796 struct uio io; 797 uint32_t strlen; 798 799 strlen = txdr_unsigned(len); 800 801 iov[0].iov_base = &strlen; 802 iov[0].iov_len = sizeof(uint32_t); 803 iov[1].iov_base = str; 804 iov[1].iov_len = len; 805 806 io.uio_iov = iov; 807 io.uio_iovcnt = 2; 808 io.uio_resid = sizeof(uint32_t) + len; 809 io.uio_segflg = UIO_SYSSPACE; 810 io.uio_rw = UIO_WRITE; 811 812 nfsm_uiotombuf(mp, &io, io.uio_resid); 813 } 814 815 /* 816 * Help break down an mbuf chain by setting the first siz bytes contiguous 817 * pointed to by returned val. 818 * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 819 * cases. (The macros use the vars. dpos and dpos2) 820 */ 821 int 822 nfsm_disct(mdp, dposp, siz, left, cp2) 823 struct mbuf **mdp; 824 caddr_t *dposp; 825 int siz; 826 int left; 827 caddr_t *cp2; 828 { 829 struct mbuf *mp, *mp2; 830 int siz2, xfer; 831 caddr_t p; 832 833 mp = *mdp; 834 while (left == 0) { 835 *mdp = mp = mp->m_next; 836 if (mp == NULL) 837 return (EBADRPC); 838 left = mp->m_len; 839 *dposp = mtod(mp, caddr_t); 840 } 841 if (left >= siz) { 842 *cp2 = *dposp; 843 *dposp += siz; 844 } else if (mp->m_next == NULL) { 845 return (EBADRPC); 846 } else if (siz > MHLEN) { 847 panic("nfs S too big"); 848 } else { 849 MGET(mp2, M_WAIT, MT_DATA); 850 mp2->m_next = mp->m_next; 851 mp->m_next = mp2; 852 mp->m_len -= left; 853 mp = mp2; 854 *cp2 = p = mtod(mp, caddr_t); 855 bcopy(*dposp, p, left); /* Copy what was left */ 856 siz2 = siz-left; 857 p += left; 858 mp2 = mp->m_next; 859 /* Loop around copying up the siz2 bytes */ 860 while (siz2 > 0) { 861 if (mp2 == NULL) 862 return (EBADRPC); 863 xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 864 if (xfer > 0) { 865 bcopy(mtod(mp2, caddr_t), p, xfer); 866 mp2->m_data += xfer; 867 mp2->m_len -= xfer; 868 p += xfer; 869 siz2 -= xfer; 870 } 871 if (siz2 > 0) 872 mp2 = mp2->m_next; 873 } 874 mp->m_len = siz; 875 *mdp = mp2; 876 *dposp = mtod(mp2, caddr_t); 877 } 878 return (0); 879 } 880 881 /* 882 * Advance the position in the mbuf chain. 883 */ 884 int 885 nfs_adv(mdp, dposp, offs, left) 886 struct mbuf **mdp; 887 caddr_t *dposp; 888 int offs; 889 int left; 890 { 891 struct mbuf *m; 892 int s; 893 894 m = *mdp; 895 s = left; 896 while (s < offs) { 897 offs -= s; 898 m = m->m_next; 899 if (m == NULL) 900 return (EBADRPC); 901 s = m->m_len; 902 } 903 *mdp = m; 904 *dposp = mtod(m, caddr_t)+offs; 905 return (0); 906 } 907 908 /* 909 * Called once to initialize data structures... 910 */ 911 void 912 nfs_init() 913 { 914 static struct timeout nfs_timer_to; 915 916 nfsrtt.pos = 0; 917 rpc_vers = txdr_unsigned(RPC_VER2); 918 rpc_call = txdr_unsigned(RPC_CALL); 919 rpc_reply = txdr_unsigned(RPC_REPLY); 920 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 921 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 922 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 923 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 924 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 925 nfs_prog = txdr_unsigned(NFS_PROG); 926 nfs_true = txdr_unsigned(1); 927 nfs_false = txdr_unsigned(0); 928 nfs_xdrneg1 = txdr_unsigned(-1); 929 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 930 if (nfs_ticks < 1) 931 nfs_ticks = 1; 932 #ifdef NFSSERVER 933 nfsrv_init(0); /* Init server data structures */ 934 nfsrv_initcache(); /* Init the server request cache */ 935 #endif /* NFSSERVER */ 936 937 pool_init(&nfsreqpl, sizeof(struct nfsreq), 0, 0, 0, "nfsreqpl", 938 &pool_allocator_nointr); 939 940 /* 941 * Initialize reply list and start timer 942 */ 943 TAILQ_INIT(&nfs_reqq); 944 945 timeout_set(&nfs_timer_to, nfs_timer, &nfs_timer_to); 946 nfs_timer(&nfs_timer_to); 947 } 948 949 #ifdef NFSCLIENT 950 int 951 nfs_vfs_init(vfsp) 952 struct vfsconf *vfsp; 953 { 954 TAILQ_INIT(&nfs_bufq); 955 nfs_nhinit(); /* Init the nfsnode table */ 956 957 return (0); 958 } 959 960 /* 961 * Attribute cache routines. 962 * nfs_loadattrcache() - loads or updates the cache contents from attributes 963 * that are on the mbuf list 964 * nfs_getattrcache() - returns valid attributes if found in cache, returns 965 * error otherwise 966 */ 967 968 /* 969 * Load the attribute cache (that lives in the nfsnode entry) with 970 * the values on the mbuf list and 971 * Iff vap not NULL 972 * copy the attributes to *vaper 973 */ 974 int 975 nfs_loadattrcache(vpp, mdp, dposp, vaper) 976 struct vnode **vpp; 977 struct mbuf **mdp; 978 caddr_t *dposp; 979 struct vattr *vaper; 980 { 981 struct vnode *vp = *vpp; 982 struct vattr *vap; 983 struct nfs_fattr *fp; 984 extern int (**spec_nfsv2nodeop_p)(void *); 985 struct nfsnode *np; 986 int32_t t1; 987 caddr_t cp2; 988 int error = 0; 989 int32_t rdev; 990 struct mbuf *md; 991 enum vtype vtyp; 992 mode_t vmode; 993 struct timespec mtime; 994 struct vnode *nvp; 995 int v3 = NFS_ISV3(vp); 996 uid_t uid; 997 gid_t gid; 998 999 md = *mdp; 1000 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 1001 error = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1, &cp2); 1002 if (error) 1003 return (error); 1004 fp = (struct nfs_fattr *)cp2; 1005 if (v3) { 1006 vtyp = nfsv3tov_type(fp->fa_type); 1007 vmode = fxdr_unsigned(mode_t, fp->fa_mode); 1008 rdev = makedev(fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata1), 1009 fxdr_unsigned(u_int32_t, fp->fa3_rdev.specdata2)); 1010 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 1011 } else { 1012 vtyp = nfsv2tov_type(fp->fa_type); 1013 vmode = fxdr_unsigned(mode_t, fp->fa_mode); 1014 if (vtyp == VNON || vtyp == VREG) 1015 vtyp = IFTOVT(vmode); 1016 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 1017 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 1018 1019 /* 1020 * Really ugly NFSv2 kludge. 1021 */ 1022 if (vtyp == VCHR && rdev == 0xffffffff) 1023 vtyp = VFIFO; 1024 } 1025 1026 /* 1027 * If v_type == VNON it is a new node, so fill in the v_type, 1028 * n_mtime fields. Check to see if it represents a special 1029 * device, and if so, check for a possible alias. Once the 1030 * correct vnode has been obtained, fill in the rest of the 1031 * information. 1032 */ 1033 np = VTONFS(vp); 1034 if (vp->v_type != vtyp) { 1035 vp->v_type = vtyp; 1036 if (vp->v_type == VFIFO) { 1037 #ifndef FIFO 1038 return (EOPNOTSUPP); 1039 #else 1040 extern int (**fifo_nfsv2nodeop_p)(void *); 1041 vp->v_op = fifo_nfsv2nodeop_p; 1042 #endif /* FIFO */ 1043 } 1044 if (vp->v_type == VCHR || vp->v_type == VBLK) { 1045 vp->v_op = spec_nfsv2nodeop_p; 1046 nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 1047 if (nvp) { 1048 /* 1049 * Discard unneeded vnode, but save its nfsnode. 1050 * Since the nfsnode does not have a lock, its 1051 * vnode lock has to be carried over. 1052 */ 1053 1054 nvp->v_data = vp->v_data; 1055 vp->v_data = NULL; 1056 vp->v_op = spec_vnodeop_p; 1057 vrele(vp); 1058 vgone(vp); 1059 /* 1060 * Reinitialize aliased node. 1061 */ 1062 np->n_vnode = nvp; 1063 *vpp = vp = nvp; 1064 } 1065 } 1066 np->n_mtime = mtime; 1067 } 1068 vap = &np->n_vattr; 1069 vap->va_type = vtyp; 1070 vap->va_rdev = (dev_t)rdev; 1071 vap->va_mtime = mtime; 1072 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 1073 1074 uid = fxdr_unsigned(uid_t, fp->fa_uid); 1075 gid = fxdr_unsigned(gid_t, fp->fa_gid); 1076 /* Invalidate access cache if uid, gid or mode changed. */ 1077 if (np->n_accstamp != -1 && 1078 (gid != vap->va_gid || uid != vap->va_uid || 1079 (vmode & 07777) != vap->va_mode)) 1080 np->n_accstamp = -1; 1081 1082 vap->va_mode = (vmode & 07777); 1083 1084 switch (vtyp) { 1085 case VBLK: 1086 vap->va_blocksize = BLKDEV_IOSIZE; 1087 break; 1088 case VCHR: 1089 vap->va_blocksize = MAXBSIZE; 1090 break; 1091 default: 1092 vap->va_blocksize = v3 ? vp->v_mount->mnt_stat.f_iosize : 1093 fxdr_unsigned(int32_t, fp->fa2_blocksize); 1094 break; 1095 } 1096 if (v3) { 1097 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink); 1098 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1099 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1100 vap->va_size = fxdr_hyper(&fp->fa3_size); 1101 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 1102 vap->va_fileid = fxdr_unsigned(int32_t, 1103 fp->fa3_fileid.nfsuquad[1]); 1104 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 1105 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 1106 vap->va_flags = 0; 1107 vap->va_filerev = 0; 1108 } else { 1109 vap->va_nlink = fxdr_unsigned(nlink_t, fp->fa_nlink); 1110 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 1111 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 1112 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 1113 vap->va_bytes = 1114 (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) * 1115 NFS_FABLKSIZE; 1116 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 1117 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 1118 vap->va_flags = 0; 1119 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 1120 fp->fa2_ctime.nfsv2_sec); 1121 vap->va_ctime.tv_nsec = 0; 1122 vap->va_gen = fxdr_unsigned(u_int32_t,fp->fa2_ctime.nfsv2_usec); 1123 vap->va_filerev = 0; 1124 } 1125 1126 if (vap->va_size != np->n_size) { 1127 if (vap->va_type == VREG) { 1128 if (np->n_flag & NMODIFIED) { 1129 if (vap->va_size < np->n_size) 1130 vap->va_size = np->n_size; 1131 else 1132 np->n_size = vap->va_size; 1133 } else 1134 np->n_size = vap->va_size; 1135 uvm_vnp_setsize(vp, np->n_size); 1136 } else 1137 np->n_size = vap->va_size; 1138 } 1139 np->n_attrstamp = time_second; 1140 if (vaper != NULL) { 1141 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 1142 if (np->n_flag & NCHG) { 1143 if (np->n_flag & NACC) 1144 vaper->va_atime = np->n_atim; 1145 if (np->n_flag & NUPD) 1146 vaper->va_mtime = np->n_mtim; 1147 } 1148 } 1149 return (0); 1150 } 1151 1152 int 1153 nfs_attrtimeo (np) 1154 struct nfsnode *np; 1155 { 1156 struct vnode *vp = np->n_vnode; 1157 struct nfsmount *nmp = VFSTONFS(vp->v_mount); 1158 int tenthage = (time_second - np->n_mtime.tv_sec) / 10; 1159 int minto, maxto; 1160 1161 if (vp->v_type == VDIR) { 1162 maxto = nmp->nm_acdirmax; 1163 minto = nmp->nm_acdirmin; 1164 } 1165 else { 1166 maxto = nmp->nm_acregmax; 1167 minto = nmp->nm_acregmin; 1168 } 1169 1170 if (np->n_flag & NMODIFIED || tenthage < minto) 1171 return minto; 1172 else if (tenthage < maxto) 1173 return tenthage; 1174 else 1175 return maxto; 1176 } 1177 1178 /* 1179 * Check the time stamp 1180 * If the cache is valid, copy contents to *vap and return 0 1181 * otherwise return an error 1182 */ 1183 int 1184 nfs_getattrcache(vp, vaper) 1185 struct vnode *vp; 1186 struct vattr *vaper; 1187 { 1188 struct nfsnode *np = VTONFS(vp); 1189 struct vattr *vap; 1190 1191 if (np->n_attrstamp == 0 || 1192 (time_second - np->n_attrstamp) >= nfs_attrtimeo(np)) { 1193 nfsstats.attrcache_misses++; 1194 return (ENOENT); 1195 } 1196 nfsstats.attrcache_hits++; 1197 vap = &np->n_vattr; 1198 if (vap->va_size != np->n_size) { 1199 if (vap->va_type == VREG) { 1200 if (np->n_flag & NMODIFIED) { 1201 if (vap->va_size < np->n_size) 1202 vap->va_size = np->n_size; 1203 else 1204 np->n_size = vap->va_size; 1205 } else 1206 np->n_size = vap->va_size; 1207 uvm_vnp_setsize(vp, np->n_size); 1208 } else 1209 np->n_size = vap->va_size; 1210 } 1211 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 1212 if (np->n_flag & NCHG) { 1213 if (np->n_flag & NACC) 1214 vaper->va_atime = np->n_atim; 1215 if (np->n_flag & NUPD) 1216 vaper->va_mtime = np->n_mtim; 1217 } 1218 return (0); 1219 } 1220 #endif /* NFSCLIENT */ 1221 1222 /* 1223 * Set up nameidata for a lookup() call and do it 1224 */ 1225 int 1226 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, retdirp, p) 1227 struct nameidata *ndp; 1228 fhandle_t *fhp; 1229 int len; 1230 struct nfssvc_sock *slp; 1231 struct mbuf *nam; 1232 struct mbuf **mdp; 1233 caddr_t *dposp; 1234 struct vnode **retdirp; 1235 struct proc *p; 1236 { 1237 int i, rem; 1238 struct mbuf *md; 1239 char *fromcp, *tocp; 1240 struct vnode *dp; 1241 int error, rdonly; 1242 struct componentname *cnp = &ndp->ni_cnd; 1243 1244 *retdirp = (struct vnode *)0; 1245 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK); 1246 /* 1247 * Copy the name from the mbuf list to ndp->ni_pnbuf 1248 * and set the various ndp fields appropriately. 1249 */ 1250 fromcp = *dposp; 1251 tocp = cnp->cn_pnbuf; 1252 md = *mdp; 1253 rem = mtod(md, caddr_t) + md->m_len - fromcp; 1254 cnp->cn_hash = 0; 1255 for (i = 0; i < len; i++) { 1256 while (rem == 0) { 1257 md = md->m_next; 1258 if (md == NULL) { 1259 error = EBADRPC; 1260 goto out; 1261 } 1262 fromcp = mtod(md, caddr_t); 1263 rem = md->m_len; 1264 } 1265 if (*fromcp == '\0' || *fromcp == '/') { 1266 error = EACCES; 1267 goto out; 1268 } 1269 cnp->cn_hash += (u_char)*fromcp; 1270 *tocp++ = *fromcp++; 1271 rem--; 1272 } 1273 *tocp = '\0'; 1274 *mdp = md; 1275 *dposp = fromcp; 1276 len = nfsm_padlen(len); 1277 if (len > 0) { 1278 if (rem >= len) 1279 *dposp += len; 1280 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 1281 goto out; 1282 } 1283 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 1284 cnp->cn_nameptr = cnp->cn_pnbuf; 1285 /* 1286 * Extract and set starting directory. 1287 */ 1288 error = nfsrv_fhtovp(fhp, 0, &dp, ndp->ni_cnd.cn_cred, slp, 1289 nam, &rdonly); 1290 if (error) 1291 goto out; 1292 if (dp->v_type != VDIR) { 1293 vrele(dp); 1294 error = ENOTDIR; 1295 goto out; 1296 } 1297 VREF(dp); 1298 *retdirp = dp; 1299 ndp->ni_startdir = dp; 1300 if (rdonly) 1301 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 1302 else 1303 cnp->cn_flags |= NOCROSSMOUNT; 1304 /* 1305 * And call lookup() to do the real work 1306 */ 1307 cnp->cn_proc = p; 1308 error = lookup(ndp); 1309 if (error) 1310 goto out; 1311 /* 1312 * Check for encountering a symbolic link 1313 */ 1314 if (cnp->cn_flags & ISSYMLINK) { 1315 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 1316 vput(ndp->ni_dvp); 1317 else 1318 vrele(ndp->ni_dvp); 1319 vput(ndp->ni_vp); 1320 ndp->ni_vp = NULL; 1321 error = EINVAL; 1322 goto out; 1323 } 1324 /* 1325 * Check for saved name request 1326 */ 1327 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 1328 cnp->cn_flags |= HASBUF; 1329 return (0); 1330 } 1331 out: 1332 pool_put(&namei_pool, cnp->cn_pnbuf); 1333 return (error); 1334 } 1335 1336 /* 1337 * A fiddled version of m_adj() that ensures null fill to a long 1338 * boundary and only trims off the back end 1339 */ 1340 void 1341 nfsm_adj(mp, len, nul) 1342 struct mbuf *mp; 1343 int len; 1344 int nul; 1345 { 1346 struct mbuf *m; 1347 int count, i; 1348 char *cp; 1349 1350 /* 1351 * Trim from tail. Scan the mbuf chain, 1352 * calculating its length and finding the last mbuf. 1353 * If the adjustment only affects this mbuf, then just 1354 * adjust and return. Otherwise, rescan and truncate 1355 * after the remaining size. 1356 */ 1357 count = 0; 1358 m = mp; 1359 for (;;) { 1360 count += m->m_len; 1361 if (m->m_next == (struct mbuf *)0) 1362 break; 1363 m = m->m_next; 1364 } 1365 if (m->m_len > len) { 1366 m->m_len -= len; 1367 if (nul > 0) { 1368 cp = mtod(m, caddr_t)+m->m_len-nul; 1369 for (i = 0; i < nul; i++) 1370 *cp++ = '\0'; 1371 } 1372 return; 1373 } 1374 count -= len; 1375 if (count < 0) 1376 count = 0; 1377 /* 1378 * Correct length for chain is "count". 1379 * Find the mbuf with last data, adjust its length, 1380 * and toss data from remaining mbufs on chain. 1381 */ 1382 for (m = mp; m; m = m->m_next) { 1383 if (m->m_len >= count) { 1384 m->m_len = count; 1385 if (nul > 0) { 1386 cp = mtod(m, caddr_t)+m->m_len-nul; 1387 for (i = 0; i < nul; i++) 1388 *cp++ = '\0'; 1389 } 1390 break; 1391 } 1392 count -= m->m_len; 1393 } 1394 for (m = m->m_next;m;m = m->m_next) 1395 m->m_len = 0; 1396 } 1397 1398 /* 1399 * Make these functions instead of macros, so that the kernel text size 1400 * doesn't get too big... 1401 */ 1402 void 1403 nfsm_srvwcc(nfsd, before_ret, before_vap, after_ret, after_vap, mbp) 1404 struct nfsrv_descript *nfsd; 1405 int before_ret; 1406 struct vattr *before_vap; 1407 int after_ret; 1408 struct vattr *after_vap; 1409 struct mbuf **mbp; 1410 { 1411 struct mbuf *mb = *mbp; 1412 u_int32_t *tl; 1413 1414 if (before_ret) { 1415 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1416 *tl = nfs_false; 1417 } else { 1418 tl = nfsm_build(&mb, 7 * NFSX_UNSIGNED); 1419 *tl++ = nfs_true; 1420 txdr_hyper(before_vap->va_size, tl); 1421 tl += 2; 1422 txdr_nfsv3time(&(before_vap->va_mtime), tl); 1423 tl += 2; 1424 txdr_nfsv3time(&(before_vap->va_ctime), tl); 1425 } 1426 *mbp = mb; 1427 nfsm_srvpostop_attr(nfsd, after_ret, after_vap, mbp); 1428 } 1429 1430 void 1431 nfsm_srvpostop_attr(nfsd, after_ret, after_vap, mbp) 1432 struct nfsrv_descript *nfsd; 1433 int after_ret; 1434 struct vattr *after_vap; 1435 struct mbuf **mbp; 1436 { 1437 struct mbuf *mb = *mbp; 1438 u_int32_t *tl; 1439 struct nfs_fattr *fp; 1440 1441 if (after_ret) { 1442 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1443 *tl = nfs_false; 1444 } else { 1445 tl = nfsm_build(&mb, NFSX_UNSIGNED + NFSX_V3FATTR); 1446 *tl++ = nfs_true; 1447 fp = (struct nfs_fattr *)tl; 1448 nfsm_srvfattr(nfsd, after_vap, fp); 1449 } 1450 *mbp = mb; 1451 } 1452 1453 void 1454 nfsm_srvfattr(nfsd, vap, fp) 1455 struct nfsrv_descript *nfsd; 1456 struct vattr *vap; 1457 struct nfs_fattr *fp; 1458 { 1459 1460 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 1461 fp->fa_uid = txdr_unsigned(vap->va_uid); 1462 fp->fa_gid = txdr_unsigned(vap->va_gid); 1463 if (nfsd->nd_flag & ND_NFSV3) { 1464 fp->fa_type = vtonfsv3_type(vap->va_type); 1465 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 1466 txdr_hyper(vap->va_size, &fp->fa3_size); 1467 txdr_hyper(vap->va_bytes, &fp->fa3_used); 1468 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 1469 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 1470 fp->fa3_fsid.nfsuquad[0] = 0; 1471 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 1472 fp->fa3_fileid.nfsuquad[0] = 0; 1473 fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 1474 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 1475 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 1476 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 1477 } else { 1478 fp->fa_type = vtonfsv2_type(vap->va_type); 1479 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 1480 fp->fa2_size = txdr_unsigned(vap->va_size); 1481 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 1482 if (vap->va_type == VFIFO) 1483 fp->fa2_rdev = 0xffffffff; 1484 else 1485 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 1486 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 1487 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 1488 fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 1489 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 1490 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 1491 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 1492 } 1493 } 1494 1495 /* 1496 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1497 * - look up fsid in mount list (if not found ret error) 1498 * - get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP() 1499 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1500 * - if not lockflag unlock it with VOP_UNLOCK() 1501 */ 1502 int 1503 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 1504 fhandle_t *fhp; 1505 int lockflag; 1506 struct vnode **vpp; 1507 struct ucred *cred; 1508 struct nfssvc_sock *slp; 1509 struct mbuf *nam; 1510 int *rdonlyp; 1511 { 1512 struct proc *p = curproc; /* XXX */ 1513 struct mount *mp; 1514 int i; 1515 struct ucred *credanon; 1516 int error, exflags; 1517 struct sockaddr_in *saddr; 1518 1519 *vpp = (struct vnode *)0; 1520 mp = vfs_getvfs(&fhp->fh_fsid); 1521 1522 if (!mp) 1523 return (ESTALE); 1524 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 1525 if (error) 1526 return (error); 1527 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 1528 if (error) 1529 return (error); 1530 1531 saddr = mtod(nam, struct sockaddr_in *); 1532 if (saddr->sin_family == AF_INET && 1533 (ntohs(saddr->sin_port) >= IPPORT_RESERVED || 1534 (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) { 1535 vput(*vpp); 1536 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 1537 } 1538 1539 /* Check/setup credentials. */ 1540 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1541 cred->cr_uid = credanon->cr_uid; 1542 cred->cr_gid = credanon->cr_gid; 1543 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1544 cred->cr_groups[i] = credanon->cr_groups[i]; 1545 cred->cr_ngroups = i; 1546 } 1547 if (exflags & MNT_EXRDONLY) 1548 *rdonlyp = 1; 1549 else 1550 *rdonlyp = 0; 1551 if (!lockflag) 1552 VOP_UNLOCK(*vpp, 0, p); 1553 1554 return (0); 1555 } 1556 1557 /* 1558 * This function compares two net addresses by family and returns non zero 1559 * if they are the same host, or if there is any doubt it returns 0. 1560 * The AF_INET family is handled as a special case so that address mbufs 1561 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1562 */ 1563 int 1564 netaddr_match(family, haddr, nam) 1565 int family; 1566 union nethostaddr *haddr; 1567 struct mbuf *nam; 1568 { 1569 struct sockaddr_in *inetaddr; 1570 1571 switch (family) { 1572 case AF_INET: 1573 inetaddr = mtod(nam, struct sockaddr_in *); 1574 if (inetaddr->sin_family == AF_INET && 1575 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1576 return (1); 1577 break; 1578 default: 1579 break; 1580 }; 1581 return (0); 1582 } 1583 1584 /* 1585 * The write verifier has changed (probably due to a server reboot), so all 1586 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 1587 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 1588 * flag. Once done the new write verifier can be set for the mount point. 1589 */ 1590 void 1591 nfs_clearcommit(mp) 1592 struct mount *mp; 1593 { 1594 struct vnode *vp, *nvp; 1595 struct buf *bp, *nbp; 1596 int s; 1597 1598 s = splbio(); 1599 loop: 1600 for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp != NULL; vp = nvp) { 1601 if (vp->v_mount != mp) /* Paranoia */ 1602 goto loop; 1603 nvp = LIST_NEXT(vp, v_mntvnodes); 1604 for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp != NULL; bp = nbp) { 1605 nbp = LIST_NEXT(bp, b_vnbufs); 1606 if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT)) 1607 == (B_DELWRI | B_NEEDCOMMIT)) 1608 bp->b_flags &= ~B_NEEDCOMMIT; 1609 } 1610 } 1611 splx(s); 1612 } 1613 1614 void 1615 nfs_merge_commit_ranges(vp) 1616 struct vnode *vp; 1617 { 1618 struct nfsnode *np = VTONFS(vp); 1619 1620 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) { 1621 np->n_pushedlo = np->n_pushlo; 1622 np->n_pushedhi = np->n_pushhi; 1623 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID; 1624 } else { 1625 if (np->n_pushlo < np->n_pushedlo) 1626 np->n_pushedlo = np->n_pushlo; 1627 if (np->n_pushhi > np->n_pushedhi) 1628 np->n_pushedhi = np->n_pushhi; 1629 } 1630 1631 np->n_pushlo = np->n_pushhi = 0; 1632 np->n_commitflags &= ~NFS_COMMIT_PUSH_VALID; 1633 } 1634 1635 int 1636 nfs_in_committed_range(vp, bp) 1637 struct vnode *vp; 1638 struct buf *bp; 1639 { 1640 struct nfsnode *np = VTONFS(vp); 1641 off_t lo, hi; 1642 1643 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) 1644 return 0; 1645 lo = (off_t)bp->b_blkno * DEV_BSIZE; 1646 hi = lo + bp->b_dirtyend; 1647 1648 return (lo >= np->n_pushedlo && hi <= np->n_pushedhi); 1649 } 1650 1651 int 1652 nfs_in_tobecommitted_range(vp, bp) 1653 struct vnode *vp; 1654 struct buf *bp; 1655 { 1656 struct nfsnode *np = VTONFS(vp); 1657 off_t lo, hi; 1658 1659 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) 1660 return 0; 1661 lo = (off_t)bp->b_blkno * DEV_BSIZE; 1662 hi = lo + bp->b_dirtyend; 1663 1664 return (lo >= np->n_pushlo && hi <= np->n_pushhi); 1665 } 1666 1667 void 1668 nfs_add_committed_range(vp, bp) 1669 struct vnode *vp; 1670 struct buf *bp; 1671 { 1672 struct nfsnode *np = VTONFS(vp); 1673 off_t lo, hi; 1674 1675 lo = (off_t)bp->b_blkno * DEV_BSIZE; 1676 hi = lo + bp->b_dirtyend; 1677 1678 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) { 1679 np->n_pushedlo = lo; 1680 np->n_pushedhi = hi; 1681 np->n_commitflags |= NFS_COMMIT_PUSHED_VALID; 1682 } else { 1683 if (hi > np->n_pushedhi) 1684 np->n_pushedhi = hi; 1685 if (lo < np->n_pushedlo) 1686 np->n_pushedlo = lo; 1687 } 1688 } 1689 1690 void 1691 nfs_del_committed_range(vp, bp) 1692 struct vnode *vp; 1693 struct buf *bp; 1694 { 1695 struct nfsnode *np = VTONFS(vp); 1696 off_t lo, hi; 1697 1698 if (!(np->n_commitflags & NFS_COMMIT_PUSHED_VALID)) 1699 return; 1700 1701 lo = (off_t)bp->b_blkno * DEV_BSIZE; 1702 hi = lo + bp->b_dirtyend; 1703 1704 if (lo > np->n_pushedhi || hi < np->n_pushedlo) 1705 return; 1706 if (lo <= np->n_pushedlo) 1707 np->n_pushedlo = hi; 1708 else if (hi >= np->n_pushedhi) 1709 np->n_pushedhi = lo; 1710 else { 1711 /* 1712 * XXX There's only one range. If the deleted range 1713 * is in the middle, pick the largest of the 1714 * contiguous ranges that it leaves. 1715 */ 1716 if ((np->n_pushedlo - lo) > (hi - np->n_pushedhi)) 1717 np->n_pushedhi = lo; 1718 else 1719 np->n_pushedlo = hi; 1720 } 1721 } 1722 1723 void 1724 nfs_add_tobecommitted_range(vp, bp) 1725 struct vnode *vp; 1726 struct buf *bp; 1727 { 1728 struct nfsnode *np = VTONFS(vp); 1729 off_t lo, hi; 1730 1731 lo = (off_t)bp->b_blkno * DEV_BSIZE; 1732 hi = lo + bp->b_dirtyend; 1733 1734 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) { 1735 np->n_pushlo = lo; 1736 np->n_pushhi = hi; 1737 np->n_commitflags |= NFS_COMMIT_PUSH_VALID; 1738 } else { 1739 if (lo < np->n_pushlo) 1740 np->n_pushlo = lo; 1741 if (hi > np->n_pushhi) 1742 np->n_pushhi = hi; 1743 } 1744 } 1745 1746 void 1747 nfs_del_tobecommitted_range(vp, bp) 1748 struct vnode *vp; 1749 struct buf *bp; 1750 { 1751 struct nfsnode *np = VTONFS(vp); 1752 off_t lo, hi; 1753 1754 if (!(np->n_commitflags & NFS_COMMIT_PUSH_VALID)) 1755 return; 1756 1757 lo = (off_t)bp->b_blkno * DEV_BSIZE; 1758 hi = lo + bp->b_dirtyend; 1759 1760 if (lo > np->n_pushhi || hi < np->n_pushlo) 1761 return; 1762 1763 if (lo <= np->n_pushlo) 1764 np->n_pushlo = hi; 1765 else if (hi >= np->n_pushhi) 1766 np->n_pushhi = lo; 1767 else { 1768 /* 1769 * XXX There's only one range. If the deleted range 1770 * is in the middle, pick the largest of the 1771 * contiguous ranges that it leaves. 1772 */ 1773 if ((np->n_pushlo - lo) > (hi - np->n_pushhi)) 1774 np->n_pushhi = lo; 1775 else 1776 np->n_pushlo = hi; 1777 } 1778 } 1779 1780 /* 1781 * Map errnos to NFS error numbers. For Version 3 also filter out error 1782 * numbers not specified for the associated procedure. 1783 */ 1784 int 1785 nfsrv_errmap(nd, err) 1786 struct nfsrv_descript *nd; 1787 int err; 1788 { 1789 short *defaulterrp, *errp; 1790 1791 if (nd->nd_flag & ND_NFSV3) { 1792 if (nd->nd_procnum <= NFSPROC_COMMIT) { 1793 errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 1794 while (*++errp) { 1795 if (*errp == err) 1796 return (err); 1797 else if (*errp > err) 1798 break; 1799 } 1800 return ((int)*defaulterrp); 1801 } else 1802 return (err & 0xffff); 1803 } 1804 if (err <= nitems(nfsrv_v2errmap)) 1805 return ((int)nfsrv_v2errmap[err - 1]); 1806 return (NFSERR_IO); 1807 } 1808 1809 /* 1810 * Sort the group list in increasing numerical order. 1811 * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 1812 * that used to be here.) 1813 */ 1814 void 1815 nfsrvw_sort(list, num) 1816 gid_t *list; 1817 int num; 1818 { 1819 int i, j; 1820 gid_t v; 1821 1822 /* Insertion sort. */ 1823 for (i = 1; i < num; i++) { 1824 v = list[i]; 1825 /* find correct slot for value v, moving others up */ 1826 for (j = i; --j >= 0 && v < list[j];) 1827 list[j + 1] = list[j]; 1828 list[j + 1] = v; 1829 } 1830 } 1831 1832 /* 1833 * copy credentials making sure that the result can be compared with bcmp(). 1834 */ 1835 void 1836 nfsrv_setcred(incred, outcred) 1837 struct ucred *incred, *outcred; 1838 { 1839 int i; 1840 1841 bzero((caddr_t)outcred, sizeof (struct ucred)); 1842 outcred->cr_ref = 1; 1843 outcred->cr_uid = incred->cr_uid; 1844 outcred->cr_gid = incred->cr_gid; 1845 outcred->cr_ngroups = incred->cr_ngroups; 1846 for (i = 0; i < incred->cr_ngroups; i++) 1847 outcred->cr_groups[i] = incred->cr_groups[i]; 1848 nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 1849 } 1850 1851 /* 1852 * If full is non zero, set all fields, otherwise just set mode and time fields 1853 */ 1854 void 1855 nfsm_v3attrbuild(struct mbuf **mp, struct vattr *a, int full) 1856 { 1857 struct mbuf *mb; 1858 u_int32_t *tl; 1859 1860 mb = *mp; 1861 1862 if (a->va_mode != (mode_t)VNOVAL) { 1863 tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED); 1864 *tl++ = nfs_true; 1865 *tl = txdr_unsigned(a->va_mode); 1866 } else { 1867 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1868 *tl = nfs_false; 1869 } 1870 if (full && a->va_uid != (uid_t)VNOVAL) { 1871 tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED); 1872 *tl++ = nfs_true; 1873 *tl = txdr_unsigned(a->va_uid); 1874 } else { 1875 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1876 *tl = nfs_false; 1877 } 1878 if (full && a->va_gid != (gid_t)VNOVAL) { 1879 tl = nfsm_build(&mb, 2 * NFSX_UNSIGNED); 1880 *tl++ = nfs_true; 1881 *tl = txdr_unsigned((a)->va_gid); 1882 } else { 1883 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1884 *tl = nfs_false; 1885 } 1886 if (full && a->va_size != VNOVAL) { 1887 tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED); 1888 *tl++ = nfs_true; 1889 txdr_hyper(a->va_size, tl); 1890 } else { 1891 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1892 *tl = nfs_false; 1893 } 1894 if (a->va_atime.tv_sec != VNOVAL) { 1895 if (a->va_atime.tv_sec != time_second) { 1896 tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED); 1897 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1898 txdr_nfsv3time(&a->va_atime, tl); 1899 } else { 1900 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1901 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1902 } 1903 } else { 1904 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1905 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1906 } 1907 if (a->va_mtime.tv_sec != VNOVAL) { 1908 if (a->va_mtime.tv_sec != time_second) { 1909 tl = nfsm_build(&mb, 3 * NFSX_UNSIGNED); 1910 *tl++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1911 txdr_nfsv3time(&a->va_mtime, tl); 1912 } else { 1913 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1914 *tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1915 } 1916 } else { 1917 tl = nfsm_build(&mb, NFSX_UNSIGNED); 1918 *tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1919 } 1920 1921 *mp = mb; 1922 } 1923 1924 /* 1925 * Ensure a contiguous buffer len bytes long 1926 */ 1927 void * 1928 nfsm_build(struct mbuf **mp, u_int len) 1929 { 1930 struct mbuf *mb, *mb2; 1931 caddr_t bpos; 1932 1933 mb = *mp; 1934 bpos = mb_offset(mb); 1935 1936 if (len > M_TRAILINGSPACE(mb)) { 1937 MGET(mb2, M_WAIT, MT_DATA); 1938 if (len > MLEN) 1939 panic("build > MLEN"); 1940 mb->m_next = mb2; 1941 mb = mb2; 1942 mb->m_len = 0; 1943 bpos = mtod(mb, caddr_t); 1944 } 1945 mb->m_len += len; 1946 1947 *mp = mb; 1948 1949 return (bpos); 1950 } 1951 1952 int 1953 nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep, 1954 caddr_t *dposp) 1955 { 1956 struct mbuf *md; 1957 uint32_t *tl, t1; 1958 caddr_t dpos, cp2; 1959 int error = 0; 1960 1961 md = *mp; 1962 dpos = *dposp; 1963 1964 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1965 if (*tl == nfs_true) { 1966 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1967 va->va_mode = nfstov_mode(*tl); 1968 } 1969 1970 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1971 if (*tl == nfs_true) { 1972 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1973 va->va_uid = fxdr_unsigned(uid_t, *tl); 1974 } 1975 1976 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1977 if (*tl == nfs_true) { 1978 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1979 va->va_gid = fxdr_unsigned(gid_t, *tl); 1980 } 1981 1982 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1983 if (*tl == nfs_true) { 1984 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1985 va->va_size = fxdr_hyper(tl); 1986 } 1987 1988 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 1989 switch (fxdr_unsigned(int, *tl)) { 1990 case NFSV3SATTRTIME_TOCLIENT: 1991 va->va_vaflags &= ~VA_UTIMES_NULL; 1992 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 1993 fxdr_nfsv3time(tl, &va->va_atime); 1994 break; 1995 case NFSV3SATTRTIME_TOSERVER: 1996 getnanotime(&va->va_atime); 1997 break; 1998 }; 1999 2000 nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED); 2001 switch (fxdr_unsigned(int, *tl)) { 2002 case NFSV3SATTRTIME_TOCLIENT: 2003 va->va_vaflags &= ~VA_UTIMES_NULL; 2004 nfsm_dissect(tl, u_int32_t *, 2 * NFSX_UNSIGNED); 2005 fxdr_nfsv3time(tl, &va->va_mtime); 2006 break; 2007 case NFSV3SATTRTIME_TOSERVER: 2008 getnanotime(&va->va_mtime); 2009 break; 2010 }; 2011 2012 *dposp = dpos; 2013 *mp = md; 2014 nfsmout: 2015 return (error); 2016 } 2017