Blame gfs2/libgfs2/rgrp.c

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