Blame gfs2/libgfs2/fs_bits.c

Packit Service 360c39
#include "clusterautoconfig.h"
Packit Service 360c39
Packit Service 360c39
#include <inttypes.h>
Packit Service 360c39
#include <stdlib.h>
Packit Service 360c39
#include <string.h>
Packit Service 360c39
#include <unistd.h>
Packit Service 360c39
#include <limits.h>
Packit Service 360c39
Packit Service 360c39
#include "libgfs2.h"
Packit Service 360c39
Packit Service 360c39
#if BITS_PER_LONG == 32
Packit Service 360c39
#define LBITMASK   (0x55555555UL)
Packit Service 360c39
#define LBITSKIP55 (0x55555555UL)
Packit Service 360c39
#define LBITSKIP00 (0x00000000UL)
Packit Service 360c39
#else
Packit Service 360c39
#define LBITMASK   (0x5555555555555555UL)
Packit Service 360c39
#define LBITSKIP55 (0x5555555555555555UL)
Packit Service 360c39
#define LBITSKIP00 (0x0000000000000000UL)
Packit Service 360c39
#endif
Packit Service 360c39
Packit Service 360c39
#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1))
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * gfs2_bit_search
Packit Service 360c39
 * @ptr: Pointer to bitmap data
Packit Service 360c39
 * @mask: Mask to use (normally 0x55555.... but adjusted for search start)
Packit Service 360c39
 * @state: The state we are searching for
Packit Service 360c39
 *
Packit Service 360c39
 * We xor the bitmap data with a patter which is the bitwise opposite
Packit Service 360c39
 * of what we are looking for, this gives rise to a pattern of ones
Packit Service 360c39
 * wherever there is a match. Since we have two bits per entry, we
Packit Service 360c39
 * take this pattern, shift it down by one place and then and it with
Packit Service 360c39
 * the original. All the even bit positions (0,2,4, etc) then represent
Packit Service 360c39
 * successful matches, so we mask with 0x55555..... to remove the unwanted
Packit Service 360c39
 * odd bit positions.
Packit Service 360c39
 *
Packit Service 360c39
 * This allows searching of a whole u64 at once (32 blocks) with a
Packit Service 360c39
 * single test (on 64 bit arches).
Packit Service 360c39
 */
Packit Service 360c39
Packit Service 360c39
static inline uint64_t gfs2_bit_search(const unsigned long long *ptr,
Packit Service 360c39
				       unsigned long long mask,
Packit Service 360c39
				       uint8_t state)
Packit Service 360c39
{
Packit Service 360c39
	unsigned long long tmp;
Packit Service 360c39
	static const unsigned long long search[] = {
Packit Service 360c39
		[0] = 0xffffffffffffffffULL,
Packit Service 360c39
		[1] = 0xaaaaaaaaaaaaaaaaULL,
Packit Service 360c39
		[2] = 0x5555555555555555ULL,
Packit Service 360c39
		[3] = 0x0000000000000000ULL,
Packit Service 360c39
	};
Packit Service 360c39
	tmp = le64_to_cpu(*ptr) ^ search[state];
Packit Service 360c39
	tmp &= (tmp >> 1);
Packit Service 360c39
	tmp &= mask;
Packit Service 360c39
	return tmp;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/**
Packit Service 360c39
 * gfs2_bitfit - Find a free block in the bitmaps
Packit Service 360c39
 * @buffer: the buffer that holds the bitmaps
Packit Service 360c39
 * @buflen: the length (in bytes) of the buffer
Packit Service 360c39
 * @goal: the block to try to allocate
Packit Service 360c39
 * @old_state: the state of the block we're looking for
Packit Service 360c39
 *
Packit Service 360c39
 * Return: the block number that was allocated
Packit Service 360c39
 */
Packit Service 360c39
unsigned long gfs2_bitfit(const unsigned char *buf, const unsigned int len,
Packit Service 360c39
			  unsigned long goal, unsigned char state)
Packit Service 360c39
{
Packit Service 360c39
	unsigned long spoint = (goal << 1) & ((8 * sizeof(unsigned long long)) - 1);
Packit Service 360c39
	const unsigned long long *ptr = ((unsigned long long *)buf) + (goal >> 5);
Packit Service 360c39
	const unsigned long long *end = (unsigned long long *)
Packit Service 360c39
		(buf + ALIGN(len, sizeof(unsigned long long)));
Packit Service 360c39
	unsigned long long tmp;
Packit Service 360c39
	unsigned long long mask = 0x5555555555555555ULL;
Packit Service 360c39
	unsigned long bit;
Packit Service 360c39
Packit Service 360c39
	if (state > 3)
Packit Service 360c39
		return 0;
Packit Service 360c39
Packit Service 360c39
	/* Mask off bits we don't care about at the start of the search */
Packit Service 360c39
	mask <<= spoint;
Packit Service 360c39
	tmp = gfs2_bit_search(ptr, mask, state);
Packit Service 360c39
	ptr++;
Packit Service 360c39
	while(tmp == 0 && ptr < end) {
Packit Service 360c39
		tmp = gfs2_bit_search(ptr, 0x5555555555555555ULL, state);
Packit Service 360c39
		ptr++;
Packit Service 360c39
	}
Packit Service 360c39
	/* Mask off any bits which are more than len bytes from the start */
Packit Service 360c39
	if (ptr == end && (len & (sizeof(unsigned long long) - 1)))
Packit Service 360c39
		tmp &= (((unsigned long long)~0) >>
Packit Service 360c39
			(64 - 8 * (len & (sizeof(unsigned long long) - 1))));
Packit Service 360c39
	/* Didn't find anything, so return */
Packit Service 360c39
	if (tmp == 0)
Packit Service 360c39
		return BFITNOENT;
Packit Service 360c39
	ptr--;
Packit Service 360c39
	bit = ffsll(tmp);
Packit Service 360c39
	bit /= 2;	/* two bits per entry in the bitmap */
Packit Service 360c39
	return (((const unsigned char *)ptr - buf) * GFS2_NBBY) + bit;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * check_range - check if blkno is within FS limits
Packit Service 360c39
 * @sdp: super block
Packit Service 360c39
 * @blkno: block number
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 if ok, -1 if out of bounds
Packit Service 360c39
 */
Packit Service 360c39
int gfs2_check_range(struct gfs2_sbd *sdp, uint64_t blkno)
Packit Service 360c39
{
Packit Service 360c39
	if((blkno > sdp->fssize) || (blkno <= LGFS2_SB_ADDR(sdp)))
Packit Service 360c39
		return -1;
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * gfs2_set_bitmap
Packit Service 360c39
 * @sdp: super block
Packit Service 360c39
 * @blkno: block number relative to file system
Packit Service 360c39
 * @state: one of three possible states
Packit Service 360c39
 *
Packit Service 360c39
 * This function sets the value of a bit of the
Packit Service 360c39
 * file system bitmap.
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: 0 on success, -1 on error
Packit Service 360c39
 */
Packit Service 360c39
int gfs2_set_bitmap(lgfs2_rgrp_t rgd, uint64_t blkno, int state)
Packit Service 360c39
{
Packit Service 360c39
	int           buf;
Packit Service 360c39
	uint32_t        rgrp_block;
Packit Service 360c39
	struct gfs2_bitmap *bits = NULL;
Packit Service 360c39
	unsigned char *byte, cur_state;
Packit Service 360c39
	unsigned int bit;
Packit Service 360c39
Packit Service 360c39
	/* FIXME: should GFS2_BLKST_INVALID be allowed */
Packit Service 360c39
	if ((state < GFS2_BLKST_FREE) || (state > GFS2_BLKST_DINODE))
Packit Service 360c39
		return -1;
Packit Service 360c39
Packit Service 360c39
	if(!rgd || blkno < rgd->ri.ri_data0)
Packit Service 360c39
		return -1;
Packit Service 360c39
Packit Service 360c39
	rgrp_block = (uint32_t)(blkno - rgd->ri.ri_data0);
Packit Service 360c39
	for(buf= 0; buf < rgd->ri.ri_length; buf++){
Packit Service 360c39
		bits = &(rgd->bits[buf]);
Packit Service 360c39
		if(rgrp_block < ((bits->bi_start + bits->bi_len)*GFS2_NBBY))
Packit Service 360c39
			break;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (bits == NULL)
Packit Service 360c39
		return -1;
Packit Service 360c39
	byte = (unsigned char *)(bits->bi_bh->b_data + bits->bi_offset) +
Packit Service 360c39
		(rgrp_block/GFS2_NBBY - bits->bi_start);
Packit Service 360c39
	bit = (rgrp_block % GFS2_NBBY) * GFS2_BIT_SIZE;
Packit Service 360c39
Packit Service 360c39
	cur_state = (*byte >> bit) & GFS2_BIT_MASK;
Packit Service 360c39
	*byte ^= cur_state << bit;
Packit Service 360c39
	*byte |= state << bit;
Packit Service 360c39
Packit Service 360c39
	bmodified(bits->bi_bh);
Packit Service 360c39
	return 0;
Packit Service 360c39
}
Packit Service 360c39
Packit Service 360c39
/*
Packit Service 360c39
 * gfs2_get_bitmap - get value of FS bitmap
Packit Service 360c39
 * @sdp: super block
Packit Service 360c39
 * @blkno: block number relative to file system
Packit Service 360c39
 *
Packit Service 360c39
 * This function gets the value of a bit of the
Packit Service 360c39
 * file system bitmap.
Packit Service 360c39
 * Possible state values for a block in the bitmap are:
Packit Service 360c39
 *  GFS_BLKST_FREE     (0)
Packit Service 360c39
 *  GFS_BLKST_USED     (1)
Packit Service 360c39
 *  GFS_BLKST_INVALID  (2)
Packit Service 360c39
 *  GFS_BLKST_DINODE   (3)
Packit Service 360c39
 *
Packit Service 360c39
 * Returns: state on success, -1 on error
Packit Service 360c39
 */
Packit Service 360c39
int lgfs2_get_bitmap(struct gfs2_sbd *sdp, uint64_t blkno, struct rgrp_tree *rgd)
Packit Service 360c39
{
Packit Service 360c39
	uint64_t offset;
Packit Service 360c39
	uint32_t i = 0;
Packit Service 360c39
	char *byte;
Packit Service 360c39
	unsigned int bit;
Packit Service 360c39
	struct gfs2_bitmap *bi;
Packit Service 360c39
Packit Service 360c39
	if (rgd == NULL) {
Packit Service 360c39
		rgd = gfs2_blk2rgrpd(sdp, blkno);
Packit Service 360c39
		if(rgd == NULL)
Packit Service 360c39
			return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	offset = blkno - rgd->ri.ri_data0;
Packit Service 360c39
	if (offset > UINT_MAX) {
Packit Service 360c39
		errno = EINVAL;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
	if (offset >= rgd->ri.ri_data0 + rgd->ri.ri_data) {
Packit Service 360c39
		errno = E2BIG;
Packit Service 360c39
		return -1;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	if (offset >= (rgd->bits->bi_start + rgd->bits->bi_len) * GFS2_NBBY) {
Packit Service 360c39
		offset += (sizeof(struct gfs2_rgrp) - sizeof(struct gfs2_meta_header))
Packit Service 360c39
		          * GFS2_NBBY;
Packit Service 360c39
		i = offset / sdp->sd_blocks_per_bitmap;
Packit Service 360c39
		offset -= i * sdp->sd_blocks_per_bitmap;
Packit Service 360c39
	}
Packit Service 360c39
Packit Service 360c39
	bi = &rgd->bits[i];
Packit Service 360c39
	if (!bi->bi_bh)
Packit Service 360c39
		return GFS2_BLKST_FREE;
Packit Service 360c39
Packit Service 360c39
	byte = (bi->bi_bh->b_data + bi->bi_offset) + (offset/GFS2_NBBY);
Packit Service 360c39
	bit = (offset % GFS2_NBBY) * GFS2_BIT_SIZE;
Packit Service 360c39
Packit Service 360c39
	return (*byte >> bit) & GFS2_BIT_MASK;
Packit Service 360c39
}