patch: portable dirhash
Ted Unangst
tedu at zeitbombe.org
Tue Dec 16 19:12:14 PST 2003
can somebody please review/commit this to freebsd? it is most of the
differences to permit openbsd to use the code. it should not change the
code in any functional way.
Index: ufs_dirhash.c
===================================================================
RCS file: /home/ncvs/src/sys/ufs/ufs/ufs_dirhash.c,v
retrieving revision 1.17
diff -u -r1.17 ufs_dirhash.c
--- ufs_dirhash.c 11 Jun 2003 06:34:30 -0000 1.17
+++ ufs_dirhash.c 17 Dec 2003 03:04:58 -0000
@@ -89,13 +89,28 @@
static doff_t ufsdirhash_getprev(struct direct *dp, doff_t offset);
static int ufsdirhash_recycle(int wanted);
-static uma_zone_t ufsdirhash_zone;
-
/* Dirhash list; recently-used entries are near the tail. */
static TAILQ_HEAD(, dirhash) ufsdirhash_list;
/* Protects: ufsdirhash_list, `dh_list' field, ufs_dirhashmem. */
+#ifdef __FreeBSD__
+static uma_zone_t ufsdirhash_zone;
+#define DIRHASH_ALLOC() uma_zalloc(ufsdirhash_zone, M_WAITOK)
+#define DIRHASH_FREE(v) uma_zfree(ufsdirhash_zone, v)
+
static struct mtx ufsdirhash_mtx;
+#define LOCK(l) mtx_lock(l)
+#define UNLOCK(l) mtx_unlock(l)
+#else
+struct pool ufsdirhash_pool;
+#define DIRHASH_ALLOC() pool_get(&ufsdirhash_pool, PR_WAITOK)
+#define DIRHASH_FREE(v) pool_put(&ufsdirhash_pool, v)
+
+struct rwlock ufsdirhash_mtx;
+#define LOCK(l) rw_enter_write(l, curproc)
+#define UNLOCK(l) rw_exit_write(l)
+#define mtx_assert(l, f) /* nothing */
+#endif
/*
* Locking order:
@@ -156,9 +171,9 @@
memreqd = sizeof(*dh) + narrays * sizeof(*dh->dh_hash) +
narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
nblocks * sizeof(*dh->dh_blkfree);
- mtx_lock(&ufsdirhash_mtx);
+ LOCK(&ufsdirhash_mtx);
if (memreqd + ufs_dirhashmem > ufs_dirhashmaxmem) {
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
if (memreqd > ufs_dirhashmaxmem / 2)
return (-1);
@@ -168,7 +183,7 @@
/* Enough was freed, and ufsdirhash_mtx has been locked. */
}
ufs_dirhashmem += memreqd;
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
/*
* Use non-blocking mallocs so that we will revert to a linear
@@ -176,9 +191,9 @@
*/
MALLOC(dh, struct dirhash *, sizeof *dh, M_DIRHASH, M_NOWAIT | M_ZERO);
if (dh == NULL) {
- mtx_lock(&ufsdirhash_mtx);
+ LOCK(&ufsdirhash_mtx);
ufs_dirhashmem -= memreqd;
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
return (-1);
}
MALLOC(dh->dh_hash, doff_t **, narrays * sizeof(dh->dh_hash[0]),
@@ -188,15 +203,18 @@
if (dh->dh_hash == NULL || dh->dh_blkfree == NULL)
goto fail;
for (i = 0; i < narrays; i++) {
- if ((dh->dh_hash[i] = uma_zalloc(ufsdirhash_zone,
- M_WAITOK)) == NULL)
+ if ((dh->dh_hash[i] = DIRHASH_ALLOC()) == NULL)
goto fail;
for (j = 0; j < DH_NBLKOFF; j++)
dh->dh_hash[i][j] = DIRHASH_EMPTY;
}
/* Initialise the hash table and block statistics. */
+#ifdef __FreeBSD__
mtx_init(&dh->dh_mtx, "dirhash", NULL, MTX_DEF);
+#else
+ rw_init(&dh->dh_mtx);
+#endif
dh->dh_narrays = narrays;
dh->dh_hlen = nslots;
dh->dh_nblk = nblocks;
@@ -244,26 +262,26 @@
if (bp != NULL)
brelse(bp);
- mtx_lock(&ufsdirhash_mtx);
+ LOCK(&ufsdirhash_mtx);
TAILQ_INSERT_TAIL(&ufsdirhash_list, dh, dh_list);
dh->dh_onlist = 1;
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
return (0);
fail:
if (dh->dh_hash != NULL) {
for (i = 0; i < narrays; i++)
if (dh->dh_hash[i] != NULL)
- uma_zfree(ufsdirhash_zone, dh->dh_hash[i]);
+ DIRHASH_FREE(dh->dh_hash[i]);
FREE(dh->dh_hash, M_DIRHASH);
}
if (dh->dh_blkfree != NULL)
FREE(dh->dh_blkfree, M_DIRHASH);
FREE(dh, M_DIRHASH);
ip->i_dirhash = NULL;
- mtx_lock(&ufsdirhash_mtx);
+ LOCK(&ufsdirhash_mtx);
ufs_dirhashmem -= memreqd;
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
return (-1);
}
@@ -278,32 +296,34 @@
if ((dh = ip->i_dirhash) == NULL)
return;
- mtx_lock(&ufsdirhash_mtx);
- mtx_lock(&dh->dh_mtx);
+ LOCK(&ufsdirhash_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_onlist)
TAILQ_REMOVE(&ufsdirhash_list, dh, dh_list);
- mtx_unlock(&dh->dh_mtx);
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&dh->dh_mtx);
+ UNLOCK(&ufsdirhash_mtx);
/* The dirhash pointed to by 'dh' is exclusively ours now. */
mem = sizeof(*dh);
if (dh->dh_hash != NULL) {
for (i = 0; i < dh->dh_narrays; i++)
- uma_zfree(ufsdirhash_zone, dh->dh_hash[i]);
+ DIRHASH_FREE(dh->dh_hash[i]);
FREE(dh->dh_hash, M_DIRHASH);
FREE(dh->dh_blkfree, M_DIRHASH);
mem += dh->dh_narrays * sizeof(*dh->dh_hash) +
dh->dh_narrays * DH_NBLKOFF * sizeof(**dh->dh_hash) +
dh->dh_nblk * sizeof(*dh->dh_blkfree);
}
+#ifdef __FreeBSD__
mtx_destroy(&dh->dh_mtx);
+#endif
FREE(dh, M_DIRHASH);
ip->i_dirhash = NULL;
- mtx_lock(&ufsdirhash_mtx);
+ LOCK(&ufsdirhash_mtx);
ufs_dirhashmem -= mem;
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
}
/*
@@ -339,8 +359,8 @@
* In both cases, end up holding just dh_mtx.
*/
if (TAILQ_NEXT(dh, dh_list) != NULL) {
- mtx_lock(&ufsdirhash_mtx);
- mtx_lock(&dh->dh_mtx);
+ LOCK(&ufsdirhash_mtx);
+ LOCK(&dh->dh_mtx);
/*
* If the new score will be greater than that of the next
* entry, then move this entry past it. With both mutexes
@@ -355,13 +375,13 @@
TAILQ_INSERT_AFTER(&ufsdirhash_list, dh_next, dh,
dh_list);
}
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
} else {
/* Already the last, though that could change as we wait. */
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
}
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return (EJUSTRETURN);
}
@@ -403,7 +423,7 @@
slot = WRAPINCR(slot, dh->dh_hlen)) {
if (offset == DIRHASH_DEL)
continue;
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
if (offset < 0 || offset >= ip->i_size)
panic("ufsdirhash_lookup: bad offset in hash array");
@@ -447,9 +467,9 @@
return (0);
}
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
if (bp != NULL)
brelse(bp);
ufsdirhash_free(ip);
@@ -464,7 +484,7 @@
goto restart;
}
}
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
if (bp != NULL)
brelse(bp);
return (ENOENT);
@@ -497,9 +517,9 @@
if ((dh = ip->i_dirhash) == NULL)
return (-1);
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return (-1);
}
@@ -510,14 +530,14 @@
if ((dirblock = dh->dh_firstfree[i]) != -1)
break;
if (dirblock == -1) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
return (-1);
}
KASSERT(dirblock < dh->dh_nblk &&
dh->dh_blkfree[dirblock] >= howmany(slotneeded, DIRALIGN),
("ufsdirhash_findfree: bad stats"));
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
pos = dirblock * DIRBLKSIZ;
error = UFS_BLKATOFF(ip->i_vnode, (off_t)pos, (char **)&dp, &bp);
if (error)
@@ -577,22 +597,22 @@
if ((dh = ip->i_dirhash) == NULL)
return (-1);
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return (-1);
}
if (dh->dh_blkfree[dh->dh_dirblks - 1] != DIRBLKSIZ / DIRALIGN) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
return (-1);
}
for (i = dh->dh_dirblks - 1; i >= 0; i--)
if (dh->dh_blkfree[i] != DIRBLKSIZ / DIRALIGN)
break;
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
return ((doff_t)(i + 1) * DIRBLKSIZ);
}
@@ -609,9 +629,9 @@
if ((dh = ip->i_dirhash) == NULL)
return;
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -623,7 +643,7 @@
* remove the hash entirely and let it be rebuilt later.
*/
if (dh->dh_hused >= (dh->dh_hlen * 3) / 4) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -638,7 +658,7 @@
/* Update the per-block summary info. */
ufsdirhash_adjfree(dh, offset, -DIRSIZ(0, dirp));
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
}
/*
@@ -654,9 +674,9 @@
if ((dh = ip->i_dirhash) == NULL)
return;
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -671,7 +691,7 @@
/* Update the per-block summary info. */
ufsdirhash_adjfree(dh, offset, DIRSIZ(0, dirp));
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
}
/*
@@ -687,9 +707,9 @@
if ((dh = ip->i_dirhash) == NULL)
return;
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -700,7 +720,7 @@
/* Find the entry, and update the offset. */
slot = ufsdirhash_findslot(dh, dirp->d_name, dirp->d_namlen, oldoff);
DH_ENTRY(dh, slot) = newoff;
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
}
/*
@@ -715,9 +735,9 @@
if ((dh = ip->i_dirhash) == NULL)
return;
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -727,7 +747,7 @@
block = offset / DIRBLKSIZ;
if (block >= dh->dh_nblk) {
/* Out of space; must rebuild. */
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -737,7 +757,7 @@
dh->dh_blkfree[block] = DIRBLKSIZ / DIRALIGN;
if (dh->dh_firstfree[DH_NFSTATS] == -1)
dh->dh_firstfree[DH_NFSTATS] = block;
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
}
/*
@@ -751,9 +771,9 @@
if ((dh = ip->i_dirhash) == NULL)
return;
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -768,7 +788,7 @@
* if necessary.
*/
if (block < dh->dh_nblk / 8 && dh->dh_narrays > 1) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -787,7 +807,7 @@
if (dh->dh_firstfree[i] >= block)
panic("ufsdirhash_dirtrunc: first free corrupt");
dh->dh_dirblks = block;
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
}
/*
@@ -810,9 +830,9 @@
return;
if ((dh = ip->i_dirhash) == NULL)
return;
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
if (dh->dh_hash == NULL) {
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
ufsdirhash_free(ip);
return;
}
@@ -859,7 +879,7 @@
panic("ufsdirhash_checkblock: bad first-free");
if (dh->dh_firstfree[ffslot] == -1)
panic("ufsdirhash_checkblock: missing first-free entry");
- mtx_unlock(&dh->dh_mtx);
+ UNLOCK(&dh->dh_mtx);
}
/*
@@ -1018,20 +1038,20 @@
u_int8_t *blkfree;
int i, mem, narrays;
- mtx_lock(&ufsdirhash_mtx);
+ LOCK(&ufsdirhash_mtx);
while (wanted + ufs_dirhashmem > ufs_dirhashmaxmem) {
/* Find a dirhash, and lock it. */
if ((dh = TAILQ_FIRST(&ufsdirhash_list)) == NULL) {
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&ufsdirhash_mtx);
return (-1);
}
- mtx_lock(&dh->dh_mtx);
+ LOCK(&dh->dh_mtx);
KASSERT(dh->dh_hash != NULL, ("dirhash: NULL hash on list"));
/* Decrement the score; only recycle if it becomes zero. */
if (--dh->dh_score > 0) {
- mtx_unlock(&dh->dh_mtx);
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&dh->dh_mtx);
+ UNLOCK(&ufsdirhash_mtx);
return (-1);
}
@@ -1048,15 +1068,15 @@
dh->dh_nblk * sizeof(*dh->dh_blkfree);
/* Unlock everything, free the detached memory. */
- mtx_unlock(&dh->dh_mtx);
- mtx_unlock(&ufsdirhash_mtx);
+ UNLOCK(&dh->dh_mtx);
+ UNLOCK(&ufsdirhash_mtx);
for (i = 0; i < narrays; i++)
- uma_zfree(ufsdirhash_zone, hash[i]);
+ DIRHASH_FREE(hash[i]);
FREE(hash, M_DIRHASH);
FREE(blkfree, M_DIRHASH);
/* Account for the returned memory, and repeat if necessary. */
- mtx_lock(&ufsdirhash_mtx);
+ LOCK(&ufsdirhash_mtx);
ufs_dirhashmem -= mem;
}
/* Success; return with ufsdirhash_mtx locked. */
@@ -1067,9 +1087,15 @@
void
ufsdirhash_init()
{
+#ifdef __FreeBSD__
ufsdirhash_zone = uma_zcreate("DIRHASH", DH_NBLKOFF * sizeof(doff_t),
NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
mtx_init(&ufsdirhash_mtx, "dirhash list", NULL, MTX_DEF);
+#else
+ pool_init(&umadirhash_pool, DH_NBLKOFF * sizeof(doff_t), 0, 0,
+ "dirhash", &pool_allocator_nointr);
+ rw_init(&ufsdirhash_mtx);
+#endif
TAILQ_INIT(&ufsdirhash_list);
}
@@ -1077,8 +1103,12 @@
ufsdirhash_uninit()
{
KASSERT(TAILQ_EMPTY(&ufsdirhash_list), ("ufsdirhash_uninit"));
+#ifdef __FreeBSD__
uma_zdestroy(ufsdirhash_zone);
mtx_destroy(&ufsdirhash_mtx);
+#else
+ pool_destroy(&ufsdirhash_pool);
+#endif
}
#endif /* UFS_DIRHASH */
--
you are more than the sum of what you consume
More information about the freebsd-hackers
mailing list