diff --git a/sys/vfs/tmpfs/tmpfs.h b/sys/vfs/tmpfs/tmpfs.h index 7e8a7e6..6f1da36 100644 --- a/sys/vfs/tmpfs/tmpfs.h +++ b/sys/vfs/tmpfs/tmpfs.h @@ -47,6 +47,7 @@ #include #include #include +#include /* --------------------------------------------------------------------- */ #include @@ -58,11 +59,13 @@ MALLOC_DECLARE(M_TMPFSMNT); /* --------------------------------------------------------------------- */ + /* * Internal representation of a tmpfs directory entry. */ struct tmpfs_dirent { TAILQ_ENTRY(tmpfs_dirent) td_entries; + RB_ENTRY(tmpfs_dirent) rb_node; /* Length of the name stored in this directory entry. This avoids * the need to recalculate it every time the name is used. */ @@ -77,6 +80,12 @@ struct tmpfs_dirent { struct tmpfs_node * td_node; }; +struct tmpfs_dirtree; +RB_HEAD(tmpfs_dirtree, tmpfs_dirent); +RB_PROTOTYPE(tmpfs_dirtree, tmpfs_dirent, rb_node, + tmpfs_dirtree_compare); + + /* A directory in tmpfs holds a sorted list of directory entries, which in * turn point to other files (which can be directories themselves). * @@ -256,6 +265,7 @@ struct tmpfs_node { * the directory together. See above for a * description of its contents. */ struct tmpfs_dir tn_dirhead; + struct tmpfs_dirtree tn_dirtree; /* Number and pointer of the first directory entry * returned by the readdir operation if it were diff --git a/sys/vfs/tmpfs/tmpfs_subr.c b/sys/vfs/tmpfs/tmpfs_subr.c index 14e70b9..c6cd8a0 100644 --- a/sys/vfs/tmpfs/tmpfs_subr.c +++ b/sys/vfs/tmpfs/tmpfs_subr.c @@ -55,6 +55,11 @@ #include static ino_t tmpfs_fetch_ino(struct tmpfs_mount *); +static int tmpfs_dirtree_compare(struct tmpfs_dirent *a, + struct tmpfs_dirent *b); + +RB_GENERATE(tmpfs_dirtree, tmpfs_dirent, rb_node, tmpfs_dirtree_compare); + /* --------------------------------------------------------------------- */ @@ -130,6 +135,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type, case VDIR: TAILQ_INIT(&nnode->tn_dir.tn_dirhead); + RB_INIT(&nnode->tn_dir.tn_dirtree); KKASSERT(parent != nnode); KKASSERT(IMPLIES(parent == NULL, tmp->tm_root == NULL)); nnode->tn_dir.tn_parent = parent; @@ -610,6 +616,7 @@ tmpfs_dir_attach(struct tmpfs_node *dnode, struct tmpfs_dirent *de) { TMPFS_NODE_LOCK(dnode); TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_dirhead, de, td_entries); + RB_INSERT(tmpfs_dirtree, &dnode->tn_dir.tn_dirtree, de); TMPFS_ASSERT_ELOCKED(dnode); dnode->tn_size += sizeof(struct tmpfs_dirent); @@ -634,6 +641,7 @@ tmpfs_dir_detach(struct tmpfs_node *dnode, struct tmpfs_dirent *de) dnode->tn_dir.tn_readdir_lastp = NULL; } TAILQ_REMOVE(&dnode->tn_dir.tn_dirhead, de, td_entries); + RB_REMOVE(tmpfs_dirtree, &dnode->tn_dir.tn_dirtree, de); TMPFS_ASSERT_ELOCKED(dnode); dnode->tn_size -= sizeof(struct tmpfs_dirent); @@ -658,17 +666,14 @@ tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f, { struct tmpfs_dirent *de; int len = ncp->nc_nlen; + struct tmpfs_dirent wanted; + + wanted.td_namelen = len; + wanted.td_name = ncp->nc_name; TMPFS_VALIDATE_DIR(node); - TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) { - if (f != NULL && de->td_node != f) - continue; - if (len == de->td_namelen) { - if (!memcmp(ncp->nc_name, de->td_name, len)) - break; - } - } + de = RB_FIND(tmpfs_dirtree, &node->tn_dir.tn_dirtree, &wanted); TMPFS_NODE_LOCK(node); node->tn_status |= TMPFS_NODE_ACCESSED; @@ -1346,3 +1351,13 @@ tmpfs_fetch_ino(struct tmpfs_mount *tmp) return (ret); } + +static int tmpfs_dirtree_compare(struct tmpfs_dirent *a, struct tmpfs_dirent *b) +{ + if (a->td_namelen > b->td_namelen) + return 1; + else if (b->td_namelen > a->td_namelen) + return -1; + else + return strncmp(a->td_name, b->td_name, a->td_namelen); +} diff --git a/sys/vfs/tmpfs/tmpfs_vnops.c b/sys/vfs/tmpfs/tmpfs_vnops.c index 990a1ce..d7ee0c0 100644 --- a/sys/vfs/tmpfs/tmpfs_vnops.c +++ b/sys/vfs/tmpfs/tmpfs_vnops.c @@ -1039,6 +1039,9 @@ tmpfs_nrename(struct vop_nrename_args *v) */ if (fdnode != tdnode) tmpfs_dir_detach(fdnode, de); + else { + RB_REMOVE(tmpfs_dirtree, &fdnode->tn_dir.tn_dirtree, de); + } /* * Handle any name change. Swap with newname, we will @@ -1084,6 +1087,7 @@ tmpfs_nrename(struct vop_nrename_args *v) } else { TMPFS_NODE_LOCK(tdnode); tdnode->tn_status |= TMPFS_NODE_MODIFIED; + RB_INSERT(tmpfs_dirtree, &tdnode->tn_dir.tn_dirtree, de); TMPFS_NODE_UNLOCK(tdnode); }