Blame gfs2/libgfs2/rgrp.c.bz1698858-mkfs_gfs2_Improve_alignment_of_first_resource_group

Packit 605d12
#include "clusterautoconfig.h"
Packit 605d12
Packit 605d12
#include <inttypes.h>
Packit 605d12
#include <limits.h>
Packit 605d12
#include <stdio.h>
Packit 605d12
#include <stdlib.h>
Packit 605d12
#include <string.h>
Packit 605d12
#include <unistd.h>
Packit 605d12
Packit 605d12
#include "libgfs2.h"
Packit 605d12
#include "rgrp.h"
Packit 605d12
Packit 605d12
#define RG_SYNC_TOLERANCE 1000
Packit 605d12
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
Packit 605d12
Packit 605d12
static void compute_bitmaps(lgfs2_rgrp_t rg, const unsigned bsize)
Packit 605d12
{
Packit 605d12
	int x;
Packit 605d12
Packit 605d12
	rg->bits[0].bi_offset = sizeof(struct gfs2_rgrp);
Packit 605d12
	rg->bits[0].bi_start = 0;
Packit 605d12
	rg->bits[0].bi_len = bsize - sizeof(struct gfs2_rgrp);
Packit 605d12
Packit 605d12
	for (x = 1; x < rg->ri.ri_length; x++) {
Packit 605d12
		rg->bits[x].bi_offset = sizeof(struct gfs2_meta_header);
Packit 605d12
		rg->bits[x].bi_start = rg->bits[x - 1].bi_start + rg->bits[x - 1].bi_len;
Packit 605d12
		rg->bits[x].bi_len = bsize - sizeof(struct gfs2_meta_header);
Packit 605d12
	}
Packit 605d12
	x--;
Packit 605d12
	rg->bits[x].bi_len = rg->ri.ri_bitbytes - rg->bits[x].bi_start;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * gfs2_compute_bitstructs - Compute the bitmap sizes
Packit 605d12
 * bsize: Block size
Packit 605d12
 * rgd: The resource group descriptor
Packit 605d12
 * Returns: 0 on success, -1 on error
Packit 605d12
 */
Packit 605d12
int gfs2_compute_bitstructs(const uint32_t bsize, struct rgrp_tree *rgd)
Packit 605d12
{
Packit 605d12
	uint32_t length = rgd->ri.ri_length;
Packit 605d12
	uint32_t bytes_left;
Packit 605d12
	int ownbits = 0;
Packit 605d12
Packit 605d12
	/* Max size of an rg is 2GB.  A 2GB RG with (minimum) 512-byte blocks
Packit 605d12
	   has 4194304 blocks.  We can represent 4 blocks in one bitmap byte.
Packit 605d12
	   Therefore, all 4194304 blocks can be represented in 1048576 bytes.
Packit 605d12
	   Subtract a metadata header for each 512-byte block and we get
Packit 605d12
	   488 bytes of bitmap per block.  Divide 1048576 by 488 and we can
Packit 605d12
	   be assured we should never have more than 2149 of them. */
Packit 605d12
	errno = EINVAL;
Packit 605d12
	if (length > 2149 || length == 0)
Packit 605d12
		return -1;
Packit 605d12
Packit 605d12
	if(rgd->bits == NULL) {
Packit 605d12
		rgd->bits = calloc(length, sizeof(struct gfs2_bitmap));
Packit 605d12
		if(rgd->bits == NULL)
Packit 605d12
			return -1;
Packit 605d12
		ownbits = 1;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	compute_bitmaps(rgd, bsize);
Packit 605d12
	bytes_left = rgd->ri.ri_bitbytes - (rgd->bits[rgd->ri.ri_length - 1].bi_start +
Packit 605d12
	                                   rgd->bits[rgd->ri.ri_length - 1].bi_len);
Packit 605d12
	errno = EINVAL;
Packit 605d12
	if(bytes_left)
Packit 605d12
		goto errbits;
Packit 605d12
Packit 605d12
	if((rgd->bits[length - 1].bi_start +
Packit 605d12
	    rgd->bits[length - 1].bi_len) * GFS2_NBBY != rgd->ri.ri_data)
Packit 605d12
		goto errbits;
Packit 605d12
Packit 605d12
	return 0;
Packit 605d12
errbits:
Packit 605d12
	if (ownbits) {
Packit 605d12
		free(rgd->bits);
Packit 605d12
		rgd->bits = NULL;
Packit 605d12
	}
Packit 605d12
	return -1;
Packit 605d12
}
Packit 605d12
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * blk2rgrpd - Find resource group for a given data block number
Packit 605d12
 * @sdp: The GFS superblock
Packit 605d12
 * @n: The data block number
Packit 605d12
 *
Packit 605d12
 * Returns: Ths resource group, or NULL if not found
Packit 605d12
 */
Packit 605d12
struct rgrp_tree *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, uint64_t blk)
Packit 605d12
{
Packit 605d12
	struct rgrp_tree *rgd = (struct rgrp_tree *)sdp->rgtree.osi_node;
Packit 605d12
	while (rgd) {
Packit 605d12
		if (blk < rgd->ri.ri_addr)
Packit 605d12
			rgd = (struct rgrp_tree *)rgd->node.osi_left;
Packit 605d12
		else if (blk >= rgd->ri.ri_data0 + rgd->ri.ri_data)
Packit 605d12
			rgd = (struct rgrp_tree *)rgd->node.osi_right;
Packit 605d12
		else
Packit 605d12
			return rgd;
Packit 605d12
	}
Packit 605d12
	return NULL;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Allocate a multi-block buffer for a resource group's bitmaps. This is done
Packit 605d12
 * as one chunk and should be freed using lgfs2_rgrp_bitbuf_free().
Packit 605d12
 * Returns 0 on success with the bitmap buffer allocated in the resource group,
Packit 605d12
 * or non-zero on failure with errno set.
Packit 605d12
 */
Packit 605d12
int lgfs2_rgrp_bitbuf_alloc(lgfs2_rgrp_t rg)
Packit 605d12
{
Packit 605d12
	struct gfs2_sbd *sdp = rg->rgrps->sdp;
Packit 605d12
	struct gfs2_buffer_head *bhs;
Packit 605d12
	size_t len = rg->ri.ri_length * sdp->bsize;
Packit 605d12
	unsigned long io_align = sdp->bsize;
Packit 605d12
	unsigned i;
Packit 605d12
	char *bufs;
Packit 605d12
Packit 605d12
	if (rg->rgrps->align > 0) {
Packit 605d12
		len = ROUND_UP(len, rg->rgrps->align * sdp->bsize);
Packit 605d12
		io_align = rg->rgrps->align_off * sdp->bsize;
Packit 605d12
	}
Packit 605d12
	bhs = calloc(rg->ri.ri_length, sizeof(struct gfs2_buffer_head));
Packit 605d12
	if (bhs == NULL)
Packit 605d12
		return 1;
Packit 605d12
Packit 605d12
	if (posix_memalign((void **)&bufs, io_align, len) != 0) {
Packit 605d12
		errno = ENOMEM;
Packit 605d12
		free(bhs);
Packit 605d12
		return 1;
Packit 605d12
	}
Packit 605d12
	memset(bufs, 0, len);
Packit 605d12
Packit 605d12
	for (i = 0; i < rg->ri.ri_length; i++) {
Packit 605d12
		rg->bits[i].bi_bh = bhs + i;
Packit 605d12
		rg->bits[i].bi_bh->iov.iov_base = bufs + (i * sdp->bsize);
Packit 605d12
		rg->bits[i].bi_bh->iov.iov_len = sdp->bsize;
Packit 605d12
		rg->bits[i].bi_bh->b_blocknr = rg->ri.ri_addr + i;
Packit 605d12
		rg->bits[i].bi_bh->sdp = sdp;
Packit 605d12
	}
Packit 605d12
	return 0;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Free the multi-block bitmap buffer from a resource group. The buffer should
Packit 605d12
 * have been allocated as a single chunk as in lgfs2_rgrp_bitbuf_alloc().
Packit 605d12
 * This does not implicitly write the bitmaps to disk. Use lgfs2_rgrp_write()
Packit 605d12
 * for that.
Packit 605d12
 * rg: The resource groups whose bitmap buffer should be freed.
Packit 605d12
 */
Packit 605d12
void lgfs2_rgrp_bitbuf_free(lgfs2_rgrp_t rg)
Packit 605d12
{
Packit 605d12
	unsigned i;
Packit 605d12
	free(rg->bits[0].bi_bh->iov.iov_base);
Packit 605d12
	free(rg->bits[0].bi_bh);
Packit 605d12
	for (i = 0; i < rg->ri.ri_length; i++)
Packit 605d12
		rg->bits[i].bi_bh = NULL;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Check a resource group's crc
Packit 605d12
 * Returns 0 on success, non-zero if crc is bad
Packit 605d12
 */
Packit 605d12
int lgfs2_rgrp_crc_check(char *buf)
Packit 605d12
{
Packit 605d12
	int ret = 0;
Packit 605d12
#ifdef GFS2_HAS_RG_RI_FIELDS
Packit 605d12
	struct gfs2_rgrp *rg = (struct gfs2_rgrp *)buf;
Packit 605d12
	uint32_t crc = rg->rg_crc;
Packit 605d12
Packit 605d12
	if (crc == 0)
Packit 605d12
		return 0;
Packit 605d12
Packit 605d12
	rg->rg_crc = 0;
Packit 605d12
	if (be32_to_cpu(crc) != gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp)))
Packit 605d12
		ret = 1;
Packit 605d12
	rg->rg_crc = crc;
Packit 605d12
#endif
Packit 605d12
	return ret;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Set the crc of an on-disk resource group
Packit 605d12
 */
Packit 605d12
void lgfs2_rgrp_crc_set(char *buf)
Packit 605d12
{
Packit 605d12
#ifdef GFS2_HAS_RG_RI_FIELDS
Packit 605d12
	struct gfs2_rgrp *rg = (struct gfs2_rgrp *)buf;
Packit 605d12
	uint32_t crc;
Packit 605d12
Packit 605d12
	rg->rg_crc = 0;
Packit 605d12
	crc = gfs2_disk_hash(buf, sizeof(struct gfs2_rgrp));
Packit 605d12
	rg->rg_crc = cpu_to_be32(crc);
Packit 605d12
#endif
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * gfs2_rgrp_read - read in the resource group information from disk.
Packit 605d12
 * @rgd - resource group structure
Packit 605d12
 * returns: 0 if no error, otherwise the block number that failed
Packit 605d12
 */
Packit 605d12
uint64_t gfs2_rgrp_read(struct gfs2_sbd *sdp, struct rgrp_tree *rgd)
Packit 605d12
{
Packit 605d12
	unsigned x, length = rgd->ri.ri_length;
Packit 605d12
	struct gfs2_buffer_head **bhs;
Packit 605d12
Packit 605d12
	if (length == 0 || gfs2_check_range(sdp, rgd->ri.ri_addr))
Packit 605d12
		return -1;
Packit 605d12
Packit 605d12
	bhs = calloc(length, sizeof(struct gfs2_buffer_head *));
Packit 605d12
	if (bhs == NULL)
Packit 605d12
		return -1;
Packit 605d12
Packit 605d12
	if (breadm(sdp, bhs, length, rgd->ri.ri_addr)) {
Packit 605d12
		free(bhs);
Packit 605d12
		return -1;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	for (x = 0; x < length; x++) {
Packit 605d12
		struct gfs2_bitmap *bi = &rgd->bits[x];
Packit 605d12
		int mtype = (x ? GFS2_METATYPE_RB : GFS2_METATYPE_RG);
Packit 605d12
Packit 605d12
		bi->bi_bh = bhs[x];
Packit 605d12
		if (gfs2_check_meta(bi->bi_bh, mtype)) {
Packit 605d12
			unsigned err = x;
Packit 605d12
			do {
Packit 605d12
				brelse(rgd->bits[x].bi_bh);
Packit 605d12
				rgd->bits[x].bi_bh = NULL;
Packit 605d12
			} while (x-- != 0);
Packit 605d12
			free(bhs);
Packit 605d12
			return rgd->ri.ri_addr + err;
Packit 605d12
		}
Packit 605d12
	}
Packit 605d12
	if (sdp->gfs1)
Packit 605d12
		gfs_rgrp_in((struct gfs_rgrp *)&rgd->rg, rgd->bits[0].bi_bh);
Packit 605d12
	else {
Packit 605d12
		if (lgfs2_rgrp_crc_check(rgd->bits[0].bi_bh->b_data)) {
Packit 605d12
			free(bhs);
Packit 605d12
			return rgd->ri.ri_addr;
Packit 605d12
		}
Packit 605d12
		gfs2_rgrp_in(&rgd->rg, rgd->bits[0].bi_bh->b_data);
Packit 605d12
	}
Packit 605d12
	free(bhs);
Packit 605d12
	return 0;
Packit 605d12
}
Packit 605d12
Packit 605d12
void gfs2_rgrp_relse(struct rgrp_tree *rgd)
Packit 605d12
{
Packit 605d12
	int x, length = rgd->ri.ri_length;
Packit 605d12
Packit 605d12
	if (rgd->bits == NULL)
Packit 605d12
		return;
Packit 605d12
	for (x = 0; x < length; x++) {
Packit 605d12
		if (rgd->bits[x].bi_bh && rgd->bits[x].bi_bh->b_data) {
Packit 605d12
			brelse(rgd->bits[x].bi_bh);
Packit 605d12
			rgd->bits[x].bi_bh = NULL;
Packit 605d12
		}
Packit 605d12
	}
Packit 605d12
}
Packit 605d12
Packit 605d12
struct rgrp_tree *rgrp_insert(struct osi_root *rgtree, uint64_t rgblock)
Packit 605d12
{
Packit 605d12
	struct osi_node **newn = &rgtree->osi_node, *parent = NULL;
Packit 605d12
	struct rgrp_tree *data;
Packit 605d12
Packit 605d12
	/* Figure out where to put new node */
Packit 605d12
	while (*newn) {
Packit 605d12
		struct rgrp_tree *cur = (struct rgrp_tree *)*newn;
Packit 605d12
Packit 605d12
		parent = *newn;
Packit 605d12
		if (rgblock < cur->ri.ri_addr)
Packit 605d12
			newn = &((*newn)->osi_left);
Packit 605d12
		else if (rgblock > cur->ri.ri_addr)
Packit 605d12
			newn = &((*newn)->osi_right);
Packit 605d12
		else
Packit 605d12
			return cur;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	data = calloc(1, sizeof(struct rgrp_tree));
Packit 605d12
	if (!data)
Packit 605d12
		return NULL;
Packit 605d12
	/* Add new node and rebalance tree. */
Packit 605d12
	data->ri.ri_addr = rgblock;
Packit 605d12
	osi_link_node(&data->node, parent, newn);
Packit 605d12
	osi_insert_color(&data->node, rgtree);
Packit 605d12
Packit 605d12
	return data;
Packit 605d12
}
Packit 605d12
Packit 605d12
void gfs2_rgrp_free(struct osi_root *rgrp_tree)
Packit 605d12
{
Packit 605d12
	struct rgrp_tree *rgd;
Packit 605d12
	int rgs_since_sync = 0;
Packit 605d12
	struct osi_node *n;
Packit 605d12
	struct gfs2_sbd *sdp = NULL;
Packit 605d12
Packit 605d12
	if (OSI_EMPTY_ROOT(rgrp_tree))
Packit 605d12
		return;
Packit 605d12
	while ((n = osi_first(rgrp_tree))) {
Packit 605d12
		rgd = (struct rgrp_tree *)n;
Packit 605d12
Packit 605d12
		if (rgd->bits) {
Packit 605d12
			if (rgd->bits[0].bi_bh) { /* if a buffer exists */
Packit 605d12
				rgs_since_sync++;
Packit 605d12
				if (rgs_since_sync >= RG_SYNC_TOLERANCE) {
Packit 605d12
					if (!sdp)
Packit 605d12
						sdp = rgd->bits[0].bi_bh->sdp;
Packit 605d12
					fsync(sdp->device_fd);
Packit 605d12
					rgs_since_sync = 0;
Packit 605d12
				}
Packit 605d12
				gfs2_rgrp_relse(rgd); /* free them all. */
Packit 605d12
			}
Packit 605d12
			free(rgd->bits);
Packit 605d12
		}
Packit 605d12
		osi_erase(&rgd->node, rgrp_tree);
Packit 605d12
		free(rgd);
Packit 605d12
	}
Packit 605d12
}
Packit 605d12
Packit 605d12
static uint64_t align_block(const uint64_t base, const uint64_t align)
Packit 605d12
{
Packit 605d12
	if ((align > 0) && ((base % align) > 0))
Packit 605d12
		return (base - (base % align)) + align;
Packit 605d12
	return base;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Calculate the aligned block address of a resource group.
Packit 605d12
 * rgs: The resource groups handle
Packit 605d12
 * base: The base address of the first resource group address, in blocks
Packit 605d12
 * Returns the aligned address of the first resource group.
Packit 605d12
 */
Packit 605d12
uint64_t lgfs2_rgrp_align_addr(const lgfs2_rgrps_t rgs, uint64_t addr)
Packit 605d12
{
Packit 605d12
	return align_block(addr, rgs->align);
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Calculate the aligned relative address of the next resource group (and thus
Packit 605d12
 * the aligned length of this one).
Packit 605d12
 * rgs: The resource groups handle
Packit 605d12
 * base: The base length of the current resource group, in blocks
Packit 605d12
 * Returns the length of the resource group (the aligned relative address of
Packit 605d12
 * the next one)
Packit 605d12
 */
Packit 605d12
uint32_t lgfs2_rgrp_align_len(const lgfs2_rgrps_t rgs, uint32_t len)
Packit 605d12
{
Packit 605d12
	return align_block(len, rgs->align) + rgs->align_off;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Plan the sizes of resource groups for remaining free space, based on a
Packit 605d12
 * target maximum size. In order to make best use of the space while keeping
Packit 605d12
 * the resource groups aligned appropriately we need to either reduce the
Packit 605d12
 * length of every resource group or of a subset of the resource groups, so
Packit 605d12
 * we're left with either one or two resource group sizes. We keep track of
Packit 605d12
 * both of these and the numbers of each size of resource group inside the
Packit 605d12
 * resource groups descriptor.
Packit 605d12
 * rgs: The resource groups descriptor
Packit 605d12
 * space: The number of remaining blocks to be allocated
Packit 605d12
 * tgtsize: The target resource group size in blocks
Packit 605d12
 * Returns the number of resource groups planned to fit in the given space, or
Packit 605d12
 * 0 if the smallest resource group would be smaller than GFS2_MIN_RGSIZE.
Packit 605d12
 */
Packit 605d12
uint32_t lgfs2_rgrps_plan(const lgfs2_rgrps_t rgs, uint64_t space, uint32_t tgtsize)
Packit 605d12
{
Packit 605d12
	uint32_t maxlen = (GFS2_MAX_RGSIZE << 20) / rgs->sdp->bsize;
Packit 605d12
	uint32_t minlen = (GFS2_MIN_RGSIZE << 20) / rgs->sdp->bsize;
Packit 605d12
Packit 605d12
	/* Apps should already have checked that the rg size is <=
Packit 605d12
	   GFS2_MAX_RGSIZE but just in case alignment pushes it over we clamp
Packit 605d12
	   it back down while calculating the initial rgrp length.  */
Packit 605d12
	do {
Packit 605d12
		rgs->plan[0].len = lgfs2_rgrp_align_len(rgs, tgtsize);
Packit 605d12
		tgtsize -= (rgs->align + 1);
Packit 605d12
	} while (rgs->plan[0].len > maxlen);
Packit 605d12
Packit 605d12
	rgs->plan[0].num = space / rgs->plan[0].len;
Packit 605d12
Packit 605d12
	if ((space - (rgs->plan[0].num * rgs->plan[0].len)) > rgs->align) {
Packit 605d12
		unsigned adj = (rgs->align > 0) ? rgs->align : 1;
Packit 605d12
Packit 605d12
		/* Spread the adjustment required to fit a new rgrp at the end
Packit 605d12
		   over all of the rgrps so that we don't end with a single
Packit 605d12
		   tiny one.  */
Packit 605d12
		rgs->plan[0].num++;
Packit 605d12
		while (((rgs->plan[0].len - adj) * (uint64_t)rgs->plan[0].num) >= space)
Packit 605d12
			rgs->plan[0].len -= adj;
Packit 605d12
Packit 605d12
		/* We've adjusted the size of the rgrps down as far as we can
Packit 605d12
		   without leaving a large gap at the end of the device now,
Packit 605d12
		   but we still need to reduce the size of some rgrps in order
Packit 605d12
		   to make everything fit, so we use the second rgplan to
Packit 605d12
		   specify a second length for a subset of the resource groups.
Packit 605d12
		   If plan[0].len already divides the space with no remainder,
Packit 605d12
		   plan[1].num will stay 0 and it won't be used.  */
Packit 605d12
		rgs->plan[1].len = rgs->plan[0].len - adj;
Packit 605d12
		rgs->plan[1].num = 0;
Packit 605d12
Packit 605d12
		while (((rgs->plan[0].len * rgs->plan[0].num) +
Packit 605d12
		        (rgs->plan[1].len * rgs->plan[1].num)) >= space) {
Packit 605d12
			/* Total number of rgrps stays constant now. We just
Packit 605d12
			   need to shift some weight around */
Packit 605d12
			rgs->plan[0].num--;
Packit 605d12
			rgs->plan[1].num++;
Packit 605d12
		}
Packit 605d12
	}
Packit 605d12
Packit 605d12
	/* Once we've reached this point,
Packit 605d12
	   (plan[0].num * plan[0].len) + (plan[1].num * plan[1].len)
Packit 605d12
	   will be less than one adjustment smaller than 'space'.  */
Packit 605d12
	if (rgs->plan[0].len < minlen)
Packit 605d12
		return 0;
Packit 605d12
Packit 605d12
	return rgs->plan[0].num + rgs->plan[1].num;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Create and initialise an empty set of resource groups
Packit 605d12
 * bsize: The block size of the fs
Packit 605d12
 * devlen: The length of the device, in fs blocks
Packit 605d12
 * align: The required stripe alignment of the resource groups. Must be a multiple of 'offset'.
Packit 605d12
 * offset: The required stripe offset of the resource groups
Packit 605d12
 * Returns an initialised lgfs2_rgrps_t or NULL if unsuccessful with errno set
Packit 605d12
 */
Packit 605d12
lgfs2_rgrps_t lgfs2_rgrps_init(struct gfs2_sbd *sdp, uint64_t align, uint64_t offset)
Packit 605d12
{
Packit 605d12
	lgfs2_rgrps_t rgs;
Packit 605d12
Packit 605d12
	errno = EINVAL;
Packit 605d12
	if (offset != 0 && (align % offset) != 0)
Packit 605d12
		return NULL;
Packit 605d12
Packit 605d12
	rgs = calloc(1, sizeof(*rgs));
Packit 605d12
	if (rgs == NULL)
Packit 605d12
		return NULL;
Packit 605d12
Packit 605d12
	rgs->sdp = sdp;
Packit 605d12
	rgs->align = align;
Packit 605d12
	rgs->align_off = offset;
Packit 605d12
	memset(&rgs->root, 0, sizeof(rgs->root));
Packit 605d12
Packit 605d12
	return rgs;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Populate a set of resource groups from a gfs2 rindex file.
Packit 605d12
 * fd: An open file descriptor for the rindex file.
Packit 605d12
 * rgs: The set of resource groups.
Packit 605d12
 * Returns the number of resource groups added to the set or 0 on error with
Packit 605d12
 * errno set.
Packit 605d12
 */
Packit 605d12
unsigned lgfs2_rindex_read_fd(int fd, lgfs2_rgrps_t rgs)
Packit 605d12
{
Packit 605d12
	unsigned count = 0;
Packit 605d12
	char buf[sizeof(struct gfs2_rindex)];
Packit 605d12
Packit 605d12
	errno = EINVAL;
Packit 605d12
	if (fd < 0 || rgs == NULL)
Packit 605d12
		return 0;
Packit 605d12
Packit 605d12
	while (1) {
Packit 605d12
		lgfs2_rgrp_t rg;
Packit 605d12
		struct gfs2_rindex ri;
Packit 605d12
		ssize_t ret = read(fd, buf, sizeof(struct gfs2_rindex));
Packit 605d12
		if (ret == 0)
Packit 605d12
			break;
Packit 605d12
Packit 605d12
		if (ret != sizeof(struct gfs2_rindex))
Packit 605d12
			return 0;
Packit 605d12
Packit 605d12
		gfs2_rindex_in(&ri, buf);
Packit 605d12
		rg = lgfs2_rgrps_append(rgs, &ri, 0);
Packit 605d12
		if (rg == NULL)
Packit 605d12
			return 0;
Packit 605d12
		count++;
Packit 605d12
	}
Packit 605d12
	return count;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Read a rindex entry into a set of resource groups
Packit 605d12
 * rip: The inode of the rindex file
Packit 605d12
 * rgs: The set of resource groups.
Packit 605d12
 * i: The index of the entry to read from the rindex file
Packit 605d12
 * Returns the new rindex entry added to the set or NULL on error with errno
Packit 605d12
 * set.
Packit 605d12
 */
Packit 605d12
const struct gfs2_rindex *lgfs2_rindex_read_one(struct gfs2_inode *rip, lgfs2_rgrps_t rgs, unsigned i)
Packit 605d12
{
Packit 605d12
	uint64_t off = i * sizeof(struct gfs2_rindex);
Packit 605d12
	char buf[sizeof(struct gfs2_rindex)];
Packit 605d12
	struct gfs2_rindex ri;
Packit 605d12
	lgfs2_rgrp_t rg;
Packit 605d12
	int ret;
Packit 605d12
Packit 605d12
	errno = EINVAL;
Packit 605d12
	if (rip == NULL || rgs == NULL)
Packit 605d12
		return NULL;
Packit 605d12
Packit 605d12
	ret = gfs2_readi(rip, buf, off, sizeof(struct gfs2_rindex));
Packit 605d12
	if (ret != sizeof(struct gfs2_rindex))
Packit 605d12
		return NULL;
Packit 605d12
Packit 605d12
	gfs2_rindex_in(&ri, buf);
Packit 605d12
	rg = lgfs2_rgrps_append(rgs, &ri, 0);
Packit 605d12
	if (rg == NULL)
Packit 605d12
		return NULL;
Packit 605d12
Packit 605d12
	return &rg->ri;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Free a set of resource groups created with lgfs2_rgrps_append() etc. This
Packit 605d12
 * does not write any dirty buffers to disk. See lgfs2_rgrp_write().
Packit 605d12
 * rgs: A pointer to the set of resource groups to be freed.
Packit 605d12
 */
Packit 605d12
void lgfs2_rgrps_free(lgfs2_rgrps_t *rgs)
Packit 605d12
{
Packit 605d12
	lgfs2_rgrp_t rg;
Packit 605d12
	struct osi_root *tree = &(*rgs)->root;
Packit 605d12
Packit 605d12
	while ((rg = (struct rgrp_tree *)osi_first(tree))) {
Packit 605d12
		int i;
Packit 605d12
		for (i = 0; i < rg->ri.ri_length; i++) {
Packit 605d12
			if (rg->bits[i].bi_bh != NULL) {
Packit 605d12
				free(rg->bits[i].bi_bh);
Packit 605d12
				rg->bits[i].bi_bh = NULL;
Packit 605d12
			}
Packit 605d12
		}
Packit 605d12
		osi_erase(&rg->node, tree);
Packit 605d12
		free(rg);
Packit 605d12
	}
Packit 605d12
	free(*rgs);
Packit 605d12
	*rgs = NULL;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Calculate the fields for a new entry in the resource group index.
Packit 605d12
 * ri: A pointer to the resource group index entry to be calculated.
Packit 605d12
 * addr: The address at which to place this resource group
Packit 605d12
 * len: The required length of the resource group, in fs blocks.
Packit 605d12
 *        If rglen is 0, geometry previously calculated by lgfs2_rgrps_plan() will be used.
Packit 605d12
 * Returns the calculated address of the next resource group or 0 with errno set:
Packit 605d12
 *   EINVAL - The entry pointer is NULL
Packit 605d12
 *   ENOSPC - This rgrp would extend past the end of the device
Packit 605d12
 */
Packit 605d12
uint64_t lgfs2_rindex_entry_new(lgfs2_rgrps_t rgs, struct gfs2_rindex *ri, uint64_t addr, uint32_t len)
Packit 605d12
{
Packit 605d12
	int plan = -1;
Packit 605d12
	errno = EINVAL;
Packit 605d12
	if (!ri)
Packit 605d12
		return 0;
Packit 605d12
Packit 605d12
	errno = ENOSPC;
Packit 605d12
	if (rgs->plan[0].num > 0)
Packit 605d12
		plan = 0;
Packit 605d12
	else if (rgs->plan[1].num > 0)
Packit 605d12
		plan = 1;
Packit 605d12
	else if (len == 0)
Packit 605d12
		return 0;
Packit 605d12
Packit 605d12
	if (plan >= 0 && (len == 0 || len == rgs->plan[plan].len)) {
Packit 605d12
		len = rgs->plan[plan].len;
Packit 605d12
		rgs->plan[plan].num--;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	if (addr + len > rgs->sdp->device.length)
Packit 605d12
		return 0;
Packit 605d12
Packit 605d12
	ri->ri_addr = addr;
Packit 605d12
	ri->ri_length = rgblocks2bitblocks(rgs->sdp->bsize, len, &ri->ri_data);
Packit 605d12
	ri->__pad = 0;
Packit 605d12
	ri->ri_data0 = ri->ri_addr + ri->ri_length;
Packit 605d12
	ri->ri_bitbytes = ri->ri_data / GFS2_NBBY;
Packit 605d12
	memset(&ri->ri_reserved, 0, sizeof(ri->ri_reserved));
Packit 605d12
Packit 605d12
	return ri->ri_addr + len;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Return the rindex structure relating to a resource group.
Packit 605d12
 * The return type is const to advise callers that making changes to this
Packit 605d12
 * structure directly isn't wise. libgfs2 functions should be used instead.
Packit 605d12
 */
Packit 605d12
const struct gfs2_rindex *lgfs2_rgrp_index(lgfs2_rgrp_t rg)
Packit 605d12
{
Packit 605d12
	return &rg->ri;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Return the rgrp structure relating to a resource group.
Packit 605d12
 * The return type is const to advise callers that making changes to this
Packit 605d12
 * structure directly isn't wise. libgfs2 functions should be used instead.
Packit 605d12
 */
Packit 605d12
const struct gfs2_rgrp *lgfs2_rgrp_rgrp(lgfs2_rgrp_t rg)
Packit 605d12
{
Packit 605d12
	return &rg->rg;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Returns the total resource group size, in blocks, required to give blksreq data blocks
Packit 605d12
 */
Packit 605d12
unsigned lgfs2_rgsize_for_data(uint64_t blksreq, unsigned bsize)
Packit 605d12
{
Packit 605d12
	const uint32_t blks_rgrp = GFS2_NBBY * (bsize - sizeof(struct gfs2_rgrp));
Packit 605d12
	const uint32_t blks_meta = GFS2_NBBY * (bsize - sizeof(struct gfs2_meta_header));
Packit 605d12
	unsigned bitblocks = 1;
Packit 605d12
	blksreq = (blksreq + 3) & ~3;
Packit 605d12
	if (blksreq > blks_rgrp)
Packit 605d12
		bitblocks += ((blksreq - blks_rgrp) + blks_meta - 1) / blks_meta;
Packit 605d12
	return bitblocks + blksreq;
Packit 605d12
}
Packit 605d12
Packit 605d12
// Temporary function to aid in API migration
Packit 605d12
struct osi_node *lgfs2_rgrps_root(lgfs2_rgrps_t rgs)
Packit 605d12
{
Packit 605d12
	return rgs->root.osi_node;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Insert a new resource group after the last resource group in a set.
Packit 605d12
 * rgs: The set of resource groups
Packit 605d12
 * entry: The entry to be added
Packit 605d12
 * rg_skip: The value to be used for this resource group's rg_skip field
Packit 605d12
 * Returns the new resource group on success or NULL on failure with errno set.
Packit 605d12
 */
Packit 605d12
lgfs2_rgrp_t lgfs2_rgrps_append(lgfs2_rgrps_t rgs, struct gfs2_rindex *entry, uint32_t rg_skip)
Packit 605d12
{
Packit 605d12
	lgfs2_rgrp_t rg;
Packit 605d12
	struct osi_node **link = &rgs->root.osi_node;
Packit 605d12
	struct osi_node *parent = osi_last(&rgs->root);
Packit 605d12
	lgfs2_rgrp_t lastrg = (lgfs2_rgrp_t)parent;
Packit 605d12
Packit 605d12
	errno = EINVAL;
Packit 605d12
	if (entry == NULL)
Packit 605d12
		return NULL;
Packit 605d12
Packit 605d12
	if (lastrg != NULL) { /* Tree is not empty */
Packit 605d12
		if (entry->ri_addr <= lastrg->ri.ri_addr)
Packit 605d12
			return NULL; /* Appending with a lower address doesn't make sense */
Packit 605d12
		link = &lastrg->node.osi_right;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	rg = calloc(1, sizeof(*rg) + (entry->ri_length * sizeof(struct gfs2_bitmap)));
Packit 605d12
	if (rg == NULL)
Packit 605d12
		return NULL;
Packit 605d12
Packit 605d12
	rg->bits = (struct gfs2_bitmap *)(rg + 1);
Packit 605d12
Packit 605d12
	osi_link_node(&rg->node, parent, link);
Packit 605d12
	osi_insert_color(&rg->node, &rgs->root);
Packit 605d12
Packit 605d12
	memcpy(&rg->ri, entry, sizeof(struct gfs2_rindex));
Packit 605d12
	rg->rg.rg_header.mh_magic = GFS2_MAGIC;
Packit 605d12
	rg->rg.rg_header.mh_type = GFS2_METATYPE_RG;
Packit 605d12
	rg->rg.rg_header.mh_format = GFS2_FORMAT_RG;
Packit 605d12
	rg->rg.rg_free = rg->ri.ri_data;
Packit 605d12
#ifdef GFS2_HAS_RG_SKIP
Packit 605d12
	rg->rg.rg_skip = rg_skip;
Packit 605d12
#endif
Packit 605d12
#ifdef GFS2_HAS_RG_RI_FIELDS
Packit 605d12
	rg->rg.rg_data0 = rg->ri.ri_data0;
Packit 605d12
	rg->rg.rg_data = rg->ri.ri_data;
Packit 605d12
	rg->rg.rg_bitbytes = rg->ri.ri_bitbytes;
Packit 605d12
	rg->rg.rg_crc = 0;
Packit 605d12
#endif
Packit 605d12
	compute_bitmaps(rg, rgs->sdp->bsize);
Packit 605d12
	rg->rgrps = rgs;
Packit 605d12
	return rg;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * Write a resource group to a file descriptor.
Packit 605d12
 * Returns 0 on success or non-zero on failure with errno set
Packit 605d12
 */
Packit 605d12
int lgfs2_rgrp_write(int fd, const lgfs2_rgrp_t rg)
Packit 605d12
{
Packit 605d12
	struct gfs2_sbd *sdp = rg->rgrps->sdp;
Packit 605d12
	unsigned int i;
Packit 605d12
	const struct gfs2_meta_header bmh = {
Packit 605d12
		.mh_magic = GFS2_MAGIC,
Packit 605d12
		.mh_type = GFS2_METATYPE_RB,
Packit 605d12
		.mh_format = GFS2_FORMAT_RB,
Packit 605d12
	};
Packit 605d12
	int freebufs = 0;
Packit 605d12
	ssize_t ret;
Packit 605d12
	size_t len;
Packit 605d12
Packit 605d12
	if (rg->bits[0].bi_bh == NULL) {
Packit 605d12
		freebufs = 1;
Packit 605d12
		if (lgfs2_rgrp_bitbuf_alloc(rg) != 0)
Packit 605d12
			return -1;
Packit 605d12
	}
Packit 605d12
	gfs2_rgrp_out(&rg->rg, rg->bits[0].bi_bh->b_data);
Packit 605d12
	for (i = 1; i < rg->ri.ri_length; i++)
Packit 605d12
		gfs2_meta_header_out(&bmh, rg->bits[i].bi_bh->b_data);
Packit 605d12
Packit 605d12
	len = sdp->bsize * rg->ri.ri_length;
Packit 605d12
	if (rg->rgrps->align > 0)
Packit 605d12
		len = ROUND_UP(len, rg->rgrps->align * sdp->bsize);
Packit 605d12
Packit 605d12
	ret = pwrite(sdp->device_fd, rg->bits[0].bi_bh->b_data, len,
Packit 605d12
	             rg->bits[0].bi_bh->b_blocknr * sdp->bsize);
Packit 605d12
Packit 605d12
	if (freebufs)
Packit 605d12
		lgfs2_rgrp_bitbuf_free(rg);
Packit 605d12
Packit 605d12
	return ret == len ? 0 : -1;
Packit 605d12
}
Packit 605d12
Packit 605d12
lgfs2_rgrp_t lgfs2_rgrp_first(lgfs2_rgrps_t rgs)
Packit 605d12
{
Packit 605d12
	return (lgfs2_rgrp_t)osi_first(&rgs->root);
Packit 605d12
}
Packit 605d12
Packit 605d12
lgfs2_rgrp_t lgfs2_rgrp_next(lgfs2_rgrp_t rg)
Packit 605d12
{
Packit 605d12
	return (lgfs2_rgrp_t)osi_next(&rg->node);
Packit 605d12
}
Packit 605d12
Packit 605d12
lgfs2_rgrp_t lgfs2_rgrp_prev(lgfs2_rgrp_t rg)
Packit 605d12
{
Packit 605d12
	return (lgfs2_rgrp_t)osi_prev(&rg->node);
Packit 605d12
}
Packit 605d12
Packit 605d12
lgfs2_rgrp_t lgfs2_rgrp_last(lgfs2_rgrps_t rgs)
Packit 605d12
{
Packit 605d12
	return (lgfs2_rgrp_t)osi_last(&rgs->root);
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * gfs2_rbm_from_block - Set the rbm based upon rgd and block number
Packit 605d12
 * @rbm: The rbm with rgd already set correctly
Packit 605d12
 * @block: The block number (filesystem relative)
Packit 605d12
 *
Packit 605d12
 * This sets the bi and offset members of an rbm based on a
Packit 605d12
 * resource group and a filesystem relative block number. The
Packit 605d12
 * resource group must be set in the rbm on entry, the bi and
Packit 605d12
 * offset members will be set by this function.
Packit 605d12
 *
Packit 605d12
 * Returns: 0 on success, or non-zero with errno set
Packit 605d12
 */
Packit 605d12
int lgfs2_rbm_from_block(struct lgfs2_rbm *rbm, uint64_t block)
Packit 605d12
{
Packit 605d12
	uint64_t rblock = block - rbm->rgd->ri.ri_data0;
Packit 605d12
	struct gfs2_sbd *sdp = rbm_bi(rbm)->bi_bh->sdp;
Packit 605d12
Packit 605d12
	if (rblock > UINT_MAX) {
Packit 605d12
		errno = EINVAL;
Packit 605d12
		return 1;
Packit 605d12
	}
Packit 605d12
	if (block >= rbm->rgd->ri.ri_data0 + rbm->rgd->ri.ri_data) {
Packit 605d12
		errno = E2BIG;
Packit 605d12
		return 1;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	rbm->bii = 0;
Packit 605d12
	rbm->offset = (uint32_t)(rblock);
Packit 605d12
	/* Check if the block is within the first block */
Packit 605d12
	if (rbm->offset < (rbm_bi(rbm)->bi_len * GFS2_NBBY))
Packit 605d12
		return 0;
Packit 605d12
Packit 605d12
	/* Adjust for the size diff between gfs2_meta_header and gfs2_rgrp */
Packit 605d12
	rbm->offset += (sizeof(struct gfs2_rgrp) -
Packit 605d12
			sizeof(struct gfs2_meta_header)) * GFS2_NBBY;
Packit 605d12
	rbm->bii = rbm->offset / sdp->sd_blocks_per_bitmap;
Packit 605d12
	rbm->offset -= rbm->bii * sdp->sd_blocks_per_bitmap;
Packit 605d12
	return 0;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * lgfs2_rbm_incr - increment an rbm structure
Packit 605d12
 * @rbm: The rbm with rgd already set correctly
Packit 605d12
 *
Packit 605d12
 * This function takes an existing rbm structure and increments it to the next
Packit 605d12
 * viable block offset.
Packit 605d12
 *
Packit 605d12
 * Returns: If incrementing the offset would cause the rbm to go past the
Packit 605d12
 *          end of the rgrp, true is returned, otherwise false.
Packit 605d12
 *
Packit 605d12
 */
Packit 605d12
static int lgfs2_rbm_incr(struct lgfs2_rbm *rbm)
Packit 605d12
{
Packit 605d12
	if (rbm->offset + 1 < (rbm_bi(rbm)->bi_len * GFS2_NBBY)) { /* in the same bitmap */
Packit 605d12
		rbm->offset++;
Packit 605d12
		return 0;
Packit 605d12
	}
Packit 605d12
	if (rbm->bii == rbm->rgd->ri.ri_length - 1) /* at the last bitmap */
Packit 605d12
		return 1;
Packit 605d12
Packit 605d12
	rbm->offset = 0;
Packit 605d12
	rbm->bii++;
Packit 605d12
	return 0;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * lgfs2_testbit - test a bit in the bitmaps
Packit 605d12
 * @rbm: The bit to test
Packit 605d12
 *
Packit 605d12
 * Returns: The two bit block state of the requested bit
Packit 605d12
 */
Packit 605d12
static inline uint8_t lgfs2_testbit(const struct lgfs2_rbm *rbm)
Packit 605d12
{
Packit 605d12
	struct gfs2_bitmap *bi = rbm_bi(rbm);
Packit 605d12
	const uint8_t *buffer = (uint8_t *)bi->bi_bh->b_data + bi->bi_offset;
Packit 605d12
	const uint8_t *byte;
Packit 605d12
	unsigned int bit;
Packit 605d12
Packit 605d12
	byte = buffer + (rbm->offset / GFS2_NBBY);
Packit 605d12
	bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE;
Packit 605d12
Packit 605d12
	return (*byte >> bit) & GFS2_BIT_MASK;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * lgfs2_unaligned_extlen - Look for free blocks which are not byte aligned
Packit 605d12
 * @rbm: Position to search (value/result)
Packit 605d12
 * @n_unaligned: Number of unaligned blocks to check
Packit 605d12
 * @len: Decremented for each block found (terminate on zero)
Packit 605d12
 *
Packit 605d12
 * Returns: true if a non-free block is encountered
Packit 605d12
 */
Packit 605d12
static int lgfs2_unaligned_extlen(struct lgfs2_rbm *rbm, uint32_t n_unaligned, uint32_t *len)
Packit 605d12
{
Packit 605d12
	uint32_t n;
Packit 605d12
	uint8_t res;
Packit 605d12
Packit 605d12
	for (n = 0; n < n_unaligned; n++) {
Packit 605d12
		res = lgfs2_testbit(rbm);
Packit 605d12
		if (res != GFS2_BLKST_FREE)
Packit 605d12
			return 1;
Packit 605d12
		(*len)--;
Packit 605d12
		if (*len == 0)
Packit 605d12
			return 1;
Packit 605d12
		if (lgfs2_rbm_incr(rbm))
Packit 605d12
			return 1;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	return 0;
Packit 605d12
}
Packit 605d12
Packit 605d12
static uint8_t *check_bytes8(const uint8_t *start, uint8_t value, unsigned bytes)
Packit 605d12
{
Packit 605d12
	while (bytes) {
Packit 605d12
		if (*start != value)
Packit 605d12
			return (void *)start;
Packit 605d12
		start++;
Packit 605d12
		bytes--;
Packit 605d12
	}
Packit 605d12
	return NULL;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * lgfs2_free_extlen - Return extent length of free blocks
Packit 605d12
 * @rbm: Starting position
Packit 605d12
 * @len: Max length to check
Packit 605d12
 *
Packit 605d12
 * Starting at the block specified by the rbm, see how many free blocks
Packit 605d12
 * there are, not reading more than len blocks ahead. This can be done
Packit 605d12
 * using check_bytes8 when the blocks are byte aligned, but has to be done
Packit 605d12
 * on a block by block basis in case of unaligned blocks. Also this
Packit 605d12
 * function can cope with bitmap boundaries (although it must stop on
Packit 605d12
 * a resource group boundary)
Packit 605d12
 *
Packit 605d12
 * Returns: Number of free blocks in the extent
Packit 605d12
 */
Packit 605d12
static uint32_t lgfs2_free_extlen(const struct lgfs2_rbm *rrbm, uint32_t len)
Packit 605d12
{
Packit 605d12
	struct lgfs2_rbm rbm = *rrbm;
Packit 605d12
	uint32_t n_unaligned = rbm.offset & 3;
Packit 605d12
	uint32_t size = len;
Packit 605d12
	uint32_t bytes;
Packit 605d12
	uint32_t chunk_size;
Packit 605d12
	uint8_t *ptr, *start, *end;
Packit 605d12
	uint64_t block;
Packit 605d12
	struct gfs2_bitmap *bi;
Packit 605d12
Packit 605d12
	if (n_unaligned &&
Packit 605d12
	    lgfs2_unaligned_extlen(&rbm, 4 - n_unaligned, &len))
Packit 605d12
		goto out;
Packit 605d12
Packit 605d12
	n_unaligned = len & 3;
Packit 605d12
	/* Start is now byte aligned */
Packit 605d12
	while (len > 3) {
Packit 605d12
		bi = rbm_bi(&rbm;;
Packit 605d12
		start = (uint8_t *)bi->bi_bh->b_data;
Packit 605d12
		end = start + bi->bi_bh->sdp->bsize;
Packit 605d12
		start += bi->bi_offset;
Packit 605d12
		start += (rbm.offset / GFS2_NBBY);
Packit 605d12
		bytes = (len / GFS2_NBBY) < (end - start) ? (len / GFS2_NBBY):(end - start);
Packit 605d12
		ptr = check_bytes8(start, 0, bytes);
Packit 605d12
		chunk_size = ((ptr == NULL) ? bytes : (ptr - start));
Packit 605d12
		chunk_size *= GFS2_NBBY;
Packit 605d12
		len -= chunk_size;
Packit 605d12
		block = lgfs2_rbm_to_block(&rbm;;
Packit 605d12
		if (lgfs2_rbm_from_block(&rbm, block + chunk_size)) {
Packit 605d12
			n_unaligned = 0;
Packit 605d12
			break;
Packit 605d12
		}
Packit 605d12
		if (ptr) {
Packit 605d12
			n_unaligned = 3;
Packit 605d12
			break;
Packit 605d12
		}
Packit 605d12
		n_unaligned = len & 3;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	/* Deal with any bits left over at the end */
Packit 605d12
	if (n_unaligned)
Packit 605d12
		lgfs2_unaligned_extlen(&rbm, n_unaligned, &len;;
Packit 605d12
out:
Packit 605d12
	return size - len;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * gfs2_rbm_find - Look for blocks of a particular state
Packit 605d12
 * @rbm: Value/result starting position and final position
Packit 605d12
 * @state: The state which we want to find
Packit 605d12
 * @minext: Pointer to the requested extent length (NULL for a single block)
Packit 605d12
 *          This is updated to be the actual reservation size.
Packit 605d12
 *
Packit 605d12
 * Returns: 0 on success, non-zero with errno == ENOSPC if there is no block of the requested state
Packit 605d12
 */
Packit 605d12
int lgfs2_rbm_find(struct lgfs2_rbm *rbm, uint8_t state, uint32_t *minext)
Packit 605d12
{
Packit 605d12
	int initial_bii;
Packit 605d12
	uint32_t offset;
Packit 605d12
	int n = 0;
Packit 605d12
	int iters = rbm->rgd->ri.ri_length;
Packit 605d12
	uint32_t extlen;
Packit 605d12
Packit 605d12
	/* If we are not starting at the beginning of a bitmap, then we
Packit 605d12
	 * need to add one to the bitmap count to ensure that we search
Packit 605d12
	 * the starting bitmap twice.
Packit 605d12
	 */
Packit 605d12
	if (rbm->offset != 0)
Packit 605d12
		iters++;
Packit 605d12
Packit 605d12
	for (n = 0; n < iters; n++) {
Packit 605d12
		struct gfs2_bitmap *bi = rbm_bi(rbm);
Packit 605d12
		struct gfs2_buffer_head *bh = bi->bi_bh;
Packit 605d12
		uint8_t *buf = (uint8_t *)bh->b_data + bi->bi_offset;
Packit 605d12
		uint64_t block;
Packit 605d12
		int ret;
Packit 605d12
Packit 605d12
		if ((rbm->rgd->rg.rg_free < *minext) && (state == GFS2_BLKST_FREE))
Packit 605d12
			goto next_bitmap;
Packit 605d12
Packit 605d12
		offset = gfs2_bitfit(buf, bi->bi_len, rbm->offset, state);
Packit 605d12
		if (offset == BFITNOENT)
Packit 605d12
			goto next_bitmap;
Packit 605d12
Packit 605d12
		rbm->offset = offset;
Packit 605d12
		initial_bii = rbm->bii;
Packit 605d12
		block = lgfs2_rbm_to_block(rbm);
Packit 605d12
		extlen = 1;
Packit 605d12
Packit 605d12
		if (*minext != 0)
Packit 605d12
			extlen = lgfs2_free_extlen(rbm, *minext);
Packit 605d12
Packit 605d12
		if (extlen >= *minext)
Packit 605d12
			return 0;
Packit 605d12
Packit 605d12
		ret = lgfs2_rbm_from_block(rbm, block + extlen);
Packit 605d12
		if (ret == 0) {
Packit 605d12
			n += (rbm->bii - initial_bii);
Packit 605d12
			continue;
Packit 605d12
		}
Packit 605d12
Packit 605d12
		if (errno == E2BIG) {
Packit 605d12
			rbm->bii = 0;
Packit 605d12
			rbm->offset = 0;
Packit 605d12
			n += (rbm->bii - initial_bii);
Packit 605d12
			goto res_covered_end_of_rgrp;
Packit 605d12
		}
Packit 605d12
Packit 605d12
		return ret;
Packit 605d12
Packit 605d12
next_bitmap:	/* Find next bitmap in the rgrp */
Packit 605d12
		rbm->offset = 0;
Packit 605d12
		rbm->bii++;
Packit 605d12
		if (rbm->bii == rbm->rgd->ri.ri_length)
Packit 605d12
			rbm->bii = 0;
Packit 605d12
Packit 605d12
res_covered_end_of_rgrp:
Packit 605d12
		if (rbm->bii == 0)
Packit 605d12
			break;
Packit 605d12
	}
Packit 605d12
Packit 605d12
	errno = ENOSPC;
Packit 605d12
	return 1;
Packit 605d12
}
Packit 605d12
Packit 605d12
/**
Packit 605d12
 * lgfs2_alloc_extent - allocate an extent from a given bitmap
Packit 605d12
 * @rbm: the resource group information
Packit 605d12
 * @state: The state of the first block, GFS2_BLKST_DINODE or GFS2_BLKST_USED
Packit 605d12
 * @elen: The requested extent length
Packit 605d12
 * Returns the length of the extent allocated.
Packit 605d12
 */
Packit 605d12
unsigned lgfs2_alloc_extent(const struct lgfs2_rbm *rbm, int state, const unsigned elen)
Packit 605d12
{
Packit 605d12
	struct lgfs2_rbm pos = { .rgd = rbm->rgd, };
Packit 605d12
	const uint64_t block = lgfs2_rbm_to_block(rbm);
Packit 605d12
	unsigned len;
Packit 605d12
Packit 605d12
	gfs2_set_bitmap(rbm->rgd, block, state);
Packit 605d12
Packit 605d12
	for (len = 1; len < elen; len++) {
Packit 605d12
		int ret = lgfs2_rbm_from_block(&pos, block + len);
Packit 605d12
		if (ret || lgfs2_testbit(&pos) != GFS2_BLKST_FREE)
Packit 605d12
			break;
Packit 605d12
		gfs2_set_bitmap(pos.rgd, block + len, GFS2_BLKST_USED);
Packit 605d12
	}
Packit 605d12
	return len;
Packit 605d12
}