Annotation of 43BSDReno/sys/kern/vm_text.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * Redistribution is only permitted until one year after the first shipment
        !             6:  * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
        !             7:  * binary forms are permitted provided that: (1) source distributions retain
        !             8:  * this entire copyright notice and comment, and (2) distributions including
        !             9:  * binaries display the following acknowledgement:  This product includes
        !            10:  * software developed by the University of California, Berkeley and its
        !            11:  * contributors'' in the documentation or other materials provided with the
        !            12:  * distribution and in all advertising materials mentioning features or use
        !            13:  * of this software.  Neither the name of the University nor the names of
        !            14:  * its contributors may be used to endorse or promote products derived from
        !            15:  * this software without specific prior written permission.
        !            16:  * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
        !            17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
        !            18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            19:  *
        !            20:  *     @(#)vm_text.c   7.9 (Berkeley) 6/28/90
        !            21:  */
        !            22: 
        !            23: #include "param.h"
        !            24: #include "systm.h"
        !            25: #include "user.h"
        !            26: #include "proc.h"
        !            27: #include "text.h"
        !            28: #include "vnode.h"
        !            29: #include "buf.h"
        !            30: #include "seg.h"
        !            31: #include "cmap.h"
        !            32: #include "uio.h"
        !            33: #include "exec.h"
        !            34: #include "vm.h"
        !            35: 
        !            36: #include "machine/pte.h"
        !            37: #include "machine/cpu.h"
        !            38: 
        !            39: #define X_LOCK(xp) { \
        !            40:        while ((xp)->x_flag & XLOCK) { \
        !            41:                (xp)->x_flag |= XWANT; \
        !            42:                sleep((caddr_t)(xp), PSWP); \
        !            43:        } \
        !            44:        (xp)->x_flag |= XLOCK; \
        !            45: }
        !            46: #define        XUNLOCK(xp) { \
        !            47:        if ((xp)->x_flag & XWANT) \
        !            48:                wakeup((caddr_t)(xp)); \
        !            49:        (xp)->x_flag &= ~(XLOCK|XWANT); \
        !            50: }
        !            51: #define FREE_AT_HEAD(xp) { \
        !            52:        (xp)->x_forw = xhead; \
        !            53:        xhead = (xp); \
        !            54:        (xp)->x_back = &xhead; \
        !            55:        if (xtail == &xhead) \
        !            56:                xtail = &(xp)->x_forw; \
        !            57:        else \
        !            58:                (xp)->x_forw->x_back = &(xp)->x_forw; \
        !            59: }
        !            60: #define FREE_AT_TAIL(xp) { \
        !            61:        (xp)->x_back = xtail; \
        !            62:        *xtail = (xp); \
        !            63:        xtail = &(xp)->x_forw; \
        !            64:        /* x_forw is NULL */ \
        !            65: }
        !            66: #define        ALLOC(xp) { \
        !            67:        *((xp)->x_back) = (xp)->x_forw; \
        !            68:        if ((xp)->x_forw) \
        !            69:                (xp)->x_forw->x_back = (xp)->x_back; \
        !            70:        else \
        !            71:                xtail = (xp)->x_back; \
        !            72:        (xp)->x_forw = NULL; \
        !            73:        (xp)->x_back = NULL; \
        !            74: }
        !            75: 
        !            76: /*
        !            77:  * The text-cache:
        !            78:  *
        !            79:  * We place up to ``maxtextcache'' free text table entries on a free list
        !            80:  * to form an LRU cache.  This causes the swap (but not RAM) resources to
        !            81:  * be saved.  These text images are treated as "sticky", and are placed on
        !            82:  * the free list when unused.  They may be reclaimed from the free list
        !            83:  * until reused.  The cache changes to MRU once the maximum limit is
        !            84:  * reached since we just cease caching new texts rather than replacing
        !            85:  * the LRU one (should be fixed).  All cached text resources may be
        !            86:  * reclaimed by calling xpurge().  Currently, swpexpand() and xalloc() do
        !            87:  * this if an attempted swap allocation fails.
        !            88:  *
        !            89:  * Note that although true "sticky" texts are handling in the same way,
        !            90:  * they are not considered part of the cache; i.e. they are not subject
        !            91:  * to the maximum limit nor are they purged with xpurge().  They are in
        !            92:  * a sense "locked down" cache entries.
        !            93:  */
        !            94: struct text *xhead, **xtail;           /* text table free list */
        !            95: int    xcache;                         /* number of "sticky" texts retained */
        !            96: int    maxtextcache = -1;              /* maximum number of "sticky" texts */
        !            97: struct xstats xstats;                  /* cache statistics */
        !            98: 
        !            99: /*
        !           100:  * initialize text table
        !           101:  */
        !           102: xinit()
        !           103: {
        !           104:        register struct text *xp;
        !           105: 
        !           106:        xtail = &xhead;
        !           107:        for (xp = text; xp < textNTEXT; xp++)
        !           108:                FREE_AT_TAIL(xp);
        !           109:        if (maxtextcache == -1)
        !           110:                maxtextcache = ntext;
        !           111: }
        !           112: 
        !           113: /*
        !           114:  * relinquish use of the shared text segment
        !           115:  * of a process.
        !           116:  */
        !           117: xfree()
        !           118: {
        !           119:        register struct text *xp;
        !           120:        register struct vnode *vp;
        !           121:        struct vattr vattr;
        !           122: 
        !           123:        if ((xp = u.u_procp->p_textp) == NULL)
        !           124:                return;
        !           125:        xstats.free++;
        !           126:        X_LOCK(xp);
        !           127:        vp = xp->x_vptr;
        !           128:        if (--xp->x_count == 0 &&
        !           129:            (VOP_GETATTR(vp, &vattr, u.u_cred) != 0 ||
        !           130:            (vattr.va_mode & VSVTX) == 0)) {
        !           131:                if (xcache >= maxtextcache || xp->x_flag & XTRC ||
        !           132:                    vattr.va_nlink == 0) {                      /* XXX */
        !           133:                        xp->x_rssize -= vmemfree(tptopte(u.u_procp, 0),
        !           134:                                (int)u.u_tsize);
        !           135:                        if (xp->x_rssize != 0)
        !           136:                                panic("xfree rssize");
        !           137:                        while (xp->x_poip)
        !           138:                                sleep((caddr_t)&xp->x_poip, PSWP+1);
        !           139:                        xp->x_flag &= ~XLOCK;
        !           140:                        xuntext(xp);
        !           141:                        FREE_AT_HEAD(xp);
        !           142:                } else {
        !           143:                        if (xp->x_flag & XWRIT) {
        !           144:                                xstats.free_cacheswap++;
        !           145:                                xp->x_flag |= XUNUSED;
        !           146:                        }
        !           147:                        xcache++;
        !           148:                        xstats.free_cache++;
        !           149:                        xp->x_flag |= XCACHED;
        !           150:                        xccdec(xp, u.u_procp);
        !           151: #if defined(tahoe)     
        !           152:                        xp->x_ckey = 0;
        !           153: #endif
        !           154:                        FREE_AT_TAIL(xp);
        !           155:                }
        !           156:        } else {
        !           157: #if defined(tahoe)
        !           158:                if (xp->x_count == 0)
        !           159:                        xp->x_ckey = 0;
        !           160: #endif
        !           161:                xccdec(xp, u.u_procp);
        !           162:                xstats.free_inuse++;
        !           163:        }
        !           164:        xunlink(u.u_procp);
        !           165:        XUNLOCK(xp);
        !           166:        u.u_procp->p_textp = NULL;
        !           167: }
        !           168: 
        !           169: /*
        !           170:  * Attach to a shared text segment.
        !           171:  * If there is no shared text, just return.
        !           172:  * If there is, hook up to it:
        !           173:  * if it is not currently being used, it has to be read
        !           174:  * in from the vnode (vp); the written bit is set to force it
        !           175:  * to be written out as appropriate.
        !           176:  * If it is being used, but is not currently in core,
        !           177:  * a swap has to be done to get it back.
        !           178:  */
        !           179: xalloc(vp, ep, toff, cred)
        !           180:        register struct vnode *vp;
        !           181:        struct exec *ep;
        !           182:        off_t toff;
        !           183:        struct ucred *cred;
        !           184: {
        !           185:        register struct text *xp;
        !           186:        register struct proc *p;
        !           187: 
        !           188:        if (ep->a_text == 0)
        !           189:                return;
        !           190:        xstats.alloc++;
        !           191:        p = u.u_procp;
        !           192:        while ((xp = vp->v_text) != NULL) {
        !           193:                if (xp->x_flag&XLOCK) {
        !           194:                        /*
        !           195:                         * Wait for text to be unlocked,
        !           196:                         * then start over (may have changed state).
        !           197:                         */
        !           198:                        xwait(xp);
        !           199:                        continue;
        !           200:                }
        !           201:                X_LOCK(xp);
        !           202:                if (xp->x_flag & XCACHED) {
        !           203:                        xstats.alloc_cachehit++;
        !           204:                        ALLOC(xp);
        !           205:                        xp->x_flag &= ~(XCACHED|XUNUSED);
        !           206:                        xcache--;
        !           207:                } else
        !           208:                        xstats.alloc_inuse++;
        !           209:                xp->x_count++;
        !           210:                p->p_textp = xp;
        !           211:                xlink(p);
        !           212:                XUNLOCK(xp);
        !           213: #if defined(tahoe)
        !           214:                ckeyrelease(p->p_ckey);
        !           215:                if (ckey_cnt[xp->x_ckey])
        !           216:                        ckey_cnt[xp->x_ckey]++;
        !           217:                else            /* dead key */
        !           218:                        xp->x_ckey = getcodekey();
        !           219:                p->p_ckey = xp->x_ckey;
        !           220: #endif
        !           221:                return;
        !           222:        }
        !           223:        xp = xhead;
        !           224:        if (xp == NULL) {
        !           225:                tablefull("text");
        !           226:                psignal(p, SIGKILL);
        !           227:                return;
        !           228:        }
        !           229:        ALLOC(xp);
        !           230:        if (xp->x_vptr)
        !           231:                xuntext(xp);
        !           232:        xp->x_flag = XLOAD|XLOCK;
        !           233:        if (p->p_flag & SPAGV)
        !           234:                xp->x_flag |= XPAGV;
        !           235:        xp->x_size = clrnd(btoc(ep->a_text));
        !           236:        if (vsxalloc(xp) == NULL) {
        !           237:                /* flush text cache and try again */
        !           238:                if (xpurge() == 0 || vsxalloc(xp) == NULL) {
        !           239:                        swkill(p, "xalloc: no swap space");
        !           240:                        return;
        !           241:                }
        !           242:        }
        !           243:        xp->x_count = 1;
        !           244:        xp->x_ccount = 0;
        !           245:        xp->x_rssize = 0;
        !           246:        xp->x_mtime = 0;
        !           247:        xp->x_vptr = vp;
        !           248:        vp->v_flag |= VTEXT;
        !           249:        vp->v_text = xp;
        !           250:        VREF(vp);
        !           251:        p->p_textp = xp;
        !           252:        xlink(p);
        !           253:        if ((p->p_flag & SPAGV) == 0) {
        !           254:                settprot(RW);
        !           255:                p->p_flag |= SKEEP;
        !           256:                (void) vn_rdwr(UIO_READ, vp,
        !           257:                        (caddr_t)ctob(tptov(p, 0)),
        !           258:                        (int)ep->a_text, toff,
        !           259:                        UIO_USERSPACE, (IO_UNIT|IO_NODELOCKED), cred, (int *)0);
        !           260:                p->p_flag &= ~SKEEP;
        !           261:        }
        !           262:        settprot(RO);
        !           263: #if defined(tahoe)
        !           264:        ckeyrelease(p->p_ckey);
        !           265:        xp->x_ckey = getcodekey();
        !           266:        p->p_ckey = xp->x_ckey;
        !           267: #endif
        !           268:        xp->x_flag |= XWRIT;
        !           269:        xp->x_flag &= ~XLOAD;
        !           270:        XUNLOCK(xp);
        !           271: }
        !           272: 
        !           273: /*
        !           274:  * Lock and unlock a text segment from swapping
        !           275:  */
        !           276: xlock(xp)
        !           277:        register struct text *xp;
        !           278: {
        !           279: 
        !           280:        X_LOCK(xp);
        !           281: }
        !           282: 
        !           283: /*
        !           284:  * Wait for xp to be unlocked if it is currently locked.
        !           285:  */
        !           286: xwait(xp)
        !           287:        register struct text *xp;
        !           288: {
        !           289: 
        !           290:        X_LOCK(xp);
        !           291:        XUNLOCK(xp);
        !           292: }
        !           293: 
        !           294: xunlock(xp)
        !           295:        register struct text *xp;
        !           296: {
        !           297: 
        !           298:        XUNLOCK(xp);
        !           299: }
        !           300: 
        !           301: /*
        !           302:  * Decrement the in-core usage count of a shared text segment,
        !           303:  * which must be locked.  When the count drops to zero,
        !           304:  * free the core space.
        !           305:  */
        !           306: xccdec(xp, p)
        !           307:        register struct text *xp;
        !           308:        register struct proc *p;
        !           309: {
        !           310: 
        !           311:        if (--xp->x_ccount == 0) {
        !           312:                if (xp->x_flag & XWRIT) {
        !           313:                        vsswap(p, tptopte(p, 0), CTEXT, 0, (int)xp->x_size,
        !           314:                            (struct dmap *)0);
        !           315:                        if (xp->x_flag & XPAGV)
        !           316:                                (void) swap(p, xp->x_ptdaddr,
        !           317:                                    (caddr_t)tptopte(p, 0),
        !           318:                                    (int)xp->x_size * sizeof (struct pte),
        !           319:                                    B_WRITE, B_PAGET, swapdev_vp, 0);
        !           320:                        xp->x_flag &= ~XWRIT;
        !           321:                } else
        !           322:                        xp->x_rssize -= vmemfree(tptopte(p, 0),
        !           323:                            (int)xp->x_size);
        !           324:                if (xp->x_rssize != 0)
        !           325:                        panic("text rssize");
        !           326:        }
        !           327: }
        !           328: 
        !           329: /*
        !           330:  * Detach a process from the in-core text.
        !           331:  * External interface to xccdec, used when swapping out a process.
        !           332:  */
        !           333: xdetach(xp, p)
        !           334:        register struct text *xp;
        !           335:        struct proc *p;
        !           336: {
        !           337: 
        !           338:        if (xp && xp->x_ccount != 0) {
        !           339:                X_LOCK(xp);
        !           340:                xccdec(xp, p);
        !           341:                xunlink(p);
        !           342:                XUNLOCK(xp);
        !           343:        }
        !           344: }
        !           345: 
        !           346: /*
        !           347:  * Free the swap image of all unused saved-text text segments
        !           348:  * which are from file system mp (used by umount system call).
        !           349:  */
        !           350: xumount(mp)
        !           351:        struct mount *mp;
        !           352: {
        !           353:        register struct text *xp;
        !           354: 
        !           355:        for (xp = text; xp < textNTEXT; xp++) 
        !           356:                if (xp->x_vptr != NULL &&
        !           357:                    (mp == NULL || (xp->x_vptr->v_mount == mp)) &&
        !           358:                    (xp->x_flag & XLOCK) == 0)
        !           359:                        xuntext(xp);
        !           360:        mpurgemp(mp);
        !           361: }
        !           362: 
        !           363: /*
        !           364:  * Flush all cached text segments to reclaim swap space.
        !           365:  * Used during swap allocation when out of swap space.
        !           366:  */
        !           367: xpurge()
        !           368: {
        !           369:        register struct text *xp;
        !           370:        int found = 0;
        !           371: 
        !           372:        xstats.purge++;
        !           373:        for (xp = text; xp < textNTEXT; xp++)
        !           374:                if (xp->x_vptr && (xp->x_flag & (XLOCK|XCACHED)) == XCACHED) {
        !           375:                        xuntext(xp);
        !           376:                        /* really gone? */
        !           377:                        if (xp->x_vptr == NULL)
        !           378:                                found++;
        !           379:                }
        !           380:        return(found);
        !           381: }
        !           382: 
        !           383: /*
        !           384:  * remove a shared text segment from the text table, if possible.
        !           385:  */
        !           386: xrele(vp)
        !           387:        register struct vnode *vp;
        !           388: {
        !           389: 
        !           390:        if (vp->v_flag & VTEXT)
        !           391:                xuntext(vp->v_text);
        !           392: }
        !           393: 
        !           394: /*
        !           395:  * remove text image from the text table.
        !           396:  * the use count must be zero.
        !           397:  */
        !           398: xuntext(xp)
        !           399:        register struct text *xp;
        !           400: {
        !           401:        register struct vnode *vp;
        !           402: 
        !           403:        X_LOCK(xp);
        !           404:        if (xp->x_count == 0) {
        !           405:                vp = xp->x_vptr;
        !           406:                xp->x_vptr = NULL;
        !           407:                vsxfree(xp, (long)xp->x_size);
        !           408:                vp->v_flag &= ~VTEXT;
        !           409:                vp->v_text = NULL;
        !           410:                mpurge(vp);
        !           411:                vrele(vp);
        !           412:                /*
        !           413:                 * Take care of text cache statistics
        !           414:                 */
        !           415:                if (xp->x_flag & XCACHED) {
        !           416:                        if (xp->x_flag & XUNUSED)
        !           417:                                xstats.alloc_unused++;
        !           418:                        xp->x_flag &= ~(XCACHED|XUNUSED);
        !           419:                        xstats.alloc_cacheflush++;
        !           420:                        xcache--;
        !           421:                }
        !           422:        }
        !           423:        XUNLOCK(xp);
        !           424: }
        !           425: 
        !           426: /*
        !           427:  * Add a process to those sharing a text segment by
        !           428:  * getting the page tables and then linking to x_caddr.
        !           429:  */
        !           430: xlink(p)
        !           431:        register struct proc *p;
        !           432: {
        !           433:        register struct text *xp = p->p_textp;
        !           434: 
        !           435:        if (xp == 0)
        !           436:                return;
        !           437:        vinitpt(p);
        !           438:        p->p_xlink = xp->x_caddr;
        !           439:        xp->x_caddr = p;
        !           440:        xp->x_ccount++;
        !           441: }
        !           442: 
        !           443: xunlink(p)
        !           444:        register struct proc *p;
        !           445: {
        !           446:        register struct text *xp = p->p_textp;
        !           447:        register struct proc *q;
        !           448: 
        !           449:        if (xp == 0)
        !           450:                return;
        !           451:        if (xp->x_caddr == p) {
        !           452:                xp->x_caddr = p->p_xlink;
        !           453:                p->p_xlink = 0;
        !           454:                return;
        !           455:        }
        !           456:        for (q = xp->x_caddr; q->p_xlink; q = q->p_xlink)
        !           457:                if (q->p_xlink == p) {
        !           458:                        q->p_xlink = p->p_xlink;
        !           459:                        p->p_xlink = 0;
        !           460:                        return;
        !           461:                }
        !           462:        panic("lost text");
        !           463: }
        !           464: 
        !           465: /*
        !           466:  * Replace p by q in a text incore linked list.
        !           467:  * Used by vfork(), internally.
        !           468:  */
        !           469: xrepl(p, q)
        !           470:        struct proc *p, *q;
        !           471: {
        !           472:        register struct text *xp = q->p_textp;
        !           473: 
        !           474:        if (xp == 0)
        !           475:                return;
        !           476:        xunlink(p);
        !           477:        q->p_xlink = xp->x_caddr;
        !           478:        xp->x_caddr = q;
        !           479: }
        !           480: 
        !           481: int xkillcnt = 0;
        !           482: 
        !           483: /*
        !           484:  * Invalidate the text associated with vp.
        !           485:  * Purge in core cache of pages associated with vp and kill all active
        !           486:  * processes.
        !           487:  */
        !           488: xinval(vp)
        !           489:        struct vnode *vp;
        !           490: {
        !           491:        register struct text *xp;
        !           492:        register struct proc *p;
        !           493:        int found = 0;
        !           494: 
        !           495:        mpurge(vp);
        !           496:        xp = vp->v_text;
        !           497:        if (xp->x_flag & XPAGV) {
        !           498:                for (p = xp->x_caddr; p; p = p->p_xlink) {
        !           499:                        /*
        !           500:                         * swkill without uprintf
        !           501:                         */
        !           502:                        printf("pid %d killed due to text modification\n",
        !           503:                                p->p_pid);
        !           504:                        psignal(p, SIGKILL);
        !           505:                        p->p_flag |= SULOCK;
        !           506:                        xkillcnt++;
        !           507:                        found++;
        !           508:                }
        !           509:                /*
        !           510:                 * Take care of the text cache.
        !           511:                 * If there was a process still using the text just mark
        !           512:                 * the text as XTRC so it won't be cached.  If no one was
        !           513:                 * using it then it is in the cache and we need to flush
        !           514:                 * it with xuntext.
        !           515:                 */
        !           516:                if (found)
        !           517:                        xp->x_flag |= XTRC;
        !           518:                else
        !           519:                        xuntext(xp);
        !           520:        }
        !           521: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.