Re: [PATCH 09/14] repair: track logical to physical block mapping moreeffeciently

Christoph Hellwig
2009-11-12T10:18:03Z

On Wed, Oct 21, 2009 at 02:06:19PM -0500, Alex Elder wrote:
> Christoph Hellwig wrote:
> > Currently we track the logical to physical block mapping by a structure which
> > contains an array of physicial blocks. This is extremly efficient and is
>
> Should this be "extremely inefficient?"
>
> > replaced with the normal starblock storage we use in the kernel and on disk
> > in this patch.
>
> While you're at fixing the above comment, maybe just re-word this
> sentence because I don't really grok it very well...

Thanks, updated in the version below.

> > + ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
> > +
> > if (nex < 1)
> > nex = 1;
> > - if ((blkmap = malloc(BLKMAP_SIZE(nex))) == NULL) {
> > - do_warn(_("malloc failed in blkmap_alloc (%u bytes)\n"),
> > - BLKMAP_SIZE(nex));
> > - return blkmap;
> > +
> > + key = whichfork ? ablkmap_key : dblkmap_key;
> > + blkmap = pthread_getspecific(key);
> > + if (!blkmap || blkmap->naexts < nex) {
> > + blkmap = realloc(blkmap, BLKMAP_SIZE(nex));
>
> Does the above really have to be a realloc() call, or can
> it simply be a free()/malloc() instead? Also, could the
> existing ts_alloc() function be adjusted to accomodate the
> usage here?

It has to be a realloc, we need to keep the existing content. We really
need to do the growing based on the existing size, so ts_alloc doesn't
fit. We could try to introduce a ts_realloc, but I'm not sure it's
worth it.

> > {
> > - blkent_t **entp;
> > - xfs_extnum_t i;
> > -
> > - if (blkmap == NULL)
> > - return;
> > - for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++)
> > - free(*entp);
> > - free(blkmap);
> > + /* nothing to do! - keep the memory around for the next inode */
>
> Nobody ever frees it though, either. I guess it gets done at
> exit but I like things tidy (could arrange for a destructor
> function to be called, at pthread_key_create() time).

This would complicate things quite a bit, and it would actually cause a
lot more malloc/free cycles that potentially slow repair down. Right
now we only have to allocate the map if the next inode has a larger
extent map than the previously processed one, which means we can safe
a lot of malloc/free cycles. Which still can be quite slow in
multi-threaded programs.

--

Subject: repair: track logical to physical block mapping more effeciently
From: Barry Naujok <bnaujok@sgi.com>

Currently we track the logical to physical block mapping by a structure which
contains an array of physicial blocks. This is extremly inefficient and is
replaced with the normal startblock, length extent descriptors.

In addition also use thread-local storage for the block map, this is possible
because repair only processes one inode at a given time per thread, and the
block map does not have to outlive the processing of a single inode.

The combination of those factors means we can use pthread thread-local
storage to store the block map, and we can re-use the allocation over
and over again.

This should be ported over to xfs_db eventually, or even better we could try
to share the code.

[hch: added a small fix in blkmap_set_ext to not call memmove unless needed]

Signed-off-by: Barry Naujok <bnaujok@sgi.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Alex Elder <aelder@sgi.com>

Index: xfsprogs-dev/repair/bmap.c
===================================================================
--- xfsprogs-dev.orig/repair/bmap.c 2009-10-19 01:55:18.807285612 +0200
+++ xfsprogs-dev/repair/bmap.c 2009-11-12 11:17:04.371006486 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2001,2005,2008 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -21,106 +21,46 @@
#include "bmap.h"

/*
- * Block mapping code taken from xfs_db.
- */
-
-/*
- * Append an extent to the block entry.
- */
-void
-blkent_append(
- blkent_t **entp,
- xfs_dfsbno_t b,
- xfs_dfilblks_t c)
-{
- blkent_t *ent;
- size_t size;
- int i;
-
- ent = *entp;
- size = BLKENT_SIZE(c + ent->nblks);
- if ((*entp = ent = realloc(ent, size)) == NULL) {
- do_warn(_("realloc failed in blkent_append (%u bytes)\n"),
- size);
- return;
- }
- for (i = 0; i < c; i++)
- ent->blks[ent->nblks + i] = b + i;
- ent->nblks += c;
-}
-
-/*
- * Make a new block entry.
- */
-blkent_t *
-blkent_new(
- xfs_dfiloff_t o,
- xfs_dfsbno_t b,
- xfs_dfilblks_t c)
-{
- blkent_t *ent;
- int i;
-
- if ((ent = malloc(BLKENT_SIZE(c))) == NULL) {
- do_warn(_("malloc failed in blkent_new (%u bytes)\n"),
- BLKENT_SIZE(c));
- return ent;
- }
- ent->nblks = c;
- ent->startoff = o;
- for (i = 0; i < c; i++)
- ent->blks[i] = b + i;
- return ent;
-}
-
-/*
- * Prepend an extent to the block entry.
+ * Track the logical to physical block mapping for inodes.
+ *
+ * Repair only processes one inode at a given time per thread, and the
+ * block map does not have to outlive the processing of a single inode.
+ *
+ * The combination of those factors means we can use pthreads thread-local
+ * storage to store the block map, and we can re-use the allocation over
+ * and over again.
*/
-void
-blkent_prepend(
- blkent_t **entp,
- xfs_dfsbno_t b,
- xfs_dfilblks_t c)
-{
- int i;
- blkent_t *newent;
- blkent_t *oldent;

- oldent = *entp;
- if ((newent = malloc(BLKENT_SIZE(oldent->nblks + c))) == NULL) {
- do_warn(_("malloc failed in blkent_prepend (%u bytes)\n"),
- BLKENT_SIZE(oldent->nblks + c));
- *entp = newent;
- return;
- }
- newent->nblks = oldent->nblks + c;
- newent->startoff = oldent->startoff - c;
- for (i = 0; i < c; i++)
- newent->blks[i] = b + c;
- for (; i < oldent->nblks + c; i++)
- newent->blks[i] = oldent->blks[i - c];
- free(oldent);
- *entp = newent;
-}
+pthread_key_t dblkmap_key;
+pthread_key_t ablkmap_key;

-/*
- * Allocate a block map.
- */
blkmap_t *
blkmap_alloc(
- xfs_extnum_t nex)
+ xfs_extnum_t nex,
+ int whichfork)
{
+ pthread_key_t key;
blkmap_t *blkmap;

+ ASSERT(whichfork == XFS_DATA_FORK || whichfork == XFS_ATTR_FORK);
+
if (nex < 1)
nex = 1;
- if ((blkmap = malloc(BLKMAP_SIZE(nex))) == NULL) {
- do_warn(_("malloc failed in blkmap_alloc (%u bytes)\n"),
- BLKMAP_SIZE(nex));
- return blkmap;
+
+ key = whichfork ? ablkmap_key : dblkmap_key;
+ blkmap = pthread_getspecific(key);
+ if (!blkmap || blkmap->naexts < nex) {
+ blkmap = realloc(blkmap, BLKMAP_SIZE(nex));
+ if (!blkmap) {
+ do_warn(_("malloc failed in blkmap_alloc (%u bytes)\n"),
+ BLKMAP_SIZE(nex));
+ return NULL;
+ }
+ pthread_setspecific(key, blkmap);
+ blkmap->naexts = nex;
}
- blkmap->naents = nex;
- blkmap->nents = 0;
+
+ blkmap->nexts = 0;
return blkmap;
}

@@ -131,14 +71,7 @@ void
blkmap_free(
blkmap_t *blkmap)
{
- blkent_t **entp;
- xfs_extnum_t i;
-
- if (blkmap == NULL)
- return;
- for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++)
- free(*entp);
- free(blkmap);
+ /* nothing to do! - keep the memory around for the next inode */
}

/*
@@ -149,20 +82,18 @@ blkmap_get(
blkmap_t *blkmap,
xfs_dfiloff_t o)
{
- blkent_t *ent;
- blkent_t **entp;
+ bmap_ext_t *ext = blkmap->exts;
int i;

- for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) {
- ent = *entp;
- if (o >= ent->startoff && o < ent->startoff + ent->nblks)
- return ent->blks[o - ent->startoff];
+ for (i = 0; i < blkmap->nexts; i++, ext++) {
+ if (o >= ext->startoff && o < ext->startoff + ext->blockcount)
+ return ext->startblock + (o - ext->startoff);
}
return NULLDFSBNO;
}

/*
- * Get a chunk of entries from a block map.
+ * Get a chunk of entries from a block map - only used for reading dirv2 blocks
*/
int
blkmap_getn(
@@ -172,93 +103,62 @@ blkmap_getn(
bmap_ext_t **bmpp,
bmap_ext_t *bmpp_single)
{
- bmap_ext_t *bmp;
- blkent_t *ent;
- xfs_dfiloff_t ento;
- blkent_t **entp;
+ bmap_ext_t *bmp = NULL;
+ bmap_ext_t *ext;
int i;
int nex;

if (nb == 1) {
- /*
+ /*
* in the common case, when mp->m_dirblkfsbs == 1,
* avoid additional malloc/free overhead
*/
bmpp_single->startblock = blkmap_get(blkmap, o);
- bmpp_single->blockcount = 1;
- bmpp_single->startoff = 0;
- bmpp_single->flag = 0;
- *bmpp = bmpp_single;
- return (bmpp_single->startblock != NULLDFSBNO) ? 1 : 0;
+ goto single_ext;
}
- for (i = nex = 0, bmp = NULL, entp = blkmap->ents;
- i < blkmap->nents;
- i++, entp++) {
- ent = *entp;
- if (ent->startoff >= o + nb)
+ ext = blkmap->exts;
+ nex = 0;
+ for (i = 0; i < blkmap->nexts; i++, ext++) {
+
+ if (ext->startoff >= o + nb)
break;
- if (ent->startoff + ent->nblks <= o)
+ if (ext->startoff + ext->blockcount <= o)
continue;
- for (ento = ent->startoff;
- ento < ent->startoff + ent->nblks && ento < o + nb;
- ento++) {
- if (ento < o)
- continue;
- if (bmp &&
- bmp[nex - 1].startoff + bmp[nex - 1].blockcount ==
- ento &&
- bmp[nex - 1].startblock + bmp[nex - 1].blockcount ==
- ent->blks[ento - ent->startoff])
- bmp[nex - 1].blockcount++;
- else {
- bmp = realloc(bmp, ++nex * sizeof(*bmp));
- if (bmp == NULL) {
- do_warn(_("blkmap_getn realloc failed"
- " (%u bytes)\n"),
- nex * sizeof(*bmp));
- continue;
- }
- bmp[nex - 1].startoff = ento;
- bmp[nex - 1].startblock =
- ent->blks[ento - ent->startoff];
- bmp[nex - 1].blockcount = 1;
- bmp[nex - 1].flag = 0;
- }
+
+ /*
+ * if all the requested blocks are in one extent (also common),
+ * use the bmpp_single option as well
+ */
+ if (!bmp && o >= ext->startoff &&
+ o + nb <= ext->startoff + ext->blockcount) {
+ bmpp_single->startblock =
+ ext->startblock + (o - ext->startoff);
+ goto single_ext;
}
+
+ /*
+ * rare case - multiple extents for a single dir block
+ */
+ bmp = malloc(nb * sizeof(bmap_ext_t));
+ if (!bmp)
+ do_error(_("blkmap_getn malloc failed (%u bytes)\n"),
+ nb * sizeof(bmap_ext_t));
+
+ bmp[nex].startblock = ext->startblock + (o - ext->startoff);
+ bmp[nex].blockcount = MIN(nb, ext->blockcount -
+ (bmp[nex].startblock - ext->startblock));
+ o += bmp[nex].blockcount;
+ nb -= bmp[nex].blockcount;
+ nex++;
}
*bmpp = bmp;
return nex;
-}
-
-/*
- * Make a block map larger.
- */
-void
-blkmap_grow(
- blkmap_t **blkmapp,
- blkent_t **entp,
- blkent_t *newent)
-{
- blkmap_t *blkmap;
- size_t size;
- int i;
- int idx;

- blkmap = *blkmapp;
- idx = (int)(entp - blkmap->ents);
- if (blkmap->naents == blkmap->nents) {
- size = BLKMAP_SIZE(blkmap->nents + 1);
- if ((*blkmapp = blkmap = realloc(blkmap, size)) == NULL) {
- do_warn(_("realloc failed in blkmap_grow (%u bytes)\n"),
- size);
- return;
- }
- blkmap->naents++;
- }
- for (i = blkmap->nents; i > idx; i--)
- blkmap->ents[i] = blkmap->ents[i - 1];
- blkmap->ents[idx] = newent;
- blkmap->nents++;
+single_ext:
+ bmpp_single->blockcount = nb;
+ bmpp_single->startoff = 0; /* not even used by caller! */
+ *bmpp = bmpp_single;
+ return (bmpp_single->startblock != NULLDFSBNO) ? 1 : 0;
}

/*
@@ -268,12 +168,12 @@ xfs_dfiloff_t
blkmap_last_off(
blkmap_t *blkmap)
{
- blkent_t *ent;
+ bmap_ext_t *ext;

- if (!blkmap->nents)
+ if (!blkmap->nexts)
return NULLDFILOFF;
- ent = blkmap->ents[blkmap->nents - 1];
- return ent->startoff + ent->nblks;
+ ext = blkmap->exts + blkmap->nexts - 1;
+ return ext->startoff + ext->blockcount;
}

/*
@@ -285,73 +185,45 @@ blkmap_next_off(
xfs_dfiloff_t o,
int *t)
{
- blkent_t *ent;
- blkent_t **entp;
+ bmap_ext_t *ext;

- if (!blkmap->nents)
+ if (!blkmap->nexts)
return NULLDFILOFF;
if (o == NULLDFILOFF) {
*t = 0;
- ent = blkmap->ents[0];
- return ent->startoff;
+ return blkmap->exts[0].startoff;
}
- entp = &blkmap->ents[*t];
- ent = *entp;
- if (o < ent->startoff + ent->nblks - 1)
+ ext = blkmap->exts + *t;
+ if (o < ext->startoff + ext->blockcount - 1)
return o + 1;
- entp++;
- if (entp >= &blkmap->ents[blkmap->nents])
+ if (*t >= blkmap->nexts - 1)
return NULLDFILOFF;
(*t)++;
- ent = *entp;
- return ent->startoff;
+ return ext[1].startoff;
}

/*
- * Set a block value in a block map.
+ * Make a block map larger.
*/
-void
-blkmap_set_blk(
- blkmap_t **blkmapp,
- xfs_dfiloff_t o,
- xfs_dfsbno_t b)
+static blkmap_t *
+blkmap_grow(
+ blkmap_t **blkmapp)
{
- blkmap_t *blkmap;
- blkent_t *ent;
- blkent_t **entp;
- blkent_t *nextent;
-
- blkmap = *blkmapp;
- for (entp = blkmap->ents; entp < &blkmap->ents[blkmap->nents]; entp++) {
- ent = *entp;
- if (o < ent->startoff - 1) {
- ent = blkent_new(o, b, 1);
- blkmap_grow(blkmapp, entp, ent);
- return;
- }
- if (o == ent->startoff - 1) {
- blkent_prepend(entp, b, 1);
- return;
- }
- if (o >= ent->startoff && o < ent->startoff + ent->nblks) {
- ent->blks[o - ent->startoff] = b;
- return;
- }
- if (o > ent->startoff + ent->nblks)
- continue;
- blkent_append(entp, b, 1);
- if (entp == &blkmap->ents[blkmap->nents - 1])
- return;
- ent = *entp;
- nextent = entp[1];
- if (ent->startoff + ent->nblks < nextent->startoff)
- return;
- blkent_append(entp, nextent->blks[0], nextent->nblks);
- blkmap_shrink(blkmap, &entp[1]);
- return;
+ pthread_key_t key = dblkmap_key;
+ blkmap_t *blkmap = *blkmapp;
+
+ if (pthread_getspecific(key) != blkmap) {
+ key = ablkmap_key;
+ ASSERT(pthread_getspecific(key) == blkmap);
}
- ent = blkent_new(o, b, 1);
- blkmap_grow(blkmapp, entp, ent);
+
+ blkmap->naexts += 4;
+ blkmap = realloc(blkmap, BLKMAP_SIZE(blkmap->naexts));
+ if (blkmap == NULL)
+ do_error(_("realloc failed in blkmap_grow\n"));
+ *blkmapp = blkmap;
+ pthread_setspecific(key, blkmap);
+ return blkmap;
}

/*
@@ -364,46 +236,23 @@ blkmap_set_ext(
xfs_dfsbno_t b,
xfs_dfilblks_t c)
{
- blkmap_t *blkmap;
- blkent_t *ent;
- blkent_t **entp;
+ blkmap_t *blkmap = *blkmapp;
xfs_extnum_t i;

- blkmap = *blkmapp;
- if (!blkmap->nents) {
- blkmap->ents[0] = blkent_new(o, b, c);
- blkmap->nents = 1;
- return;
- }
- entp = &blkmap->ents[blkmap->nents - 1];
- ent = *entp;
- if (ent->startoff + ent->nblks == o) {
- blkent_append(entp, b, c);
- return;
- }
- if (ent->startoff + ent->nblks < o) {
- ent = blkent_new(o, b, c);
- blkmap_grow(blkmapp, &blkmap->ents[blkmap->nents], ent);
- return;
- }
- for (i = 0; i < c; i++)
- blkmap_set_blk(blkmapp, o + i, b + i);
-}
+ if (blkmap->nexts == blkmap->naexts)
+ blkmap = blkmap_grow(blkmapp);

-/*
- * Make a block map smaller.
- */
-void
-blkmap_shrink(
- blkmap_t *blkmap,
- blkent_t **entp)
-{
- int i;
- int idx;
+ for (i = 0; i < blkmap->nexts; i++) {
+ if (blkmap->exts[i].startoff > o) {
+ memmove(blkmap->exts + i + 1,
+ blkmap->exts + i,
+ sizeof(bmap_ext_t) * (blkmap->nexts - i));
+ break;
+ }
+ }

- free(*entp);
- idx = (int)(entp - blkmap->ents);
- for (i = idx + 1; i < blkmap->nents; i++)
- blkmap->ents[i] = blkmap->ents[i - 1];
- blkmap->nents--;
+ blkmap->exts[i].startoff = o;
+ blkmap->exts[i].startblock = b;
+ blkmap->exts[i].blockcount = c;
+ blkmap->nexts++;
}
Index: xfsprogs-dev/repair/bmap.h
===================================================================
--- xfsprogs-dev.orig/repair/bmap.h 2009-10-19 01:55:18.824256628 +0200
+++ xfsprogs-dev/repair/bmap.h 2009-11-12 11:12:12.138274565 +0100
@@ -16,59 +16,41 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

-/*
- * Block mapping code taken from xfs_db.
- */
+#ifndef _XFS_REPAIR_BMAP_H
+#define _XFS_REPAIR_BMAP_H

/*
- * Block map entry.
+ * Extent descriptor.
*/
-typedef struct blkent {
+typedef struct bmap_ext {
xfs_dfiloff_t startoff;
- xfs_dfilblks_t nblks;
- xfs_dfsbno_t blks[1];
-} blkent_t;
-#define BLKENT_SIZE(n) \
- (offsetof(blkent_t, blks) + (sizeof(xfs_dfsbno_t) * (n)))
+ xfs_dfsbno_t startblock;
+ xfs_dfilblks_t blockcount;
+} bmap_ext_t;

/*
* Block map.
*/
typedef struct blkmap {
- int naents;
- int nents;
- blkent_t *ents[1];
+ int naexts;
+ int nexts;
+ bmap_ext_t exts[1];
} blkmap_t;
-#define BLKMAP_SIZE(n) \
- (offsetof(blkmap_t, ents) + (sizeof(blkent_t *) * (n)))

-/*
- * Extent descriptor.
- */
-typedef struct bmap_ext {
- xfs_dfiloff_t startoff;
- xfs_dfsbno_t startblock;
- xfs_dfilblks_t blockcount;
- int flag;
-} bmap_ext_t;
+#define BLKMAP_SIZE(n) \
+ (offsetof(blkmap_t, exts) + (sizeof(bmap_ext_t) * (n)))

-void blkent_append(blkent_t **entp, xfs_dfsbno_t b,
- xfs_dfilblks_t c);
-blkent_t *blkent_new(xfs_dfiloff_t o, xfs_dfsbno_t b, xfs_dfilblks_t c);
-void blkent_prepend(blkent_t **entp, xfs_dfsbno_t b,
- xfs_dfilblks_t c);
-blkmap_t *blkmap_alloc(xfs_extnum_t);
+blkmap_t *blkmap_alloc(xfs_extnum_t nex, int whichfork);
void blkmap_free(blkmap_t *blkmap);
+
+void blkmap_set_ext(blkmap_t **blkmapp, xfs_dfiloff_t o,
+ xfs_dfsbno_t b, xfs_dfilblks_t c);
+
xfs_dfsbno_t blkmap_get(blkmap_t *blkmap, xfs_dfiloff_t o);
int blkmap_getn(blkmap_t *blkmap, xfs_dfiloff_t o,
- xfs_dfilblks_t nb, bmap_ext_t **bmpp,
+ xfs_dfilblks_t nb, bmap_ext_t **bmpp,
bmap_ext_t *bmpp_single);
-void blkmap_grow(blkmap_t **blkmapp, blkent_t **entp,
- blkent_t *newent);
xfs_dfiloff_t blkmap_last_off(blkmap_t *blkmap);
xfs_dfiloff_t blkmap_next_off(blkmap_t *blkmap, xfs_dfiloff_t o, int *t);
-void blkmap_set_blk(blkmap_t **blkmapp, xfs_dfiloff_t o,
- xfs_dfsbno_t b);
-void blkmap_set_ext(blkmap_t **blkmapp, xfs_dfiloff_t o,
- xfs_dfsbno_t b, xfs_dfilblks_t c);
-void blkmap_shrink(blkmap_t *blkmap, blkent_t **entp);
+
+#endif /* _XFS_REPAIR_BMAP_H */
Index: xfsprogs-dev/repair/dinode.c
===================================================================
--- xfsprogs-dev.orig/repair/dinode.c 2009-10-19 01:55:18.842284064 +0200
+++ xfsprogs-dev/repair/dinode.c 2009-11-12 11:12:12.143274713 +0100
@@ -2050,7 +2050,7 @@ process_inode_data_fork(
*nextents = 1;

if (dinoc->di_format != XFS_DINODE_FMT_LOCAL && type != XR_INO_RTDATA)
- *dblkmap = blkmap_alloc(*nextents);
+ *dblkmap = blkmap_alloc(*nextents, XFS_DATA_FORK);
*nextents = 0;

switch (dinoc->di_format) {
@@ -2172,14 +2172,14 @@ process_inode_attr_fork(
err = process_lclinode(mp, agno, ino, dino, XFS_ATTR_FORK);
break;
case XFS_DINODE_FMT_EXTENTS:
- ablkmap = blkmap_alloc(*anextents);
+ ablkmap = blkmap_alloc(*anextents, XFS_ATTR_FORK);
*anextents = 0;
err = process_exinode(mp, agno, ino, dino, type, dirty,
atotblocks, anextents, &ablkmap,
XFS_ATTR_FORK, check_dups);
break;
case XFS_DINODE_FMT_BTREE:
- ablkmap = blkmap_alloc(*anextents);
+ ablkmap = blkmap_alloc(*anextents, XFS_ATTR_FORK);
*anextents = 0;
err = process_btinode(mp, agno, ino, dino, type, dirty,
atotblocks, anextents, &ablkmap,
Index: xfsprogs-dev/repair/init.c
===================================================================
--- xfsprogs-dev.orig/repair/init.c 2009-11-12 11:11:41.025026345 +0100
+++ xfsprogs-dev/repair/init.c 2009-11-12 11:12:12.143274713 +0100
@@ -24,19 +24,24 @@
#include "pthread.h"
#include "avl.h"
#include "dir.h"
+#include "bmap.h"
#include "incore.h"
#include "prefetch.h"
#include <sys/resource.h>

+/* TODO: dirbuf/freemap key usage is completely b0rked - only used for dirv1 */
static pthread_key_t dirbuf_key;
static pthread_key_t dir_freemap_key;
static pthread_key_t attr_freemap_key;

+extern pthread_key_t dblkmap_key;
+extern pthread_key_t ablkmap_key;
+
static void
ts_alloc(pthread_key_t key, unsigned n, size_t size)
{
void *voidp;
- voidp = malloc((n)*(size));
+ voidp = calloc(n, size);
if (voidp == NULL) {
do_error(_("ts_alloc: cannot allocate thread specific storage\n"));
/* NO RETURN */
@@ -52,6 +57,9 @@ ts_create(void)
pthread_key_create(&dirbuf_key, NULL);
pthread_key_create(&dir_freemap_key, NULL);
pthread_key_create(&attr_freemap_key, NULL);
+
+ pthread_key_create(&dblkmap_key, NULL);
+ pthread_key_create(&ablkmap_key, NULL);
}

void