154947Sheideman /* 263248Sbostic * Copyright (c) 1992, 1993 363248Sbostic * The Regents of the University of California. All rights reserved. 454947Sheideman * 554947Sheideman * This code is derived from software donated to Berkeley by 654947Sheideman * Jan-Simon Pendry. 754947Sheideman * 854947Sheideman * %sccs.include.redist.c% 954947Sheideman * 10*68623Smckusick * @(#)umap_subr.c 8.8 (Berkeley) 03/29/95 1154947Sheideman * 1265491Spendry * $Id: lofs_subr.c, v 1.11 1992/05/30 10:05:43 jsp Exp jsp $ 1354947Sheideman */ 1454947Sheideman 1554947Sheideman #include <sys/param.h> 1654947Sheideman #include <sys/systm.h> 1754947Sheideman #include <sys/time.h> 1854947Sheideman #include <sys/types.h> 1954947Sheideman #include <sys/vnode.h> 2054947Sheideman #include <sys/mount.h> 2154947Sheideman #include <sys/namei.h> 2254947Sheideman #include <sys/malloc.h> 2355031Smckusick #include <miscfs/umapfs/umap.h> 2454947Sheideman 2554947Sheideman #define LOG2_SIZEVNODE 7 /* log2(sizeof struct vnode) */ 2654947Sheideman #define NUMAPNODECACHE 16 2754947Sheideman 2854947Sheideman /* 2954947Sheideman * Null layer cache: 3054947Sheideman * Each cache entry holds a reference to the target vnode 3154947Sheideman * along with a pointer to the alias vnode. When an 3254947Sheideman * entry is added the target vnode is VREF'd. When the 3354947Sheideman * alias is removed the target vnode is vrele'd. 3454947Sheideman */ 3554947Sheideman 3667717Smckusick #define UMAP_NHASH(vp) \ 3767717Smckusick (&umap_node_hashtbl[(((u_long)vp)>>LOG2_SIZEVNODE) & umap_node_hash]) 3867717Smckusick LIST_HEAD(umap_node_hashhead, umap_node) *umap_node_hashtbl; 3967717Smckusick u_long umap_node_hash; 4054947Sheideman 4154947Sheideman /* 4254947Sheideman * Initialise cache headers 4354947Sheideman */ 44*68623Smckusick umapfs_init(vfsp) 45*68623Smckusick struct vfsconf *vfsp; 4654947Sheideman { 4767717Smckusick 4854947Sheideman #ifdef UMAPFS_DIAGNOSTIC 4954947Sheideman printf("umapfs_init\n"); /* printed during system boot */ 5054947Sheideman #endif 5167717Smckusick umap_node_hashtbl = hashinit(NUMAPNODECACHE, M_CACHE, &umap_node_hash); 5254947Sheideman } 5354947Sheideman 5454947Sheideman /* 5565491Spendry * umap_findid is called by various routines in umap_vnodeops.c to 5665491Spendry * find a user or group id in a map. 5765491Spendry */ 5865491Spendry static u_long 5965491Spendry umap_findid(id, map, nentries) 6065491Spendry u_long id; 6165491Spendry u_long map[][2]; 6265491Spendry int nentries; 6365491Spendry { 6465491Spendry int i; 6565491Spendry 6665491Spendry /* Find uid entry in map */ 6765491Spendry i = 0; 6865491Spendry while ((i<nentries) && ((map[i][0]) != id)) 6965491Spendry i++; 7065491Spendry 7165491Spendry if (i < nentries) 7265491Spendry return (map[i][1]); 7365491Spendry else 7465491Spendry return (-1); 7565491Spendry 7665491Spendry } 7765491Spendry 7865491Spendry /* 7965491Spendry * umap_reverse_findid is called by umap_getattr() in umap_vnodeops.c to 8065491Spendry * find a user or group id in a map, in reverse. 8165491Spendry */ 8265491Spendry u_long 8365491Spendry umap_reverse_findid(id, map, nentries) 8465491Spendry u_long id; 8565491Spendry u_long map[][2]; 8665491Spendry int nentries; 8765491Spendry { 8865491Spendry int i; 8965491Spendry 9065491Spendry /* Find uid entry in map */ 9165491Spendry i = 0; 9265491Spendry while ((i<nentries) && ((map[i][1]) != id)) 9365491Spendry i++; 9465491Spendry 9565491Spendry if (i < nentries) 9665491Spendry return (map[i][0]); 9765491Spendry else 9865491Spendry return (-1); 9965491Spendry 10065491Spendry } 10165491Spendry 10265491Spendry /* 10354947Sheideman * Return alias for target vnode if already exists, else 0. 10454947Sheideman */ 10554958Sheideman static struct vnode * 10654947Sheideman umap_node_find(mp, targetvp) 10754947Sheideman struct mount *mp; 10854947Sheideman struct vnode *targetvp; 10954947Sheideman { 11067717Smckusick struct umap_node_hashhead *hd; 11154947Sheideman struct umap_node *a; 11254958Sheideman struct vnode *vp; 11354947Sheideman 11454947Sheideman #ifdef UMAPFS_DIAGNOSTIC 11554947Sheideman printf("umap_node_find(mp = %x, target = %x)\n", mp, targetvp); 11654947Sheideman #endif 11754947Sheideman 11854947Sheideman /* 11954947Sheideman * Find hash base, and then search the (two-way) linked 12054947Sheideman * list looking for a umap_node structure which is referencing 12154947Sheideman * the target vnode. If found, the increment the umap_node 12254947Sheideman * reference count (but NOT the target vnode's VREF counter). 12354947Sheideman */ 12467717Smckusick hd = UMAP_NHASH(targetvp); 12567717Smckusick loop: 12667717Smckusick for (a = hd->lh_first; a != 0; a = a->umap_hash.le_next) { 12755031Smckusick if (a->umap_lowervp == targetvp && 12855031Smckusick a->umap_vnode->v_mount == mp) { 12954958Sheideman vp = UMAPTOV(a); 13054958Sheideman /* 13154958Sheideman * We need vget for the VXLOCK 13254958Sheideman * stuff, but we don't want to lock 13354958Sheideman * the lower node. 13454958Sheideman */ 13565132Smckusick if (vget(vp, 0)) { 13665491Spendry #ifdef UMAPFS_DIAGNOSTIC 13765491Spendry printf ("umap_node_find: vget failed.\n"); 13865491Spendry #endif 13954958Sheideman goto loop; 14055031Smckusick } 14154958Sheideman return (vp); 14254947Sheideman } 14354947Sheideman } 14454947Sheideman 14554947Sheideman #ifdef UMAPFS_DIAGNOSTIC 14654947Sheideman printf("umap_node_find(%x, %x): NOT found\n", mp, targetvp); 14754947Sheideman #endif 14854947Sheideman 14954947Sheideman return (0); 15054947Sheideman } 15154947Sheideman 15254947Sheideman /* 15354958Sheideman * Make a new umap_node node. 15454958Sheideman * Vp is the alias vnode, lofsvp is the target vnode. 15554958Sheideman * Maintain a reference to (targetvp). 15654958Sheideman */ 15754958Sheideman static int 15854958Sheideman umap_node_alloc(mp, lowervp, vpp) 15954958Sheideman struct mount *mp; 16054958Sheideman struct vnode *lowervp; 16154958Sheideman struct vnode **vpp; 16254958Sheideman { 16367717Smckusick struct umap_node_hashhead *hd; 16454958Sheideman struct umap_node *xp; 16554958Sheideman struct vnode *othervp, *vp; 16654958Sheideman int error; 16754958Sheideman 16865423Spendry if (error = getnewvnode(VT_UMAP, mp, umap_vnodeop_p, vpp)) 16965423Spendry return (error); 17054958Sheideman vp = *vpp; 17154958Sheideman 17255031Smckusick MALLOC(xp, struct umap_node *, sizeof(struct umap_node), 17355031Smckusick M_TEMP, M_WAITOK); 17454958Sheideman vp->v_type = lowervp->v_type; 17554958Sheideman xp->umap_vnode = vp; 17654958Sheideman vp->v_data = xp; 17754958Sheideman xp->umap_lowervp = lowervp; 17854958Sheideman /* 17954958Sheideman * Before we insert our new node onto the hash chains, 18054958Sheideman * check to see if someone else has beaten us to it. 18154958Sheideman * (We could have slept in MALLOC.) 18254958Sheideman */ 18354958Sheideman if (othervp = umap_node_find(lowervp)) { 18454958Sheideman FREE(xp, M_TEMP); 18554958Sheideman vp->v_type = VBAD; /* node is discarded */ 18654958Sheideman vp->v_usecount = 0; /* XXX */ 18754958Sheideman *vpp = othervp; 18855031Smckusick return (0); 18955031Smckusick } 19054958Sheideman VREF(lowervp); /* Extra VREF will be vrele'd in umap_node_create */ 19167717Smckusick hd = UMAP_NHASH(lowervp); 19267717Smckusick LIST_INSERT_HEAD(hd, xp, umap_hash); 19355031Smckusick return (0); 19454958Sheideman } 19554958Sheideman 19654958Sheideman 19754958Sheideman /* 19854947Sheideman * Try to find an existing umap_node vnode refering 19954947Sheideman * to it, otherwise make a new umap_node vnode which 20054947Sheideman * contains a reference to the target vnode. 20154947Sheideman */ 20254947Sheideman int 20354947Sheideman umap_node_create(mp, targetvp, newvpp) 20454947Sheideman struct mount *mp; 20554947Sheideman struct vnode *targetvp; 20654947Sheideman struct vnode **newvpp; 20754947Sheideman { 20854947Sheideman struct vnode *aliasvp; 20954947Sheideman 21054958Sheideman if (aliasvp = umap_node_find(mp, targetvp)) { 21154947Sheideman /* 21254947Sheideman * Take another reference to the alias vnode 21354947Sheideman */ 21454947Sheideman #ifdef UMAPFS_DIAGNOSTIC 21554947Sheideman vprint("umap_node_create: exists", ap->umap_vnode); 21654947Sheideman #endif 21754958Sheideman /* VREF(aliasvp); */ 21854947Sheideman } else { 21954947Sheideman int error; 22054947Sheideman 22154947Sheideman /* 22254947Sheideman * Get new vnode. 22354947Sheideman */ 22454947Sheideman #ifdef UMAPFS_DIAGNOSTIC 22554947Sheideman printf("umap_node_create: create new alias vnode\n"); 22654947Sheideman #endif 22754947Sheideman /* 22854947Sheideman * Make new vnode reference the umap_node. 22954947Sheideman */ 23054958Sheideman if (error = umap_node_alloc(mp, targetvp, &aliasvp)) 23155031Smckusick return (error); 23254947Sheideman 23354947Sheideman /* 23454947Sheideman * aliasvp is already VREF'd by getnewvnode() 23554947Sheideman */ 23654947Sheideman } 23754947Sheideman 23854947Sheideman vrele(targetvp); 23954947Sheideman 24054947Sheideman #ifdef UMAPFS_DIAGNOSTIC 24154947Sheideman vprint("umap_node_create: alias", aliasvp); 24254947Sheideman vprint("umap_node_create: target", targetvp); 24354947Sheideman #endif 24454947Sheideman 24554947Sheideman *newvpp = aliasvp; 24654947Sheideman return (0); 24754947Sheideman } 24855031Smckusick 24954947Sheideman #ifdef UMAPFS_DIAGNOSTIC 25054947Sheideman int umap_checkvp_barrier = 1; 25154947Sheideman struct vnode * 25254947Sheideman umap_checkvp(vp, fil, lno) 25354947Sheideman struct vnode *vp; 25454947Sheideman char *fil; 25554947Sheideman int lno; 25654947Sheideman { 25754947Sheideman struct umap_node *a = VTOUMAP(vp); 25854947Sheideman #if 0 25954947Sheideman /* 26054947Sheideman * Can't do this check because vop_reclaim runs 26154947Sheideman * with funny vop vector. 26254947Sheideman */ 26354947Sheideman if (vp->v_op != umap_vnodeop_p) { 26454947Sheideman printf ("umap_checkvp: on non-umap-node\n"); 26554947Sheideman while (umap_checkvp_barrier) /*WAIT*/ ; 26654947Sheideman panic("umap_checkvp"); 26755031Smckusick } 26854947Sheideman #endif 26954947Sheideman if (a->umap_lowervp == NULL) { 27054947Sheideman /* Should never happen */ 27154947Sheideman int i; u_long *p; 27254947Sheideman printf("vp = %x, ZERO ptr\n", vp); 27354947Sheideman for (p = (u_long *) a, i = 0; i < 8; i++) 27454947Sheideman printf(" %x", p[i]); 27554947Sheideman printf("\n"); 27654947Sheideman /* wait for debugger */ 27754947Sheideman while (umap_checkvp_barrier) /*WAIT*/ ; 27854947Sheideman panic("umap_checkvp"); 27954947Sheideman } 28054947Sheideman if (a->umap_lowervp->v_usecount < 1) { 28154947Sheideman int i; u_long *p; 28254947Sheideman printf("vp = %x, unref'ed lowervp\n", vp); 28354947Sheideman for (p = (u_long *) a, i = 0; i < 8; i++) 28454947Sheideman printf(" %x", p[i]); 28554947Sheideman printf("\n"); 28654947Sheideman /* wait for debugger */ 28754947Sheideman while (umap_checkvp_barrier) /*WAIT*/ ; 28854947Sheideman panic ("umap with unref'ed lowervp"); 28955031Smckusick } 29054947Sheideman #if 0 29154947Sheideman printf("umap %x/%d -> %x/%d [%s, %d]\n", 29254947Sheideman a->umap_vnode, a->umap_vnode->v_usecount, 29354947Sheideman a->umap_lowervp, a->umap_lowervp->v_usecount, 29454947Sheideman fil, lno); 29554947Sheideman #endif 29655031Smckusick return (a->umap_lowervp); 29754947Sheideman } 29854947Sheideman #endif 29954947Sheideman 30054947Sheideman /* umap_mapids maps all of the ids in a credential, both user and group. */ 30154947Sheideman 30265491Spendry void 30365491Spendry umap_mapids(v_mount, credp) 30454958Sheideman struct mount *v_mount; 30554947Sheideman struct ucred *credp; 30654947Sheideman { 30765916Smckusick int i, unentries, gnentries; 30865916Smckusick u_long *groupmap, *usermap; 30965491Spendry uid_t uid; 31065491Spendry gid_t gid; 31154947Sheideman 31254958Sheideman unentries = MOUNTTOUMAPMOUNT(v_mount)->info_nentries; 31354958Sheideman usermap = &(MOUNTTOUMAPMOUNT(v_mount)->info_mapdata[0][0]); 31454958Sheideman gnentries = MOUNTTOUMAPMOUNT(v_mount)->info_gnentries; 31554958Sheideman groupmap = &(MOUNTTOUMAPMOUNT(v_mount)->info_gmapdata[0][0]); 31654958Sheideman 31754947Sheideman /* Find uid entry in map */ 31854947Sheideman 31965491Spendry uid = (uid_t) umap_findid(credp->cr_uid, usermap, unentries); 32054947Sheideman 32165491Spendry if (uid != -1) 32265491Spendry credp->cr_uid = uid; 32365491Spendry else 32465491Spendry credp->cr_uid = (uid_t) NOBODY; 32554947Sheideman 32665491Spendry #ifdef notdef 32765491Spendry /* cr_gid is the same as cr_groups[0] in 4BSD */ 32865491Spendry 32954947Sheideman /* Find gid entry in map */ 33054947Sheideman 33165491Spendry gid = (gid_t) umap_findid(credp->cr_gid, groupmap, gnentries); 33254947Sheideman 33365491Spendry if (gid != -1) 33465491Spendry credp->cr_gid = gid; 33565491Spendry else 33665491Spendry credp->cr_gid = NULLGROUP; 33765491Spendry #endif 33854947Sheideman 33954947Sheideman /* Now we must map each of the set of groups in the cr_groups 34054947Sheideman structure. */ 34154947Sheideman 34254947Sheideman i = 0; 34365491Spendry while (credp->cr_groups[i] != 0) { 34465491Spendry gid = (gid_t) umap_findid(credp->cr_groups[i], 34565491Spendry groupmap, gnentries); 34665491Spendry 34765491Spendry if (gid != -1) 34865491Spendry credp->cr_groups[i++] = gid; 34954947Sheideman else 35065491Spendry credp->cr_groups[i++] = NULLGROUP; 35154947Sheideman } 35254947Sheideman } 353