Files
seta75D 2e8a93c394 Init
2021-10-11 18:20:23 -03:00

357 lines
7.5 KiB
C

#ident "@(#)spec_subr.c 1.1 92/07/30 SMI"
/*LINTLIBRARY*/
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/user.h>
#include <sys/vfs.h>
#include <sys/vnode.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/trace.h>
#include <specfs/snode.h>
/*
* Find an appropriate snode.
*/
static struct snode *sfind();
/*
* Returns a special vnode for the given dev. The vnode is the
* one which is "common" to all the snodes which represent the
* same block device.
*/
struct vnode *
bdevvp(dev)
dev_t dev;
{
return (specvp((struct vnode *)NULL, dev, VBLK));
}
/*
* Return a shadow special vnode for the given dev.
* If no snode exists for this dev create one and put it
* in a table hashed by dev, realvp. If the snode for
* this dev is already in the table return it (ref count is
* incremented by sfind). The snode will be flushed from the
* table when spec_inactive calls sunsave.
*
* vp will be NULL if this is a block device that is
* to be shared via the s_bdevvp field in the snodes.
*/
struct vnode *
specvp(vp, dev, type)
struct vnode *vp;
dev_t dev;
enum vtype type;
{
register struct snode *sp;
extern struct snode *fifosp();
struct vattr va;
if ((sp = sfind(dev, vp, type)) == NULL) {
if (vp && vp->v_type == VFIFO) {
sp = fifosp(vp);
} else {
sp = (struct snode *)
new_kmem_zalloc(sizeof (*sp), KMEM_SLEEP);
STOV(sp)->v_op = &spec_vnodeops;
/* init the times in the snode to those in the vnode */
if (vp && VOP_GETATTR(vp, &va, u.u_cred) == 0) {
sp->s_atime = va.va_atime;
sp->s_mtime = va.va_mtime;
sp->s_ctime = va.va_ctime;
}
}
sp->s_realvp = vp;
sp->s_dev = dev;
trace3(TR_MP_SNODE, STOV(sp), dev, 0);
STOV(sp)->v_rdev = dev;
STOV(sp)->v_count = 1;
STOV(sp)->v_data = (caddr_t)sp;
if (vp != (struct vnode *)NULL) {
VN_HOLD(vp);
STOV(sp)->v_type = vp->v_type;
STOV(sp)->v_vfsp = vp->v_vfsp;
if (vp->v_type == VBLK) {
sp->s_bdevvp = bdevvp(dev);
sp->s_size = VTOS(sp->s_bdevvp)->s_size;
}
} else {
/* must be a `real' block device */
int (*size)();
long rsize;
STOV(sp)->v_type = VBLK;
STOV(sp)->v_vfsp = NULL;
sp->s_bdevvp = STOV(sp);
if ((major(dev) < nblkdev) &&
(size = bdevsw[major(dev)].d_psize)) {
rsize = (*size)(dev);
if (rsize == -1) /* did size fail? */
sp->s_size = 0;
else
sp->s_size = dbtob(rsize);
} else {
sp->s_size = 0;
}
}
ssave(sp);
}
return (STOV(sp));
}
/*
* Return a special vnode for the given dev; no vnode is supplied
* for it to shadow.
* If no snode exists for this dev (with a NULL realvp), create one
* and put it in a table hashed by dev, NULL. If the snode for
* this dev is already in the table return it (ref count is
* incremented by sfind). The snode will be flushed from the
* table when spec_inactive calls sunsave.
*/
struct vnode *
makespecvp(dev, type)
dev_t dev;
enum vtype type;
{
register struct snode *sp;
struct timeval ut;
if ((sp = sfind(dev, (struct vnode *)NULL, type)) == NULL) {
sp = (struct snode *)
new_kmem_zalloc((u_int)sizeof (*sp), KMEM_SLEEP);
STOV(sp)->v_op = &spec_vnodeops;
STOV(sp)->v_type = type;
STOV(sp)->v_rdev = dev;
STOV(sp)->v_count = 1;
STOV(sp)->v_data = (caddr_t)sp;
STOV(sp)->v_vfsp = NULL;
if (type == VBLK) {
sp->s_bdevvp = bdevvp(dev);
/* XXX - verify */
/* Possibly a VN_HOLD here */
sp->s_size = VTOS(sp->s_bdevvp)->s_size;
}
sp->s_realvp = NULL;
sp->s_dev = dev;
uniqtime(&ut);
sp->s_atime = ut;
sp->s_mtime = ut;
sp->s_ctime = ut;
trace3(TR_MP_SNODE, STOV(sp), dev, 1);
ssave(sp);
}
return (STOV(sp));
}
/*
* Snode lookup stuff.
* These routines maintain a table of snodes hashed by dev so
* that the snode for an dev can be found if it already exists.
*/
struct snode *stable[STABLESIZE];
/*
* Put a snode in the table
*/
static
ssave(sp)
struct snode *sp;
{
sp->s_next = stable[STABLEHASH(sp->s_dev)];
stable[STABLEHASH(sp->s_dev)] = sp;
}
/*
* Remove a snode from the hash table.
* The realvp is not released here because spec_inactive() still
* needs it to do a spec_fsync().
*/
sunsave(sp)
struct snode *sp;
{
struct snode *st;
struct snode *stprev = NULL;
st = stable[STABLEHASH(sp->s_dev)];
while (st != NULL) {
if (st == sp) {
if (stprev == NULL) {
stable[STABLEHASH(sp->s_dev)] = st->s_next;
} else {
stprev->s_next = st->s_next;
}
break;
}
stprev = st;
st = st->s_next;
}
}
/*
* Check to see how many open references there are in the snode table for
* a given device of a given type; if there are any, return 1, otherwise
* return 0.
*/
int
stillopen(dev, type)
register dev_t dev;
register enum vtype type;
{
register struct snode *st;
register int count;
count = 0;
for (st = stable[STABLEHASH(dev)]; st != NULL; st = st->s_next) {
if (st->s_dev == dev && STOV(st)->v_type == type)
count += st->s_count;
}
return (count != 0);
}
/*
* Check to see how many references there are in the snode table for
* a given device of a given type; if there are any, return 1, otherwise
* return 0.
*/
int
stillref(dev, type)
register dev_t dev;
register enum vtype type;
{
register struct snode *st;
register int count;
count = 0;
for (st = stable[STABLEHASH(dev)]; st != NULL; st = st->s_next) {
if (st->s_dev == dev && STOV(st)->v_type == type)
count += STOV(st)->v_count;
}
return (count != 0);
}
/*
* Check to see whether a given device of a given type is currently being
* closed; if so, return 1, otherwise return 0.
*/
int
isclosing(dev, type)
register dev_t dev;
register enum vtype type;
{
register struct snode *st;
for (st = stable[STABLEHASH(dev)]; st != NULL; st = st->s_next) {
if (st->s_dev == dev && STOV(st)->v_type == type &&
(st->s_flag & SCLOSING))
return (1);
}
return (0);
}
/*
* Check to see if there is an snode in the table referring to a given device
* other than the one the vnode provided is associated with. If so, return
* it.
*/
struct vnode *
other_specvp(vp)
register struct vnode *vp;
{
struct snode *sp;
register dev_t dev;
register struct snode *st;
register struct vnode *nvp;
sp = VTOS(vp);
dev = sp->s_dev;
st = stable[STABLEHASH(dev)];
while (st != NULL) {
if (st->s_dev == dev && (nvp = STOV(st)) != vp &&
nvp->v_type == vp->v_type)
return (nvp);
st = st->s_next;
}
return (NULL);
}
/*
* Lookup a snode by type and dev; return a pointer to the vnode in that snode.
*/
struct vnode *
slookup(type, dev)
enum vtype type;
dev_t dev;
{
register struct snode *st;
register struct vnode *nvp;
st = stable[STABLEHASH(dev)];
while (st != NULL) {
if (st->s_dev == dev) {
nvp = STOV(st);
if (nvp->v_type == type) {
VN_HOLD(nvp);
return (nvp);
}
}
st = st->s_next;
}
return (NULL);
}
/*
* Lookup a snode by <dev, vp, type>
*/
static struct snode *
sfind(dev, vp, type)
dev_t dev;
struct vnode *vp;
enum vtype type;
{
register struct snode *st;
st = stable[STABLEHASH(dev)];
while (st != NULL) {
if ((st->s_dev == dev) && STOV(st)->v_type == type &&
((st->s_realvp && vp && VN_CMP(st->s_realvp, vp)) ||
(st->s_realvp == NULL && vp == NULL))) {
VN_HOLD(STOV(st));
return (st);
}
st = st->s_next;
}
return (NULL);
}
/*
* Mark the accessed, updated, or changed times in an snode
* with the current (unique) time
*/
smark(sp, flag)
register struct snode *sp;
register int flag;
{
struct timeval ut;
uniqtime(&ut);
sp->s_flag |= flag;
if (flag & SACC)
sp->s_atime = ut;
if (flag & SUPD)
sp->s_mtime = ut;
if (flag & SCHG) {
sp->s_ctime = ut;
}
}