#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/vnode.h>
#include <sys/mount.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include "hpfs.h"
MALLOC_DEFINE(M_HPFSHASH, "HPFS hash", "HPFS node hash tables");
static LIST_HEAD(hphashhead, hpfsnode) *hpfs_hphashtbl;
static u_long hpfs_hphash;
#define HPNOHASH(dev, lsn) (&hpfs_hphashtbl[(minor(dev) + (lsn)) & hpfs_hphash])
#ifndef NULL_SIMPLELOCKS
static struct lwkt_token hpfs_hphash_token;
#endif
struct lock hpfs_hphash_lock;
void
hpfs_hphashinit(void)
{
int hsize = vfs_inodehashsize();
lockinit(&hpfs_hphash_lock, "hpfs_hphashlock", 0, 0);
hpfs_hphashtbl = hashinit(hsize, M_HPFSHASH, &hpfs_hphash);
lwkt_token_init(&hpfs_hphash_token, "hpfsihash");
}
int
hpfs_hphash_uninit(struct vfsconf *vfc)
{
lwkt_gettoken(&hpfs_hphash_token);
if (hpfs_hphashtbl)
hashdestroy(hpfs_hphashtbl, M_HPFSHASH, hpfs_hphash);
lwkt_reltoken(&hpfs_hphash_token);
return 0;
}
struct hpfsnode *
hpfs_hphashlookup(cdev_t dev, lsn_t ino)
{
struct hpfsnode *hp;
lwkt_gettoken(&hpfs_hphash_token);
for (hp = HPNOHASH(dev, ino)->lh_first; hp; hp = hp->h_hash.le_next) {
if (ino == hp->h_no && dev == hp->h_dev)
break;
}
lwkt_reltoken(&hpfs_hphash_token);
return (hp);
}
struct vnode *
hpfs_hphashvget(cdev_t dev, lsn_t ino)
{
struct hpfsnode *hp;
struct vnode *vp;
lwkt_gettoken(&hpfs_hphash_token);
loop:
for (hp = HPNOHASH(dev, ino)->lh_first; hp; hp = hp->h_hash.le_next) {
if (ino != hp->h_no || dev != hp->h_dev)
continue;
vp = HPTOV(hp);
if (vget(vp, LK_EXCLUSIVE))
goto loop;
for (hp = HPNOHASH(dev, ino)->lh_first; hp; hp = hp->h_hash.le_next) {
if (ino == hp->h_no && dev == hp->h_dev)
break;
}
if (hp == NULL || vp != HPTOV(hp)) {
vput(vp);
goto loop;
}
lwkt_reltoken(&hpfs_hphash_token);
return (vp);
}
lwkt_reltoken(&hpfs_hphash_token);
return (NULLVP);
}
void
hpfs_hphashins(struct hpfsnode *hp)
{
struct hphashhead *hpp;
lwkt_gettoken(&hpfs_hphash_token);
hpp = HPNOHASH(hp->h_dev, hp->h_no);
hp->h_flag |= H_HASHED;
LIST_INSERT_HEAD(hpp, hp, h_hash);
lwkt_reltoken(&hpfs_hphash_token);
}
void
hpfs_hphashrem(struct hpfsnode *hp)
{
lwkt_gettoken(&hpfs_hphash_token);
if (hp->h_flag & H_HASHED) {
hp->h_flag &= ~H_HASHED;
LIST_REMOVE(hp, h_hash);
#ifdef DIAGNOSTIC
hp->h_hash.le_next = NULL;
hp->h_hash.le_prev = NULL;
#endif
}
lwkt_reltoken(&hpfs_hphash_token);
}