#include <sys/param.h>
#include <sys/systm.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/malloc.h>
#include <sys/ubc.h>
#include <miscfs/specfs/specdev.h>
#include <miscfs/umapfs/umap.h>
#define LOG2_SIZEVNODE 7
#define NUMAPNODECACHE 16
#define UMAP_NHASH(vp) \
(&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash])
LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl;
u_long umap_node_hash;
umapfs_init()
{
#ifdef UMAPFS_DIAGNOSTIC
printf("umapfs_init\n");
#endif
umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash);
}
static u_long
umap_findid(id, map, nentries)
u_long id;
u_long map[][2];
int nentries;
{
int i;
i = 0;
while ((i<nentries) && ((map[i][0]) != id))
i++;
if (i < nentries)
return (map[i][1]);
else
return (-1);
}
u_long
umap_reverse_findid(id, map, nentries)
u_long id;
u_long map[][2];
int nentries;
{
int i;
i = 0;
while ((i<nentries) && ((map[i][1]) != id))
i++;
if (i < nentries)
return (map[i][0]);
else
return (-1);
}
static struct vnode *
umap_node_find(mp, targetvp)
struct mount *mp;
struct vnode *targetvp;
{
struct umap_node_hashhead *hd;
struct umap_node *a;
struct vnode *vp;
#ifdef UMAPFS_DIAGNOSTIC
printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp);
#endif
hd = UMAP_NHASH(targetvp);
loop:
for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) {
if (a->umap_lowervp == targetvp &&
a->umap_vnode->v_mount == mp) {
vp = UMAPTOV(a);
if (vget(vp, 0, current_proc())) {
#ifdef UMAPFS_DIAGNOSTIC
printf ("umap_node_find: vget failed.\n");
#endif
goto loop;
}
return (vp);
}
}
#ifdef UMAPFS_DIAGNOSTIC
printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp);
#endif
return (0);
}
static int
umap_node_alloc(mp, lowervp, vpp)
struct mount *mp;
struct vnode *lowervp;
struct vnode **vpp;
{
struct umap_node_hashhead *hd;
struct umap_node *xp;
struct vnode *vp, *nvp;
int error;
extern int (**dead_vnodeop_p)(void *);
struct specinfo *sp = (struct specinfo *)0;
if (lowervp->v_type == VBLK || lowervp->v_type == VCHR)
MALLOC_ZONE(sp, struct specinfo *, sizeof(struct specinfo),
M_VNODE, M_WAITOK);
MALLOC(xp, struct umap_node *, sizeof(struct umap_node), M_TEMP,
M_WAITOK);
if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, &vp)) {
FREE(xp, M_TEMP);
if (sp)
FREE_ZONE(sp, sizeof (struct specinfo), M_VNODE);
return (error);
}
vp->v_type = lowervp->v_type;
if (vp->v_type == VBLK || vp->v_type == VCHR) {
vp->v_specinfo = sp;
vp->v_rdev = lowervp->v_rdev;
}
vp->v_data = xp;
xp->umap_vnode = vp;
xp->umap_lowervp = lowervp;
if (nvp = umap_node_find(lowervp)) {
*vpp = nvp;
FREE(xp, M_TEMP);
if (sp) {
vp->v_specinfo = (struct specinfo *)0;
FREE_ZONE(sp, sizeof (struct specinfo), M_VNODE);
}
vp->v_type = VBAD;
vp->v_op = dead_vnodeop_p;
vrele(vp);
return (0);
}
if (vp->v_type == VBLK || vp->v_type == VCHR) {
struct vnode *cvp, **cvpp;
cvpp = &speclisth[SPECHASH(vp->v_rdev)];
loop:
for (cvp = *cvpp; cvp; cvp = cvp->v_specnext) {
if (vp->v_rdev != cvp->v_rdev ||
vp->v_type != cvp->v_type)
continue;
if (cvp->v_usecount == 0) {
vgone(cvp);
goto loop;
}
if (vget(cvp, 0, current_proc()))
goto loop;
break;
}
vp->v_hashchain = cvpp;
vp->v_specnext = *cvpp;
vp->v_specflags = 0;
*cvpp = vp;
#if DIAGNOSTIC
if (cvp == NULLVP)
panic("umap_node_alloc: no alias for device");
#endif
vp->v_flag |= VALIASED;
cvp->v_flag |= VALIASED;
vrele(cvp);
}
if (vp->v_type == VREG)
ubc_info_init();
*vpp = vp;
VREF(lowervp);
hd = UMAP_NHASH(lowervp);
LIST_INSERT_HEAD(hd, xp, umap_hash);
return (0);
}
int
umap_node_create(mp, targetvp, newvpp)
struct mount *mp;
struct vnode *targetvp;
struct vnode **newvpp;
{
struct vnode *aliasvp;
if (aliasvp = umap_node_find(mp, targetvp)) {
#ifdef UMAPFS_DIAGNOSTIC
vprint("umap_node_create: exists", ap->umap_vnode);
#endif
} else {
int error;
#ifdef UMAPFS_DIAGNOSTIC
printf("umap_node_create: create new alias vnode\n");
#endif
if (error = umap_node_alloc(mp, targetvp, &aliasvp))
return (error);
}
vrele(targetvp);
#ifdef UMAPFS_DIAGNOSTIC
vprint("umap_node_create: alias", aliasvp);
vprint("umap_node_create: target", targetvp);
#endif
*newvpp = aliasvp;
return (0);
}
#ifdef UMAPFS_DIAGNOSTIC
int umap_checkvp_barrier = 1;
struct vnode *
umap_checkvp(vp, fil, lno)
struct vnode *vp;
char *fil;
int lno;
{
struct umap_node *a = VTOUMAP(vp);
#if 0
if (vp->v_op != umap_vnodeop_p) {
printf ("umap_checkvp: on non-umap-node\n");
while (umap_checkvp_barrier) ;
panic("umap_checkvp");
}
#endif
if (a->umap_lowervp == NULL) {
int i; u_long *p;
printf("vp = %x, ZERO ptr\n", vp);
for (p = (u_long *) a, i = 0; i < 8; i++)
printf(" %x", p[i]);
printf("\n");
while (umap_checkvp_barrier) ;
panic("umap_checkvp");
}
if (a->umap_lowervp->v_usecount < 1) {
int i; u_long *p;
printf("vp = %x, unref'ed lowervp\n", vp);
for (p = (u_long *) a, i = 0; i < 8; i++)
printf(" %x", p[i]);
printf("\n");
while (umap_checkvp_barrier) ;
panic ("umap with unref'ed lowervp");
}
#if 0
printf("umap %x/%d -> %x/%d [%s, %d]\n",
a->umap_vnode, a->umap_vnode->v_usecount,
a->umap_lowervp, a->umap_lowervp->v_usecount,
fil, lno);
#endif
return (a->umap_lowervp);
}
#endif
void
umap_mapids(v_mount, credp)
struct mount *v_mount;
struct ucred *credp;
{
int i, unentries, gnentries;
uid_t uid, *usermap;
gid_t gid, *groupmap;
unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries;
usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]);
gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries;
groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]);
uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries);
if (uid != -1)
credp->cr_uid = uid;
else
credp->cr_uid = (uid_t) NOBODY;
#ifdef notdef
gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries);
if (gid != -1)
credp->cr_gid = gid;
else
credp->cr_gid = NULLGROUP;
#endif
i = 0;
while (credp->cr_groups[i] != 0) {
gid = (gid_t) umap_findid(credp->cr_groups[i],
groupmap, gnentries);
if (gid != -1)
credp->cr_groups[i++] = gid;
else
credp->cr_groups[i++] = NULLGROUP;
}
}