Annotation of 43BSDReno/sys/kern/vm_text.c, revision 1.1.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.