[BACK]Return to bmap.c CVS log [TXT][DIR] Up to [Development] / xfs-cmds / xfsprogs / repair

File: [Development] / xfs-cmds / xfsprogs / repair / bmap.c (download)

Revision 1.9, Fri May 12 16:03:02 2006 UTC (11 years, 5 months ago) by mvalluri
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +14 -1 lines

These changes fall into three categores which are:

1) Eliminate compiler warning (COMP)
2) Bug fixes (BUG)
3) Reduce CPU cycles. (CPU)
Update prototype for blkmap_get to accept a single blkmap.

/*
 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
 * All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <libxfs.h>
#include "err_protos.h"
#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.
 */
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;
}

/*
 * Allocate a block map.
 */
blkmap_t *
blkmap_alloc(
	xfs_extnum_t	nex)
{
	blkmap_t	*blkmap;

	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;
	}
	blkmap->naents = nex;
	blkmap->nents = 0;
	return blkmap;
}

/*
 * Free a block map.
 */
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);
}

/*
 * Get one entry from a block map.
 */
xfs_dfsbno_t
blkmap_get(
	blkmap_t	*blkmap,
	xfs_dfiloff_t	o)
{
	blkent_t	*ent;
	blkent_t	**entp;
	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];
	}
	return NULLDFSBNO;
}

/*
 * Get a chunk of entries from a block map.
 */
int
blkmap_getn(
	blkmap_t	*blkmap,
	xfs_dfiloff_t	o,
	xfs_dfilblks_t	nb,
	bmap_ext_t	**bmpp,
	bmap_ext_t	*bmpp_single)
{
	bmap_ext_t	*bmp;
	blkent_t	*ent;
	xfs_dfiloff_t	ento;
	blkent_t	**entp;
	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;
	}
	for (i = nex = 0, bmp = NULL, entp = blkmap->ents;
	     i < blkmap->nents;
	     i++, entp++) {
		ent = *entp;
		if (ent->startoff >= o + nb)
			break;
		if (ent->startoff + ent->nblks <= 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;
			}
		}
	}
	*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++;
}

/*
 * Return the last offset in a block map.
 */
xfs_dfiloff_t
blkmap_last_off(
	blkmap_t	*blkmap)
{
	blkent_t	*ent;

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

/*
 * Return the next offset in a block map.
 */
xfs_dfiloff_t
blkmap_next_off(
	blkmap_t	*blkmap,
	xfs_dfiloff_t	o,
	int		*t)
{
	blkent_t	*ent;
	blkent_t	**entp;

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

/*
 * Set a block value in a block map.
 */
void
blkmap_set_blk(
	blkmap_t	**blkmapp,
	xfs_dfiloff_t	o,
	xfs_dfsbno_t	b)
{
	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;
	}
	ent = blkent_new(o, b, 1);
	blkmap_grow(blkmapp, entp, ent);
}

/*
 * Set an extent into a block map.
 */
void
blkmap_set_ext(
	blkmap_t	**blkmapp,
	xfs_dfiloff_t	o,
	xfs_dfsbno_t	b,
	xfs_dfilblks_t	c)
{
	blkmap_t	*blkmap;
	blkent_t	*ent;
	blkent_t	**entp;
	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);
}

/*
 * Make a block map smaller.
 */
void
blkmap_shrink(
	blkmap_t	*blkmap,
	blkent_t	**entp)
{
	int		i;
	int		idx;

	free(*entp);
	idx = (int)(entp - blkmap->ents);
	for (i = idx + 1; i < blkmap->nents; i++)
		blkmap->ents[i] = blkmap->ents[i - 1];
	blkmap->nents--;
}