nfs_subs.c revision 84057
1185029Spjd/* 2185029Spjd * Copyright (c) 1989, 1993 3185029Spjd * The Regents of the University of California. All rights reserved. 4185029Spjd * 5185029Spjd * This code is derived from software contributed to Berkeley by 6185029Spjd * Rick Macklem at The University of Guelph. 7185029Spjd * 8185029Spjd * Redistribution and use in source and binary forms, with or without 9185029Spjd * modification, are permitted provided that the following conditions 10185029Spjd * are met: 11185029Spjd * 1. Redistributions of source code must retain the above copyright 12185029Spjd * notice, this list of conditions and the following disclaimer. 13185029Spjd * 2. Redistributions in binary form must reproduce the above copyright 14185029Spjd * notice, this list of conditions and the following disclaimer in the 15185029Spjd * documentation and/or other materials provided with the distribution. 16185029Spjd * 3. All advertising materials mentioning features or use of this software 17185029Spjd * must display the following acknowledgement: 18185029Spjd * This product includes software developed by the University of 19185029Spjd * California, Berkeley and its contributors. 20185029Spjd * 4. Neither the name of the University nor the names of its contributors 21185029Spjd * may be used to endorse or promote products derived from this software 22219089Spjd * without specific prior written permission. 23185029Spjd * 24185029Spjd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25185029Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26185029Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27185029Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28185029Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29185029Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30185029Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31185029Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32185029Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33185029Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34185029Spjd * SUCH DAMAGE. 35185029Spjd * 36185029Spjd * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 37185029Spjd */ 38185029Spjd 39185029Spjd#include <sys/cdefs.h> 40185029Spjd__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_subs.c 84057 2001-09-27 22:40:38Z peter $"); 41185029Spjd 42185029Spjd/* 43185029Spjd * These functions support the macros and help fiddle mbuf chains for 44185029Spjd * the nfs op functions. They do things like create the rpc header and 45185029Spjd * copy data between mbuf chains and uio lists. 46185029Spjd */ 47185029Spjd 48185029Spjd#include <sys/param.h> 49185029Spjd#include <sys/systm.h> 50185029Spjd#include <sys/kernel.h> 51185029Spjd#include <sys/bio.h> 52185029Spjd#include <sys/buf.h> 53185029Spjd#include <sys/proc.h> 54219089Spjd#include <sys/mount.h> 55185029Spjd#include <sys/vnode.h> 56185029Spjd#include <sys/namei.h> 57185029Spjd#include <sys/mbuf.h> 58185029Spjd#include <sys/socket.h> 59185029Spjd#include <sys/stat.h> 60185029Spjd#include <sys/malloc.h> 61185029Spjd#include <sys/sysent.h> 62185029Spjd#include <sys/syscall.h> 63185029Spjd#include <sys/sysproto.h> 64185029Spjd 65185029Spjd#include <vm/vm.h> 66185029Spjd#include <vm/vm_object.h> 67185029Spjd#include <vm/vm_extern.h> 68185029Spjd#include <vm/vm_zone.h> 69185029Spjd 70185029Spjd#include <nfs/rpcv2.h> 71185029Spjd#include <nfs/nfsproto.h> 72185029Spjd#include <nfsclient/nfs.h> 73185029Spjd#include <nfsclient/nfsnode.h> 74185029Spjd#include <nfs/xdr_subs.h> 75185029Spjd#include <nfsclient/nfsm_subs.h> 76185029Spjd#include <nfsclient/nfsmount.h> 77185029Spjd 78185029Spjd#include <netinet/in.h> 79185029Spjd 80185029Spjd/* 81185029Spjd * Data items converted to xdr at startup, since they are constant 82185029Spjd * This is kinda hokey, but may save a little time doing byte swaps 83185029Spjd */ 84185029Spjdu_int32_t nfs_xdrneg1; 85185029Spjdu_int32_t rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 86185029Spjd rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 87185029Spjdu_int32_t nfs_true, nfs_false; 88185029Spjd 89185029Spjd/* And other global data */ 90185029Spjdstatic u_int32_t nfs_xid = 0; 91185029Spjdstatic enum vtype nv2tov_type[8]= { 92185029Spjd VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON, VNON 93185029Spjd}; 94185029Spjd 95185029Spjdint nfs_ticks; 96185029Spjdint nfs_pbuf_freecnt = -1; /* start out unlimited */ 97185029Spjd 98185029Spjdstruct nfs_reqq nfs_reqq; 99185029Spjdstruct nfs_bufq nfs_bufq; 100185029Spjd 101185029Spjdstatic int nfs_prev_nfsclnt_sy_narg; 102185029Spjdstatic sy_call_t *nfs_prev_nfsclnt_sy_call; 103185029Spjd 104185029Spjd/* 105185029Spjd * and the reverse mapping from generic to Version 2 procedure numbers 106185029Spjd */ 107185029Spjdint nfsv2_procid[NFS_NPROCS] = { 108185029Spjd NFSV2PROC_NULL, 109185029Spjd NFSV2PROC_GETATTR, 110185029Spjd NFSV2PROC_SETATTR, 111185029Spjd NFSV2PROC_LOOKUP, 112185029Spjd NFSV2PROC_NOOP, 113185029Spjd NFSV2PROC_READLINK, 114185029Spjd NFSV2PROC_READ, 115185029Spjd NFSV2PROC_WRITE, 116185029Spjd NFSV2PROC_CREATE, 117185029Spjd NFSV2PROC_MKDIR, 118185029Spjd NFSV2PROC_SYMLINK, 119185029Spjd NFSV2PROC_CREATE, 120185029Spjd NFSV2PROC_REMOVE, 121185029Spjd NFSV2PROC_RMDIR, 122185029Spjd NFSV2PROC_RENAME, 123185029Spjd NFSV2PROC_LINK, 124185029Spjd NFSV2PROC_READDIR, 125185029Spjd NFSV2PROC_NOOP, 126185029Spjd NFSV2PROC_STATFS, 127185029Spjd NFSV2PROC_NOOP, 128185029Spjd NFSV2PROC_NOOP, 129185029Spjd NFSV2PROC_NOOP, 130185029Spjd NFSV2PROC_NOOP, 131185029Spjd}; 132185029Spjd 133185029SpjdLIST_HEAD(nfsnodehashhead, nfsnode); 134185029Spjd 135185029Spjd/* 136185029Spjd * Create the header for an rpc request packet 137185029Spjd * The hsiz is the size of the rest of the nfs request header. 138185029Spjd * (just used to decide if a cluster is a good idea) 139185029Spjd */ 140185029Spjdstruct mbuf * 141185029Spjdnfsm_reqhead(struct vnode *vp, u_long procid, int hsiz) 142185029Spjd{ 143185029Spjd struct mbuf *mb; 144185029Spjd 145185029Spjd MGET(mb, M_TRYWAIT, MT_DATA); 146185029Spjd if (hsiz >= MINCLSIZE) 147185029Spjd MCLGET(mb, M_TRYWAIT); 148185029Spjd mb->m_len = 0; 149185029Spjd return (mb); 150185029Spjd} 151185029Spjd 152185029Spjd/* 153185029Spjd * Build the RPC header and fill in the authorization info. 154185029Spjd * The authorization string argument is only used when the credentials 155185029Spjd * come from outside of the kernel. 156185029Spjd * Returns the head of the mbuf list. 157185029Spjd */ 158185029Spjdstruct mbuf * 159185029Spjdnfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type, 160185029Spjd int auth_len, struct mbuf *mrest, int mrest_len, struct mbuf **mbp, 161185029Spjd u_int32_t *xidp) 162185029Spjd{ 163185029Spjd struct mbuf *mb; 164185029Spjd u_int32_t *tl; 165185029Spjd caddr_t bpos; 166185029Spjd int i; 167185029Spjd struct mbuf *mreq; 168185029Spjd int grpsiz, authsiz; 169185029Spjd 170185029Spjd authsiz = nfsm_rndup(auth_len); 171185029Spjd MGETHDR(mb, M_TRYWAIT, MT_DATA); 172185029Spjd if ((authsiz + 10 * NFSX_UNSIGNED) >= MINCLSIZE) { 173185029Spjd MCLGET(mb, M_TRYWAIT); 174185029Spjd } else if ((authsiz + 10 * NFSX_UNSIGNED) < MHLEN) { 175185029Spjd MH_ALIGN(mb, authsiz + 10 * NFSX_UNSIGNED); 176185029Spjd } else { 177185029Spjd MH_ALIGN(mb, 8 * NFSX_UNSIGNED); 178185029Spjd } 179185029Spjd mb->m_len = 0; 180185029Spjd mreq = mb; 181185029Spjd bpos = mtod(mb, caddr_t); 182219089Spjd 183219089Spjd /* 184185029Spjd * First the RPC header. 185185029Spjd */ 186185029Spjd tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED); 187185029Spjd 188185029Spjd /* Get a pretty random xid to start with */ 189185029Spjd if (!nfs_xid) 190185029Spjd nfs_xid = random(); 191185029Spjd /* 192185029Spjd * Skip zero xid if it should ever happen. 193185029Spjd */ 194185029Spjd if (++nfs_xid == 0) 195185029Spjd nfs_xid++; 196185029Spjd 197185029Spjd *tl++ = *xidp = txdr_unsigned(nfs_xid); 198185029Spjd *tl++ = rpc_call; 199185029Spjd *tl++ = rpc_vers; 200185029Spjd *tl++ = txdr_unsigned(NFS_PROG); 201185029Spjd if (nmflag & NFSMNT_NFSV3) { 202185029Spjd *tl++ = txdr_unsigned(NFS_VER3); 203185029Spjd *tl++ = txdr_unsigned(procid); 204185029Spjd } else { 205219089Spjd *tl++ = txdr_unsigned(NFS_VER2); 206219089Spjd *tl++ = txdr_unsigned(nfsv2_procid[procid]); 207219089Spjd } 208219089Spjd 209219089Spjd /* 210185029Spjd * And then the authorization cred. 211185029Spjd */ 212219089Spjd *tl++ = txdr_unsigned(auth_type); 213219089Spjd *tl = txdr_unsigned(authsiz); 214219089Spjd switch (auth_type) { 215185029Spjd case RPCAUTH_UNIX: 216185029Spjd tl = nfsm_build(u_int32_t *, auth_len); 217185029Spjd *tl++ = 0; /* stamp ?? */ 218185029Spjd *tl++ = 0; /* NULL hostname */ 219185029Spjd *tl++ = txdr_unsigned(cr->cr_uid); 220185029Spjd *tl++ = txdr_unsigned(cr->cr_groups[0]); 221185029Spjd grpsiz = (auth_len >> 2) - 5; 222185029Spjd *tl++ = txdr_unsigned(grpsiz); 223185029Spjd for (i = 1; i <= grpsiz; i++) 224185029Spjd *tl++ = txdr_unsigned(cr->cr_groups[i]); 225185029Spjd break; 226185029Spjd } 227185029Spjd 228185029Spjd /* 229185029Spjd * And the verifier... 230185029Spjd */ 231185029Spjd tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED); 232185029Spjd *tl++ = txdr_unsigned(RPCAUTH_NULL); 233185029Spjd *tl = 0; 234185029Spjd mb->m_next = mrest; 235219089Spjd mreq->m_pkthdr.len = authsiz + 10 * NFSX_UNSIGNED + mrest_len; 236219089Spjd mreq->m_pkthdr.rcvif = (struct ifnet *)0; 237219089Spjd *mbp = mb; 238219089Spjd return (mreq); 239219089Spjd} 240219089Spjd 241219089Spjd/* 242219089Spjd * copies a uio scatter/gather list to an mbuf chain. 243219089Spjd * NOTE: can ony handle iovcnt == 1 244185029Spjd */ 245185029Spjdint 246185029Spjdnfsm_uiotombuf(struct uio *uiop, struct mbuf **mq, int siz, caddr_t *bpos) 247185029Spjd{ 248219089Spjd char *uiocp; 249219089Spjd struct mbuf *mp, *mp2; 250219089Spjd int xfer, left, mlen; 251219089Spjd int uiosiz, clflg, rem; 252219089Spjd char *cp; 253219089Spjd 254219089Spjd#ifdef DIAGNOSTIC 255219089Spjd if (uiop->uio_iovcnt != 1) 256219089Spjd panic("nfsm_uiotombuf: iovcnt != 1"); 257219089Spjd#endif 258219089Spjd 259219089Spjd if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 260185029Spjd clflg = 1; 261185029Spjd else 262185029Spjd clflg = 0; 263185029Spjd rem = nfsm_rndup(siz)-siz; 264185029Spjd mp = mp2 = *mq; 265185029Spjd while (siz > 0) { 266219089Spjd left = uiop->uio_iov->iov_len; 267219089Spjd uiocp = uiop->uio_iov->iov_base; 268219089Spjd if (left > siz) 269219089Spjd left = siz; 270219089Spjd uiosiz = left; 271219089Spjd while (left > 0) { 272185029Spjd mlen = M_TRAILINGSPACE(mp); 273185029Spjd if (mlen == 0) { 274185029Spjd MGET(mp, M_TRYWAIT, MT_DATA); 275185029Spjd if (clflg) 276185029Spjd MCLGET(mp, M_TRYWAIT); 277 mp->m_len = 0; 278 mp2->m_next = mp; 279 mp2 = mp; 280 mlen = M_TRAILINGSPACE(mp); 281 } 282 xfer = (left > mlen) ? mlen : left; 283#ifdef notdef 284 /* Not Yet.. */ 285 if (uiop->uio_iov->iov_op != NULL) 286 (*(uiop->uio_iov->iov_op)) 287 (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 288 else 289#endif 290 if (uiop->uio_segflg == UIO_SYSSPACE) 291 bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 292 else 293 copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 294 mp->m_len += xfer; 295 left -= xfer; 296 uiocp += xfer; 297 uiop->uio_offset += xfer; 298 uiop->uio_resid -= xfer; 299 } 300 uiop->uio_iov->iov_base += uiosiz; 301 uiop->uio_iov->iov_len -= uiosiz; 302 siz -= uiosiz; 303 } 304 if (rem > 0) { 305 if (rem > M_TRAILINGSPACE(mp)) { 306 MGET(mp, M_TRYWAIT, MT_DATA); 307 mp->m_len = 0; 308 mp2->m_next = mp; 309 } 310 cp = mtod(mp, caddr_t)+mp->m_len; 311 for (left = 0; left < rem; left++) 312 *cp++ = '\0'; 313 mp->m_len += rem; 314 *bpos = cp; 315 } else 316 *bpos = mtod(mp, caddr_t)+mp->m_len; 317 *mq = mp; 318 return (0); 319} 320 321/* 322 * Copy a string into mbufs for the hard cases... 323 */ 324int 325nfsm_strtmbuf(struct mbuf **mb, char **bpos, const char *cp, long siz) 326{ 327 struct mbuf *m1 = NULL, *m2; 328 long left, xfer, len, tlen; 329 u_int32_t *tl; 330 int putsize; 331 332 putsize = 1; 333 m2 = *mb; 334 left = M_TRAILINGSPACE(m2); 335 if (left > 0) { 336 tl = ((u_int32_t *)(*bpos)); 337 *tl++ = txdr_unsigned(siz); 338 putsize = 0; 339 left -= NFSX_UNSIGNED; 340 m2->m_len += NFSX_UNSIGNED; 341 if (left > 0) { 342 bcopy(cp, (caddr_t) tl, left); 343 siz -= left; 344 cp += left; 345 m2->m_len += left; 346 left = 0; 347 } 348 } 349 /* Loop around adding mbufs */ 350 while (siz > 0) { 351 MGET(m1, M_TRYWAIT, MT_DATA); 352 if (siz > MLEN) 353 MCLGET(m1, M_TRYWAIT); 354 m1->m_len = NFSMSIZ(m1); 355 m2->m_next = m1; 356 m2 = m1; 357 tl = mtod(m1, u_int32_t *); 358 tlen = 0; 359 if (putsize) { 360 *tl++ = txdr_unsigned(siz); 361 m1->m_len -= NFSX_UNSIGNED; 362 tlen = NFSX_UNSIGNED; 363 putsize = 0; 364 } 365 if (siz < m1->m_len) { 366 len = nfsm_rndup(siz); 367 xfer = siz; 368 if (xfer < len) 369 *(tl+(xfer>>2)) = 0; 370 } else { 371 xfer = len = m1->m_len; 372 } 373 bcopy(cp, (caddr_t) tl, xfer); 374 m1->m_len = len+tlen; 375 siz -= xfer; 376 cp += xfer; 377 } 378 *mb = m1; 379 *bpos = mtod(m1, caddr_t)+m1->m_len; 380 return (0); 381} 382 383/* 384 * Called once to initialize data structures... 385 */ 386int 387nfs_init(struct vfsconf *vfsp) 388{ 389 int i; 390 391 nfsmount_zone = zinit("NFSMOUNT", sizeof(struct nfsmount), 0, 0, 1); 392 rpc_vers = txdr_unsigned(RPC_VER2); 393 rpc_call = txdr_unsigned(RPC_CALL); 394 rpc_reply = txdr_unsigned(RPC_REPLY); 395 rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 396 rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 397 rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 398 rpc_autherr = txdr_unsigned(RPC_AUTHERR); 399 rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 400 nfs_true = txdr_unsigned(TRUE); 401 nfs_false = txdr_unsigned(FALSE); 402 nfs_xdrneg1 = txdr_unsigned(-1); 403 nfs_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 404 if (nfs_ticks < 1) 405 nfs_ticks = 1; 406 /* Ensure async daemons disabled */ 407 for (i = 0; i < NFS_MAXASYNCDAEMON; i++) { 408 nfs_iodwant[i] = (struct proc *)0; 409 nfs_iodmount[i] = (struct nfsmount *)0; 410 } 411 nfs_nhinit(); /* Init the nfsnode table */ 412 413 /* 414 * Initialize reply list and start timer 415 */ 416 TAILQ_INIT(&nfs_reqq); 417 418 nfs_timer(0); 419 420 nfs_prev_nfsclnt_sy_narg = sysent[SYS_nfsclnt].sy_narg; 421 sysent[SYS_nfsclnt].sy_narg = 2; 422 nfs_prev_nfsclnt_sy_call = sysent[SYS_nfsclnt].sy_call; 423 sysent[SYS_nfsclnt].sy_call = (sy_call_t *)nfsclnt; 424 425 nfs_pbuf_freecnt = nswbuf / 2 + 1; 426 427 return (0); 428} 429 430int 431nfs_uninit(struct vfsconf *vfsp) 432{ 433 434 untimeout(nfs_timer, (void *)NULL, nfs_timer_handle); 435 sysent[SYS_nfsclnt].sy_narg = nfs_prev_nfsclnt_sy_narg; 436 sysent[SYS_nfsclnt].sy_call = nfs_prev_nfsclnt_sy_call; 437 return (0); 438} 439 440/* 441 * Attribute cache routines. 442 * nfs_loadattrcache() - loads or updates the cache contents from attributes 443 * that are on the mbuf list 444 * nfs_getattrcache() - returns valid attributes if found in cache, returns 445 * error otherwise 446 */ 447 448/* 449 * Load the attribute cache (that lives in the nfsnode entry) with 450 * the values on the mbuf list and 451 * Iff vap not NULL 452 * copy the attributes to *vaper 453 */ 454int 455nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp, 456 struct vattr *vaper, int dontshrink) 457{ 458 struct vnode *vp = *vpp; 459 struct vattr *vap; 460 struct nfs_fattr *fp; 461 struct nfsnode *np; 462 int32_t t1; 463 caddr_t cp2; 464 int rdev; 465 struct mbuf *md; 466 enum vtype vtyp; 467 u_short vmode; 468 struct timespec mtime; 469 int v3 = NFS_ISV3(vp); 470 471 md = *mdp; 472 t1 = (mtod(md, caddr_t) + md->m_len) - *dposp; 473 cp2 = nfsm_disct(mdp, dposp, NFSX_FATTR(v3), t1); 474 if (cp2 == NULL) 475 return EBADRPC; 476 fp = (struct nfs_fattr *)cp2; 477 if (v3) { 478 vtyp = nfsv3tov_type(fp->fa_type); 479 vmode = fxdr_unsigned(u_short, fp->fa_mode); 480 rdev = makeudev(fxdr_unsigned(int, fp->fa3_rdev.specdata1), 481 fxdr_unsigned(int, fp->fa3_rdev.specdata2)); 482 fxdr_nfsv3time(&fp->fa3_mtime, &mtime); 483 } else { 484 vtyp = nfsv2tov_type(fp->fa_type); 485 vmode = fxdr_unsigned(u_short, fp->fa_mode); 486 /* 487 * XXX 488 * 489 * The duplicate information returned in fa_type and fa_mode 490 * is an ambiguity in the NFS version 2 protocol. 491 * 492 * VREG should be taken literally as a regular file. If a 493 * server intents to return some type information differently 494 * in the upper bits of the mode field (e.g. for sockets, or 495 * FIFOs), NFSv2 mandates fa_type to be VNON. Anyway, we 496 * leave the examination of the mode bits even in the VREG 497 * case to avoid breakage for bogus servers, but we make sure 498 * that there are actually type bits set in the upper part of 499 * fa_mode (and failing that, trust the va_type field). 500 * 501 * NFSv3 cleared the issue, and requires fa_mode to not 502 * contain any type information (while also introduing sockets 503 * and FIFOs for fa_type). 504 */ 505 if (vtyp == VNON || (vtyp == VREG && (vmode & S_IFMT) != 0)) 506 vtyp = IFTOVT(vmode); 507 rdev = fxdr_unsigned(int32_t, fp->fa2_rdev); 508 fxdr_nfsv2time(&fp->fa2_mtime, &mtime); 509 510 /* 511 * Really ugly NFSv2 kludge. 512 */ 513 if (vtyp == VCHR && rdev == 0xffffffff) 514 vtyp = VFIFO; 515 } 516 517 /* 518 * If v_type == VNON it is a new node, so fill in the v_type, 519 * n_mtime fields. Check to see if it represents a special 520 * device, and if so, check for a possible alias. Once the 521 * correct vnode has been obtained, fill in the rest of the 522 * information. 523 */ 524 np = VTONFS(vp); 525 if (vp->v_type != vtyp) { 526 vp->v_type = vtyp; 527 if (vp->v_type == VFIFO) { 528 vp->v_op = fifo_nfsv2nodeop_p; 529 } 530 if (vp->v_type == VCHR || vp->v_type == VBLK) { 531 vp->v_op = spec_nfsv2nodeop_p; 532 vp = addaliasu(vp, rdev); 533 np->n_vnode = vp; 534 } 535 np->n_mtime = mtime.tv_sec; 536 } 537 vap = &np->n_vattr; 538 vap->va_type = vtyp; 539 vap->va_mode = (vmode & 07777); 540 vap->va_rdev = rdev; 541 vap->va_mtime = mtime; 542 vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 543 if (v3) { 544 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 545 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 546 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 547 vap->va_size = fxdr_hyper(&fp->fa3_size); 548 vap->va_blocksize = NFS_FABLKSIZE; 549 vap->va_bytes = fxdr_hyper(&fp->fa3_used); 550 vap->va_fileid = fxdr_unsigned(int32_t, 551 fp->fa3_fileid.nfsuquad[1]); 552 fxdr_nfsv3time(&fp->fa3_atime, &vap->va_atime); 553 fxdr_nfsv3time(&fp->fa3_ctime, &vap->va_ctime); 554 vap->va_flags = 0; 555 vap->va_filerev = 0; 556 } else { 557 vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 558 vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 559 vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 560 vap->va_size = fxdr_unsigned(u_int32_t, fp->fa2_size); 561 vap->va_blocksize = fxdr_unsigned(int32_t, fp->fa2_blocksize); 562 vap->va_bytes = (u_quad_t)fxdr_unsigned(int32_t, fp->fa2_blocks) 563 * NFS_FABLKSIZE; 564 vap->va_fileid = fxdr_unsigned(int32_t, fp->fa2_fileid); 565 fxdr_nfsv2time(&fp->fa2_atime, &vap->va_atime); 566 vap->va_flags = 0; 567 vap->va_ctime.tv_sec = fxdr_unsigned(u_int32_t, 568 fp->fa2_ctime.nfsv2_sec); 569 vap->va_ctime.tv_nsec = 0; 570 vap->va_gen = fxdr_unsigned(u_int32_t, fp->fa2_ctime.nfsv2_usec); 571 vap->va_filerev = 0; 572 } 573 np->n_attrstamp = time_second; 574 if (vap->va_size != np->n_size) { 575 if (vap->va_type == VREG) { 576 if (dontshrink && vap->va_size < np->n_size) { 577 /* 578 * We've been told not to shrink the file; 579 * zero np->n_attrstamp to indicate that 580 * the attributes are stale. 581 */ 582 vap->va_size = np->n_size; 583 np->n_attrstamp = 0; 584 } else if (np->n_flag & NMODIFIED) { 585 if (vap->va_size < np->n_size) 586 vap->va_size = np->n_size; 587 else 588 np->n_size = vap->va_size; 589 } else { 590 np->n_size = vap->va_size; 591 } 592 vnode_pager_setsize(vp, np->n_size); 593 } else { 594 np->n_size = vap->va_size; 595 } 596 } 597 if (vaper != NULL) { 598 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 599 if (np->n_flag & NCHG) { 600 if (np->n_flag & NACC) 601 vaper->va_atime = np->n_atim; 602 if (np->n_flag & NUPD) 603 vaper->va_mtime = np->n_mtim; 604 } 605 } 606 return (0); 607} 608 609#ifdef NFS_ACDEBUG 610#include <sys/sysctl.h> 611SYSCTL_DECL(_vfs_nfs); 612static int nfs_acdebug; 613SYSCTL_INT(_vfs_nfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 614#endif 615 616/* 617 * Check the time stamp 618 * If the cache is valid, copy contents to *vap and return 0 619 * otherwise return an error 620 */ 621int 622nfs_getattrcache(struct vnode *vp, struct vattr *vaper) 623{ 624 struct nfsnode *np; 625 struct vattr *vap; 626 struct nfsmount *nmp; 627 int timeo; 628 629 np = VTONFS(vp); 630 vap = &np->n_vattr; 631 nmp = VFSTONFS(vp->v_mount); 632 /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 633 timeo = (time_second - np->n_mtime) / 10; 634 635#ifdef NFS_ACDEBUG 636 if (nfs_acdebug>1) 637 printf("nfs_getattrcache: initial timeo = %d\n", timeo); 638#endif 639 640 if (vap->va_type == VDIR) { 641 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 642 timeo = nmp->nm_acdirmin; 643 else if (timeo > nmp->nm_acdirmax) 644 timeo = nmp->nm_acdirmax; 645 } else { 646 if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 647 timeo = nmp->nm_acregmin; 648 else if (timeo > nmp->nm_acregmax) 649 timeo = nmp->nm_acregmax; 650 } 651 652#ifdef NFS_ACDEBUG 653 if (nfs_acdebug > 2) 654 printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 655 nmp->nm_acregmin, nmp->nm_acregmax, 656 nmp->nm_acdirmin, nmp->nm_acdirmax); 657 658 if (nfs_acdebug) 659 printf("nfs_getattrcache: age = %d; final timeo = %d\n", 660 (time_second - np->n_attrstamp), timeo); 661#endif 662 663 if ((time_second - np->n_attrstamp) >= timeo) { 664 nfsstats.attrcache_misses++; 665 return (ENOENT); 666 } 667 nfsstats.attrcache_hits++; 668 if (vap->va_size != np->n_size) { 669 if (vap->va_type == VREG) { 670 if (np->n_flag & NMODIFIED) { 671 if (vap->va_size < np->n_size) 672 vap->va_size = np->n_size; 673 else 674 np->n_size = vap->va_size; 675 } else { 676 np->n_size = vap->va_size; 677 } 678 vnode_pager_setsize(vp, np->n_size); 679 } else { 680 np->n_size = vap->va_size; 681 } 682 } 683 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 684 if (np->n_flag & NCHG) { 685 if (np->n_flag & NACC) 686 vaper->va_atime = np->n_atim; 687 if (np->n_flag & NUPD) 688 vaper->va_mtime = np->n_mtim; 689 } 690 return (0); 691} 692 693static nfsuint64 nfs_nullcookie = { { 0, 0 } }; 694/* 695 * This function finds the directory cookie that corresponds to the 696 * logical byte offset given. 697 */ 698nfsuint64 * 699nfs_getcookie(struct nfsnode *np, off_t off, int add) 700{ 701 struct nfsdmap *dp, *dp2; 702 int pos; 703 704 pos = (uoff_t)off / NFS_DIRBLKSIZ; 705 if (pos == 0 || off < 0) { 706#ifdef DIAGNOSTIC 707 if (add) 708 panic("nfs getcookie add at <= 0"); 709#endif 710 return (&nfs_nullcookie); 711 } 712 pos--; 713 dp = LIST_FIRST(&np->n_cookies); 714 if (!dp) { 715 if (add) { 716 MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 717 M_NFSDIROFF, M_WAITOK); 718 dp->ndm_eocookie = 0; 719 LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 720 } else 721 return ((nfsuint64 *)0); 722 } 723 while (pos >= NFSNUMCOOKIES) { 724 pos -= NFSNUMCOOKIES; 725 if (LIST_NEXT(dp, ndm_list)) { 726 if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 727 pos >= dp->ndm_eocookie) 728 return ((nfsuint64 *)0); 729 dp = LIST_NEXT(dp, ndm_list); 730 } else if (add) { 731 MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 732 M_NFSDIROFF, M_WAITOK); 733 dp2->ndm_eocookie = 0; 734 LIST_INSERT_AFTER(dp, dp2, ndm_list); 735 dp = dp2; 736 } else 737 return ((nfsuint64 *)0); 738 } 739 if (pos >= dp->ndm_eocookie) { 740 if (add) 741 dp->ndm_eocookie = pos + 1; 742 else 743 return ((nfsuint64 *)0); 744 } 745 return (&dp->ndm_cookies[pos]); 746} 747 748/* 749 * Invalidate cached directory information, except for the actual directory 750 * blocks (which are invalidated separately). 751 * Done mainly to avoid the use of stale offset cookies. 752 */ 753void 754nfs_invaldir(struct vnode *vp) 755{ 756 struct nfsnode *np = VTONFS(vp); 757 758#ifdef DIAGNOSTIC 759 if (vp->v_type != VDIR) 760 panic("nfs: invaldir not dir"); 761#endif 762 np->n_direofoffset = 0; 763 np->n_cookieverf.nfsuquad[0] = 0; 764 np->n_cookieverf.nfsuquad[1] = 0; 765 if (LIST_FIRST(&np->n_cookies)) 766 LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 767} 768 769/* 770 * The write verifier has changed (probably due to a server reboot), so all 771 * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 772 * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 773 * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 774 * mount point. 775 * 776 * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 777 * writes are not clusterable. 778 */ 779void 780nfs_clearcommit(struct mount *mp) 781{ 782 struct vnode *vp, *nvp; 783 struct buf *bp, *nbp; 784 int s; 785 786 GIANT_REQUIRED; 787 788 s = splbio(); 789 mtx_lock(&mntvnode_mtx); 790loop: 791 for (vp = LIST_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) { 792 if (vp->v_mount != mp) /* Paranoia */ 793 goto loop; 794 nvp = LIST_NEXT(vp, v_mntvnodes); 795 for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) { 796 nbp = TAILQ_NEXT(bp, b_vnbufs); 797 if (BUF_REFCNT(bp) == 0 && 798 (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 799 == (B_DELWRI | B_NEEDCOMMIT)) 800 bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 801 } 802 } 803 mtx_unlock(&mntvnode_mtx); 804 splx(s); 805} 806 807/* 808 * Helper functions for former macros. Some of these should be 809 * moved to their callers. 810 */ 811 812int 813nfsm_mtofh_xx(struct vnode *d, struct vnode **v, int v3, int *f, 814 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 815{ 816 struct nfsnode *ttnp; 817 struct vnode *ttvp; 818 nfsfh_t *ttfhp; 819 int ttfhsize; 820 int t1; 821 822 if (v3) { 823 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 824 if (*tl == NULL) 825 return EBADRPC; 826 *f = fxdr_unsigned(int, **tl); 827 } else 828 *f = 1; 829 if (*f) { 830 t1 = nfsm_getfh_xx(&ttfhp, &ttfhsize, (v3), tl, md, dpos); 831 if (t1 != 0) 832 return t1; 833 t1 = nfs_nget(d->v_mount, ttfhp, ttfhsize, &ttnp); 834 if (t1 != 0) 835 return t1; 836 *v = NFSTOV(ttnp); 837 } 838 if (v3) { 839 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 840 if (*tl == NULL) 841 return EBADRPC; 842 if (*f) 843 *f = fxdr_unsigned(int, **tl); 844 else if (fxdr_unsigned(int, **tl)) 845 nfsm_adv_xx(NFSX_V3FATTR, tl, md, dpos); 846 } 847 if (*f) { 848 ttvp = *v; 849 t1 = nfs_loadattrcache(&ttvp, md, dpos, (struct vattr *)0, 0); 850 if (t1) 851 return t1; 852 *v = ttvp; 853 } 854 return 0; 855} 856 857int 858nfsm_getfh_xx(nfsfh_t **f, int *s, int v3, 859 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 860{ 861 862 if (v3) { 863 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 864 if (*tl == NULL) 865 return EBADRPC; 866 *s = fxdr_unsigned(int, **tl); 867 if (*s <= 0 || *s > NFSX_V3FHMAX) 868 return EBADRPC; 869 } else 870 *s = NFSX_V2FH; 871 *f = nfsm_dissect_xx(nfsm_rndup(*s), md, dpos); 872 if (*f == NULL) 873 return EBADRPC; 874 else 875 return 0; 876} 877 878 879int 880nfsm_loadattr_xx(struct vnode **v, struct vattr *va, 881 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 882{ 883 int t1; 884 885 struct vnode *ttvp = *v; 886 t1 = nfs_loadattrcache(&ttvp, md, dpos, va, 0); 887 if (t1 != 0) 888 return t1; 889 *v = ttvp; 890 return 0; 891} 892 893int 894nfsm_postop_attr_xx(struct vnode **v, int *f, 895 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 896{ 897 int t1; 898 899 struct vnode *ttvp = *v; 900 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 901 if (*tl == NULL) 902 return EBADRPC; 903 *f = fxdr_unsigned(int, **tl); 904 if (*f != 0) { 905 t1 = nfs_loadattrcache(&ttvp, md, dpos, (struct vattr *)0, 1); 906 if (t1 != 0) { 907 *f = 0; 908 return t1; 909 } 910 *v = ttvp; 911 } 912 return 0; 913} 914 915int 916nfsm_wcc_data_xx(struct vnode **v, int *f, 917 u_int32_t **tl, struct mbuf **md, caddr_t *dpos) 918{ 919 int ttattrf, ttretf = 0; 920 int t1; 921 922 *tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos); 923 if (*tl == NULL) 924 return EBADRPC; 925 if (**tl == nfs_true) { 926 *tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos); 927 if (*tl == NULL) 928 return EBADRPC; 929 if (*f) 930 ttretf = (VTONFS(*v)->n_mtime == 931 fxdr_unsigned(u_int32_t, *((*tl) + 2))); 932 } 933 t1 = nfsm_postop_attr_xx(v, &ttattrf, tl, md, dpos); 934 if (t1) 935 return t1; 936 if (*f) 937 *f = ttretf; 938 else 939 *f = ttattrf; 940 return 0; 941} 942 943int 944nfsm_strtom_xx(const char *a, int s, int m, 945 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 946{ 947 int t1; 948 949 if (s > m) 950 return ENAMETOOLONG; 951 t1 = nfsm_rndup(s) + NFSX_UNSIGNED; 952 if (t1 <= M_TRAILINGSPACE(*mb)) { 953 *tl = nfsm_build_xx(t1, mb, bpos); 954 *(*tl)++ = txdr_unsigned(s); 955 *((*tl) + ((t1 >> 2) - 2)) = 0; 956 bcopy(a, *tl, s); 957 } else { 958 t1 = nfsm_strtmbuf(mb, bpos, a, s); 959 if (t1 != 0) 960 return t1; 961 } 962 return 0; 963} 964 965int 966nfsm_fhtom_xx(struct vnode *v, int v3, 967 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 968{ 969 int t1; 970 caddr_t cp; 971 972 if (v3) { 973 t1 = nfsm_rndup(VTONFS(v)->n_fhsize) + NFSX_UNSIGNED; 974 if (t1 < M_TRAILINGSPACE(*mb)) { 975 *tl = nfsm_build_xx(t1, mb, bpos); 976 *(*tl)++ = txdr_unsigned(VTONFS(v)->n_fhsize); 977 *((*tl) + ((t1 >> 2) - 2)) = 0; 978 bcopy(VTONFS(v)->n_fhp, *tl, VTONFS(v)->n_fhsize); 979 } else { 980 t1 = nfsm_strtmbuf(mb, bpos, 981 (const char *)VTONFS(v)->n_fhp, 982 VTONFS(v)->n_fhsize); 983 if (t1 != 0) 984 return t1; 985 } 986 } else { 987 cp = nfsm_build_xx(NFSX_V2FH, mb, bpos); 988 bcopy(VTONFS(v)->n_fhp, cp, NFSX_V2FH); 989 } 990 return 0; 991} 992 993void 994nfsm_v3attrbuild_xx(struct vattr *va, int full, 995 u_int32_t **tl, struct mbuf **mb, caddr_t *bpos) 996{ 997 998 if (va->va_mode != (mode_t)VNOVAL) { 999 *tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1000 *(*tl)++ = nfs_true; 1001 **tl = txdr_unsigned(va->va_mode); 1002 } else { 1003 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1004 **tl = nfs_false; 1005 } 1006 if (full && va->va_uid != (uid_t)VNOVAL) { 1007 *tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1008 *(*tl)++ = nfs_true; 1009 **tl = txdr_unsigned(va->va_uid); 1010 } else { 1011 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1012 **tl = nfs_false; 1013 } 1014 if (full && va->va_gid != (gid_t)VNOVAL) { 1015 *tl = nfsm_build_xx(2 * NFSX_UNSIGNED, mb, bpos); 1016 *(*tl)++ = nfs_true; 1017 **tl = txdr_unsigned(va->va_gid); 1018 } else { 1019 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1020 **tl = nfs_false; 1021 } 1022 if (full && va->va_size != VNOVAL) { 1023 *tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1024 *(*tl)++ = nfs_true; 1025 txdr_hyper(va->va_size, *tl); 1026 } else { 1027 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1028 **tl = nfs_false; 1029 } 1030 if (va->va_atime.tv_sec != VNOVAL) { 1031 if (va->va_atime.tv_sec != time_second) { 1032 *tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1033 *(*tl)++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1034 txdr_nfsv3time(&va->va_atime, *tl); 1035 } else { 1036 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1037 **tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1038 } 1039 } else { 1040 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1041 **tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1042 } 1043 if (va->va_mtime.tv_sec != VNOVAL) { 1044 if (va->va_mtime.tv_sec != time_second) { 1045 *tl = nfsm_build_xx(3 * NFSX_UNSIGNED, mb, bpos); 1046 *(*tl)++ = txdr_unsigned(NFSV3SATTRTIME_TOCLIENT); 1047 txdr_nfsv3time(&va->va_mtime, *tl); 1048 } else { 1049 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1050 **tl = txdr_unsigned(NFSV3SATTRTIME_TOSERVER); 1051 } 1052 } else { 1053 *tl = nfsm_build_xx(NFSX_UNSIGNED, mb, bpos); 1054 **tl = txdr_unsigned(NFSV3SATTRTIME_DONTCHANGE); 1055 } 1056} 1057