Blame gfs2/libgfs2/rgrp.c

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