📄 gfs_gnode.c
字号:
#ifndef lintstatic char *sccsid = "@(#)gfs_gnode.c 4.2 (ULTRIX) 11/9/90";#endif/************************************************************************ * * * Copyright (c) 1986 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//*********************************************************************** * * Modification History * * 10 May 90 -- prs for cb * Added wantid argument to ggrab(). ufs_namei() calls ggrab with * the expected g_id, so ggrab() can perform an advisory check * before locking gnode. * * 2 Feb 90 -- chet * Change getegnode to use cacheinval() * * 12-Jan-90 -- prs * Changed km_free to use KM_FREE macro to keep malloc * counters in sync with actual number of free's. * * 09-Nov-89 -- jaw * remove smp_owner check on gnode lock. * * 24 Jul 89 -- prs * Added unggrab() primitive. * * 06 Apr 89 -- prs * Added SMP quota locks. Cleaned up gflush(). * * 9 Mar 89 -- chet * Put code in gget() to ask NFS dnlc to give up gnode * references when out of free gnodes. * * 05 jan 89 -- condylis * Added check for state of mount table entry to ggrab. * Restructured gflush for SMP umount, mount and sync. Added fref * primitive. * * 06 Sep 88 -- prs * SMP - Changed grele() to dealloc space associated with a * named pipe since fifo_rele() is not called. * * 19 May 88 -- cb * Added SMP lock mechanisms. Changed GFS interface. * * 11 Sep 86 -- koehler * changed gflush * * 16 Oct 86 -- koehler * ggrab needs to make sure that the last free gnode is not being * consumed. * ***********************************************************************/#include "../h/param.h"#include "../h/systm.h"#include "../h/mount.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/gnode.h"#include "../h/conf.h"#include "../h/buf.h"#ifdef QUOTA#include "../h/quota.h"#include "../h/kmalloc.h"#endif#include "../h/kernel.h"union ghead ghead[GNOHSZ]; struct gnode *gfreeh, **gfreet;struct lock_t lk_gnode;struct gstats { int greuse; int greclaims; int gfound; int grefs; int greles; int gfrees;};struct gstats gstats;/* * Initialize hash links for gnodes * and build gnode free list. */ghinit(){ register int i; register struct gnode *gp = gnode; register union ghead *gh = ghead; for (i = GNOHSZ; --i >= 0; gh++) { gh->gh_head[0] = gh; gh->gh_head[1] = gh; } gfreeh = gp; gfreet = &gp->g_freef; gp->g_freeb = &gfreeh; gp->g_forw = gp; gp->g_back = gp; lockinit(&gp->g_lk, &lock_eachgnode_d); for (i = ngnode; --i > 0; ) { ++gp; gp->g_forw = gp; gp->g_back = gp; *gfreet = gp; gp->g_freeb = gfreet; gfreet = &gp->g_freef; lockinit(&gp->g_lk, &lock_eachgnode_d); } gp->g_freef = NULL; gstats.greuse = 0; gstats.greclaims = 0; gstats.gfound = 0; gstats.grefs = 0; gstats.greles = 0; gstats.gfrees = 0; finit(); /* initialize the file table */}/* * Convert a pointer to an gnode into a reference to an gnode. * * This is basically the internal piece of gget (after the * gnode pointer is located) but without the test for mounted * filesystems. It is caller's responsibility to check that * the gnode pointer is valid. ufs_namei() is currently the * only invoker. Please note the unggrab() must be used * to deallocate the gnode if the gnode pointer is not valid. */struct gnode *ggrab(gp, wantid) register struct gnode *gp; int wantid;{ caddr_t ptr = (caddr_t) NULL; /* XXX */ smp_lock(&lk_gnode, LK_RETRY); /* * Has the file system been unmounted */ if (!(gp->g_mp->m_flgs & MTE_DONE)) { smp_unlock(&lk_gnode); return(NULL); } /* * get an advisory opinion, that's binding if * it says the gnode has been reused, the * caller must check again (while holding * the lock) if it looks like the right gnode. */ if (gp->g_id != wantid) { smp_unlock(&lk_gnode); return(NULL); } gp->g_count++; if (gp->g_count != 1) gstats.grefs++; else { gstats.greclaims++; gremque(gp); if (gisready(gp)) panic("ggrab: active unreferenced gnode"); } smp_unlock(&lk_gnode); gfs_lock(gp); if (!gisready(gp)) { if (!ginitialize(gp, ptr)) { gclobber(gp); gfs_unlock(gp); grele(gp); return(NULL); } } return(gp);}/* * ufs_namei() needs to un ggrab a gnode. The ggrab() routine * pays no attention to nlink. The case where nlink is equal to * zero, and we hold the only reference, we must set the g_init * field to the reclaim state, or the sfs inactive routine * will attempt to deallocate a previously deallocated gnode. * All other cases will go through proper channels. */unggrab(gp) register struct gnode *gp;{ gassert(gp); if ((gp->g_count == 1) && (gp->g_nlink == 0)) gp->g_init = RECLAIM_GNODE; gfs_unlock(gp); grele(gp);}/* * Decrement reference count of * an gnode structure. * On the last reference, * write the gnode out and if necessary, * truncate and deallocate the file. */gput(gp) register struct gnode *gp;{ gactive(gp); if(gp->g_count == 1 && (gp->g_mode& GFMT) != GFPIPE) { GINACTIVE(gp); gp->g_init = RECLAIM_GNODE; } gfs_unlock(gp); grele(gp);}/* * remove any gnodes in the gnode cache belonging to dev * * There should not be any active ones, return error if any are found * (nb: this is a user error, not a system err) * * Also, count the references to dev by block devices - this really * has nothing to do with the object of the procedure, but as we have * to scan the gnode table here anyway, we might as well get the * extra benefit. * */#ifdef QUOTAgflush(dev, gq, mgp) dev_t dev; register struct gnode *gq; struct gnode *mgp;#elsegflush(dev, mgp) dev_t dev; struct gnode *mgp;#endif{ register struct gnode *gp; register int open = 0;#ifdef QUOTA register struct dquot *dq; struct dquot **dqq; struct dquot *dquot_array; KM_ALLOC(dquot_array, struct dquot *, (ngnode + 1) * 4, KM_TEMP, KM_CLEAR); dqq = (struct dquot **)dquot_array;#endifsmp_lock(&lk_gnode, LK_RETRY); for (gp = gnode; gp < gnodeNGNODE; gp++) {#ifdef QUOTA if (gp != gq && gp->g_dev == dev && gp != gp->g_mp->m_gnodp) {#else if ((gp->g_dev == dev) && (gp != gp->g_mp->m_gnodp)) {#endif if((gp == mgp) && (mgp->g_count == 1)) continue; if (gp->g_count) { smp_unlock(&lk_gnode); open = -1; goto out; } else { remque(gp); gp->g_forw = gp; gp->g_back = gp; /* * as g_count == 0, the gnode was on the free * list already, just leave it there, it will * fall off the bottom eventually. We could * perhaps move it to the head of the free * list, but as umounts are done so * infrequently, we would gain very little, * while making the code bigger. */#ifdef QUOTA if (gp->g_dquot != NODQUOT) { *dqq = gp->g_dquot; dqq++; } gp->g_dquot = NODQUOT;#endif } } else if (gp->g_count && (gp->g_mode&GFMT)==GFBLK && gp->g_rdev == dev) /* hack? */ open++; } if (mgp != NULL) { smp_lock(&mgp->g_mp->m_lk, LK_RETRY); mgp->g_mp->m_flgs &= ~MTE_DONE; /* mount table entry is being /* unmounted. (Can't get a ref /* on gnode in file system and /* mount table entry cannot be /* reclaimed) */ smp_unlock(&mgp->g_mp->m_lk); } smp_unlock(&lk_gnode);out:#ifdef QUOTA /* Now free up quota related stuff */ for (dqq = (struct dquot **)dquot_array; *dqq; dqq++) { dquot_lock((*dqq)); dqrele((*dqq)); dquot_unlock((*dqq)); } KM_FREE(dquot_array, KM_TEMP);#endif return (open);}int getegnode_ufs, getegnode_nfs;int getegnode_purge_worked, getegnode_purge1_worked;/* * Look up a gnode by device, number. If it is in core (in the gnode * table), return it locked. If it is not in core, get an empty gnode * and call a filesystem-specific routine to initialize it. If the gnode * is mounted on, jump over the mount point. In all cases a pointer to * a locked gnode is returned. */struct gnode *gget(mp, gno, nocross, ptr) register struct mount *mp; register gno_t gno; int nocross; caddr_t ptr;{ register struct gnode *gp = (struct gnode *)0; register union ghead *gh; struct gnode *rootgp; register dev_t dev = mp->m_dev; int purge_state = 0;start: gh = &ghead[GNOHASH(mp->m_dev, gno)]; smp_lock(&lk_gnode, LK_RETRY); for (gp = gh->gh_chain[0]; gp != (struct gnode *)gh; gp = gp->g_forw) { if (gno == gp->g_number && dev == gp->g_dev && GMATCH(gp, ptr)) { gp->g_count++; if ((gp->g_flag&GMOUNT) && (nocross == 0)) { mp = gp->g_mpp; rootgp = mp->m_rootgp; gp->g_count--; rootgp->g_count++; smp_unlock(&lk_gnode); gfs_lock(rootgp); return(rootgp); } if (gp->g_count == 1) { gremque(gp); } smp_unlock(&lk_gnode); gfs_lock(gp); if (gisready(gp)) gstats.gfound++; else { gstats.greclaims++; gp->g_mp = mp; if (!ginitialize(gp, ptr)) { gclobber(gp); gfs_unlock(gp); grele(gp); return(NULL); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -