|
|
researchv10 Norman
/*
* This file contains the routines which support mounted
* streams (file system type 3).
*/
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/inode.h"
#include "sys/stream.h"
#include "sys/user.h"
#include "sys/file.h"
#include "sys/stat.h"
#include "sys/conf.h"
int msupdat(), msread(), mswrite(), msstat();
int msmount(), msioctl();
struct inode *msopen();
struct fstypsw msfs =
fsinit(nulldev, msupdat, msread, mswrite, nulldev, msstat,
nullnami, msmount, msioctl, msopen, nodev);
/*
* The following definitions apply to all comments:
* - `locked' means that an inode has had `plock' applied to it
* - `reserved' means that the inode's i_count has been incremented to
* ensure that the inode will be freed during an operation.
*/
/*
* To ensure consistency
*/
#define SETMOUNT(d,r) d->i_mroot = r
#define CLRMOUNT(d) d->i_mroot = NULL
msmount(cip, dip, flag, mnt, fstyp)
struct inode *cip, *dip;
{
if(accowner(dip) == 0) /* only owner can mount */
return; /* errno set by accowner */
if (mnt) {
/*
* from fmount(), `dip' is locked and reserved
*/
mson(cip, dip, flag, fstyp);
/*
* iput occurs in fmount();
*/
} else {
/*
* from fmount(), nothing locked or reserved
*/
msoff(dip, 0);
}
}
/*
* Create an in core root node, mount it, and attach a communications inode.
* On entry, `dip' is locked and reserved. On exit, `dip' is still locked
* and reserved (i.e. shoud be iput).
*/
mson(cip, dip, flag, fstyp)
register struct inode *cip; /* stream being mounted */
register struct inode *dip; /* mount point */
{
register struct inode *rip; /* root inode for new fs */
/* must be mounting a stream */
if(cip->i_sptr == NULL) {
u.u_error = ENXIO;
return;
}
/* already mounted? */
if(dip->i_fstyp == fstyp) {
u.u_error = EBUSY; /* in use */
return;
}
/* create a new inode for the fs root */
rip = iuniq(fstyp);
if(rip == NULL)
return; /* errno already set */
rip->i_un.i_cip = cip;
rip->i_mpoint = dip;
rip->i_mode &= IFMT;
rip->i_mode |= dip->i_mode & ~IFMT;
rip->i_flag |= IACC; /* force update */
prele(rip);
cip->i_count++;
/* mount the root */
SETMOUNT(dip,rip);
dip->i_count++;
}
/*
* Unmount the stream and close it if approriate.
* On entry, `dip' is neither reserved or locked.
*/
msoff(dip, rlocked)
register struct inode *dip; /* mount point */
{
register struct inode *rip; /* root inode */
register struct inode *cip; /* mounted stream */
/* if not mounted, we're done */
if (dip->i_mroot==NULL)
return;
/*
* To avoid deadlock, always lock the resources in the same order.
* Since the root may already be locked on the way in, it comes
* first.
*/
rip = dip->i_mroot;
if (!rlocked)
plock(rip);
plock(dip);
/* make sure nothing changed while we were locking the inodes */
if (dip->i_mroot!=rip) {
prele(dip);
if (!rlocked)
prele(rip);
return;
}
/* disassociate the stream from the mount point */
cip = rip->i_un.i_cip;
rip->i_un.i_cip = NULL;
if(cip != NULL) {
if(cip->i_count==1)
stclose(cip, 1);
iput(cip);
}
/* unmount root from file system */
rip->i_mpoint = NULL;
CLRMOUNT(dip);
iput(dip);
iput(rip);
}
/*
* If the node is still mounted and the stream has hung up,
* unmount it. On entry, rip is locked.
* This is called by `update()'.
*
* This is called because IACC is set in rip in mson above.
* update routines are meant to clear IACC|IUPD|ICHG, but
* we don't, so the calls keep coming.
*
* stat and open should probably check the stream too.
*/
msupdat(rip, ta, tm, waitfor)
register struct inode *rip;
time_t *ta, *tm;
{
register struct inode *cip;
register struct inode *dip;
cip = rip->i_un.i_cip;
if (cip==NULL || cip->i_sptr==NULL || cip->i_sptr->flag&HUNGUP) {
dip = rip->i_mpoint;
if (dip != NULL) {
if (!(rip->i_flag&ILOCK))
panic("msupdate: inode not locked");
msoff(dip, 1);
}
}
}
/*
* Pass read onto the stream's inode.
* `rip' is locked during this operation.
*/
msread(rip)
struct inode *rip;
{
register struct inode *cip;
cip = rip->i_un.i_cip;
if (cip!=NULL)
readi(cip);
else
u.u_error = EPIPE;
}
/*
* Pass write onto the stream's inode.
* `rip' is locked during this operation.
*/
mswrite(rip)
struct inode *rip;
{
register struct inode *cip;
cip = rip->i_un.i_cip;
if (cip!=NULL)
writei(cip);
else
u.u_error = EPIPE;
}
/*
* Pass ioctl onto the stream's inode.
* `rip' is locked during this operation.
*/
msioctl(rip, cmd, cmarg, flag)
register struct inode *rip;
caddr_t cmarg;
{
register struct inode *cip;
cip = rip->i_un.i_cip;
if (cip!=NULL)
stioctl(cip, cmd, cmarg);
else
u.u_error = EPIPE;
}
/*
* stat `mounted' inode
*/
msstat(rip, ub)
struct inode *rip;
struct stat *ub;
{
struct stat ds;
ds.st_dev = rip->i_dev;
ds.st_ino = rip->i_number;
ds.st_mode = rip->i_mode;
ds.st_nlink = 0;
ds.st_uid = rip->i_uid;
ds.st_gid = rip->i_gid;
ds.st_rdev = (dev_t)0;
ds.st_size = 0;
ds.st_atime = time;
ds.st_mtime = time;
ds.st_ctime = time;
if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
u.u_error = EFAULT;
}
/*
* Change an open of the root into a stopen of the communications inode.
*/
struct inode *
msopen(rip, rw)
register struct inode *rip;
{
register struct inode *cip;
register struct inode *nip;
/*
* Locking the root also locks out cip changes.
*/
plock(rip);
/* return error if stream is dead */
cip = rip->i_un.i_cip;
if (cip==NULL||cip->i_sptr==NULL||cip->i_sptr->flag&HUNGUP) {
u.u_error = ENXIO;
iput(rip);
return(NULL);
}
/*
* Reopen stream, perhaps returning a fresh inode,
* or NULL on error, which is what we should do too.
* either this is a fresh reference to cip, or stopen will iput.
*/
cip->i_count++;
nip = stopen((struct streamtab *)NULL, cip->i_un.i_rdev, rw, cip);
iput(rip);
return(nip);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.