Module Name: src
Committed By: reinoud
Date: Tue Jul 7 10:23:36 UTC 2009
Modified Files:
src/sys/fs/udf: udf.h udf_subr.c udf_subr.h udf_vfsops.c udf_vnops.c
Log Message:
Replace the old hashtable and sorted list implemenation by a RB-tree.
Benefits are significant speed improvements on node creation/insertion while
keeping the lookup times low and still allowing sequential iteration over the
nodes.
To generate a diff of this commit:
cvs rdiff -u -r1.35 -r1.36 src/sys/fs/udf/udf.h
cvs rdiff -u -r1.97 -r1.98 src/sys/fs/udf/udf_subr.c
cvs rdiff -u -r1.16 -r1.17 src/sys/fs/udf/udf_subr.h
cvs rdiff -u -r1.58 -r1.59 src/sys/fs/udf/udf_vfsops.c
cvs rdiff -u -r1.50 -r1.51 src/sys/fs/udf/udf_vnops.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/fs/udf/udf.h
diff -u src/sys/fs/udf/udf.h:1.35 src/sys/fs/udf/udf.h:1.36
--- src/sys/fs/udf/udf.h:1.35 Mon Jul 6 17:08:04 2009
+++ src/sys/fs/udf/udf.h Tue Jul 7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf.h,v 1.35 2009/07/06 17:08:04 reinoud Exp $ */
+/* $NetBSD: udf.h,v 1.36 2009/07/07 10:23:36 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -30,6 +30,7 @@
#define _FS_UDF_UDF_H_
#include <sys/queue.h>
+#include <sys/rb.h>
#include <sys/uio.h>
#include <sys/mutex.h>
@@ -333,8 +334,7 @@
/* hash table to lookup icb -> udf_node and sorted list for sync */
kmutex_t ihash_lock;
kmutex_t get_node_lock;
- LIST_HEAD(, udf_node) udf_nodes[UDF_INODE_HASHSIZE];
- LIST_HEAD(, udf_node) sorted_udf_nodes; /* sorted sync list */
+ struct rb_tree udf_node_tree;
/* syncing */
int syncing; /* are we syncing? */
@@ -354,6 +354,11 @@
};
+#define RBTOUDFNODE(node) \
+ ((node) ? \
+ (void *)((uintptr_t)(node) - offsetof(struct udf_node, rbnode)) \
+ : NULL)
+
/*
* UDF node describing a file/directory.
*
@@ -369,6 +374,9 @@
char const *lock_fname;
int lock_lineno;
+ /* rb_node for fast lookup and fast sequentual visiting */
+ struct rb_node rbnode;
+
/* one of `fe' or `efe' can be set, not both (UDF file entry dscr.) */
struct file_entry *fe;
struct extfile_entry *efe;
Index: src/sys/fs/udf/udf_subr.c
diff -u src/sys/fs/udf/udf_subr.c:1.97 src/sys/fs/udf/udf_subr.c:1.98
--- src/sys/fs/udf/udf_subr.c:1.97 Mon Jul 6 17:06:57 2009
+++ src/sys/fs/udf/udf_subr.c Tue Jul 7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.c,v 1.97 2009/07/06 17:06:57 reinoud Exp $ */
+/* $NetBSD: udf_subr.c,v 1.98 2009/07/07 10:23:36 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -29,7 +29,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.97 2009/07/06 17:06:57 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_subr.c,v 1.98 2009/07/07 10:23:36 reinoud Exp $");
#endif /* not lint */
@@ -3366,7 +3366,7 @@
/* To make absolutely sure we are NOT returning zero, add one :) */
long
-udf_calchash(struct long_ad *icbptr)
+udf_get_node_id(const struct long_ad *icbptr)
{
/* ought to be enough since each mountpoint has its own chain */
return udf_rw32(icbptr->loc.lb_num) + 1;
@@ -3374,120 +3374,102 @@
int
-udf_check_icb_equal(struct long_ad *a, struct long_ad *b)
+udf_compare_icb(const struct long_ad *a, const struct long_ad *b)
{
- return (a->loc.lb_num == b->loc.lb_num &&
- a->loc.part_num == b->loc.part_num);
+ if (udf_rw16(a->loc.part_num) < udf_rw16(b->loc.part_num))
+ return -1;
+ if (udf_rw16(a->loc.part_num) > udf_rw16(b->loc.part_num))
+ return 1;
+
+ if (udf_rw32(a->loc.lb_num) < udf_rw32(b->loc.lb_num))
+ return -1;
+ if (udf_rw32(a->loc.lb_num) > udf_rw32(b->loc.lb_num))
+ return 1;
+
+ return 0;
}
-static struct udf_node *
-udf_hash_lookup(struct udf_mount *ump, struct long_ad *icbptr)
+static int
+udf_compare_rbnodes(const struct rb_node *a, const struct rb_node *b)
{
- struct udf_node *node;
- struct vnode *vp;
- uint32_t hashline;
-
-loop:
- mutex_enter(&ump->ihash_lock);
+ struct udf_node *a_node = RBTOUDFNODE(a);
+ struct udf_node *b_node = RBTOUDFNODE(b);
- hashline = udf_calchash(icbptr) & UDF_INODE_HASHMASK;
- LIST_FOREACH(node, &ump->udf_nodes[hashline], hashchain) {
- assert(node);
- if (udf_check_icb_equal(&node->loc, icbptr)) {
- vp = node->vnode;
- assert(vp);
- mutex_enter(&vp->v_interlock);
- mutex_exit(&ump->ihash_lock);
- if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
- goto loop;
- return node;
- }
- }
- mutex_exit(&ump->ihash_lock);
-
- return NULL;
+ return udf_compare_icb(&a_node->loc, &b_node->loc);
}
-static void
-udf_sorted_list_insert(struct udf_node *node)
+static int
+udf_compare_rbnode_icb(const struct rb_node *a, const void *key)
{
- struct udf_mount *ump;
- struct udf_node *s_node, *last_node;
- uint32_t loc, s_loc;
+ struct udf_node *a_node = RBTOUDFNODE(a);
+ const struct long_ad * const icb = key;
- ump = node->ump;
- last_node = NULL; /* XXX gcc */
+ return udf_compare_icb(&a_node->loc, icb);
+}
- if (LIST_EMPTY(&ump->sorted_udf_nodes)) {
- LIST_INSERT_HEAD(&ump->sorted_udf_nodes, node, sortchain);
- return;
- }
- /*
- * We sort on logical block number here and not on physical block
- * number here. Ideally we should go for the physical block nr to get
- * better sync performance though this sort will ensure that packets
- * won't get spit up unnessisarily.
- */
+static const struct rb_tree_ops udf_node_rbtree_ops = {
+ .rbto_compare_nodes = udf_compare_rbnodes,
+ .rbto_compare_key = udf_compare_rbnode_icb,
+};
- loc = udf_rw32(node->loc.loc.lb_num);
- LIST_FOREACH(s_node, &ump->sorted_udf_nodes, sortchain) {
- s_loc = udf_rw32(s_node->loc.loc.lb_num);
- if (s_loc > loc) {
- LIST_INSERT_BEFORE(s_node, node, sortchain);
- return;
- }
- last_node = s_node;
- }
- LIST_INSERT_AFTER(last_node, node, sortchain);
+
+void
+udf_init_nodes_tree(struct udf_mount *ump)
+{
+ rb_tree_init(&ump->udf_node_tree, &udf_node_rbtree_ops);
}
-static void
-udf_register_node(struct udf_node *node)
+static struct udf_node *
+udf_node_lookup(struct udf_mount *ump, struct long_ad *icbptr)
{
- struct udf_mount *ump;
- struct udf_node *chk;
- uint32_t hashline;
+ struct rb_node *rb_node;
+ struct udf_node *udf_node;
+ struct vnode *vp;
- ump = node->ump;
+loop:
mutex_enter(&ump->ihash_lock);
- /* add to our hash table */
- hashline = udf_calchash(&node->loc) & UDF_INODE_HASHMASK;
-#ifdef DEBUG
- LIST_FOREACH(chk, &ump->udf_nodes[hashline], hashchain) {
- assert(chk);
- if (chk->loc.loc.lb_num == node->loc.loc.lb_num &&
- chk->loc.loc.part_num == node->loc.loc.part_num)
- panic("Double node entered\n");
+ rb_node = rb_tree_find_node(&ump->udf_node_tree, icbptr);
+ if (rb_node) {
+ udf_node = RBTOUDFNODE(rb_node);
+ vp = udf_node->vnode;
+ assert(vp);
+ mutex_enter(&vp->v_interlock);
+ mutex_exit(&ump->ihash_lock);
+ if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
+ goto loop;
+ return udf_node;
}
-#else
- chk = NULL;
-#endif
- LIST_INSERT_HEAD(&ump->udf_nodes[hashline], node, hashchain);
-
- /* add to our sorted list */
- udf_sorted_list_insert(node);
-
mutex_exit(&ump->ihash_lock);
+
+ return NULL;
}
static void
-udf_deregister_node(struct udf_node *node)
+udf_register_node(struct udf_node *udf_node)
{
- struct udf_mount *ump;
+ struct udf_mount *ump = udf_node->ump;
- ump = node->ump;
+ /* add node to the rb tree */
mutex_enter(&ump->ihash_lock);
+ rb_tree_insert_node(&ump->udf_node_tree, &udf_node->rbnode);
+ mutex_exit(&ump->ihash_lock);
+}
- /* from hash and sorted list */
- LIST_REMOVE(node, hashchain);
- LIST_REMOVE(node, sortchain);
+static void
+udf_deregister_node(struct udf_node *udf_node)
+{
+ struct udf_mount *ump = udf_node->ump;
+
+ /* remove node from the rb tree */
+ mutex_enter(&ump->ihash_lock);
+ rb_tree_remove_node(&ump->udf_node_tree, &udf_node->rbnode);
mutex_exit(&ump->ihash_lock);
}
@@ -5274,7 +5256,7 @@
/* lookup in hash table */
assert(ump);
assert(node_icb_loc);
- udf_node = udf_hash_lookup(ump, node_icb_loc);
+ udf_node = udf_node_lookup(ump, node_icb_loc);
if (udf_node) {
DPRINTF(NODE, ("\tgot it from the hash!\n"));
/* vnode is returned locked */
@@ -6319,7 +6301,7 @@
if (fid->file_char & UDF_FILE_CHAR_PAR)
strcpy(dirent->d_name, "..");
- dirent->d_fileno = udf_calchash(&fid->icb); /* inode hash XXX */
+ dirent->d_fileno = udf_get_node_id(&fid->icb); /* inode hash XXX */
dirent->d_namlen = strlen(dirent->d_name);
dirent->d_reclen = _DIRENT_SIZE(dirent);
@@ -6355,7 +6337,7 @@
KASSERT(mutex_owned(&mntvnode_lock));
DPRINTF(SYNC, ("sync_pass %d\n", pass));
- udf_node = LIST_FIRST(&ump->sorted_udf_nodes);
+ udf_node = RBTOUDFNODE(RB_TREE_MIN(&ump->udf_node_tree));
for (;udf_node; udf_node = n_udf_node) {
DPRINTF(SYNC, ("."));
@@ -6363,7 +6345,10 @@
vp = udf_node->vnode;
mutex_enter(&vp->v_interlock);
- n_udf_node = LIST_NEXT(udf_node, sortchain);
+ n_udf_node = RBTOUDFNODE(rb_tree_iterate(
+ &ump->udf_node_tree, &udf_node->rbnode,
+ RB_DIR_RIGHT));
+
if (n_udf_node)
n_udf_node->i_flags |= IN_SYNCED;
Index: src/sys/fs/udf/udf_subr.h
diff -u src/sys/fs/udf/udf_subr.h:1.16 src/sys/fs/udf/udf_subr.h:1.17
--- src/sys/fs/udf/udf_subr.h:1.16 Thu Jun 25 17:16:33 2009
+++ src/sys/fs/udf/udf_subr.h Tue Jul 7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_subr.h,v 1.16 2009/06/25 17:16:33 reinoud Exp $ */
+/* $NetBSD: udf_subr.h,v 1.17 2009/07/07 10:23:36 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -182,8 +182,9 @@
struct timespec *mod, struct timespec *birth, int updflags);
/* helpers and converters */
-long udf_calchash(struct long_ad *icbptr); /* for `inode' numbering */
-int udf_check_icb_equal(struct long_ad *a, struct long_ad *b);
+void udf_init_nodes_tree(struct udf_mount *ump);
+long udf_get_node_id(const struct long_ad *icbptr); /* for `inode' numbering */
+int udf_compare_icb(const struct long_ad *a, const struct long_ad *b);
uint32_t udf_getaccessmode(struct udf_node *node);
void udf_setaccessmode(struct udf_node *udf_node, mode_t mode);
void udf_getownership(struct udf_node *udf_node, uid_t *uidp, gid_t *gidp);
Index: src/sys/fs/udf/udf_vfsops.c
diff -u src/sys/fs/udf/udf_vfsops.c:1.58 src/sys/fs/udf/udf_vfsops.c:1.59
--- src/sys/fs/udf/udf_vfsops.c:1.58 Mon Jun 29 05:08:17 2009
+++ src/sys/fs/udf/udf_vfsops.c Tue Jul 7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_vfsops.c,v 1.58 2009/06/29 05:08:17 dholland Exp $ */
+/* $NetBSD: udf_vfsops.c,v 1.59 2009/07/07 10:23:36 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -28,7 +28,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.58 2009/06/29 05:08:17 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_vfsops.c,v 1.59 2009/07/07 10:23:36 reinoud Exp $");
#endif /* not lint */
@@ -565,7 +565,7 @@
struct udf_mount *ump;
uint32_t sector_size, lb_size, bshift;
uint32_t logvol_integrity;
- int num_anchors, error, lst;
+ int num_anchors, error;
/* flush out any old buffers remaining from a previous use. */
if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)))
@@ -578,6 +578,7 @@
mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
mp->mnt_stat.f_namemax = UDF_MAX_NAMELEN;
mp->mnt_flag |= MNT_LOCAL;
+// mp->mnt_iflag |= IMNT_MPSAFE;
/* allocate udf part of mount structure; malloc always succeeds */
ump = malloc(sizeof(struct udf_mount), M_UDFMNT, M_WAITOK | M_ZERO);
@@ -589,10 +590,8 @@
mutex_init(&ump->allocate_mutex, MUTEX_DEFAULT, IPL_NONE);
cv_init(&ump->dirtynodes_cv, "udfsync2");
- /* init `ino_t' to udf_node hash table and other lists */
- for (lst = 0; lst < UDF_INODE_HASHSIZE; lst++) {
- LIST_INIT(&ump->udf_nodes[lst]);
- }
+ /* init rbtree for nodes, ordered by their icb address (long_ad) */
+ udf_init_nodes_tree(ump);
/* set up linkage */
mp->mnt_data = ump;
Index: src/sys/fs/udf/udf_vnops.c
diff -u src/sys/fs/udf/udf_vnops.c:1.50 src/sys/fs/udf/udf_vnops.c:1.51
--- src/sys/fs/udf/udf_vnops.c:1.50 Mon Jul 6 17:06:57 2009
+++ src/sys/fs/udf/udf_vnops.c Tue Jul 7 10:23:36 2009
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_vnops.c,v 1.50 2009/07/06 17:06:57 reinoud Exp $ */
+/* $NetBSD: udf_vnops.c,v 1.51 2009/07/07 10:23:36 reinoud Exp $ */
/*
* Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -32,7 +32,7 @@
#include <sys/cdefs.h>
#ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.50 2009/07/06 17:06:57 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.51 2009/07/07 10:23:36 reinoud Exp $");
#endif /* not lint */
@@ -561,7 +561,7 @@
if (uio->uio_offset == 0) {
DPRINTF(READDIR, ("\t'.' inserted\n"));
strcpy(dirent->d_name, ".");
- dirent->d_fileno = udf_calchash(&udf_node->loc);
+ dirent->d_fileno = udf_get_node_id(&udf_node->loc);
dirent->d_type = DT_DIR;
dirent->d_namlen = strlen(dirent->d_name);
dirent->d_reclen = _DIRENT_SIZE(dirent);
@@ -889,7 +889,7 @@
vap->va_uid = uid;
vap->va_gid = gid;
vap->va_fsid = vp->v_mount->mnt_stat.f_fsidx.__fsid_val[0];
- vap->va_fileid = udf_calchash(&udf_node->loc); /* inode hash XXX */
+ vap->va_fileid = udf_get_node_id(&udf_node->loc); /* inode hash XXX */
vap->va_size = filesize;
vap->va_blocksize = udf_node->ump->discinfo.sector_size; /* wise? */
@@ -1871,13 +1871,13 @@
root_icb = &ump->fileset_desc->rootdir_icb;
/* if nodes are equal, it is no use looking */
- if (udf_check_icb_equal(&source->loc, &target->loc)) {
+ if (udf_compare_icb(&source->loc, &target->loc) == 0) {
error = EEXIST;
goto out;
}
/* nothing can exist before the root */
- if (udf_check_icb_equal(root_icb, &target->loc)) {
+ if (udf_compare_icb(root_icb, &target->loc) == 0) {
error = 0;
goto out;
}
@@ -1905,13 +1905,13 @@
goto out;
/* did we encounter source node? */
- if (udf_check_icb_equal(&icb_loc, &source->loc)) {
+ if (udf_compare_icb(&icb_loc, &source->loc) == 0) {
error = EINVAL;
goto out;
}
/* did we encounter the root node? */
- if (udf_check_icb_equal(&icb_loc, root_icb)) {
+ if (udf_compare_icb(&icb_loc, root_icb) == 0) {
error = 0;
goto out;
}