|
|
researchv10 Norman
/*
* traditional disk filesystem
*/
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/ino.h"
#include "sys/buf.h"
#include "sys/filsys.h"
#include "sys/mount.h"
#include "sys/dir.h"
#include "sys/user.h"
#include "sys/inode.h"
#include "sys/file.h"
#include "sys/conf.h"
#include "sys/vlimit.h"
#include "sys/stat.h"
#include "sys/filio.h"
#include "sys/cmap.h"
#include "sys/stream.h"
int fsput(), fsupdat(), fsread(), fswrite(), fstrunc(), fsstat();
int fsnami(), fsmount(), fsioctl(), fsdirread();
struct inode *fsopen();
struct fstypsw fsfs =
fsinit(fsput, fsupdat, fsread, fswrite, fstrunc, fsstat,
fsnami, fsmount, fsioctl, fsopen, fsdirread);
extern struct mount fsmtab[];
extern int fscnt;
/*
* silly mount/unmount routine for fs type 0
*/
fsmount(sip, ip, flag, mnt, fstyp)
register struct inode *ip, *sip;
int flag, mnt, fstyp;
{
if (!suser())
return;
if (mnt)
fson(sip, ip, flag, fstyp);
else
fsoff(ip, fstyp);
}
/*
* mount a type 0 filesystem (sip on ip)
* maintain the mount table for vm code's sake
*
* magic to help booting:
* if rootdir == NULL, we are being called from iinit, so
* - allow s_valid == 0 on bitmapped filesystems so root may be mounted
* - call clkinit to set the clock from the super-block time
*/
fson(sip, ip, ronly, fstyp)
register struct inode *ip, *sip;
int ronly, fstyp;
{
dev_t dev;
register struct mount *mp;
struct mount *emp;
struct inode *rip;
register struct filsys *fp;
struct buf *bp;
struct inode pi; /* primer */
if ((sip->i_mode&IFMT) != IFBLK) {
u.u_error = EINVAL;
return;
}
if (ip->i_fstyp == fstyp && ip->i_dev == sip->i_un.i_rdev) {
u.u_error = EBUSY;
return;
}
emp = NULL;
for (mp = &fsmtab[fscnt-1]; mp >= fsmtab; mp--) {
if (mp->m_dev == NULL)
emp = mp;
else if (mp->m_dev == sip)
goto hopeless;
}
if (emp == NULL)
goto hopeless;
emp->m_dev = sip;
dev = (dev_t)sip->i_un.i_rdev;
bp = bread(dev, SUPERB);
if(u.u_error) {
emp->m_dev = NULL;
brelse(bp);
return;
}
bp->b_flags |= B_LOCKED;
brelse(bp);
fp = bp->b_un.b_filsys;
fp->s_ilock = 0;
fp->s_flock = 0;
fp->s_ronly = ronly & 1;
fp->s_nbehind = 0;
fp->s_lasti = 1;
if(fp->s_cylsize == 0)
fp->s_cylsize = 40; /* transition hack */
if(fp->s_aspace == 0)
fp->s_aspace = 4; /* likewise */
if(BITFS(dev) && !fp->s_valid && !fp->s_ronly && rootdir != NULL)
goto failed; /* NOT IMPLEMENTED */
if(BITFS(dev) && fp->U.N.S_flag) {
if(fsbiton(dev, fp))
goto failed;
/* hack until pjw fixes chuck */
} else if (BITFS(dev) && fp->s_isize + BITMAP*BITCELL < fp->s_fsize)
if(fsbiton(dev, fp))
goto failed;
pi.i_dev = dev;
pi.i_fstyp = fstyp;
pi.i_un.i_bufp = bp;
if ((rip = iget(&pi, dev, ROOTINO)) == NULL)
goto failed;
if (rip->i_count == 1 && fsiread(&pi, rip) < 0)
goto failed;
if (rip->i_count != 1) { /* already mounted */
iput(rip);
goto failed;
}
emp->m_mroot = rip;
ip->i_mroot = rip;
rip->i_mpoint = ip;
ip->i_count++;
sip->i_count++;
prele(rip);
if (rootdir == NULL)
clkinit(fp->s_time);
return;
failed:
bp->b_flags &= ~B_LOCKED;
emp->m_dev = NULL;
hopeless:
if (u.u_error == 0)
u.u_error = EBUSY;
}
fsoff(mip, fstyp)
register struct inode *mip;
{
dev_t dev;
register struct mount *mp;
register struct inode *rip;
struct buf *bp;
struct filsys *fp;
rip = mip->i_mroot;
for (mp = &fsmtab[fscnt-1]; mp >= fsmtab; mp--)
if (mp->m_mroot == rip)
break;
if (mp < fsmtab)
panic("umount mp");
plock(rip);
xumount(rip);
update(); /* silly */
if (rip->i_count > 1 || ifsbusy(rip)) {
u.u_error = EBUSY;
prele(rip);
return;
}
plock(mip);
mip->i_mroot = NULL;
iput(mip);
dev = rip->i_dev;
if ((bp = getblk(dev, SUPERB)) != rip->i_un.i_bufp)
panic("umount");
iput(rip);
bp->b_flags &= ~(B_LOCKED|B_ASYNC); /* ~async needed? */
if (bp->b_un.b_filsys->s_ronly)
brelse(bp);
else {
if (BITFS(dev)) {
fp = bp->b_un.b_filsys;
fp->s_valid = 1;
if(fp->U.N.S_flag)
fsbitoff(dev, fp, 1);
}
bwrite(bp);
}
mpurge(mp - fsmtab);
idec(mp->m_dev);
mp->m_dev = NULL;
}
fsbiton(dev, fp)
dev_t dev;
register struct filsys *fp;
{
register int i, nf;
register struct buf **bpp;
register struct buf *bp;
/* two chuck should do */
fp->U.N.S_flag = 1; /* bit map not in superblock */
nf = fp->U.N.S_bsize = BSIZE(dev) * NBBY;
if (fp->s_ronly)
return (0);
nf = (fp->s_fsize + nf - 1) / nf;
bpp = fp->U.N.S_blk;
for(i = 0; i < nf; i++)
bpp[i] = 0;
for(i = 0; i < nf; i++) {
bp = bread(dev, fp->s_fsize-nf+i);
if(u.u_error) {
brelse(bp);
goto failed;
}
bp->b_flags |= B_LOCKED;
brelse(bp);
bpp[i] = bp;
}
return(0);
failed:
fsbitoff(dev, fp, 0);
return(1);
}
fsbitoff(dev, fp, wrtflg)
dev_t dev;
struct filsys *fp;
{
register struct buf **bpp;
register struct buf *bp;
register int i, nf;
if (fp->s_ronly)
return;
nf = fp->U.N.S_bsize;
nf = (fp->s_fsize + nf-1)/nf;
bpp = fp->U.N.S_blk;
for(i = 0; i < nf; i++)
if(bpp[i]) {
if ((bp = getblk(dev, fp->s_fsize - nf + i)) != bpp[i])
panic("fsbitoff");
bp->b_flags &= ~B_LOCKED;
if(wrtflg)
bwrite(bp);
bpp[i] = 0; /* safety first */
}
}
/*
* fill in inode ip from the disk copy
* in filesystem fip
* ip is an inode fresh from iget
*/
fsiread(fip, ip)
register struct inode *fip, *ip;
{
register struct buf *bp;
daddr_t bno;
if (ip->i_number <= 0) {
u.u_error = EINVAL;
iput(ip);
return (-1);
}
bno = itod(fip->i_dev, (ino_t)ip->i_number);
if (bno >= getfs(fip)->s_isize) {
u.u_error = EINVAL;
iput(ip);
return (-1);
}
bp = bread(fip->i_dev, bno);
if((bp->b_flags&B_ERROR) != 0) {
brelse(bp);
iput(ip);
return(-1);
}
iexpand(ip, bp->b_un.b_dino+itoo(fip->i_dev, (ino_t)ip->i_number));
brelse(bp);
ip->i_un.i_bufp = fip->i_un.i_bufp;
ip->i_un.i_lastr = 0;
return (0);
}
iexpand(ip, dp)
register struct inode *ip;
register struct dinode *dp;
{
register char *p1, *p2;
register int i;
ip->i_mode = dp->di_mode;
ip->i_nlink = dp->di_nlink;
ip->i_uid = dp->di_uid;
ip->i_gid = dp->di_gid;
ip->i_size = dp->di_size;
p1 = (char *)ip->i_un.i_addr;
p2 = (char *)dp->di_addr;
for(i=0; i<NADDR; i++) {
*p1++ = *p2++;
*p1++ = *p2++;
*p1++ = *p2++;
*p1++ = 0;
}
}
fsput(ip)
struct inode *ip;
{
if (ip->i_nlink == 0) {
fstrunc(ip);
ifree(ip);
ip->i_mode = 0;
ip->i_flag |= IUPD|ICHG;
}
if ((ip->i_flag&(IUPD|IACC|ICHG)) != 0)
fsiupdat(ip, &time, &time, 0);
}
fsupdat(ip, ta, tm, waitfor)
register struct inode *ip;
time_t *ta, *tm;
{
fsiupdat(ip, ta, tm, waitfor);
if (ip->i_un.i_bufp->b_un.b_filsys->s_fmod)
fsfupdat(ip);
}
/*
* update the inode on disk
* if the super-block is dirty, write it too
*/
fsiupdat(ip, ta, tm, waitfor)
register struct inode *ip;
time_t *ta, *tm;
{
register struct buf *bp;
struct dinode *dp;
register char *p1, *p2;
register int i;
if (ip->i_un.i_bufp->b_un.b_filsys->s_ronly)
return;
bp = bread(ip->i_dev, itod(ip->i_dev, ip->i_number));
if (bp->b_flags & B_ERROR) {
brelse(bp);
return;
}
dp = bp->b_un.b_dino;
dp += itoo(ip->i_dev, ip->i_number);
dp->di_mode = ip->i_mode;
dp->di_nlink = ip->i_nlink;
dp->di_uid = ip->i_uid;
dp->di_gid = ip->i_gid;
dp->di_size = ip->i_size;
p1 = (char *)dp->di_addr;
p2 = (char *)ip->i_un.i_addr;
for(i=0; i<NADDR; i++) {
*p1++ = *p2++;
*p1++ = *p2++;
*p1++ = *p2++;
if(*p2++)
printf("ino %d dev #%x addr #%x\n", ip->i_number, ip->i_dev, ip->i_un.i_addr[i]);
}
if(ip->i_flag&IACC)
dp->di_atime = *ta;
if(ip->i_flag&IUPD)
dp->di_mtime = *tm;
if(ip->i_flag&ICHG)
dp->di_ctime = time;
ip->i_flag &= ~(IUPD|IACC|ICHG);
if (waitfor)
bwrite(bp);
else
bdwrite(bp);
}
/*
* write the super-block
*/
fsfupdat(ip)
struct inode *ip;
{
register struct filsys *fp;
struct buf *bp;
fp = ip->i_un.i_bufp->b_un.b_filsys;
if (fp->s_fmod == 0 || fp->s_ilock || fp->s_flock || fp->s_ronly)
return;
bp = getblk(ip->i_dev, SUPERB);
if (bp->b_un.b_filsys != fp)
panic("fsfupdat");
fp->s_fmod = 0;
fp->s_time = time;
bwrite(bp);
}
fsstat(ip, ub)
register struct inode *ip;
struct stat *ub;
{
register struct dinode *dp;
register struct buf *bp;
struct stat ds;
/*
* first copy from inode table
*/
ds.st_dev = ip->i_dev;
ds.st_ino = ip->i_number;
ds.st_mode = ip->i_mode;
ds.st_nlink = ip->i_nlink;
ds.st_uid = ip->i_uid;
ds.st_gid = ip->i_gid;
ds.st_rdev = (dev_t)ip->i_un.i_rdev;
ds.st_size = ip->i_size;
/*
* next the dates in the disk
*/
bp = bread(ip->i_dev, itod(ip->i_dev, ip->i_number));
dp = bp->b_un.b_dino;
dp += itoo(ip->i_dev, ip->i_number);
ds.st_atime = dp->di_atime;
ds.st_mtime = dp->di_mtime;
ds.st_ctime = dp->di_ctime;
brelse(bp);
if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
u.u_error = EFAULT;
}
fstrunc(ip)
register struct inode *ip;
{
register i;
daddr_t bn;
struct inode itmp;
i = ip->i_mode & IFMT;
if (i!=IFREG && i!=IFDIR && i!=IFLNK)
return;
/*
* Clean inode on disk before freeing blocks
* to insure no duplicates if system crashes.
*/
itmp = *ip;
itmp.i_size = 0;
for (i = 0; i < NADDR; i++)
itmp.i_un.i_addr[i] = 0;
itmp.i_flag |= ICHG|IUPD;
fsiupdat(&itmp, &time, &time, 1);
ip->i_flag &= ~(IUPD|IACC|ICHG);
/*
* Now return blocks to free list... if machine
* crashes, they will be harmless MISSING blocks.
*/
for(i=NADDR-1; i>=0; i--) {
bn = ip->i_un.i_addr[i];
if(bn == (daddr_t)0)
continue;
ip->i_un.i_addr[i] = (daddr_t)0;
switch(i) {
default:
free(ip, bn);
break;
case NADDR-3:
tloop(ip, bn, 0, 0);
break;
case NADDR-2:
tloop(ip, bn, 1, 0);
break;
case NADDR-1:
tloop(ip, bn, 1, 1);
}
}
ip->i_size = 0;
/*
* Inode was written and flags updated above.
* No need to modify flags here.
*/
}
tloop(fip, bn, f1, f2)
register struct inode *fip;
daddr_t bn;
{
register i;
register struct buf *bp;
register daddr_t *bap;
daddr_t nb;
bp = NULL;
for(i=NINDIR(fip->i_dev)-1; i>=0; i--) {
if(bp == NULL) {
bp = bread(fip->i_dev, bn);
if (bp->b_flags & B_ERROR) {
brelse(bp);
return;
}
bap = bp->b_un.b_daddr;
}
nb = bap[i];
if(nb == (daddr_t)0)
continue;
if(f1) {
brelse(bp);
bp = NULL;
tloop(fip, nb, f2, 0);
} else
free(fip, nb);
}
if(bp != NULL)
brelse(bp);
free(fip, bn);
}
fsioctl(ip, cmd, cmarg, flag)
register struct inode *ip;
caddr_t cmarg;
{
int fmt;
register dev_t dev;
fmt = ip->i_mode & IFMT;
if (fmt != IFCHR) {
if (cmd==FIONREAD && (fmt == IFREG || fmt == IFDIR)) {
off_t nread = ip->i_size; /* - fp->f_offset */
if (copyout((caddr_t)&nread, cmarg, sizeof(off_t)))
u.u_error = EFAULT;
} else
u.u_error = ENOTTY;
return;
}
dev = ip->i_un.i_rdev;
u.u_r.r_val1 = 0;
(*cdevsw[major(dev)]->d_ioctl)(dev, cmd, cmarg, flag);
}
struct inode *
fsopen(ip, rw)
register struct inode *ip;
{
dev_t dev;
register unsigned int maj;
dev = (dev_t)ip->i_un.i_rdev;
maj = major(dev);
switch(ip->i_mode&IFMT) {
case IFCHR:
if(maj >= nchrdev || cdevsw[maj] == NULL)
goto bad;
if (cdevsw[maj]->qinfo) /* stream device */
return(stopen(cdevsw[major(dev)]->qinfo, dev, rw, ip));
(*cdevsw[maj]->d_open)(dev, rw);
break;
case IFBLK:
if(maj >= nblkdev || bdevsw[maj] == NULL)
goto bad;
(*bdevsw[maj]->d_open)(dev, rw);
}
if (u.u_error) {
iput(ip);
return (NULL);
}
return (ip);
bad:
u.u_error = ENXIO;
iput(ip);
return(NULL);
}
fsread(ip)
register struct inode *ip;
{
struct buf *bp;
dev_t dev;
daddr_t lbn, bn;
off_t diff;
register int on, type;
register unsigned n;
dev = (dev_t)ip->i_un.i_rdev;
type = ip->i_mode&IFMT;
if (type==IFCHR) {
(*cdevsw[major(dev)]->d_read)(dev);
return;
}
if (Lsign(u.u_offset) < 0) { /* and not IFCHR */
u.u_error = EINVAL;
return;
}
if (type != IFBLK) { /* if offset >= size, avoid overflow */
if (Lsign(Lladd(u.u_offset, -ip->i_size))>=0)
return;
dev = ip->i_dev;
}
do {
lbn = bn = Lshift(u.u_offset, BSHIFT(dev));
on = Ltol(u.u_offset) & BMASK(dev);
n = MIN((unsigned)(BSIZE(dev)-on), u.u_count);
if (type!=IFBLK) {
diff = ip->i_size - Ltol(u.u_offset);
if (diff <= 0)
return;
if (diff < n)
n = diff;
bn = bmap(ip, bn, B_READ);
if (u.u_error)
return;
} else
rablock = bn+1;
if ((long)bn<0) {
bp = geteblk();
clrbuf(bp);
} else if (ip->i_un.i_lastr+1==lbn)
bp = breada(dev, bn, rablock);
else
bp = bread(dev, bn);
ip->i_un.i_lastr = lbn;
n = MIN(n, BSIZE(dev)-bp->b_resid);
if (n!=0)
iomove(bp->b_un.b_addr+on, n, B_READ);
brelse(bp);
} while(u.u_error==0 && u.u_count!=0 && n!=0);
}
fsdirread(ip, len)
struct inode *ip;
{ struct buf *bp = 0, *outb;
dev_t dev;
daddr_t bn, lbn;
int on, type, j, m, new = 0;
char *p, *lp, *lastp;
struct direct *dp;
char ncvt[24];
if(Lsign(u.u_offset) < 0) {
u.u_error = EINVAL;
return;
}
type = ip->i_mode & IFMT;
if(type != IFDIR) {
u.u_error = ENOTDIR;
return;
}
dev = ip->i_dev;
outb = geteblk(); /* to hold the stuff for the user */
if(len > BSIZE(dev))
len = BSIZE(dev);
p = lp = outb->b_un.b_addr;
lastp = p + len;
loop:
if(new <= 0) { /* get some goo */
lbn = bn = Lshift(u.u_offset, BSHIFT(dev));
on = Ltol(u.u_offset) & BMASK(dev);
if(ip->i_size <= Ltol(u.u_offset))
goto done;
bn = bmap(ip, bn, B_READ);
if(u.u_error)
return;
if((long)bn < 0) { /* holes in dirs? */
u.u_offset = Lladd(u.u_offset, BSIZE(dev)-on);
goto loop; /* try the next block */
}
if(bp)
brelse(bp);
if(ip->i_un.i_lastr + 1 == lbn)
bp = breada(dev, bn, rablock);
else
bp = bread(dev, bn);
ip->i_un.i_lastr = lbn;
new = BSIZE(dev) - on;
if(new > BSIZE(dev) - bp->b_resid) /* io error? */
new = BSIZE(dev) - bp->b_resid; /* or paranoia */
if(new > ip->i_size - Ltol(u.u_offset))
new = ip->i_size - Ltol(u.u_offset);
dp = (struct direct *) (bp->b_un.b_addr + on);
}
if(dp->d_ino == 0)
goto incr;
for(m = dp->d_ino, j = sizeof(ncvt)-1; m; j--) {
ncvt[j] = m%10 + '0';
m /= 10;
}
for(++j; j < sizeof(ncvt) && p < lastp; )
*p++ = ncvt[j++];
if(j != sizeof(ncvt) || p >= lastp)
goto early;
*p++ = '\t';
for(j = 0; j < DIRSIZ && dp->d_name[j] && p < lastp; j++)
*p++ = dp->d_name[j];
if(p >= lastp)
goto early;
*p++ = 0;
incr:
lp = p;
new -= sizeof(*dp);
u.u_offset = Lladd(u.u_offset, sizeof(*dp));
dp++;
if(p < lastp)
goto loop;
done:
j = lp - outb->b_un.b_addr;
if(j > 0)
if(copyout((caddr_t)outb->b_un.b_addr, u.u_base, j))
u.u_error = EFAULT;
if(bp)
brelse(bp);
brelse(outb);
u.u_r.r_val1 = j;
return;
early:
*lp = 0;
if(lp > outb->b_un.b_addr)
goto done;
u.u_error = ENOSPC;
if(bp)
brelse(bp);
brelse(outb);
}
fswrite(ip)
register struct inode *ip;
{
struct buf *bp;
dev_t dev;
daddr_t bn;
register int on, type;
register unsigned n;
register int i;
dev = (dev_t)ip->i_un.i_rdev;
type = ip->i_mode&IFMT;
if (type==IFCHR) {
ip->i_flag |= IUPD|ICHG;
(*cdevsw[major(dev)]->d_write)(dev);
return;
}
if (Lsign(u.u_offset) < 0) { /* and not IFCHR */
u.u_error = EINVAL;
return;
}
if (u.u_count == 0)
return;
if ((ip->i_mode&IFMT)==IFREG &&
(Lsign(Luadd(u.u_offset, u.u_count))!=0 ||
Ltol(u.u_offset) + u.u_count > u.u_limit[LIM_FSIZE])) {
u.u_error = EMFILE;
return;
}
if (type != IFBLK)
dev = ip->i_dev;
do {
bn = Lshift(u.u_offset, BSHIFT(dev));
on = Ltol(u.u_offset) & BMASK(dev);
n = MIN((unsigned)(BSIZE(dev)-on), u.u_count);
if (type!=IFBLK) {
bn = bmap(ip, bn, B_WRITE);
if((long)bn<0)
return;
}
i = getfsx(dev);
if (bn && mfind(i, bn))
munhash(i, bn);
if(n == BSIZE(dev))
bp = getblk(dev, bn);
else
bp = bread(dev, bn);
iomove(bp->b_un.b_addr+on, n, B_WRITE);
if(u.u_error != 0)
brelse(bp);
else {
if ((ip->i_mode&IFMT) == IFDIR &&
((struct direct *)(bp->b_un.b_addr+on))->d_ino == 0)
bwrite(bp); /* consistency */
else if ((n+on) == BSIZE(dev))
bawrite(bp);
else
bdwrite(bp);
}
if(Ltol(u.u_offset) > ip->i_size &&
(type==IFDIR || type==IFREG || type==IFLNK))
ip->i_size = Ltol(u.u_offset);
ip->i_flag |= IUPD|ICHG;
} while(u.u_error==0 && u.u_count!=0);
}
/*
* Getfsx returns the index in the file system
* table of the specified device. The swap device
* is also assigned a pseudo-index. The index may
* be used as a compressed indication of the location
* of a block, recording
* <getfsx(dev),blkno>
* rather than
* <dev, blkno>
* provided the information need remain valid only
* as long as the file system is mounted.
*
* only the vm code calls this.
*/
getfsx(dev)
dev_t dev;
{
register struct mount *mp;
if (dev == swapdev)
return (MSWAPX);
for (mp = &fsmtab[fscnt-1]; mp >= fsmtab; mp--) {
if (mp->m_dev == NULL)
continue;
if (mp->m_dev->i_un.i_rdev == dev)
return (mp - fsmtab);
}
return (-1);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.