📄 gfs_gnode.c
字号:
/* XXX gp->g_blocks = G_TO_I(gp)->di_blocks; XXX */ return(gp); } } /* * Get a free gnode. * If there aren't any, then ask NFS to give one up from * its name lookup cache. * If that doesn't work, ask NFS to free all of its lookup * cache gnode references. * If that doesn't work, bail out. */ if((gp = getegnode(GNOHASH(dev, gno), mp, gno)) == NULL) { smp_unlock(&lk_gnode); switch (purge_state) { case 0: if (major(dev) < nblkdev + nchrdev) getegnode_ufs++; else getegnode_nfs++; dnlc_purge1(); purge_state++; goto start; break; case 1: dnlc_purge(); purge_state++; goto start; break; default: tablefull("gnode"); u.u_error = ENFILE; return(NULL); break; } } else if (purge_state) { switch (purge_state) { case 1: getegnode_purge1_worked++; break; default: getegnode_purge_worked++; break; } } gp->g_count++; gstats.greuse++; smp_unlock(&lk_gnode); gfs_lock(gp);#ifdef QUOTA dquot_lock(gp->g_dquot); dqrele(gp->g_dquot); dquot_unlock(gp->g_dquot);#endif if (!gisready(gp)) { if (!ginitialize(gp, ptr)) { gclobber(gp); gfs_unlock(gp); grele(gp); return(NULL); } }#ifdef QUOTA if (gp->g_mode == 0) gp->g_dquot = NODQUOT; else gp->g_dquot = inoquota(gp);#endif return (gp);}/*intgfs_lock(gp) register struct gnode *gp;{ if (gp->g_count < 1) panic("gfs_lock: locking unrefed gnode"); smp_lock(&gp->g_lk, LK_RETRY);}intgfs_unlock(gp) register struct gnode *gp;{ if (gp->g_count < 1) panic("gfs_unlock: unlocking unrefed gnode"); if (!glocked(gp)) panic("gfs_unlock: unlocking unlocked gnode"); smp_unlock(&gp->g_lk);}*//* * Pull an empty gnode off of the free list and prepare to reuse it for * another file. Link it onto its new hash chain. Caller must hold * the gnode table spin lock. */struct gnode *getegnode(hash, mp, gno) register int hash; struct mount *mp; register gno_t gno;{ register struct gnode *gp; register struct gnode *gq; register struct gnode *xp; dev_t dev = mp->m_dev; if ((gp = gfreeh) == NULL) { return(NULL); } if (gp->g_count) { cprintf("getegnode: gp 0x%x (%d)\n", gp, gp->g_number); panic("getegnode: free gnode isn't"); } /* * Free resources hanging off the gnode from its previous life. * XXX What if the filesystem has already been unmounted? This * code is unused by UFS and NFS and it causes problems. It should * probably be moved up to gget() since we can't release the spin * lock here. * if ((gp->g_mp) && (gp->g_mp->m_dev != NODEV)) (void)GFREEGN(gp); */ /* * Take the gnode off of the free list. We could call gremque * but we can do it faster here. */ if (gq = gp->g_freef) gq->g_freeb = &gfreeh; gfreeh = gq; gp->g_freef = NULL; gp->g_freeb = NULL; /* * Now to take gnode off the hash chain it was on (initially, or * after a gflush, it is on a "hash chain" consisting entirely of * itself, and pointed to by no-one, but that doesn't matter), and * put it on the chain for its new (gno, dev) pair. */ remque(gp); insque(gp, &ghead[hash]); /* * Initialize some of the easy stuff. We leave the rest for the * caller to do, but these we to set up here for convenience. */ gp->g_dev = dev; gp->g_mp = mp; gp->g_number = gno; gp->g_lastr = 0; gp->g_textp = NULL; gp->g_rdev = 0; gp->g_blocks = 0; gp->g_flag = 0; gp->g_fifo = 0; gp->g_init = NEW_GNODE; bzero((caddr_t)gp->g_in.pad, sizeof(gp->g_in)); cacheinval(gp); if (glocked(gp)) { printf("getegnode: free gnode locked 0x%x\n", gp); panic("getegnode: locked gnode on freelist"); } return(gp);}/* * Put a gnode on the end of the free list. Caller must hold gnode table * spin lock. Historical comment: * * "Possibly in some cases it would be better to put the inode at the head * of the free list, eg: where g_mode == 0 || g_number == 0). The g_number * field is rarely 0 - only after an i/o error in gget, where g_mode == 0, * the gnode will probably be wanted again soon for an ialloc, so possibly * we should keep it." - kre */freegnode(gp) register struct gnode *gp;{ if (gp < gnode || gp > gnodeNGNODE) panic("freegnode: not a gnode"); if(gp->g_count != 0) { cprintf("freegnode: gp 0x%x (%d)\n", gp, gp->g_number); panic("freegnode: freeing active gnode"); } if(glocked(gp)) { cprintf("freegnode: gp 0x%x (%d)\n", gp, gp->g_number); panic("freegnode: freeing locked gnode"); } if (gfreeh) { *gfreet = gp; gp->g_freeb = gfreet; } else { gfreeh = gp; gp->g_freeb = &gfreeh; wakeup((caddr_t)&gfreeh); } gp->g_freef = NULL; gfreet = &gp->g_freef;}/* * Call the correct filesystem-specific initialization routine * to initialize a gnode, and return success or failure. */intginitialize(gp, ptr) register struct gnode *gp; caddr_t ptr;{ int status = 0; switch (gp->g_init) { case NEW_GNODE: status = GINIT(gp, gp->g_init, ptr); break; case RECLAIM_GNODE: status = GRECLAIM(gp, gp->g_init, ptr); break; default: panic("initializing ready gnode"); } if (status == 1) gp->g_init = READY_GNODE; return(status);}/* * Called when an error occurred while initializing a gnode. * The gnode doesn't contain anything useful, so it would be * misleading to leave it on its hash chain. */gclobber(gp) struct gnode *gp;{ gassert(gp); smp_lock(&lk_gnode, LK_RETRY); remque(gp); gp->g_forw = gp; gp->g_back = gp; gp->g_number = 0;#ifdef QUOTA gp->g_dquot = NODQUOT;#endif smp_unlock(&lk_gnode);}/* * Insist that a gnode be active. We panic if the gnode has * a zero reference count or is marked as uninitialized. * Caller (must, should, can) hold the gnode table spin lock. */gactive(gp) struct gnode *gp;{ if (gp->g_count <= 0) panic("gnode is inactive"); if (gp->g_init != READY_GNODE) panic("uninitialized gnode");}/* * There are several examples in gput() and grele() of the gnode count * being examined without holding the spin lock. Some are safe because * the result is used only as a "hint" on whether or not we are releasing * the last reference...we grab the spin lock and check again before * deciding to make the gnode inactive. Others are safe because we hold * a lock on the gnode, so we know that although a new reference can be * created, it is safe to make the gnode inactive because a new LOCKED * reference cannot be created. * * Also, in the while loop in grele, we look at the g_init field without * holding the gnode sleep lock. This is safe because we know that we * have the only reference to the gnode, and we hold the gnode table spin * lock so we know that no new references can be created. * * The while loop in grele is necessary because there is a window between * making the gnode inactive and placing it on the free list when we have * released both the gnode sleep lock and the gnode table spin lock. Another * process(or) could conceivably come in, create a reference to the gnode, * reinitialize it, and destroy their reference before we get the spin lock * back again, leaving us with the last reference to a gnode which needs to * be made inactive again. In practice this will never happen, but the code * needs to protect against it. * * The routine inactive_hack() is the internal part of that while loop. It * tries to lock the gnode (failure ==> not last reference, so give up), * checks to make sure that no new references have been created, and calls * the fs-specific inactive routine. We check the count without holding the * spin lock: this is safe because we hold the gnode sleep lock so no new * LOCKED references to this gnode may be created while we're making it * inactive (see above). Unlocked references are OK. */voidinactive_hack(gp) struct gnode *gp;{ if (smp_lock(&gp->g_lk, 0) == LK_WON) { /* XXX hack? */ if (gp->g_count == 1) { GINACTIVE(gp); gp->g_init = RECLAIM_GNODE; } gfs_unlock(gp); } else {#ifdef GFSDEBUG smp_lock(&lk_gnode, LK_RETRY); if ((gp->g_count == 1) && glocked(gp)) panic("grele: inactive gnode is locked"); smp_unlock(&lk_gnode);#endif GFSDEBUG }}voidgrele(gp) register struct gnode *gp;{ int loopcount = 0; register int ret; if ((gp->g_mode & GFMT) == GFPIPE) { fifo_rele(gp); return; }#ifdef notdef if (gp < gnode || gp > (gnode + ngnode * sizeof (struct gnode))) panic("grele: not a gnode");#endif smp_lock(&lk_gnode, LK_RETRY); gstats.greles++; while ((gp->g_count == 1) && gisready(gp)) { smp_unlock(&lk_gnode);#ifdef GFSDEBUG if (loopcount++ > 1) panic("grele: round and round and round we go");#endif GFSDEBUG inactive_hack(gp); smp_lock(&lk_gnode, LK_RETRY); } if (gp->g_count == 1) {#ifdef GFSDEBUG if (gisready(gp)) panic("grele: freeing initialized gnode");#endif GFSDEBUG gstats.gfrees++; gp->g_flag = 0; gp->g_count--; freegnode(gp); smp_unlock(&lk_gnode); return; } if((gp->g_count--) < 1) panic("grele: gp count bad"); smp_unlock(&lk_gnode);}/* * Create a new reference to a previously referenced gnode. */gref(gp) register struct gnode *gp;{ smp_lock(&lk_gnode, LK_RETRY); gactive(gp); gstats.grefs++; gp->g_count++; smp_unlock(&lk_gnode);}/* * Create a ref on a file system to prevent it from * being umounted. Ref is destroyed by calling grele * with returned gnode pointer. dev is optional. */struct gnode *fref(mp, dev) register struct mount *mp; register dev_t dev;{ smp_lock(&lk_gnode, LK_RETRY); if ((mp == NULL) || (mp == (struct mount *) MSWAPX) || !(mp->m_flgs & MTE_DONE) || (dev && (mp->m_dev != dev))) { smp_unlock(&lk_gnode); return(NULL); } gactive(mp->m_rootgp); mp->m_rootgp->g_count++; smp_unlock(&lk_gnode); return(mp->m_rootgp);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -