Annotation of researchv9/sys.vax/sys/vmmem.c, revision 1.1

1.1     ! root        1: /*     vmmem.c 4.7     81/07/09        */
        !             2: 
        !             3: #include "../h/param.h"
        !             4: #include "../h/systm.h"
        !             5: #include "../h/pte.h"
        !             6: #include "../h/cmap.h"
        !             7: #include "../h/dir.h"
        !             8: #include "../h/user.h"
        !             9: #include "../h/proc.h"
        !            10: #include "../h/mtpr.h"
        !            11: #include "../h/text.h"
        !            12: #include "../h/vm.h"
        !            13: #include "../h/file.h"
        !            14: #include "../h/inode.h"
        !            15: #include "../h/buf.h"
        !            16: #include "../h/mount.h"
        !            17: #include "../h/trace.h"
        !            18: #include "../h/map.h"
        !            19: 
        !            20: /*
        !            21:  * Allocate memory, and always succeed
        !            22:  * by jolting page-out daemon
        !            23:  * so as to obtain page frames.
        !            24:  * To be used in conjunction with vmemfree().
        !            25:  */
        !            26: vmemall(pte, size, p, type)
        !            27:        register struct pte *pte;
        !            28:        int size;
        !            29:        struct proc *p;
        !            30: {
        !            31:        register int m;
        !            32: 
        !            33:        if (size <= 0 || size > maxmem)
        !            34:                panic("vmemall size");
        !            35:        while (size > 0) {
        !            36:                if (freemem < desfree)
        !            37:                        wakeup((caddr_t)&proc[2]);      /* jolt daemon */
        !            38:                while (freemem == 0)
        !            39:                        sleep((caddr_t)&freemem, PSWP+2);
        !            40:                m = imin(size, freemem);
        !            41:                (void) memall(pte, m, p, type);
        !            42:                size -= m;
        !            43:                pte += m;
        !            44:        }
        !            45:        if (freemem < desfree)
        !            46:                wakeup((caddr_t)&proc[2]);              /* jolt daemon */
        !            47:        /*
        !            48:         * Always succeeds, but return success for
        !            49:         * vgetu and vgetpt (e.g.) which call either
        !            50:         * memall or vmemall depending on context.
        !            51:         */
        !            52:        return (1);
        !            53: }
        !            54: 
        !            55: /*
        !            56:  * Free valid and reclaimable page frames belonging to the
        !            57:  * count pages starting at pte.  If a page is valid
        !            58:  * or reclaimable and locked (but not a system page), then
        !            59:  * we simply mark the page as c_gone and let the pageout
        !            60:  * daemon free the page when it is through with it.
        !            61:  * If a page is reclaimable, and already in the free list, then
        !            62:  * we mark the page as c_gone, and (of course) don't free it.
        !            63:  *
        !            64:  * Determines the largest contiguous cluster of
        !            65:  * valid pages and frees them in one call to memfree.
        !            66:  */
        !            67: vmemfree(pte, count)
        !            68:        register struct pte *pte;
        !            69:        register int count;
        !            70: {
        !            71:        register struct cmap *c;
        !            72:        register struct pte *spte;
        !            73:        register int j;
        !            74:        int size, pcnt, fileno;
        !            75: 
        !            76:        if (count % CLSIZE)
        !            77:                panic("vmemfree");
        !            78:        for (size = 0, pcnt = 0; count > 0; pte += CLSIZE, count -= CLSIZE) {
        !            79:                if (pte->pg_fod == 0 && pte->pg_pfnum) {
        !            80:                        c = &cmap[pgtocm(pte->pg_pfnum)];
        !            81:                        pcnt += CLSIZE;
        !            82:                        if (c->c_lock && c->c_type != CSYS) {
        !            83:                                for (j = 0; j < CLSIZE; j++)
        !            84:                                        *(int *)(pte+j) &= (PG_PROT|PG_VREADM);
        !            85:                                c->c_gone = 1;
        !            86:                                goto free;
        !            87:                        }
        !            88:                        if (c->c_free) {
        !            89:                                pcnt -= CLSIZE;
        !            90:                                for (j = 0; j < CLSIZE; j++)
        !            91:                                        *(int *)(pte+j) &= (PG_PROT|PG_VREADM);
        !            92:                                if (c->c_type == CTEXT)
        !            93:                                        distpte(&text[c->c_ndx], (int)c->c_page, pte);
        !            94:                                c->c_gone = 1;
        !            95:                                goto free;
        !            96:                        }
        !            97:                        if (size == 0)
        !            98:                                spte = pte;
        !            99:                        size += CLSIZE;
        !           100:                        continue;
        !           101:                }
        !           102:                if (pte->pg_fod) {
        !           103:                        fileno = ((struct fpte *)pte)->pg_source + PG_FMIN;
        !           104:                        if (fileno > PG_FMAX)
        !           105:                                panic("vmemfree pg_source");
        !           106:                        if (fileno < NOFILE)
        !           107:                                panic("vmemfree, vrpages ref'd");
        !           108:                        for (j = 0; j < CLSIZE; j++)
        !           109:                                *(int *)(pte+j) &= (PG_PROT|PG_VREADM);
        !           110:                }
        !           111: free:
        !           112:                if (size) {
        !           113:                        memfree(spte, size, 1);
        !           114:                        size = 0;
        !           115:                }
        !           116:        }
        !           117:        if (size)
        !           118:                memfree(spte, size, 1);
        !           119:        return (pcnt);
        !           120: }
        !           121: 
        !           122: /*
        !           123:  * Unlink a page frame from the free list -
        !           124:  *
        !           125:  * Performed if the page being reclaimed
        !           126:  * is in the free list.
        !           127:  */
        !           128: munlink(pf)
        !           129:        unsigned pf;
        !           130: {
        !           131:        register int next, prev;
        !           132: 
        !           133:        next = cmap[pgtocm(pf)].c_next;
        !           134:        prev = cmap[pgtocm(pf)].c_prev;
        !           135:        cmap[prev].c_next = next;
        !           136:        cmap[next].c_prev = prev;
        !           137:        cmap[pgtocm(pf)].c_free = 0;
        !           138:        if (freemem < minfree)
        !           139:                wakeup((caddr_t)&proc[2]);      /* jolt paging daemon */
        !           140:        freemem -= CLSIZE;
        !           141: }
        !           142: 
        !           143: /*
        !           144:  * Allocate memory -
        !           145:  *
        !           146:  * The free list appears as a doubly linked list
        !           147:  * in the core map with cmap[0] serving as a header.
        !           148:  */
        !           149: memall(pte, size, p, type)
        !           150:        register struct pte *pte;
        !           151:        int size;
        !           152:        struct proc *p;
        !           153: {
        !           154:        register struct cmap *c;
        !           155:        register struct pte *rpte;
        !           156:        register struct proc *rp;
        !           157:        int i, j, next, curpos;
        !           158:        unsigned pf;
        !           159:        struct cmap *c1, *c2;
        !           160: 
        !           161:        if (size % CLSIZE)
        !           162:                panic("memall");
        !           163:        if (size > freemem)
        !           164:                return (0);
        !           165:        trace(TR_MALL, size, u.u_procp->p_pid);
        !           166:        for (i = size; i > 0; i -= CLSIZE) {
        !           167:                curpos = cmap[CMHEAD].c_next;
        !           168:                c = &cmap[curpos];
        !           169:                if (c->c_free == 0)
        !           170:                        panic("dup mem alloc");
        !           171:                if (cmtopg(curpos) > maxfree)
        !           172:                        panic("bad mem alloc");
        !           173:                if (c->c_gone == 0 && c->c_type != CSYS) {
        !           174:                        if (c->c_type == CTEXT)
        !           175:                                rp = text[c->c_ndx].x_caddr;
        !           176:                        else
        !           177:                                rp = &proc[c->c_ndx];
        !           178:                        while (rp->p_flag & SNOVM)
        !           179:                                rp = rp->p_xlink;
        !           180:                        switch (c->c_type) {
        !           181: 
        !           182:                        case CTEXT:
        !           183:                                rpte = tptopte(rp, c->c_page);
        !           184:                                break;
        !           185: 
        !           186:                        case CDATA:
        !           187:                                rpte = dptopte(rp, c->c_page);
        !           188:                                break;
        !           189: 
        !           190:                        case CSTACK:
        !           191:                                rpte = sptopte(rp, c->c_page);
        !           192:                                break;
        !           193:                        }
        !           194:                        zapcl(rpte, pg_pfnum) = 0;
        !           195:                        if (c->c_type == CTEXT)
        !           196:                                distpte(&text[c->c_ndx], (int)c->c_page, rpte);
        !           197:                }
        !           198:                switch (type) {
        !           199: 
        !           200:                case CSYS:
        !           201:                        c->c_ndx = p->p_ndx;
        !           202:                        break;
        !           203: 
        !           204:                case CTEXT:
        !           205:                        c->c_page = vtotp(p, ptetov(p, pte));
        !           206:                        c->c_ndx = p->p_textp - &text[0];
        !           207:                        break;
        !           208: 
        !           209:                case CDATA:
        !           210:                        c->c_page = vtodp(p, ptetov(p, pte));
        !           211:                        c->c_ndx = p->p_ndx;
        !           212:                        break;
        !           213: 
        !           214:                case CSTACK:
        !           215:                        c->c_page = vtosp(p, ptetov(p, pte));
        !           216:                        c->c_ndx = p->p_ndx;
        !           217:                        break;
        !           218:                }
        !           219:                if (c->c_blkno) {
        !           220:                        /*
        !           221:                         * This is very like munhash(), except
        !           222:                         * that we really don't want to bother
        !           223:                         * to calculate a dev to pass to it.
        !           224:                         */
        !           225:                        j = CMHASH(c->c_blkno);
        !           226:                        c1 = &cmap[cmhash[j]];
        !           227:                        if (c1 == c)
        !           228:                                cmhash[j] = c1->c_hlink;
        !           229:                        else {
        !           230:                                for (;;) {
        !           231:                                        if (c1 == ecmap)
        !           232:                                                panic("memall ecmap");
        !           233:                                        c2 = c1;
        !           234:                                        c1 = &cmap[c2->c_hlink];
        !           235:                                        if (c1 == c)
        !           236:                                                break;
        !           237:                                }
        !           238:                                c2->c_hlink = c1->c_hlink;
        !           239:                        }
        !           240:                        if (mfind(c->c_mdev == MSWAPX ?
        !           241:                              swapdev : mount[c->c_mdev].m_dev,
        !           242:                              (daddr_t)c->c_blkno))
        !           243:                                panic("memall mfind");
        !           244:                        c1->c_mdev = 0;
        !           245:                        c1->c_blkno = 0;
        !           246:                        c1->c_hlink = 0;
        !           247:                }
        !           248:                pf = cmtopg(curpos);
        !           249:                for (j = 0; j < CLSIZE; j++)
        !           250:                        *(int *)pte++ = pf++;
        !           251:                c->c_free = 0;
        !           252:                c->c_gone = 0;
        !           253:                if (c->c_intrans || c->c_want)
        !           254:                        panic("memall intrans|want");
        !           255:                c->c_lock = 1;
        !           256:                c->c_type = type;
        !           257:                freemem -= CLSIZE;
        !           258:                next = c->c_next;
        !           259:                cmap[CMHEAD].c_next = next;
        !           260:                cmap[next].c_prev = CMHEAD;
        !           261:        }
        !           262:        return (size);
        !           263: }
        !           264: 
        !           265: /*
        !           266:  * Free memory -
        !           267:  *
        !           268:  * The page frames being returned are inserted
        !           269:  * to the head/tail of the free list depending
        !           270:  * on whether there is any possible future use of them.
        !           271:  *
        !           272:  * If the freemem count had been zero,
        !           273:  * the processes sleeping for memory
        !           274:  * are awakened.
        !           275:  */
        !           276: memfree(pte, size, detach)
        !           277:        register struct pte *pte;
        !           278:        register int size;
        !           279: {
        !           280:        register int i, j, prev, next;
        !           281:        register struct cmap *c;
        !           282:        
        !           283:        if (size % CLSIZE)
        !           284:                panic("memfree");
        !           285:        if (freemem < CLSIZE * KLMAX)
        !           286:                wakeup((caddr_t)&freemem);
        !           287:        while (size > 0) {
        !           288:                size -= CLSIZE;
        !           289:                i = pte->pg_pfnum;
        !           290:                if (i < firstfree || i > maxfree)
        !           291:                        panic("bad mem free");
        !           292:                i = pgtocm(i);
        !           293:                c = &cmap[i];
        !           294:                if (c->c_free)
        !           295:                        panic("dup mem free");
        !           296:                if (detach && c->c_type != CSYS) {
        !           297:                        for (j = 0; j < CLSIZE; j++)
        !           298:                                *(int *)(pte+j) &= (PG_PROT|PG_VREADM);
        !           299:                        c->c_gone = 1;
        !           300:                }
        !           301:                if (detach && c->c_blkno == 0) {
        !           302:                        next = cmap[CMHEAD].c_next;
        !           303:                        cmap[next].c_prev = i;
        !           304:                        c->c_prev = CMHEAD;
        !           305:                        c->c_next = next;
        !           306:                        cmap[CMHEAD].c_next = i;
        !           307:                } else {
        !           308:                        prev = cmap[CMHEAD].c_prev;
        !           309:                        cmap[prev].c_next = i;
        !           310:                        c->c_next = CMHEAD;
        !           311:                        c->c_prev = prev;
        !           312:                        cmap[CMHEAD].c_prev = i;
        !           313:                }
        !           314:                c->c_free = 1;
        !           315:                freemem += CLSIZE;
        !           316:                pte += CLSIZE;
        !           317:        }
        !           318: }
        !           319: 
        !           320: /*
        !           321:  * Allocate wired-down (non-paged) pages in kernel virtual memory.
        !           322:  */
        !           323: caddr_t
        !           324: wmemall(pmemall, n)
        !           325:        int (*pmemall)(), n;
        !           326: {
        !           327:        int npg;
        !           328:        caddr_t va;
        !           329:        register int a;
        !           330: 
        !           331:        npg = btoc(n);
        !           332:        a = rmalloc(kernelmap, npg);
        !           333:        if (a == 0)
        !           334:                return (0);
        !           335:        if ((*pmemall)(&Usrptmap[a], npg, &proc[0], CSYS) == 0) {
        !           336:                rmfree(kernelmap, npg, a);
        !           337:                return (0);
        !           338:        }
        !           339:        va = (caddr_t) kmxtob(a);
        !           340:        vmaccess(&Usrptmap[a], va, npg);
        !           341:        return (va);
        !           342: }
        !           343: 
        !           344: wmemfree(va, n)
        !           345:        caddr_t va;
        !           346:        int n;
        !           347: {
        !           348:        register int a;
        !           349:        int npg;
        !           350: 
        !           351:        a = btokmx((struct pte *) va);
        !           352:        npg = btoc(n);
        !           353:        (void) memfree(&Usrptmap[a], npg, 0);
        !           354:        rmfree(kernelmap, npg, a);
        !           355: }
        !           356: 
        !           357: /*
        !           358:  * Enter clist block c on the hash chains.
        !           359:  * It contains file system block bn from device dev.
        !           360:  * Dev must either be a mounted file system or the swap device
        !           361:  * so we panic if getfsx() cannot find it.
        !           362:  */
        !           363: mhash(c, dev, bn)
        !           364:        register struct cmap *c;
        !           365:        dev_t dev;
        !           366:        daddr_t bn;
        !           367: {
        !           368:        register int i = CMHASH(bn);
        !           369: 
        !           370:        c->c_hlink = cmhash[i];
        !           371:        cmhash[i] = c - cmap;
        !           372:        c->c_blkno = bn;
        !           373:        i = getfsx(dev);
        !           374:        if (i == -1)
        !           375:                panic("mhash");
        !           376:        c->c_mdev = i;
        !           377: }
        !           378: 
        !           379: /*
        !           380:  * Pull the clist entry of <dev,bn> off the hash chains.
        !           381:  * We have checked before calling (using mfind) that the
        !           382:  * entry really needs to be unhashed, so panic if we can't
        !           383:  * find it (can't happen).
        !           384:  */
        !           385: munhash(dev, bn)
        !           386:        dev_t dev;
        !           387:        daddr_t bn;
        !           388: {
        !           389:        register int i = CMHASH(bn);
        !           390:        register struct cmap *c1, *c2;
        !           391: 
        !           392:        c1 = &cmap[cmhash[i]];
        !           393:        if (c1 == ecmap)
        !           394:                panic("munhash");
        !           395:        if (c1->c_blkno == bn && getfsx(dev) == c1->c_mdev)
        !           396:                cmhash[i] = c1->c_hlink;
        !           397:        else {
        !           398:                for (;;) {
        !           399:                        c2 = c1;
        !           400:                        c1 = &cmap[c2->c_hlink];
        !           401:                        if (c1 == ecmap)
        !           402:                                panic("munhash");
        !           403:                        if (c1->c_blkno == bn && getfsx(dev) == c1->c_mdev)
        !           404:                                break;
        !           405:                }
        !           406:                c2->c_hlink = c1->c_hlink;
        !           407:        }
        !           408:        if (mfind(dev, bn))
        !           409:                panic("munhash mfind");
        !           410:        c1->c_mdev = 0;
        !           411:        c1->c_blkno = 0;
        !           412:        c1->c_hlink = 0;
        !           413: }
        !           414: 
        !           415: /*
        !           416:  * Look for block bn of device dev in the free pool.
        !           417:  * Currently it should not be possible to find it unless it is
        !           418:  * c_free and c_gone, although this may later not be true.
        !           419:  * (This is because active texts are locked against file system
        !           420:  * writes by the system.)
        !           421:  */
        !           422: struct cmap *
        !           423: mfind(dev, bn)
        !           424:        dev_t dev;
        !           425:        daddr_t bn;
        !           426: {
        !           427:        register struct cmap *c1 = &cmap[cmhash[CMHASH(bn)]];
        !           428: 
        !           429:        while (c1 != ecmap) {
        !           430:                if (c1->c_blkno == bn && c1->c_mdev == getfsx(dev))
        !           431:                        return (c1);
        !           432:                c1 = &cmap[c1->c_hlink];
        !           433:        }
        !           434:        return ((struct cmap *)0);
        !           435: }
        !           436: 
        !           437: /*
        !           438:  * Purge blocks from device dev from incore cache
        !           439:  * before umount().
        !           440:  */
        !           441: mpurge(mdev)
        !           442:        int mdev;
        !           443: {
        !           444:        register struct cmap *c1, *c2;
        !           445:        register int i;
        !           446: 
        !           447:        for (i = 0; i < CMHSIZ; i++) {
        !           448: more:
        !           449:                c1 = &cmap[cmhash[i]];
        !           450:                if (c1 == ecmap)
        !           451:                        continue;
        !           452:                if (c1->c_mdev == mdev)
        !           453:                        cmhash[i] = c1->c_hlink;
        !           454:                else {
        !           455:                        for (;;) {
        !           456:                                c2 = c1;
        !           457:                                c1 = &cmap[c1->c_hlink];
        !           458:                                if (c1 == ecmap)
        !           459:                                        goto cont;
        !           460:                                if (c1->c_mdev == mdev)
        !           461:                                        break;
        !           462:                        }
        !           463:                        c2->c_hlink = c1->c_hlink;
        !           464:                }
        !           465:                c1->c_mdev = 0;
        !           466:                c1->c_blkno = 0;
        !           467:                c1->c_hlink = 0;
        !           468:                goto more;
        !           469: cont:
        !           470:                ;
        !           471:        }
        !           472: }
        !           473: 
        !           474: /*
        !           475:  * Initialize core map
        !           476:  */
        !           477: meminit(first, last)
        !           478:        int first, last;
        !           479: {
        !           480:        register int i;
        !           481:        register struct cmap *c;
        !           482: 
        !           483:        firstfree = clrnd(first);
        !           484:        maxfree = clrnd(last - (CLSIZE - 1));
        !           485:        freemem = maxfree - firstfree;
        !           486:        ecmx = ecmap - cmap;
        !           487:        if (ecmx < freemem / CLSIZE)
        !           488:                freemem = ecmx * CLSIZE;
        !           489:        for (i = 1; i <= freemem / CLSIZE; i++) {
        !           490:                cmap[i-1].c_next = i;
        !           491:                c = &cmap[i];
        !           492:                c->c_prev = i-1;
        !           493:                c->c_free = 1;
        !           494:                c->c_gone = 1;
        !           495:                c->c_type = CSYS;
        !           496:                c->c_mdev = 0;
        !           497:                c->c_blkno = 0;
        !           498:        }
        !           499:        cmap[freemem / CLSIZE].c_next = CMHEAD;
        !           500:        for (i = 0; i < CMHSIZ; i++)
        !           501:                cmhash[i] = ecmx;
        !           502:        cmap[CMHEAD].c_prev = freemem / CLSIZE;
        !           503:        cmap[CMHEAD].c_type = CSYS;
        !           504:        avefree = freemem;
        !           505:        hand = 0;
        !           506: }
        !           507: 
        !           508: /*
        !           509:  * Wait for frame pf to become unlocked
        !           510:  * if it is currently locked.
        !           511:  *
        !           512:  * THIS ROUTINE SHOULD TAKE A CMAP STRUCTURE AS ARGUMENT.
        !           513:  */
        !           514: mwait(pf)
        !           515:        unsigned pf;
        !           516: {
        !           517: 
        !           518:        mlock(pf);
        !           519:        munlock(pf);
        !           520: }
        !           521: 
        !           522: /*
        !           523:  * Lock a page frame.
        !           524:  *
        !           525:  * THIS ROUTINE SHOULD TAKE A CMAP STRUCTURE AS ARGUMENT.
        !           526:  */
        !           527: mlock(pf)
        !           528:        unsigned pf;
        !           529: {
        !           530:        register struct cmap *c = &cmap[pgtocm(pf)];
        !           531: 
        !           532:        while (c->c_lock) {
        !           533:                c->c_want = 1;
        !           534:                sleep((caddr_t)c, PSWP+1);
        !           535:        }
        !           536:        c->c_lock = 1;
        !           537: }
        !           538: 
        !           539: /*
        !           540:  * Unlock a page frame.
        !           541:  *
        !           542:  * THIS ROUTINE SHOULD TAKE A CMAP STRUCTURE AS ARGUMENT.
        !           543:  */
        !           544: munlock(pf)
        !           545:        unsigned pf;
        !           546: {
        !           547:        register struct cmap *c = &cmap[pgtocm(pf)];
        !           548: 
        !           549:        if (c->c_lock == 0)
        !           550:                panic("dup page unlock");
        !           551:        if (c->c_want)
        !           552:                wakeup((caddr_t)c);
        !           553:        c->c_lock = 0;
        !           554:        c->c_want = 0;
        !           555: }
        !           556: 
        !           557: /* 
        !           558:  * Lock a virtual segment.
        !           559:  *
        !           560:  * For each cluster of pages, if the cluster is not valid,
        !           561:  * touch it to fault it in, otherwise just lock page frame.
        !           562:  * Called from physio to ensure that the pages 
        !           563:  * participating in raw i/o are valid and locked.
        !           564:  * We use SDLYU to keep pagein from unlocking pages,
        !           565:  * so they make it safely back here locked.
        !           566:  */
        !           567: vslock(base, count)
        !           568:        caddr_t base;
        !           569: {
        !           570:        register unsigned v;
        !           571:        register int npf;
        !           572:        register struct pte *pte;
        !           573: 
        !           574:        u.u_procp->p_flag |= SDLYU;
        !           575:        v = btop(base);
        !           576:        pte = vtopte(u.u_procp, v);
        !           577:        npf = btoc(count + ((int)base & CLOFSET));
        !           578:        while (npf > 0) {
        !           579:                if (pte->pg_v) 
        !           580:                        mlock(pte->pg_pfnum);
        !           581:                else
        !           582:                        if (fubyte((caddr_t)ctob(v)) < 0)
        !           583:                                panic("vslock");
        !           584:                pte += CLSIZE;
        !           585:                v += CLSIZE;
        !           586:                npf -= CLSIZE;
        !           587:        }
        !           588:        u.u_procp->p_flag &= ~SDLYU;
        !           589: }
        !           590: 
        !           591: /* 
        !           592:  * Unlock a virtual segment.
        !           593:  */
        !           594: vsunlock(base, count, rw)
        !           595:        caddr_t base;
        !           596: {
        !           597:        register struct pte *pte;
        !           598:        register int npf;
        !           599: 
        !           600:        pte = vtopte(u.u_procp, btop(base));
        !           601:        npf = btoc(count + ((int)base & CLOFSET));
        !           602:        while (npf > 0) {
        !           603:                munlock(pte->pg_pfnum);
        !           604:                if (rw == B_READ)       /* Reading from device writes memory */
        !           605:                        pte->pg_m = 1;
        !           606:                pte += CLSIZE;
        !           607:                npf -= CLSIZE;
        !           608:        }
        !           609: }

unix.superglobalmegacorp.com

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