[comp.sources.misc] filedisk: make a file into a filesystem

mouse@mcgill-vision.UUCP (der Mouse ) (06/30/87)

[Comment on the below:  it sure as heck isn't seismo, so it must be sun.
I try to avoid that site anyway, as the cwruecmp!sun link has been marked
DEAD in cwruecmp's map for quite a while now.  ++bsa]

This is part 1 of 2.  Read the README (first thing in the archive) to
see what it's part 1 of.  I had to split up even this tiny thing
because someone, either sun or seismo (not sure which), has a 10000
byte limit on mail (yes, only ten thousand bytes).
					der Mouse

				(mouse@mcgill-vision.uucp)

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Sun Jun 28 17:50:43 1987
# Run this through sh to create:
#	README
echo x - README \(5589 characters\)
sed 's/^X//' > README << \SHAR_EOF
Xfiledisk: a pseudo disk driver for UNIX.  This driver makes a normal
X	file look like a filesystem volume.
X
X	Currently in use on 4.3BSD.  Originally developed on 4.2BSD,
X	but the 4.2 version is buried in the mists of the past, so all
X	this says is that it won't take much to make it work on 4.2.  I
X	have attempted to use a somewhat modified version of this under
X	mtXinu 4.3+NFS but unfortunately it keeps crashing the system
X	for reasons yet to be discovered.  I haven't dared even try to
X	make it work on a Sun.  I won't, either, until we get source.
X
XYou should have received:
X
X	- README (this file)
X	- filedisk.c
X	- fdconn.c
X	- fddisc.c
X
XYou will need to:
X
X	- Put filedisk.c somewhere; I'll assume it's in
X	   ../local/filedisk.c (that's where we have it).  If you put
X	   it somewhere else, change the filename in the next item to
X	   point to wherever you did put it.
X
X	- Put a line
Xlocal/filedisk.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	filedisk	1
X	   in ../conf/YOURSYSTEMNAME.  The 1 specifies how many pseudo
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 "filedisk.h"
X#if NFILEDISK > 0
Xextern int filediskopen();
Xextern int filediskstrategy();
Xextern int filediskread();
Xextern int filediskwrite();
Xextern int filediskioctl();
Xextern int filedisksize();
X#else
X#define filediskopen nodev
X#define filediskstrategy nodev
X#define filediskread nodev
X#define filediskwrite nodev
X#define filediskioctl nodev
X#define filedisksize 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	{ filediskopen,	nulldev,	filediskstrategy,nodev,		/* 10 */
X	  filedisksize,	0 },
X	   (the 10 should be changed to whatever number you choose to
X	   put it at).  The cdevsw entry should look like
X	filediskopen,	nulldev,	filediskread,	filediskwrite,	/* 34 */
X	filediskioctl,	nulldev,	nulldev,	0,
X	seltrue,	0,
X	   again, with the 34 changed to whatever is appropriate.
X
X	- add two #define lines to ../h/ioctl.h:
X#define LIOC_FSF_SET	_IOW(l,1,char *)		/* setup filedisk */
X#define LIOC_FSF_CLEAR	_IO(l,2)			/* clear filedisk */
X
XYou can now re-run config and rebuild your kernel.
X
XIf I haven't forgotten anything (:-), it should run fine.  Test the new
Xkernel.  When you are satisfied that adding the filedisk driver hasn't
Xbroken anything else, you can try it out:
X
X	- Create entries in /dev.  We use /dev/filedisk0 and
X	   /dev/rfiledisk0 (just 0 since we have just one configured
X	   in; if we had two, they'd be filedisk0/rfiledisk0 and
X	   filedisk1/rfiledisk1).
X
X	- Compile fdconn.c and fddisc.c; put the binaries wherever you
X	   feel 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.  Fdconn and fddisc must be able to open the raw
X	   device /dev/rfiledisk0 (or rfiledisk1, or 2, or...) in order
X	   to function.
X
XNow to test it.  I should explain what fdconn and fddisc do.  Fdconn
Xconnects a pseudo-disk unit to a file; fddisc breaks the connection
Xcreated by fdconn.  A pseudo-disk unit must be connected to a file
Xbefore it can do anything useful, of course.
X
XLet's test it by just creating a half-meg file and using that as our
Xfilesystem.  First let's create the half-meg file:
X
Xdd if=/dev/full bs=....uh, what, you mean this is the filedisk
Xdistribution rather than the /dev/full driver distribution? ;-)
X
Xyes | dd conv=sync bs=65536 count=8 > bigfile
X
X(65536*8 is 512k; conv=sync makes dd pad each bufferful to the bs=
Xfigure.)  After a few seconds, dd will report 0+8 records in, 8+0
Xrecords out.  Then you will get a "Broken pipe" message, which you
Xshould ignore.  Now we connect this to unit 0:
X
X# fdconn 0 bigfile
X
XNow /dev/filedisk0 and /dev/rfiledisk0 are pseudo-filesystems
Xcontaining lots of junk.  Let's make a filesystem there:
X
X# /etc/mkfs /dev/rfiledisk0 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/rfiledisk0 instead of /dev/filedisk0).
X
X# sync
X
XNow we can mount it somewhere:
X
X# /etc/mount /dev/filedisk0 /mnt
X
XAnd away we go!  Note that you pay two penalties for using this driver.
XOne is speed, of course; the other is storage space, since there is all
Xthe usual filesystem overhead.  Most of the uses for this driver are
Xsuch that these really don't matter.  For example, recently I wanted to
Xbuild a boot tape with a slightly non-standard mini-root filesystem on
Xit.  So I just used dd to copy the mini-root off the tape onto a disk
Xfile and then used this driver to mount the mini-root filesystem
Xsomewhere.  Then of course it was trivial to arrange things on the
Xmini-root as I wanted them.  Then just unmount and run fddisc, and use
Xdd to put it back on tape.
X
X					der Mouse
X
X				(mouse@mcgill-vision.uucp)
SHAR_EOF
if test 5589 -ne "`wc -c README`"
then
echo shar: error transmitting README \(should have been 5589 characters\)
fi
exit 0
# end of shell archive

mouse@mcgill-vision.UUCP (der Mouse ) (06/30/87)

This is part 2 of 2.  Read the README (in part 1) to see what it's part
2 of.  I had to split up even this tiny thing because someone, either
sun or seismo (not sure which), has a 10000 byte limit on mail (yes,
only ten thousand bytes).
					der Mouse

				(mouse@mcgill-vision.uucp)

#! /bin/sh
#
# Shar: Shell Archiver
#
# This archive created Sun Jun 28 17:50:43 1987
# Run this through sh to create:
#	filedisk.c
#	fdconn.c
#	fddisc.c
echo x - filedisk.c \(4378 characters\)
sed 's/^X//' > filedisk.c << \SHAR_EOF
X/*
X * Filesystem-in-a-file pseudo-disk driver.
X */
X
X#include "filedisk.h"
X
X#if NFILEDISK > 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/dir.h"
X#include "../h/file.h"
X#include "../h/inode.h"
X#include "../h/namei.h"
X#include "../h/user.h"
X#include "../h/proc.h"
X#include "../h/uio.h"
X#include "../h/mount.h"
X#include "../h/fs.h"
X#include "../h/kernel.h"
X
Xstatic struct fdinfo {
X	 int alive;
X	 int unit;
X	 struct inode *ino;
X	 int nblocks; } info[NFILEDISK];
Xstatic int didinit = 0;
X
X#define OKUNIT(u) (((u)>=0)&&((u)<NFILEDISK))
X
Xfilediskopen(dev,flag)
Xdev_t dev;
Xint flag;
X{
X int unit;
X
X#ifdef lint
X flag = flag;
X#endif
X if (! didinit)
X  { for (unit=0;unit<NFILEDISK;unit++)
X     { info[unit].alive = 0;
X       info[unit].unit = unit;
X     }
X    didinit = 1;
X  }
X unit = minor(dev);
X if (!OKUNIT(unit))
X  { return(ENXIO);
X  }
X return(0);
X}
X
Xfilediskstrategy(bp)
Xstruct buf *bp;
X{
X int s;
X
X if (! buf_ok(bp))
X  { return;
X  }
X s = splhigh();
X splx(s);
X if (s != 0)
X  { printf("IPL=%d\n",s);
X    panic("filediskstrategy: high ipl\n");
X  }
X else
X  { doionow(bp);
X  }
X}
X
Xfilediskread(dev,uio)
Xdev_t dev;
Xstruct uio *uio;
X{
X static struct buf b;
X int unit;
X
X unit = minor(dev);
X if (!OKUNIT(unit))
X  { return(ENXIO);
X  }
X return(physio(filediskstrategy,&b,dev,B_READ,minphys,uio));
X}
X
Xfilediskwrite(dev,uio)
Xdev_t dev;
Xstruct uio *uio;
X{
X static struct buf b;
X int unit;
X
X unit = minor(dev);
X if (!OKUNIT(unit))
X  { return(ENXIO);
X  }
X return(physio(filediskstrategy,&b,dev,B_WRITE,minphys,uio));
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= &mount[0];mp<&mount[NMOUNT];mp++)
X  { if (mp->m_bufp != 0)
X     { dev = mp->m_dev;
X       if ( (bdevsw[major(dev)].d_strategy == filediskstrategy) &&
X	    (minor(dev) == unit) )
X	{ splx(s);
X	  return(1);
X	}
X     }
X  }
X splx(s);
X return(0);
X}
X
Xfilediskioctl(dev,cmd,data,flag)
Xdev_t dev;
Xint cmd;
Xcaddr_t data;
Xint flag;
X{
X int unit;
X int rv;
X struct inode *ip;
X register struct nameidata *ndp;
X
X#ifdef lint
X flag = flag;
X#endif
X unit = minor(dev);
X rv = EIO;
X switch (cmd)
X  { case LIOC_FSF_SET:
X       if (! suser())
X	{ rv = EPERM;
X	  break;
X	}
X       if (info[unit].alive)
X	{ rv = EBUSY;
X	  break;
X	}
X       ndp = &u.u_nd;
X       ndp->ni_segflg = UIO_USERSPACE;
X       ndp->ni_dirp = *(char **)data;
X       ndp->ni_nameiop = LOOKUP | FOLLOW;
X       ip = namei(ndp);
X       if (ip == 0)
X	{ rv = u.u_error;
X	  break;
X	}
X       if ((ip->i_mode&IFMT) != IFREG)
X	{ iput(ip);
X	  rv = EINVAL;
X	  break;
X	}
X       info[unit].ino = ip;
X       info[unit].nblocks = btodb(ip->i_size);
X       info[unit].alive = 1;
X       iunlock(ip);
X       rv = 0;
X       break;
X    case LIOC_FSF_CLEAR:
X       if (! suser())
X	{ rv = EPERM;
X	  break;
X	}
X       if (unit_mounted(unit))
X	{ rv = EBUSY;
X	  break;
X	}
X       if (info[unit].alive)
X	{ info[unit].alive = 0;
X	  irele(info[unit].ino);
X	  rv = 0;
X	}
X       else
X	{ rv = ENXIO;
X	}
X       break;
X  }
X return(rv);
X}
X
Xfilediskdump()
X{
X return(ENXIO);
X}
X
Xfiledisksize(dev)
Xdev_t dev;
X{
X int unit;
X
X unit = minor(dev);
X if ((unit < 0) || (unit >= NFILEDISK) || !info[unit].alive)
X  { return(-1);
X  }
X return(info[unit].nblocks);
X}
X
Xfilediskreset(uban)
Xint uban;
X{
X printf("filedisk reset on %d?\n",uban);
X}
X
Xstatic int buf_ok(bp)
Xstruct buf *bp;
X{
X int unit;
X int nblk;
X
X#define FAIL() return((bp->b_flags|=B_ERROR),(iodone(bp)),0)
X unit = minor(bp->b_dev);
X if (bp->b_bcount & (DEV_BSIZE-1))
X  { FAIL();
X  }
X nblk = btodb(bp->b_bcount);
X if (! info[unit].alive)
X  { FAIL();
X  }
X if ( (bp->b_blkno < 0) ||
X      (bp->b_blkno+nblk > info[unit].nblocks) )
X  { FAIL();
X  }
X if (! info[unit].ino)
X  { FAIL();
X  }
X return(1);
X#undef FAIL
X}
X
Xstatic doionow(bp)
Xstruct buf *bp;
X{
X int unit = minor(bp->b_dev);
X struct inode *ip = info[unit].ino;
X
X ilock(ip);
X if (bp->b_flags & B_READ)
X  { bp->b_error = rdwri( UIO_READ,
X			 ip,
X			 bp->b_un.b_addr,
X			 bp->b_bcount,
X			 dbtob(bp->b_blkno),
X			 1,
X			 &bp->b_resid );
X    if (bp->b_error)
X     { bp->b_flags |= B_ERROR;
X     }
X  }
X else
X  { bp->b_error = rdwri( UIO_WRITE,
X			 ip,
X			 bp->b_un.b_addr,
X			 bp->b_bcount,
X			 dbtob(bp->b_blkno),
X			 1,
X			 &bp->b_resid );
X    if (bp->b_error)
X     { bp->b_flags |= B_ERROR;
X     }
X  }
X iunlock(ip);
X iodone(bp);
X}
X
X#endif
SHAR_EOF
if test 4378 -ne "`wc -c filedisk.c`"
then
echo shar: error transmitting filedisk.c \(should have been 4378 characters\)
fi
echo x - fdconn.c \(664 characters\)
sed 's/^X//' > fdconn.c << \SHAR_EOF
X#include <stdio.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X
Xchar **argvec;
X
X/* usage: fdconn <unit> <filename> */
X
Xchar dname[64];
Xint dfd;
X
Xmain(ac,av)
Xint ac;
Xchar **av;
X{
X int unit;
X
X argvec = av;
X if (ac != 3)
X  { fprintf(stderr,"Usage: %s unit file\n",argvec[0]);
X    exit(1);
X  }
X unit = atoi(av[1]);
X sprintf(dname,"/dev/rfiledisk%d",unit);
X dfd = open(dname,O_RDWR,0);
X if (dfd < 0)
X  { fprintf(stderr,"%s: cannot open %s: ",argvec[0],dname);
X    perror((char *)0);
X    exit(1);
X  }
X if (ioctl(dfd,LIOC_FSF_SET,&av[2]) < 0)
X  { fprintf(stderr,"%s: cannot connect %s to %s: ",argvec[0],dname,av[2]);
X    perror((char *)0);
X    exit(1);
X  }
X exit(0);
X}
SHAR_EOF
if test 664 -ne "`wc -c fdconn.c`"
then
echo shar: error transmitting fdconn.c \(should have been 664 characters\)
fi
echo x - fddisc.c \(636 characters\)
sed 's/^X//' > fddisc.c << \SHAR_EOF
X#include <stdio.h>
X#include <sys/file.h>
X#include <sys/ioctl.h>
X
Xchar **argvec;
X
X/* usage: fddisc <unit> */
X
Xchar dname[64];
Xint dfd;
X
Xmain(ac,av)
Xint ac;
Xchar **av;
X{
X int unit;
X
X argvec = av;
X if (ac != 2)
X  { fprintf(stderr,"Usage: %s unit\n",argvec[0]);
X    exit(1);
X  }
X unit = atoi(av[1]);
X sprintf(dname,"/dev/rfiledisk%d",unit);
X dfd = open(dname,O_RDWR,0);
X if (dfd < 0)
X  { fprintf(stderr,"%s: cannot open %s: ",argvec[0],dname);
X    perror((char *)0);
X    exit(1);
X  }
X if (ioctl(dfd,LIOC_FSF_CLEAR,0) < 0)
X  { fprintf(stderr,"%s: cannot disconnect %s: ",argvec[0],dname);
X    perror((char *)0);
X    exit(1);
X  }
X exit(0);
X}
SHAR_EOF
if test 636 -ne "`wc -c fddisc.c`"
then
echo shar: error transmitting fddisc.c \(should have been 636 characters\)
fi
exit 0
# end of shell archive