NetBSD/sys/ufs/chfs/chfs_ihash.c
2012-10-19 12:44:39 +00:00

213 lines
5.2 KiB
C

/* $NetBSD: chfs_ihash.c,v 1.2 2012/10/19 12:44:39 ttoth Exp $ */
/*-
* Copyright (c) 2010 Department of Software Engineering,
* University of Szeged, Hungary
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by the Department of Software Engineering, University of Szeged, Hungary
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "chfs.h"
/*
* Structures associated with inode cacheing.
*/
static LIST_HEAD(ihashhead, chfs_inode) *chfs_ihashtbl;
static u_long chfs_ihash; /* size of hash table - 1 */
#define INOHASH(device, inum) (((device) + (inum)) & chfs_ihash)
kmutex_t chfs_ihash_lock;
kmutex_t chfs_hashlock;
/*
* Initialize inode hash table.
*/
void
chfs_ihashinit(void)
{
dbg("initing\n");
mutex_init(&chfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&chfs_ihash_lock, MUTEX_DEFAULT, IPL_NONE);
chfs_ihashtbl = hashinit(desiredvnodes,
HASH_LIST, true, &chfs_ihash);
}
/*
* Reinitialize inode hash table.
*/
void
chfs_ihashreinit(void)
{
struct chfs_inode *ip;
struct ihashhead *oldhash, *hash;
u_long oldmask, mask, val;
int i;
dbg("reiniting\n");
hash = hashinit(desiredvnodes, HASH_LIST, true, &mask);
mutex_enter(&chfs_ihash_lock);
oldhash = chfs_ihashtbl;
oldmask = chfs_ihash;
chfs_ihashtbl = hash;
chfs_ihash = mask;
for (i = 0; i <= oldmask; i++) {
while ((ip = LIST_FIRST(&oldhash[i])) != NULL) {
LIST_REMOVE(ip, hash_entry);
val = INOHASH(ip->dev, ip->ino);
LIST_INSERT_HEAD(&hash[val], ip, hash_entry);
}
}
mutex_exit(&chfs_ihash_lock);
hashdone(oldhash, HASH_LIST, oldmask);
}
/*
* Free inode hash table.
*/
void
chfs_ihashdone(void)
{
dbg("destroying\n");
hashdone(chfs_ihashtbl, HASH_LIST, chfs_ihash);
mutex_destroy(&chfs_hashlock);
mutex_destroy(&chfs_ihash_lock);
}
/*
* Use the device/inum pair to find the incore inode, and return a pointer
* to it. If it is in core, return it, even if it is locked.
*/
struct vnode *
chfs_ihashlookup(dev_t dev, ino_t inum)
{
struct chfs_inode *ip;
struct ihashhead *ipp;
dbg("dev: %ju, inum: %ju\n", (uintmax_t )dev, (uintmax_t )inum);
KASSERT(mutex_owned(&chfs_ihash_lock));
ipp = &chfs_ihashtbl[INOHASH(dev, inum)];
LIST_FOREACH(ip, ipp, hash_entry) {
if (inum == ip->ino && dev == ip->dev) {
break;
}
}
if (ip) {
return (ITOV(ip));
}
return (NULLVP);
}
/*
* Use the device/inum pair to find the incore inode, and return a pointer
* to it. If it is in core, but locked, wait for it.
*/
struct vnode *
chfs_ihashget(dev_t dev, ino_t inum, int flags)
{
struct ihashhead *ipp;
struct chfs_inode *ip;
struct vnode *vp;
dbg("search for ino\n");
loop:
mutex_enter(&chfs_ihash_lock);
ipp = &chfs_ihashtbl[INOHASH(dev, inum)];
dbg("ipp: %p, chfs_ihashtbl: %p, ihash: %lu\n",
ipp, chfs_ihashtbl, chfs_ihash);
LIST_FOREACH(ip, ipp, hash_entry) {
dbg("ip: %p\n", ip);
if (inum == ip->ino && dev == ip->dev) {
vp = ITOV(ip);
KASSERT(vp != NULL);
if (VOP_ISLOCKED(vp) == LK_EXCLUSIVE) {
mutex_exit(&chfs_ihash_lock);
goto loop;
}
/*
if (VOP_ISLOCKED(vp))
dbg("locked\n");
else
dbg("isn't locked\n");
*/
if (flags == 0) {
mutex_exit(&chfs_ihash_lock);
} else {
mutex_enter(vp->v_interlock);
mutex_exit(&chfs_ihash_lock);
if (vget(vp, flags)) {
goto loop;
}
}
return (vp);
}
}
mutex_exit(&chfs_ihash_lock);
return (NULL);
}
/*
* Insert the inode into the hash table, and return it locked.
*/
void
chfs_ihashins(struct chfs_inode *ip)
{
struct ihashhead *ipp;
dbg("ip: %p\n", ip);
KASSERT(mutex_owned(&chfs_hashlock));
/* lock the inode, then put it on the appropriate hash list */
VOP_LOCK(ITOV(ip), LK_EXCLUSIVE);
mutex_enter(&chfs_ihash_lock);
ipp = &chfs_ihashtbl[INOHASH(ip->dev, ip->ino)];
LIST_INSERT_HEAD(ipp, ip, hash_entry);
mutex_exit(&chfs_ihash_lock);
}
/*
* Remove the inode from the hash table.
*/
void
chfs_ihashrem(struct chfs_inode *ip)
{
dbg("ip: %p\n", ip);
mutex_enter(&chfs_ihash_lock);
LIST_REMOVE(ip, hash_entry);
mutex_exit(&chfs_ihash_lock);
}