allbery@ncoast.UUCP (06/16/87)
I've gotten enough requests it's probably worth posting... der Mouse (mouse@mcgill-vision.uucp) #! /bin/sh # # Shar: Shell Archiver # # This archive created Tue Jun 16 15:36:41 1987 # Run this through sh to create: # memdisk.doc # memdisk.c # mdset.c echo x - memdisk.doc \(5929 characters\) sed 's/^X//' > memdisk.doc << \SHAR_EOF Xmemdisk: a silicon disk driver for UNIX. X Currently in use on 4.3BSD, mtXinu 4.3+NFS, and Sunix 3.0. X XYou should have received: X X - memdisk.doc (this file) X - memdisk.c X - mdset.c X XYou will need to: X X - Look over the configuration section at the top of memdisk.c X and change the #defines to match the system you will be X using it on. If none of the possibilities listed quite fit, X you will have to guess. If you have to guess: X For lockout(), try splhigh() first and if that doesn't X work ("loading vmunix"/"Undefined:"/"_splhigh") then X use spl7(). X For mount.h, try doing "echo ../*/*mount.h" and see if X that helps. X X - Put memdisk.c somewhere; I'll assume it's in X ../local/memdisk.c (that's where we have it). If you put it X somewhere else, change the filename in the next item to X point to wherever you did put it. X X - Put a line Xlocal/memdisk.c optional memdisk X in ../conf/files.YOURSYSTEMNAME. For example, our X configuration is in ../conf/LARRY and the kernel is built in X ../LARRY; the file with the above line is then X ../conf/files.LARRY (clear enough?). X X - Put a line Xpseudo-device memdisk 1 X in ../conf/YOURSYSTEMNAME. The 1 specifies how many silicon X disk devices you want to configure in; you may want to X increase it. X X - Edit conf.c. This file is in ../vax for VAX and MicroVAX X configurations and seems to be in ../sun (rather than X ../machine, which is a link to sun2 or sun3 depending on X which sort of Sun you have) for Suns. You will need to X insert the following, somewhere early (before both cdevsw[] X and bdevsw[]). X#include "memdisk.h" X#if NMEMDISK > 0 Xextern int memdiskopen(); Xextern int memdiskstrategy(); Xextern int memdiskread(); Xextern int memdiskwrite(); Xextern int memdiskioctl(); Xextern int memdiskdump(); Xextern int memdisksize(); X#else X#define memdiskopen nodev X#define memdiskstrategy nodev X#define memdiskread nodev X#define memdiskwrite nodev X#define memdiskioctl nodev X#define memdiskdump nodev X#define memdisksize nodev X#endif X Now you need to add a device to each of bdevsw[] and X cdevsw[]. The bdevsw entry should look like X { memdiskopen, nulldev, memdiskstrategy,memdiskdump, /* 10 */ X memdisksize, 0 }, X (the 10 should be changed to whatever number you choose to X put it at). The cdevsw entry should look like X { X memdiskopen, nulldev, memdiskread, memdiskwrite, /* 34 */ X memdiskioctl, nulldev, nodev, 0, X seltrue, 0, X }, X again, with the 34 changed to whatever is appropriate. X X - add a #define to ../h/ioctl.h: X#define LIOC_MEM_SET _IOW(l,0,int) /* start/stop disk */ X XYou can now re-run config and rebuild your kernel. If you get Xcomplaints when trying to rebuild your kernel about "Don't know how to Xmake ../h/mount.h" (or ../ufs/ufsmount.h, or ../ufs/mount.h), then try Xtaking the ones it complains about right out of memdisk.c and redoing Xthe make depend. X XIf I haven't forgotten anything (:-), it should run fine. Test the new Xkernel. When you are satisfied that adding the memdisk driver hasn't Xbroken anything else, you can try it out: X X - Create entries in /dev. We use /dev/mdisk0 and /dev/rmdisk0 X (just 0 since we have just one configured in - if we had X two, they'd be mdisk0/rmdisk0 and mdisk1/rmdisk1). X X - Compile mdset.c; put the binary wherever you feel X appropriate. As with any disk drive, the /dev entries X should be mode xx0, probably mode 600 is best, unless you X wouldn't mind entrusting all your users with your root X password. Mdset must be able to open the raw device X /dev/rmdisk0 (or rmdisk1, or 2, or...) in order to function. X X - Run mdset to allocate memory to the disk. When the system is X booted, no memory is allocated to the disk. Mdset takes two X arguments. The first argument must be the disk unit number X (the trailing number on the /dev entry), the second must be X the number of bytes of memory to allocate to the disk and X must be a multiple of 512 (the usual sector size for a X disk). The second argument can have a trailing k or m to X indicate kilo- or mega- bytes (eg, 512k indicates a half-meg X disk). If mdset runs and doesn't crash the system, the X silicon drive should now have some memory allocated to it. X You can now run mkfs (or newfs, if you give it a size) to X create a filesystem on the disk, then you can put whatever X you want there. Note that the size argument to mkfs is the X number of sectors, ie, the number of bytes divided by 512. X If you use the k abbreviation, the number to pass to mkfs X will be twice the number before the k; if you use m, the X mkfs size will be 2048 times the number before the m. X XFor example, suppose we want to allocate a half-meg to /tmp: X X# mdset 0 512k X XIf the driver can't get the memory, it will produce a message Xmdset: cannot set size for /dev/rmdisk0: <message> Xwhere <message> is one of the standard error messages (see intro(2)), Xmost likely "Not enough core". X XNow the disk has memory, but the contents of the memory are basically Xrandom. So we make a filesystem: X X# /etc/mkfs /dev/rmdisk0 1024 X....mkfs messages.... X XNow sync the disk just to be safe. It works just as well to run fsck Xon it, I find; but if you do neither, I have had it crash mysteriously Xsometimes (I suspect that some critical filesystem data, like Xsuperblocks, is still waiting to be written to the disk, because the Xmkfs used /dev/rmdisk0 instead of /dev/mdisk0). X X# sync X XNow we can mount it somewhere: X X# /etc/mount /dev/mdisk0 /tmp X XAnd away we go! Note that you do not want to put anything on a silicon Xdrive that is both important and difficult to recreate, because every Xtime the machine goes down, everything on a silicon drive is lost. X/tmp is a reasonable thing to put on a silicon drive; a read-only copy Xof something that gets used heavily could also be a win. X X der Mouse X X (mouse@mcgill-vision.uucp) SHAR_EOF if test 5929 -ne "`wc -c memdisk.doc`" then echo shar: error transmitting memdisk.doc \(should have been 5929 characters\) fi echo x - memdisk.c \(4858 characters\) sed 's/^X//' > memdisk.c << \SHAR_EOF X/* X * Silicon disk driver. X * X * Copyright 1987 by Mike Parker. X * You may do anything you like with this as long as you don't: X * - claim you wrote any part of it that you didn't (ie, you may X * of course claim any modifications you've made, but not any X * of my code); nor X * - change or delete this copyright notice. X * Note also that I do not take any responsibility for anything this code X * may do. I have tried to make it useful but I can't promise anything. X * X * If you find any bugs I'd appreciate hearing about them, especially X * if you also fix them. Write to mouse@mcgill-vision.uucp. X */ X X/* Configuration. */ X X/* What spl... do we use for total lockout? (We assume splx() un-locks.) */ X#define lockout() splhigh() /* works on 4.3BSD derivatives for the VAX */ X/* #define lockout() spl7() /* works on Sun UNIX 3.0 */ X X/* Where is mount.h? */ X#define UFS_UFSMOUNT /* ../ufs/ufsmount.h: works on mtXinu 4.3+NFS */ X/* #define H_MOUNT /* ../h/mount.h: works on 4.3 */ X/* #define UFS_MOUNT /* ../ufs/mount.h: works on Sun UNIX 3.0 */ X X#include "memdisk.h" X X#if NMEMDISK > 0 X X#include "../h/param.h" X#include "../h/systm.h" X#include "../h/ioctl.h" X#include "../h/buf.h" X#include "../h/conf.h" X#include "../h/time.h" X#include "../h/kernel.h" X#include "../h/errno.h" X#ifdef UFS_UFS_MOUNT X#include "../ufs/ufsmount.h" X#endif X#ifdef H_MOUNT X#include "../h/mount.h" X#endif X#ifdef UFS_MOUNT X#include "../ufs/mount.h" X#endif X Xint max_md_size = (2048+512) * 1024; /* 2.5Mb */ X Xstatic struct memdiskinfo { X int busy; X int live; X int unit; X int nbytes; X char *data; } memdiskinfo[NMEMDISK]; Xstatic int didinit = 0; X X#define OKUNIT(u) (((u)>=0)&&((u)<NMEMDISK)) X#define LIVEUNIT(u) (OKUNIT(u)&&memdiskinfo[u].live) X Xmemdiskopen(dev,flag) Xdev_t dev; Xint flag; X{ X int unit; X int s; X X#ifdef lint X flag = flag; X#endif X unit = minor(dev); X if (! OKUNIT(unit)) X { return(ENXIO); X } X s = lockout(); X if (! didinit) X { for (unit=0;unit<NMEMDISK;unit++) X { register struct memdiskinfo *mdi; X mdi = &memdiskinfo[unit]; X mdi->busy = 0; X mdi->live = 0; X mdi->unit = unit; X } X didinit = 1; X } X splx(s); X return(0); X} X Xmemdiskstrategy(bp) Xstruct buf *bp; X{ X int unit; X register struct memdiskinfo *mdi; X int off; X int nblk; X int s; X X unit = minor(bp->b_dev); X if (! LIVEUNIT(unit)) X { bp->b_flags |= B_ERROR; X iodone(bp); X return; X } X mdi = &memdiskinfo[unit]; X s = lockout(); X if (mdi->busy) X { splx(s); X bp->b_flags |= B_ERROR; X iodone(bp); X return; X } X off = dbtob(bp->b_blkno); X if ( (off < 0) || X (off+bp->b_bcount > mdi->nbytes) ) X { splx(s); X bp->b_flags |= B_ERROR; X iodone(bp); X return; X } X if (bp->b_flags & B_READ) X { bcopy(mdi->data+off,bp->b_un.b_addr,bp->b_bcount); X } X else X { bcopy(bp->b_un.b_addr,mdi->data+off,bp->b_bcount); X } X splx(s); X iodone(bp); X} X Xmemdiskread(dev,uio) Xdev_t dev; Xstruct uio *uio; X{ X static struct buf b[NMEMDISK]; X int unit = minor(dev); X X if (! LIVEUNIT(unit)) X { return(ENXIO); X } X return(physio(memdiskstrategy,&b[unit],dev,B_READ,minphys,uio)); X} X Xmemdiskwrite(dev,uio) Xdev_t dev; Xstruct uio *uio; X{ X static struct buf b[NMEMDISK]; X int unit = minor(dev); X X if (! LIVEUNIT(unit)) X { return(ENXIO); X } X return(physio(memdiskstrategy,&b[unit],dev,B_WRITE,minphys,uio)); X} X Xmemdiskioctl(dev,cmd,data,flag) Xdev_t dev; Xint cmd; Xcaddr_t data; Xint flag; X{ X int unit; X int rv; X int nb; X struct memdiskinfo *mdi; X int s; X X unit = minor(dev); X#ifdef lint X flag = flag; X#endif X if (! OKUNIT(unit)) X { return(ENXIO); X } X mdi = &memdiskinfo[unit]; X rv = 0; X switch (cmd) X { case LIOC_MEM_SET: X nb = * (int *) data; X if ( (nb < 0) || X (nb != dbtob(btodb(nb))) || X (nb > max_md_size) ) X { rv = EINVAL; X break; X } X if (unit_mounted(unit)) X { rv = EBUSY; X break; X } X s = lockout(); X if (mdi->busy) X { splx(s); X return(EALREADY); X } X mdi->busy = 1; X splx(s); X if (mdi->live) X { wmemfree(mdi->data,mdi->nbytes); X mdi->live = 0; X } X if (nb > 0) X { mdi->nbytes = nb; X mdi->data = wmemall(memall,nb); X if (mdi->data == 0) X { rv = ENOMEM; X } X else X { mdi->live = 1; X } X } X mdi->busy = 0; X break; X default: X rv = ENOTTY; X break; X } X return(rv); X} X Xmemdiskdump() X{ X return(ENXIO); X} X Xmemdisksize(dev) Xdev_t dev; X{ X int unit = minor(dev); X X if (! LIVEUNIT(unit)) X { return(-1); X } X return(btodb(memdiskinfo[unit].nbytes)); X} X Xstatic int unit_mounted(unit) Xint unit; X{ X struct mount *mp; X int s; X dev_t dev; X X s = spl4(); /* as long as ipl > 0, (u)mounts can't happen */ X for (mp= &mounttab[0];mp<&mounttab[NMOUNT];mp++) X { if (mp->m_bufp != NULL) X { dev = mp->m_dev; X if ( (bdevsw[major(dev)].d_strategy == memdiskstrategy) && X (minor(dev) == unit) ) X { splx(s); X return(1); X } X } X } X splx(s); X return(0); X} X X#endif SHAR_EOF if test 4858 -ne "`wc -c memdisk.c`" then echo shar: error transmitting memdisk.c \(should have been 4858 characters\) fi echo x - mdset.c \(1367 characters\) sed 's/^X//' > mdset.c << \SHAR_EOF X#include <stdio.h> X#include <sys/file.h> X#include <sys/ioctl.h> X Xchar **argvec; X X/* usage: mdset <unit> <size> */ X/* size can have suffix k or m */ X/* assumes /dev/[r]mdisk%d naming scheme */ X Xint mdfd; Xchar mdname[64]; X Xint geti(s) Xregister char *s; X{ X register int i; X X i = 0; X for (;*s;s++) X { switch (*s) X { case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X i = (i * 10) + (*s - '0'); X break; X case 'm': case 'M': X i *= 1024; X /* fall through */ X case 'k': case 'K': X i *= 1024; X break; X default: X return(-1); X } X } X return(i); X} X Xmain(ac,av) Xint ac; Xchar **av; X{ X int unit; X int size; X X argvec = av; X if (ac != 3) X { fprintf(stderr,"Usage: %s unit size\n",argvec[0]); X exit(1); X } X unit = geti(av[1]); X size = geti(av[2]); X if (unit < 0) X { fprintf(stderr,"%s: bad number `%s'\n",argvec[0],av[1]); X exit(1); X } X if (size < 0) X { fprintf(stderr,"%s: bad number `%s'\n",argvec[0],av[2]); X exit(1); X } X sprintf(mdname,"/dev/rmdisk%d",unit); X mdfd = open(mdname,O_RDWR,0); X if (mdfd < 0) X { fprintf(stderr,"%s: cannot open %s: ",argvec[0],mdname); X perror((char *)0); X exit(1); X } X if (ioctl(mdfd,LIOC_MEM_SET,&size) < 0) X { fprintf(stderr,"%s: cannot set size for %s: ",argvec[0],mdname); X perror((char *)0); X exit(1); X } X exit(0); X} SHAR_EOF if test 1367 -ne "`wc -c mdset.c`" then echo shar: error transmitting mdset.c \(should have been 1367 characters\) fi exit 0 # end of shell archive