📄 vm_mem.c
字号:
size -= CLSIZE; i = pte->pg_pfnum; if (i < firstfree || i > maxfree) panic("bad mem free"); i = pgtocm(i); c = &cmap[i];#ifdef mips if (c->c_type == CTEXT) { xp = &text[c->c_ndx]; if (xp->x_flag & XTRC) { int dev = c->c_mdev==MSWAPX?swapdev:mount[c->c_mdev].m_dev; if (c->c_blkno && mfind(dev,c->c_blkno,xp->x_gptr)) { munhash(dev,(daddr_t)(u_long)c->c_blkno,xp->x_gptr); } } }#endif mips if (c->c_free) panic("dup mem free"); if (flg && c->c_type != CSYS) { for (j = 0; j < CLSIZE; j++) *(int *)(pte+j) &= PG_PROT; c->c_gone = 1; } s = splimp(); /* * If deallocating "u" pages, place on temp "u" list * to be cleared by "vcleanu" routine * else place either at the head or tail of freelist * depending on whether it may be reclaimed */ if (flg == KMF_UAREA) { /* insure that list doesn't get too long */ if (nucmap >= UCLEAR) /* machine/vmparam.h */ vcleanu(); if (nucmap == 0) ucmap = eucmap = i; else { cmap[eucmap].c_next = i; c->c_prev = eucmap; eucmap = i; } nucmap++; } else if (flg == KMF_DETACH && c->c_blkno == 0) { next = cmap[CMHEAD].c_next; cmap[next].c_prev = i; c->c_prev = CMHEAD; c->c_next = next; cmap[CMHEAD].c_next = i; freemem += CLSIZE; } else { prev = cmap[CMHEAD].c_prev; cmap[prev].c_next = i; c->c_next = CMHEAD; c->c_prev = prev; cmap[CMHEAD].c_prev = i; freemem += CLSIZE; } c->c_free = 1; splx(s); pte += CLSIZE; }}/* ***************************************************************************** ***************************************************************************** * * Function: * * vcleanu -- kernel routine * * Function description: * * This function will remove all of the page frames on the "u" list * to the free list. Since the cmap entries have been properly * initialized and linked in memall, all that must be done is to * move the list intact onto the top of the free list. * * NOTE: This routine is currently only being called in "pagein". * If additional calls become necessary, this routine must only be * called if "nucmap != 0" (see "panic"). * * Return Value: * * None * * Interface: * * void vcleanu() * * Errors: * * None * * Panics: * * "vcleanu" * This list is empty. This routine should not have been called, * which is one indication that the list may be corrupted. * ***************************************************************************** ***************************************************************************** */voidvcleanu(){register s, next;#ifdef mips XPRINTF(XPR_VM,"enter vcleanu",0,0,0,0);#endif mips s = splimp(); if (ucmap == -1) panic("vcleanu"); if (freemem < CLSIZE * KLMAX) wakeup((caddr_t)&freemem); next = cmap[CMHEAD].c_next; cmap[next].c_prev = eucmap; cmap[ucmap].c_prev = CMHEAD; cmap[eucmap].c_next = next; cmap[CMHEAD].c_next = ucmap; freemem += nucmap * CLSIZE; ucmap = eucmap = -1; nucmap = 0; splx(s);}/* ***************************************************************************** ***************************************************************************** * * Function: * * pfalloc -- kernel routine * * Function description: * * This function will allocate page frame clusters. These * physical pages are not coupled in any manner to system page table * space. It's up to the requesting routine to allocate and map the * returned PFNs into the system page table. * * As a rule, this routine should only be used to allocate single * page frame clusters (npfc == 1). It should only be used for * multiple clusters at startup/configuration time, as the free * list will get out of order, and the overhead will become unbearable. * * Interface: * * unsigned int pfalloc (type, npfc) * int type; type must = CSYS ( ../h/cmap.h) * int npfc; number of page frame clusters requested * (normally, should == 1) * * Return Value: * * = 0 Error -- no memory to allocate * > 0 Normal -- PFN of first physical page allocated in * * In a normal return, the first PFN allocated is returned, the balance * of the PFNs in the block are easily determined since they are * contiguous. * * Error Handling: * * If return value = 0, then either: * 1. the "cmap" free list is empty. * 2. a block of size "npgf" contiguous page frames could not * be located. * * Panics: * * "pfalloc: type" * Type must equal CSYS. User types are not permitted. In the * future, other system types may exist and be permitted to use * this routine. * * "pfalloc: dup mem alloc" * The cmap entry was on the free list, but the c_free flag * indicates that the entry is NOT free. This indicates * corruption of the free list. * * "pfalloc: bad mem alloc" * The index into the cmap structures is too high for this * memory configuration. This indicates that the index is * corrupted, and memory can not be reliably allocated. * * "pfalloc: intrans|want" * At this point, the physical cluster should be free of * encumbrances, but the cmap entry indicates that the * physical cluster is intransient or wanted by an user proc. * * ***************************************************************************** ***************************************************************************** */unsignedpfalloc (type, npfc)int type; /* cluster type */int npfc; /* number of page frame clusters */{ register struct cmap *c; register next, curpos, count; int end, head; unsigned pf; int s;#ifdef mips XPRINTF(XPR_VM,"enter pfalloc",0,0,0,0);#endif mips if (type != CSYS) panic("pfalloc: type"); s = splimp(); if (freemem < npfc * CLSIZE) { splx(s); return(0); } /* * if only one cluster requested, bypass contiguous lookup * else look for contiguous page frames to pass back */ if (npfc == 1) { head = CMHEAD; pf = cmtopg(cmap[CMHEAD].c_next); } else { next = CMHEAD; end = cmap[CMHEAD].c_prev; count = npfc; while ((curpos = next = cmap[next].c_next) != end) { while (--count && (cmap[next].c_next == next + 1)) next++; if (count == 0) { head = cmap[curpos].c_prev; pf = cmtopg(curpos); goto allocate; } count = npfc; } splx(s); return(0); /* sorry, not a large enough block */ }allocate: while (npfc--) { curpos = cmap[head].c_next; c = &cmap[curpos]; freemem -= CLSIZE; next = c->c_next; cmap[head].c_next = next; cmap[next].c_prev = head; if (c->c_free == 0) panic("pfalloc: dup mem alloc"); if (cmtopg(curpos) > maxfree) panic("pfalloc: bad mem alloc"); /* clear CMAP entry */ pfclear(c); /* intialize CMAP entry */ c->c_ndx = 0; c->c_free = 0; c->c_gone = 0; if (c->c_intrans || c->c_want) panic("pfalloc: intrans|want"); c->c_type = type; }#ifdef KM_STATS km_stats.tot_pfalloc++;#endif KM_STATS splx(s); return (pf);}/* ***************************************************************************** ***************************************************************************** * * Function: * * pffree -- kernel routine * * Function description: * * This routine will free physical page clusters by placing them on the * "cmap" free list. * * Interface: * * void pffree (pfn, npfc) * unsigned int pfn First PFN in cluster to be deallocated * int npfc must equal 1 (for now) * * Return Value: * * None * * Error Handling: * * None * * Panics: * * "pffree: bad mem free" * The PFN is outside the valid range for this memory * configuration or npfc not = 1 * * "pffree: dup mem free" * The cmap entry is marked as being free. This indicates that * either the free list is corrupted or that the input PFN has * been currupted. * ***************************************************************************** ***************************************************************************** */voidpffree (pfn, npfc)unsigned pfn;int npfc;{ register int next; register struct cmap *c; register int s, i; #ifdef mips XPRINTF(XPR_VM,"enter pffree",0,0,0,0);#endif mips if (pfn < firstfree || pfn > maxfree || npfc != 1) panic("pffree: bad mem free"); i = pgtocm(pfn); c = &cmap[i]; if (c->c_free) panic("pffree: dup mem free"); if (freemem < CLSIZE * KLMAX) wakeup((caddr_t)&freemem); s = splimp(); next = cmap[CMHEAD].c_next; cmap[next].c_prev = i; c->c_prev = CMHEAD; c->c_next = next; cmap[CMHEAD].c_next = i; c->c_free = 1; freemem += CLSIZE;#ifdef KM_STATS km_stats.tot_pffree++;#endif KM_STATS splx(s);}/* * Enter clist block c on the hash chains. * It contains file system block bn from device dev. * Dev must either be a mounted file system or the swap device */mhash(c, dev, bn) register struct cmap *c; dev_t dev; daddr_t bn;{ register int i = CMHASH(bn); register struct mount *mp; register struct text *xp; #ifdef mips XPRINTF(XPR_VM,"enter mhash",0,0,0,0);#endif mips c->c_hlink = cmhash[i]; cmhash[i] = c - cmap; c->c_blkno = bn; xp = &text[c->c_ndx]; GETMP(mp, dev); if(mp == NULL) panic("mhash: no mp"); c->c_mdev = (mp == (struct mount *) MSWAPX) ? MSWAPX : mp - mount; if (X_DO_RHASH(xp)) G_SET_HCMAP(xp, xp->x_gptr, c, c - cmap);}/* * Pull the clist entry of <dev,bn> off the hash chains. * We have checked before calling (using mfind) that the * entry really needs to be unhashed, so panic if we can't * find it (can't happen). * * N.B. if dev == swapdev, gp is NULL since the block on the swap * device may not be associated with any active text or data segment */munhash(dev, bn, gp) register dev_t dev; register daddr_t bn; register struct gnode *gp;{ register struct cmap *c1, *c2; register int index; register struct gnode *gpproto = NULL; struct text *xp; int i = CMHASH(bn); struct mount *mp; int needgp = 1; int si = splimp(); #ifdef mips XPRINTF(XPR_VM,"enter munhash",0,0,0,0);#endif mips c1 = &cmap[cmhash[i]]; if (c1 == ecmap) panic("munhash"); if (gp && gp->g_dev == dev) { /* handle simple case to save */ index = gp->g_mp - mount; mp = gp->g_mp; } else { GETMP(mp, dev) index = (mp == (struct mount *) MSWAPX) ? MSWAPX : mp - mount; } /* * it is sufficient for the local case to use just dev and bn * since locally we use lbn's rather than vbn's */ if((index == MSWAPX) || (mp->m_flags & M_LOCAL)) { gpproto = gp; /* so matches work out */ needgp = 0; /* local doesn't need gp */ } else { if (c1->c_type != CTEXT) panic("munhash: unhashing non text page"); gpproto = text[c1->c_ndx].x_gptr; } if ((c1->c_blkno) == bn && (index == c1->c_mdev) && (gp == gpproto)) { cmhash[i] = c1->c_hlink; } else { for (;;) { c2 = c1; c1 = &cmap[c2->c_hlink]; if (c1 == ecmap) panic("munhash: ecmap"); if(needgp) { if (c1->c_type != CTEXT) panic("muhash: unhashing non text page 2"); gpproto = text[c1->c_ndx].x_gptr; } if ((c1->c_blkno == bn) && (index == c1->c_mdev) && (gp == gpproto)) { break; } } c2->c_hlink = c1->c_hlink; } if (mfind(dev, bn, gp)) panic("munhash mfind"); xp = &text[c1->c_ndx]; if (X_DO_RHASH(xp)) G_RST_HCMAP(xp,gp,c1); c1->c_mdev = (u_char) NODEV; c1->c_blkno = 0; c1->c_hlink = 0; splx(si);}/* * maunhash -- This routine is the same as munhash(), except that the * match is on the CMAP address not the mdev/gnode * * This gets rid of those silly "pseudo-munhashes" that have * plagued us. */maunhash(c) register struct cmap *c;{ register struct cmap *c1, *c2; register int j; register struct gnode *gp; register struct text *xp;#ifdef mips XPRINTF(XPR_VM,"enter maunhash",0,0,0,0);#endif mips j = CMHASH(c->c_blkno); c1 = &cmap[cmhash[j]]; if (c1 == c) cmhash[j] = c1->c_hlink; else { for (;;) { if (c1 == ecmap) panic("maunhash ecmap"); c2 = c1; c1 = &cmap[c2->c_hlink]; if (c1 == c) break; } c2->c_hlink = c1->c_hlink; } if (c->c_type != CTEXT) panic("maunhash: unhashing non text page"); xp = &text[c->c_ndx]; gp = xp->x_gptr; /* do an mfind() to insure that duplicates aren't found */ if (mfind(c->c_mdev==MSWAPX?swapdev:mount[c->c_mdev].m_dev, (daddr_t)c->c_blkno, gp)) { printf(" maunhash: mdev 0x%x blkno %d x_gptr 0x%x\n", c->c_mdev== MSWAPX?swapdev:mount[c->c_mdev].m_dev, c->c_blkno, gp); panic("maunhash: mfind"); } /* if remote and large, remove from hash array */ if (X_DO_RHASH(xp)) G_RST_HCMAP(xp,gp,c); /* finish unhashing the given CMAP entry */ c->c_mdev = (u_char) NODEV; c->c_blkno = 0; c->c_hlink = 0;}/* * Look for block bn of device dev in the free pool. * Currently it should not be possible to find it unless it is * c_free and c_gone, although this may later not be true. * (This is because active texts are locked against file system * writes by the system.) * * N.B. if dev == swapdev, gp is NULL since the block on the swap * device may not be associated with any active text or data segment */struct cmap *mfind(dev, bn, gp) register dev_t dev; register daddr_t bn; register struct gnode *gp;{ register struct cmap *c1 = &cmap[cmhash[CMHASH(bn)]]; register int index; register struct gnode *gpproto = NULL; struct mount *mp; int needgp = 1; int si = splimp(); #ifdef mips XPRINTF(XPR_VM,"enter mfind",0,0,0,0);#endif mips if (gp && gp->g_dev == dev) { /* handle simple case to save */ if ((mp = gp->g_mp) == NULL) { splx(si); return((struct cmap *) 0); } index = gp->g_mp - mount; } else { GETMP(mp, dev) if (mp == NULL) { splx(si); return((struct cmap *) 0); } index = (mp == (struct mount *) MSWAPX) ? MSWAPX : mp - mount; } /* * it is sufficient for the local case to use just dev and bn * since locally we use lbn's rather than vbn's * this includes the swap device */ if((index == MSWAPX) || (mp->m_flags & M_LOCAL)) { gpproto = gp; /* so matches work out */ needgp = 0; /* local doesn't need the gp */ } /* now search the core map */ while (c1 != ecmap) { if(needgp) { if (c1->c_type != CTEXT) panic("mfind: trying to find non text on hash"); gpproto = text[c1->c_ndx].x_gptr; } if((c1->c_blkno == bn) && (c1->c_mdev == index) && (gp == gpproto)) { splx(si); return (c1); } c1 = &cmap[c1->c_hlink]; } splx(si); return ((struct cmap *)0);}/* * Purge blocks from device dev from incore cache * before umount(). */mpurge(mdev) int mdev;{ register struct cmap *c1, *c2; register int i; register struct text *xp; int si = splimp();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -