Change hfs from hashlist to vcache.

- use (cnid, fork) as key.
- use pool for hfs nodes.
This commit is contained in:
hannken 2014-08-10 08:53:22 +00:00
parent dc4f4ea367
commit 265f1d8cdb
7 changed files with 80 additions and 278 deletions

View File

@ -1,8 +1,7 @@
# $NetBSD: files.hfs,v 1.2 2007/03/06 11:28:47 dillo Exp $
# $NetBSD: files.hfs,v 1.3 2014/08/10 08:53:22 hannken Exp $
deffs HFS
file fs/hfs/hfs_nhash.c hfs
file fs/hfs/hfs_subr.c hfs
file fs/hfs/hfs_vfsops.c hfs
file fs/hfs/hfs_vnops.c hfs

View File

@ -1,4 +1,4 @@
/* $NetBSD: hfs.h,v 1.8 2012/01/28 16:24:35 joerg Exp $ */
/* $NetBSD: hfs.h,v 1.9 2014/08/10 08:53:22 hannken Exp $ */
/*-
* Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
@ -65,9 +65,13 @@ struct hfsmount {
hfs_volume hm_vol; /* essential volume information */
};
struct hfsnode_key {
hfs_cnid_t hnk_cnid;
uint8_t hnk_fork;
};
struct hfsnode {
struct genfs_node h_gnode;
LIST_ENTRY(hfsnode) h_hash;/* hash chain */
struct vnode *h_vnode; /* vnode associated with this hnode */
struct hfsmount *h_hmp; /* mount point associated with this hnode */
struct vnode *h_devvp; /* vnode for block I/O */
@ -92,7 +96,8 @@ struct hfsnode {
*/
hfs_cnid_t h_parent;
uint8_t h_fork;
struct hfsnode_key h_key;
#define h_fork h_key.hnk_fork
long dummy; /* FOR DEVELOPMENT ONLY */
};
@ -149,19 +154,13 @@ extern const struct vnodeopv_desc hfs_specop_opv_desc;
extern const struct vnodeopv_desc hfs_fifoop_opv_desc;
extern int (**hfs_specop_p) (void *);
extern int (**hfs_fifoop_p) (void *);
extern struct pool hfs_node_pool;
/*
* Function prototypes
*/
/* hfs_nhash.c */
void hfs_nhashinit (void);
void hfs_nhashdone (void);
struct vnode *hfs_nhashget (dev_t, hfs_cnid_t, uint8_t, int);
void hfs_nhashinsert (struct hfsnode *);
void hfs_nhashremove (struct hfsnode *);
/* hfs_subr.c */
void hfs_vinit (struct mount *, int (**)(void *), int (**)(void *),
struct vnode **);

View File

@ -1,173 +0,0 @@
/* $NetBSD: hfs_nhash.c,v 1.13 2014/02/27 16:51:38 hannken Exp $ */
/*-
* Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Yevgeny Binder.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``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 FOUNDATION OR CONTRIBUTORS
* 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.
*/
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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 <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hfs_nhash.c,v 1.13 2014/02/27 16:51:38 hannken Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/vmmeter.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/namei.h>
#include <sys/buf.h>
#include <sys/dirent.h>
#include <sys/msgbuf.h>
#include <fs/hfs/hfs.h>
LIST_HEAD(nhashhead, hfsnode) *nhashtbl;
u_long nhash; /* size of hash table - 1 */
#define HNOHASH(device, cnid, fork) (((device) + (cnid) + (fork)) & nhash)
kmutex_t hfs_hashlock;
kmutex_t hfs_nhash_lock;
/*
* Initialize hfsnode hash table.
*/
void
hfs_nhashinit(void)
{
nhashtbl = hashinit(desiredvnodes, HASH_LIST, true, &nhash);
mutex_init(&hfs_nhash_lock, MUTEX_DEFAULT, IPL_NONE);
mutex_init(&hfs_hashlock, MUTEX_DEFAULT, IPL_NONE);
}
/*
* Free hfsnode hash table.
*/
void
hfs_nhashdone(void)
{
hashdone(nhashtbl, HASH_LIST, nhash);
mutex_destroy(&hfs_nhash_lock);
mutex_destroy(&hfs_hashlock);
}
/*
* 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 *
hfs_nhashget(dev_t dev, hfs_cnid_t cnid, uint8_t fork, int flags)
{
struct hfsnode *hp;
struct nhashhead *hpp;
struct vnode *vp;
loop:
mutex_enter(&hfs_nhash_lock);
hpp = &nhashtbl[HNOHASH(dev, cnid, fork)];
LIST_FOREACH(hp, hpp, h_hash) {
if (cnid == hp->h_rec.u.cnid && dev == hp->h_dev) {
vp = HTOV(hp);
if (flags == 0) {
mutex_exit(&hfs_nhash_lock);
} else {
mutex_enter(vp->v_interlock);
mutex_exit(&hfs_nhash_lock);
if (vget(vp, flags))
goto loop;
}
return vp;
}
}
mutex_exit(&hfs_nhash_lock);
return NULL;
}
/*
* Insert the hfsnode into the hash table, and return it locked.
*/
void
hfs_nhashinsert(struct hfsnode *hp)
{
struct nhashhead *hpp;
int error __diagused;
/* lock the inode, then put it on the appropriate hash list */
error = VOP_LOCK(HTOV(hp), LK_EXCLUSIVE);
KASSERT(error == 0);
mutex_enter(&hfs_nhash_lock);
hpp = &nhashtbl[HNOHASH(hp->h_dev, hp->h_rec.u.cnid, hp->h_fork)];
LIST_INSERT_HEAD(hpp, hp, h_hash);
mutex_exit(&hfs_nhash_lock);
}
/*
* Remove the inode from the hash table.
*/
void
hfs_nhashremove(struct hfsnode *hp)
{
mutex_enter(&hfs_nhash_lock);
LIST_REMOVE(hp, h_hash);
mutex_exit(&hfs_nhash_lock);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: hfs_vfsops.c,v 1.31 2014/04/16 18:55:18 maxv Exp $ */
/* $NetBSD: hfs_vfsops.c,v 1.32 2014/08/10 08:53:22 hannken Exp $ */
/*-
* Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
@ -99,7 +99,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hfs_vfsops.c,v 1.31 2014/04/16 18:55:18 maxv Exp $");
__KERNEL_RCSID(0, "$NetBSD: hfs_vfsops.c,v 1.32 2014/08/10 08:53:22 hannken Exp $");
#ifdef _KERNEL_OPT
#include "opt_compat_netbsd.h"
@ -139,7 +139,7 @@ MODULE(MODULE_CLASS_VFS, hfs, NULL);
MALLOC_JUSTDEFINE(M_HFSMNT, "hfs mount", "hfs mount structures");
extern kmutex_t hfs_hashlock;
struct pool hfs_node_pool;
const struct vnodeopv_desc * const hfs_vnodeopv_descs[] = {
&hfs_vnodeop_opv_desc,
@ -159,6 +159,7 @@ struct vfsops hfs_vfsops = {
.vfs_statvfs = hfs_statvfs,
.vfs_sync = hfs_sync,
.vfs_vget = hfs_vget,
.vfs_loadvnode = hfs_loadvnode,
.vfs_fhtovp = hfs_fhtovp,
.vfs_vptofh = hfs_vptofh,
.vfs_init = hfs_init,
@ -507,7 +508,18 @@ hfs_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
int
hfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
{
return hfs_vget_internal(mp, ino, HFS_DATAFORK, vpp);
int error;
error = hfs_vget_internal(mp, ino, HFS_DATAFORK, vpp);
if (error)
return error;
error = vn_lock(*vpp, LK_EXCLUSIVE);
if (error) {
vrele(*vpp);
*vpp = NULL;
return error;
}
return 0;
}
/*
@ -516,94 +528,61 @@ hfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
int
hfs_vget_internal(struct mount *mp, ino_t ino, uint8_t fork,
struct vnode **vpp)
{
struct hfsnode_key key;
memset(&key, 0, sizeof(key));
key.hnk_cnid = (hfs_cnid_t)ino;
key.hnk_fork = (fork != HFS_RSRCFORK ? HFS_DATAFORK : HFS_RSRCFORK);
return vcache_get(mp, &key, sizeof(key), vpp);
}
int
hfs_loadvnode(struct mount *mp, struct vnode *vp,
const void *key, size_t key_len, const void **new_key)
{
struct hfsmount *hmp;
struct hfsnode *hnode;
struct vnode *vp;
struct hfsnode_key hfskey;
hfs_callback_args cbargs;
hfs_cnid_t cnid;
hfs_catalog_keyed_record_t rec;
hfs_catalog_key_t key; /* the search key used to find this file on disk */
hfs_catalog_key_t cat_key; /* the search key used to find this file on disk */
dev_t dev;
int error;
#ifdef HFS_DEBUG
printf("vfsop = hfs_vget()\n");
printf("vfsop = hfs_loadvnode()\n");
#endif /* HFS_DEBUG */
hnode = NULL;
vp = NULL;
KASSERT(key_len == sizeof(hfskey));
memcpy(&hfskey, key, key_len);
hmp = VFSTOHFS(mp);
dev = hmp->hm_dev;
cnid = (hfs_cnid_t)ino;
if (fork != HFS_RSRCFORK)
fork = HFS_DATAFORK;
retry:
/* Check if this vnode has already been allocated. If so, just return it. */
if ((*vpp = hfs_nhashget(dev, cnid, fork, LK_EXCLUSIVE)) != NULL)
return 0;
/* Allocate a new vnode/inode. */
error = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, NULL, &vp);
if (error) {
goto error;
}
hnode = malloc(sizeof(struct hfsnode), M_TEMP,
M_WAITOK | M_ZERO);
/*
* If someone beat us to it while sleeping in getnewvnode(),
* push back the freshly allocated vnode we don't need, and return.
*/
mutex_enter(&hfs_hashlock);
if (hfs_nhashget(dev, cnid, fork, 0) != NULL) {
mutex_exit(&hfs_hashlock);
ungetnewvnode(vp);
free(hnode, M_TEMP);
goto retry;
}
vp->v_vflag |= VV_LOCKSWORK;
vp->v_data = hnode;
genfs_node_init(vp, &hfs_genfsops);
hnode = pool_get(&hfs_node_pool, PR_WAITOK);
memset(hnode, 0, sizeof(*hnode));
hnode->h_vnode = vp;
hnode->h_hmp = hmp;
hnode->dummy = 0x1337BABE;
/*
* We need to put this vnode into the hash chain and lock it so that other
* requests for this inode will block if they arrive while we are sleeping
* waiting for old data structures to be purged or for the contents of the
* disk portion of this inode to be read. The hash chain requires the node's
* device and cnid to be known. Since this information was passed in the
* arguments, fill in the appropriate hfsnode fields without reading having
* to read the disk.
*/
hnode->h_dev = dev;
hnode->h_rec.u.cnid = cnid;
hnode->h_fork = fork;
hfs_nhashinsert(hnode);
mutex_exit(&hfs_hashlock);
hnode->h_rec.u.cnid = hfskey.hnk_cnid;
hnode->h_fork = hfskey.hnk_fork;
hnode->h_key = hfskey;
/*
* Read catalog record from disk.
*/
hfslib_init_cbargs(&cbargs);
if (hfslib_find_catalog_record_with_cnid(&hmp->hm_vol, cnid,
&rec, &key, &cbargs) != 0) {
vput(vp);
error = EBADF;
goto error;
if (hfslib_find_catalog_record_with_cnid(&hmp->hm_vol, hfskey.hnk_cnid,
&rec, &cat_key, &cbargs) != 0) {
pool_put(&hfs_node_pool, hnode);
return EBADF;
}
memcpy(&hnode->h_rec, &rec, sizeof(hnode->h_rec));
hnode->h_parent = key.parent_cnid;
hnode->h_parent = cat_key.parent_cnid;
/* XXX Eventually need to add an "ignore permissions" mount option */
@ -613,9 +592,14 @@ hfs_vget_internal(struct mount *mp, ino_t ino, uint8_t fork,
*/
/* DATE AND TIME */
vp->v_tag = VT_HFS;
vp->v_op = hfs_vnodeop_p;
vp->v_vflag |= VV_LOCKSWORK;
vp->v_data = hnode;
genfs_node_init(vp, &hfs_genfsops);
/*
* Initialize the vnode from the hfsnode, check for aliases.
* Note that the underlying vnode may change.
*/
hfs_vinit(mp, hfs_specop_p, hfs_fifoop_p, &vp);
@ -634,13 +618,8 @@ hfs_vget_internal(struct mount *mp, ino_t ino, uint8_t fork,
else
uvm_vnp_setsize(vp, 0); /* no directly reading directories */
*vpp = vp;
*new_key = &hnode->h_key;
return 0;
error:
*vpp = NULL;
return error;
}
int
@ -675,6 +654,8 @@ hfs_init(void)
#endif /* HFS_DEBUG */
malloc_type_attach(M_HFSMNT);
pool_init(&hfs_node_pool, sizeof(struct hfsnode), 0, 0, 0, "hfsndpl",
&pool_allocator_nointr, IPL_NONE);
callbacks.error = hfs_libcb_error;
callbacks.allocmem = hfs_libcb_malloc;
@ -684,7 +665,6 @@ hfs_init(void)
callbacks.closevol = hfs_libcb_closedev;
callbacks.read = hfs_libcb_read;
hfs_nhashinit();
hfslib_init(&callbacks);
}
@ -709,8 +689,9 @@ hfs_done(void)
malloc_type_detach(M_HFSMNT);
pool_destroy(&hfs_node_pool);
hfslib_done();
hfs_nhashdone();
}
int

View File

@ -1,4 +1,4 @@
/* $NetBSD: hfs_vnops.c,v 1.30 2014/07/25 08:20:51 dholland Exp $ */
/* $NetBSD: hfs_vnops.c,v 1.31 2014/08/10 08:53:22 hannken Exp $ */
/*-
* Copyright (c) 2005, 2007 The NetBSD Foundation, Inc.
@ -101,7 +101,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: hfs_vnops.c,v 1.30 2014/07/25 08:20:51 dholland Exp $");
__KERNEL_RCSID(0, "$NetBSD: hfs_vnops.c,v 1.31 2014/08/10 08:53:22 hannken Exp $");
#ifdef _KERNEL_OPT
#include "opt_ipsec.h"
@ -115,6 +115,7 @@ __KERNEL_RCSID(0, "$NetBSD: hfs_vnops.c,v 1.30 2014/07/25 08:20:51 dholland Exp
#include <sys/proc.h>
#include <sys/vnode.h>
#include <sys/malloc.h>
#include <sys/pool.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/mount.h>
@ -335,7 +336,6 @@ hfs_vop_lookup(void *v)
struct hfsnode *dp; /* hfsnode for directory being searched */
kauth_cred_t cred;
struct vnode **vpp; /* resultant vnode */
struct vnode *pdp; /* saved dp during symlink work */
struct vnode *tdp; /* returned by VFS_VGET */
struct vnode *vdp; /* vnode for directory being searched */
hfs_catalog_key_t key; /* hfs+ catalog search key for requested child */
@ -394,12 +394,10 @@ hfs_vop_lookup(void *v)
}
#endif
pdp = vdp;
if (flags & ISDOTDOT) {
DPRINTF(("DOTDOT "));
VOP_UNLOCK(pdp); /* race to get the inode */
error = VFS_VGET(vdp->v_mount, dp->h_parent, &tdp);
vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
error = hfs_vget_internal(vdp->v_mount, dp->h_parent,
HFS_RSRCFORK, &tdp);
if (error != 0)
goto error;
*vpp = tdp;
@ -467,7 +465,8 @@ hfs_vop_lookup(void *v)
HFS_RSRCFORK, &tdp);
}
else
error = VFS_VGET(vdp->v_mount, rec.file.cnid, &tdp);
error = hfs_vget_internal(vdp->v_mount, rec.file.cnid,
HFS_DATAFORK, &tdp);
if (error != 0)
goto error;
*vpp = tdp;
@ -481,8 +480,6 @@ hfs_vop_lookup(void *v)
cache_enter(vdp, *vpp, cnp);
#endif
if (*vpp != vdp)
VOP_UNLOCK(*vpp);
error = 0;
/* FALLTHROUGH */
@ -1039,8 +1036,8 @@ hfs_vop_reclaim(void *v)
vp = ap->a_vp;
hp = VTOH(vp);
/* Remove the hfsnode from its hash chain. */
hfs_nhashremove(hp);
KASSERT(hp->h_key.hnk_cnid == hp->h_rec.u.cnid);
vcache_remove(vp->v_mount, &hp->h_key, sizeof(hp->h_key));
/* Decrement the reference count to the volume's device. */
if (hp->h_devvp) {
@ -1049,7 +1046,7 @@ hfs_vop_reclaim(void *v)
}
genfs_node_destroy(vp);
free(vp->v_data, M_TEMP);
pool_put(&hfs_node_pool, hp);
vp->v_data = NULL;
return 0;

View File

@ -1,11 +1,10 @@
# $NetBSD: Makefile,v 1.1 2008/06/28 16:11:36 rumble Exp $
# $NetBSD: Makefile,v 1.2 2014/08/10 08:53:22 hannken Exp $
.include "../Makefile.inc"
.PATH: ${S}/fs/hfs
KMOD= hfs
SRCS= hfs_nhash.c hfs_subr.c hfs_vfsops.c hfs_vnops.c libhfs.c \
unicode.c
SRCS= hfs_subr.c hfs_vfsops.c hfs_vnops.c libhfs.c unicode.c
.include <bsd.kmodule.mk>

View File

@ -1,11 +1,11 @@
# $NetBSD: Makefile,v 1.3 2010/02/16 20:42:46 pooka Exp $
# $NetBSD: Makefile,v 1.4 2014/08/10 08:53:22 hannken Exp $
#
.PATH: ${.CURDIR}/../../../../fs/hfs
LIB= rumpfs_hfs
SRCS= hfs_nhash.c hfs_subr.c hfs_vfsops.c hfs_vnops.c libhfs.c unicode.c
SRCS= hfs_subr.c hfs_vfsops.c hfs_vnops.c libhfs.c unicode.c
.include <bsd.lib.mk>
.include <bsd.klinks.mk>