/* $NetBSD$ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Taylor R Campbell. * * 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. */ /* * XXX NOTE NOTE NOTE XXX * * This code does not actually work. It is a draft of an idea. It * probably won't even compile, even if you make it include the right * header files. */ /* inode->vnode table */ struct vinotab { krwlock_t vit_lock; rb_tree_t vit_tree; }; struct vinokey { const void *vik_key; unsigned int vik_keysize; }; static int compare_vinoents(void *context __unused, const void *va, const void *vb) { const struct vinoent *const a = va; const struct vinoent *const b = vb; if (a->vie_keysize < b->vie_keysize) return -1; if (a->vie_keysize > b->vie_keysize) return +1; return memcmp(a->vie_key, b->vie_key, a->vie_keysize); } static int compare_vinoent_key(void *context __unused, const void *ve, const void *vk) { const struct vionent *const e = ve; const struct vinokey *const k = vk; if (e->vie_keysize < k->vik_keysize) return -1; if (e->vie_keysize > k->vik_keysize) return +1; return memcmp(e->vie_key, k->vik_key, e->vie_keysize); } static const rb_tree_ops_t viontab_rb_ops = { .rbto_compare_nodes_fn = &compare_vinoents, .rbto_compare_key_fn = &compare_vinoent_key, .rbto_node_offset = offsetof(struct vinoent, vie_rb_node), .rbto_context = NULL, }; struct vinotab * vinotab_create(void) { struct vinotab *const vinotab = kmem_alloc(sizeof(*vinotab), KM_SLEEP); rw_init(&vinotab->vit_lock); rb_tree_init(&vinotab->vit_tree, &vinotab_rb_ops); return vinotab; } void vinotab_destroy(struct vinotab *vinotab) { KASSERT(RB_TREE_MIN(vinotab->vit_tree) == NULL); #if 0 rb_tree_destroy(&vinotab->vit_tree); #endif rw_destroy(&vinotab->vit_lock); kmem_free(vinotab, sizeof(*vinotab)); } void vinotab_reinit(struct vinotab *vinotab __unused) { } int vinotab_get(struct vinotab *vinotab, const void *key, unsigned int keysize, int flags, struct vnode *vpp) { struct vinoent *vinoent; struct vinokey vinokey = { .vik_key = key, .vik_keysize = keysize }; int error; rw_enter(&vinotab->vit_lock, RW_READER); vinoent = rb_tree_find_node(&vinotab->vit_tree, &vinokey); if (vinoent != NULL) { vpreget(vinoent->vie_vnode); rw_exit(&vinotab->vit_lock); error = vget(vinoent->vie_vnode, flags); if (error) { *vpp = NULL; return error; } *vpp = vinoent->vie_vnode; return 0; } rw_exit(&vinotab->vit_lock); *vpp = NULL; return ENOENT; } int vinotab_intern(struct vinotab *vinotab, struct vinoent *new_vinoent, const void *key, unsigned int keysize, struct vnode *vp, int flags, struct vnode **vpp) { struct vinoent *vinoent; new_vinoent->vie_vnode = vp; new_vinoent->vie_key = key; new_vinoent->vie_keysize = keysize; retry: rw_enter(&vinotab->vit_lock, RW_WRITER); vinoent = rb_tree_insert_node(&vinotab->vit_tree, new_vinoent); if (vinoent != NULL) { vpreget(vinoent->vie_vnode); rw_exit(&vinotab->vit_lock); error = vget(vinoent->vie_node, flags); if (error) { if (error == ENOENT) goto retry; *vpp = NULL; return error; } *vpp = vinoent->vie_node; return 0; } rw_exit(&vinotab->vit_lock); *vpp = vp; return 0; } void vinotab_remove(struct vinotab *vinotab, struct vinoent *vinoent) { rw_enter(&vinotab->vit_lock, RW_WRITER); rb_tree_remove_node(&viontab->vit_tree, vinoent); rw_exit(&vinotab->vit_lock); }