nfs_clsubs.c revision 196332
133965Sjdp/*- 278828Sobrien * Copyright (c) 1989, 1993 3218822Sdim * The Regents of the University of California. All rights reserved. 433965Sjdp * 533965Sjdp * This code is derived from software contributed to Berkeley by 633965Sjdp * Rick Macklem at The University of Guelph. 733965Sjdp * 833965Sjdp * Redistribution and use in source and binary forms, with or without 933965Sjdp * modification, are permitted provided that the following conditions 1033965Sjdp * are met: 1133965Sjdp * 1. Redistributions of source code must retain the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer. 1333965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1433965Sjdp * notice, this list of conditions and the following disclaimer in the 1533965Sjdp * documentation and/or other materials provided with the distribution. 1633965Sjdp * 4. Neither the name of the University nor the names of its contributors 1733965Sjdp * may be used to endorse or promote products derived from this software 1833965Sjdp * without specific prior written permission. 1933965Sjdp * 20218822Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21218822Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2233965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2333965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2433965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2533965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2633965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2733965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2833965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2933965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3033965Sjdp * SUCH DAMAGE. 3177298Sobrien * 3233965Sjdp * from nfs_subs.c 8.8 (Berkeley) 5/22/95 33130561Sobrien */ 3433965Sjdp 3533965Sjdp#include <sys/cdefs.h> 3633965Sjdp__FBSDID("$FreeBSD: head/sys/fs/nfsclient/nfs_clsubs.c 196332 2009-08-17 16:12:28Z rmacklem $"); 3733965Sjdp 3833965Sjdp/* 39130561Sobrien * These functions support the macros and help fiddle mbuf chains for 40130561Sobrien * the nfs op functions. They do things like create the rpc header and 41130561Sobrien * copy data between mbuf chains and uio lists. 42130561Sobrien */ 43130561Sobrien 44130561Sobrien#include <sys/param.h> 45130561Sobrien#include <sys/systm.h> 46130561Sobrien#include <sys/kernel.h> 47130561Sobrien#include <sys/bio.h> 48130561Sobrien#include <sys/buf.h> 49130561Sobrien#include <sys/proc.h> 50130561Sobrien#include <sys/mount.h> 51130561Sobrien#include <sys/vnode.h> 52130561Sobrien#include <sys/namei.h> 53130561Sobrien#include <sys/mbuf.h> 54130561Sobrien#include <sys/socket.h> 55130561Sobrien#include <sys/stat.h> 56130561Sobrien#include <sys/malloc.h> 57130561Sobrien#include <sys/sysent.h> 58130561Sobrien#include <sys/syscall.h> 5933965Sjdp#include <sys/sysproto.h> 6033965Sjdp 6133965Sjdp#include <vm/vm.h> 6277298Sobrien#include <vm/vm_object.h> 6333965Sjdp#include <vm/vm_extern.h> 64130561Sobrien#include <vm/uma.h> 6533965Sjdp 6633965Sjdp#include <fs/nfs/nfsport.h> 6733965Sjdp#include <fs/nfsclient/nfsnode.h> 6833965Sjdp#include <fs/nfsclient/nfsmount.h> 6933965Sjdp#include <fs/nfsclient/nfs.h> 7033965Sjdp#include <fs/nfsclient/nfs_lock.h> 7133965Sjdp 7233965Sjdp#include <netinet/in.h> 7333965Sjdp 7433965Sjdp/* 7533965Sjdp * Note that stdarg.h and the ANSI style va_start macro is used for both 7633965Sjdp * ANSI and traditional C compilers. 7733965Sjdp */ 7877298Sobrien#include <machine/stdarg.h> 7977298Sobrien 8077298Sobrienextern struct mtx ncl_iod_mutex; 8177298Sobrienextern struct proc *ncl_iodwant[NFS_MAXRAHEAD]; 8277298Sobrienextern struct nfsmount *ncl_iodmount[NFS_MAXRAHEAD]; 8377298Sobrienextern int ncl_numasync; 84130561Sobrienextern unsigned int ncl_iodmax; 8533965Sjdpextern struct nfsstats newnfsstats; 8633965Sjdp 8733965Sjdpint 8860484Sobrienncl_uninit(struct vfsconf *vfsp) 8933965Sjdp{ 9033965Sjdp int i; 9133965Sjdp 9233965Sjdp /* 9333965Sjdp * Tell all nfsiod processes to exit. Clear ncl_iodmax, and wakeup 94218822Sdim * any sleeping nfsiods so they check ncl_iodmax and exit. 95218822Sdim */ 96218822Sdim mtx_lock(&ncl_iod_mutex); 97218822Sdim ncl_iodmax = 0; 98218822Sdim for (i = 0; i < ncl_numasync; i++) 99218822Sdim if (ncl_iodwant[i]) 100218822Sdim wakeup(&ncl_iodwant[i]); 101218822Sdim /* The last nfsiod to exit will wake us up when ncl_numasync hits 0 */ 10277298Sobrien while (ncl_numasync) 10377298Sobrien msleep(&ncl_numasync, &ncl_iod_mutex, PWAIT, "ioddie", 0); 10477298Sobrien mtx_unlock(&ncl_iod_mutex); 10577298Sobrien ncl_nhuninit(); 10677298Sobrien return (0); 10777298Sobrien} 10877298Sobrien 10933965Sjdpvoid 11033965Sjdpncl_dircookie_lock(struct nfsnode *np) 11133965Sjdp{ 11289857Sobrien mtx_lock(&np->n_mtx); 11333965Sjdp while (np->n_flag & NDIRCOOKIELK) 11433965Sjdp (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0); 11577298Sobrien np->n_flag |= NDIRCOOKIELK; 11677298Sobrien mtx_unlock(&np->n_mtx); 11777298Sobrien} 11877298Sobrien 11977298Sobrienvoid 12077298Sobrienncl_dircookie_unlock(struct nfsnode *np) 12177298Sobrien{ 12277298Sobrien mtx_lock(&np->n_mtx); 12377298Sobrien np->n_flag &= ~NDIRCOOKIELK; 12477298Sobrien wakeup(&np->n_flag); 12577298Sobrien mtx_unlock(&np->n_mtx); 12677298Sobrien} 12777298Sobrien 12877298Sobrienint 12977298Sobrienncl_upgrade_vnlock(struct vnode *vp) 13077298Sobrien{ 13177298Sobrien int old_lock; 13277298Sobrien 133130561Sobrien ASSERT_VOP_LOCKED(vp, "ncl_upgrade_vnlock"); 134130561Sobrien old_lock = VOP_ISLOCKED(vp); 135130561Sobrien if (old_lock != LK_EXCLUSIVE) { 13633965Sjdp KASSERT(old_lock == LK_SHARED, 13733965Sjdp ("ncl_upgrade_vnlock: wrong old_lock %d", old_lock)); 13833965Sjdp /* Upgrade to exclusive lock, this might block */ 13933965Sjdp vn_lock(vp, LK_UPGRADE | LK_RETRY); 14033965Sjdp } 14133965Sjdp return (old_lock); 14233965Sjdp} 14360484Sobrien 14433965Sjdpvoid 14533965Sjdpncl_downgrade_vnlock(struct vnode *vp, int old_lock) 14633965Sjdp{ 14733965Sjdp if (old_lock != LK_EXCLUSIVE) { 14877298Sobrien KASSERT(old_lock == LK_SHARED, ("wrong old_lock %d", old_lock)); 149223262Sbenl /* Downgrade from exclusive lock. */ 15033965Sjdp vn_lock(vp, LK_DOWNGRADE | LK_RETRY); 15133965Sjdp } 15233965Sjdp} 15333965Sjdp 15433965Sjdpvoid 15533965Sjdpncl_printf(const char *fmt, ...) 15633965Sjdp{ 15733965Sjdp va_list ap; 15833965Sjdp 15933965Sjdp mtx_lock(&Giant); 16033965Sjdp va_start(ap, fmt); 16133965Sjdp printf(fmt, ap); 16277298Sobrien va_end(ap); 16333965Sjdp mtx_unlock(&Giant); 16433965Sjdp} 16533965Sjdp 16633965Sjdp#ifdef NFS_ACDEBUG 16733965Sjdp#include <sys/sysctl.h> 16833965SjdpSYSCTL_DECL(_vfs_newnfs); 16933965Sjdpstatic int nfs_acdebug; 17033965SjdpSYSCTL_INT(_vfs_newnfs, OID_AUTO, acdebug, CTLFLAG_RW, &nfs_acdebug, 0, ""); 17133965Sjdp#endif 17233965Sjdp 17333965Sjdp/* 17433965Sjdp * Check the time stamp 17533965Sjdp * If the cache is valid, copy contents to *vap and return 0 17677298Sobrien * otherwise return an error 17733965Sjdp */ 17877298Sobrienint 17977298Sobrienncl_getattrcache(struct vnode *vp, struct vattr *vaper) 18033965Sjdp{ 18177298Sobrien struct nfsnode *np; 18277298Sobrien struct vattr *vap; 18377298Sobrien struct nfsmount *nmp; 18433965Sjdp int timeo; 185130561Sobrien 18633965Sjdp np = VTONFS(vp); 18733965Sjdp vap = &np->n_vattr.na_vattr; 18833965Sjdp nmp = VFSTONFS(vp->v_mount); 189130561Sobrien#ifdef NFS_ACDEBUG 19033965Sjdp mtx_lock(&Giant); /* ncl_printf() */ 19133965Sjdp#endif 19233965Sjdp mtx_lock(&np->n_mtx); 19333965Sjdp /* XXX n_mtime doesn't seem to be updated on a miss-and-reload */ 19477298Sobrien timeo = (time_second - np->n_mtime.tv_sec) / 10; 19533965Sjdp 19677298Sobrien#ifdef NFS_ACDEBUG 19777298Sobrien if (nfs_acdebug>1) 19833965Sjdp ncl_printf("nfs_getattrcache: initial timeo = %d\n", timeo); 19977298Sobrien#endif 20077298Sobrien 20177298Sobrien if (vap->va_type == VDIR) { 20277298Sobrien if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acdirmin) 20333965Sjdp timeo = nmp->nm_acdirmin; 204130561Sobrien else if (timeo > nmp->nm_acdirmax) 205130561Sobrien timeo = nmp->nm_acdirmax; 20633965Sjdp } else { 20733965Sjdp if ((np->n_flag & NMODIFIED) || timeo < nmp->nm_acregmin) 20833965Sjdp timeo = nmp->nm_acregmin; 20933965Sjdp else if (timeo > nmp->nm_acregmax) 21033965Sjdp timeo = nmp->nm_acregmax; 21133965Sjdp } 21233965Sjdp 21333965Sjdp#ifdef NFS_ACDEBUG 21433965Sjdp if (nfs_acdebug > 2) 21533965Sjdp ncl_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n", 21633965Sjdp nmp->nm_acregmin, nmp->nm_acregmax, 21733965Sjdp nmp->nm_acdirmin, nmp->nm_acdirmax); 21860484Sobrien 21960484Sobrien if (nfs_acdebug) 22060484Sobrien ncl_printf("nfs_getattrcache: age = %d; final timeo = %d\n", 22160484Sobrien (time_second - np->n_attrstamp), timeo); 22260484Sobrien#endif 22338889Sjdp 22438889Sjdp if ((time_second - np->n_attrstamp) >= timeo) { 22538889Sjdp newnfsstats.attrcache_misses++; 22633965Sjdp mtx_unlock(&np->n_mtx); 22733965Sjdp return( ENOENT); 22833965Sjdp } 22933965Sjdp newnfsstats.attrcache_hits++; 23033965Sjdp if (vap->va_size != np->n_size) { 23177298Sobrien if (vap->va_type == VREG) { 23277298Sobrien if (np->n_flag & NMODIFIED) { 23377298Sobrien if (vap->va_size < np->n_size) 23433965Sjdp vap->va_size = np->n_size; 23533965Sjdp else 236130561Sobrien np->n_size = vap->va_size; 237130561Sobrien } else { 238130561Sobrien np->n_size = vap->va_size; 23933965Sjdp } 24033965Sjdp vnode_pager_setsize(vp, np->n_size); 24133965Sjdp } else { 24233965Sjdp np->n_size = vap->va_size; 24333965Sjdp } 24433965Sjdp } 24533965Sjdp bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 24633965Sjdp if (np->n_flag & NCHG) { 24733965Sjdp if (np->n_flag & NACC) 24833965Sjdp vaper->va_atime = np->n_atim; 24960484Sobrien if (np->n_flag & NUPD) 25060484Sobrien vaper->va_mtime = np->n_mtim; 25160484Sobrien } 25260484Sobrien mtx_unlock(&np->n_mtx); 25360484Sobrien#ifdef NFS_ACDEBUG 25438889Sjdp mtx_unlock(&Giant); /* ncl_printf() */ 25538889Sjdp#endif 25638889Sjdp return (0); 25733965Sjdp} 25833965Sjdp 25933965Sjdpstatic nfsuint64 nfs_nullcookie = { { 0, 0 } }; 26077298Sobrien/* 26133965Sjdp * This function finds the directory cookie that corresponds to the 26277298Sobrien * logical byte offset given. 26377298Sobrien */ 26477298Sobriennfsuint64 * 265130561Sobrienncl_getcookie(struct nfsnode *np, off_t off, int add) 26633965Sjdp{ 26733965Sjdp struct nfsdmap *dp, *dp2; 26833965Sjdp int pos; 26933965Sjdp nfsuint64 *retval = NULL; 27033965Sjdp 27133965Sjdp pos = (uoff_t)off / NFS_DIRBLKSIZ; 272130561Sobrien if (pos == 0 || off < 0) { 273130561Sobrien#ifdef DIAGNOSTIC 274130561Sobrien if (add) 275130561Sobrien panic("nfs getcookie add at <= 0"); 276130561Sobrien#endif 277130561Sobrien return (&nfs_nullcookie); 278130561Sobrien } 279130561Sobrien pos--; 28033965Sjdp dp = LIST_FIRST(&np->n_cookies); 28133965Sjdp if (!dp) { 28233965Sjdp if (add) { 28333965Sjdp MALLOC(dp, struct nfsdmap *, sizeof (struct nfsdmap), 28433965Sjdp M_NFSDIROFF, M_WAITOK); 28533965Sjdp dp->ndm_eocookie = 0; 28633965Sjdp LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list); 28777298Sobrien } else 288130561Sobrien goto out; 28933965Sjdp } 29033965Sjdp while (pos >= NFSNUMCOOKIES) { 29133965Sjdp pos -= NFSNUMCOOKIES; 29233965Sjdp if (LIST_NEXT(dp, ndm_list)) { 29377298Sobrien if (!add && dp->ndm_eocookie < NFSNUMCOOKIES && 29433965Sjdp pos >= dp->ndm_eocookie) 29577298Sobrien goto out; 29677298Sobrien dp = LIST_NEXT(dp, ndm_list); 29738889Sjdp } else if (add) { 29833965Sjdp MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap), 29933965Sjdp M_NFSDIROFF, M_WAITOK); 30033965Sjdp dp2->ndm_eocookie = 0; 30133965Sjdp LIST_INSERT_AFTER(dp, dp2, ndm_list); 30233965Sjdp dp = dp2; 30333965Sjdp } else 30433965Sjdp goto out; 30533965Sjdp } 30633965Sjdp if (pos >= dp->ndm_eocookie) { 30733965Sjdp if (add) 30833965Sjdp dp->ndm_eocookie = pos + 1; 30933965Sjdp else 31033965Sjdp goto out; 31133965Sjdp } 31233965Sjdp retval = &dp->ndm_cookies[pos]; 31333965Sjdpout: 31433965Sjdp return (retval); 31533965Sjdp} 31633965Sjdp 31777298Sobrien/* 318130561Sobrien * Invalidate cached directory information, except for the actual directory 319130561Sobrien * blocks (which are invalidated separately). 32033965Sjdp * Done mainly to avoid the use of stale offset cookies. 32133965Sjdp */ 32233965Sjdpvoid 32333965Sjdpncl_invaldir(struct vnode *vp) 32433965Sjdp{ 32533965Sjdp struct nfsnode *np = VTONFS(vp); 32633965Sjdp 32733965Sjdp#ifdef DIAGNOSTIC 32877298Sobrien if (vp->v_type != VDIR) 32977298Sobrien panic("nfs: invaldir not dir"); 33077298Sobrien#endif 33177298Sobrien ncl_dircookie_lock(np); 33277298Sobrien np->n_direofoffset = 0; 33377298Sobrien np->n_cookieverf.nfsuquad[0] = 0; 33477298Sobrien np->n_cookieverf.nfsuquad[1] = 0; 33577298Sobrien if (LIST_FIRST(&np->n_cookies)) 33677298Sobrien LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0; 33777298Sobrien ncl_dircookie_unlock(np); 33877298Sobrien} 33977298Sobrien 34077298Sobrien/* 34177298Sobrien * The write verifier has changed (probably due to a server reboot), so all 34277298Sobrien * B_NEEDCOMMIT blocks will have to be written again. Since they are on the 34377298Sobrien * dirty block list as B_DELWRI, all this takes is clearing the B_NEEDCOMMIT 34477298Sobrien * and B_CLUSTEROK flags. Once done the new write verifier can be set for the 34577298Sobrien * mount point. 34677298Sobrien * 34777298Sobrien * B_CLUSTEROK must be cleared along with B_NEEDCOMMIT because stage 1 data 34877298Sobrien * writes are not clusterable. 349130561Sobrien */ 35077298Sobrienvoid 35177298Sobrienncl_clearcommit(struct mount *mp) 35277298Sobrien{ 35377298Sobrien struct vnode *vp, *nvp; 35477298Sobrien struct buf *bp, *nbp; 35577298Sobrien struct bufobj *bo; 35677298Sobrien 35777298Sobrien MNT_ILOCK(mp); 35877298Sobrien MNT_VNODE_FOREACH(vp, mp, nvp) { 35938889Sjdp bo = &vp->v_bufobj; 360130561Sobrien VI_LOCK(vp); 36133965Sjdp if (vp->v_iflag & VI_DOOMED) { 36233965Sjdp VI_UNLOCK(vp); 36333965Sjdp continue; 36460484Sobrien } 36577298Sobrien vholdl(vp); 36677298Sobrien VI_UNLOCK(vp); 36733965Sjdp MNT_IUNLOCK(mp); 36833965Sjdp BO_LOCK(bo); 36960484Sobrien TAILQ_FOREACH_SAFE(bp, &bo->bo_dirty.bv_hd, b_bobufs, nbp) { 370130561Sobrien if (!BUF_ISLOCKED(bp) && 37160484Sobrien (bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) 37277298Sobrien == (B_DELWRI | B_NEEDCOMMIT)) 37360484Sobrien bp->b_flags &= ~(B_NEEDCOMMIT | B_CLUSTEROK); 37460484Sobrien } 37533965Sjdp BO_UNLOCK(bo); 376130561Sobrien vdrop(vp); 37733965Sjdp MNT_ILOCK(mp); 378130561Sobrien } 37933965Sjdp MNT_IUNLOCK(mp); 38033965Sjdp} 38133965Sjdp 38233965Sjdp/* 38333965Sjdp * Called once to initialize data structures... 38433965Sjdp */ 38533965Sjdpint 386218822Sdimncl_init(struct vfsconf *vfsp) 387218822Sdim{ 388218822Sdim int i; 389218822Sdim 390218822Sdim /* Ensure async daemons disabled */ 391218822Sdim for (i = 0; i < NFS_MAXRAHEAD; i++) { 392218822Sdim ncl_iodwant[i] = NULL; 393218822Sdim ncl_iodmount[i] = NULL; 394218822Sdim } 395218822Sdim ncl_nhinit(); /* Init the nfsnode table */ 396218822Sdim 397218822Sdim return (0); 398218822Sdim} 399218822Sdim 400218822Sdim