HelenOS sources
This source file includes following definitions.
- mfs_alloc_inode
- mfs_free_inode
- mfs_alloc_zone
- mfs_free_zone
- mfs_count_free_zones
- mfs_count_free_inodes
- mfs_count_free_bits
- mfs_free_bit
- mfs_alloc_bit
- find_free_bit_and_set
#include <stdlib.h>
#include "mfs.h"
static int
find_free_bit_and_set(bitchunk_t *b, const int bsize,
const bool native, unsigned start_bit);
static errno_t
mfs_free_bit(struct mfs_instance *inst, uint32_t idx, bmap_id_t bid);
static errno_t
mfs_alloc_bit(struct mfs_instance *inst, uint32_t *idx, bmap_id_t bid);
static errno_t
mfs_count_free_bits(struct mfs_instance *inst, bmap_id_t bid, uint32_t *free);
errno_t
mfs_alloc_inode(struct mfs_instance *inst, uint32_t *inum)
{
errno_t r = mfs_alloc_bit(inst, inum, BMAP_INODE);
return r;
}
errno_t
mfs_free_inode(struct mfs_instance *inst, uint32_t inum)
{
return mfs_free_bit(inst, inum, BMAP_INODE);
}
errno_t
mfs_alloc_zone(struct mfs_instance *inst, uint32_t *zone)
{
errno_t r = mfs_alloc_bit(inst, zone, BMAP_ZONE);
if (r != EOK)
return r;
struct mfs_sb_info *sbi = inst->sbi;
if (sbi->nfree_zones_valid)
sbi->nfree_zones--;
*zone += inst->sbi->firstdatazone - 1;
return r;
}
errno_t
mfs_free_zone(struct mfs_instance *inst, uint32_t zone)
{
errno_t r;
zone -= inst->sbi->firstdatazone - 1;
r = mfs_free_bit(inst, zone, BMAP_ZONE);
if (r != EOK)
return r;
struct mfs_sb_info *sbi = inst->sbi;
if (sbi->nfree_zones_valid)
sbi->nfree_zones++;
return r;
}
errno_t
mfs_count_free_zones(struct mfs_instance *inst, uint32_t *zones)
{
return mfs_count_free_bits(inst, BMAP_ZONE, zones);
}
errno_t
mfs_count_free_inodes(struct mfs_instance *inst, uint32_t *inodes)
{
return mfs_count_free_bits(inst, BMAP_INODE, inodes);
}
static errno_t
mfs_count_free_bits(struct mfs_instance *inst, bmap_id_t bid, uint32_t *free)
{
errno_t r;
unsigned start_block;
unsigned long nblocks;
unsigned long nbits;
unsigned long block;
unsigned long free_bits = 0;
bitchunk_t chunk;
size_t const bitchunk_bits = sizeof(bitchunk_t) * 8;
block_t *b;
struct mfs_sb_info *sbi = inst->sbi;
start_block = MFS_BMAP_START_BLOCK(sbi, bid);
nblocks = MFS_BMAP_SIZE_BLOCKS(sbi, bid);
nbits = MFS_BMAP_SIZE_BITS(sbi, bid);
for (block = 0; block < nblocks; ++block) {
r = block_get(&b, inst->service_id, block + start_block,
BLOCK_FLAGS_NONE);
if (r != EOK)
return r;
size_t i;
bitchunk_t *data = (bitchunk_t *) b->data;
for (i = 0; i < sbi->block_size / sizeof(bitchunk_t); ++i) {
chunk = conv32(sbi->native, data[i]);
size_t bit;
for (bit = 0; bit < bitchunk_bits && nbits > 0;
++bit, --nbits) {
if (!(chunk & (1 << bit)))
free_bits++;
}
if (nbits == 0)
break;
}
r = block_put(b);
if (r != EOK)
return r;
}
*free = free_bits;
assert(nbits == 0);
return EOK;
}
static errno_t
mfs_free_bit(struct mfs_instance *inst, uint32_t idx, bmap_id_t bid)
{
struct mfs_sb_info *sbi;
errno_t r;
unsigned start_block;
unsigned *search;
block_t *b;
sbi = inst->sbi;
start_block = MFS_BMAP_START_BLOCK(sbi, bid);
if (bid == BMAP_ZONE) {
search = &sbi->zsearch;
if (idx > sbi->nzones) {
printf(NAME ": Error! Trying to free beyond the "
"bitmap max size\n");
return EIO;
}
} else {
search = &sbi->isearch;
if (idx > sbi->ninodes) {
printf(NAME ": Error! Trying to free beyond the "
"bitmap max size\n");
return EIO;
}
}
uint32_t block = idx / (sbi->block_size * 8) + start_block;
r = block_get(&b, inst->service_id, block, BLOCK_FLAGS_NONE);
if (r != EOK)
goto out_err;
idx %= (sbi->block_size * 8);
bitchunk_t *ptr = b->data;
bitchunk_t chunk;
const size_t chunk_bits = sizeof(bitchunk_t) * 8;
chunk = conv32(sbi->native, ptr[idx / chunk_bits]);
chunk &= ~(1 << (idx % chunk_bits));
ptr[idx / chunk_bits] = conv32(sbi->native, chunk);
b->dirty = true;
r = block_put(b);
if (*search > idx)
*search = idx;
out_err:
return r;
}
static errno_t
mfs_alloc_bit(struct mfs_instance *inst, uint32_t *idx, bmap_id_t bid)
{
struct mfs_sb_info *sbi;
uint32_t limit;
unsigned long nblocks;
unsigned *search, i, start_block;
unsigned bits_per_block;
errno_t r;
int freebit;
sbi = inst->sbi;
start_block = MFS_BMAP_START_BLOCK(sbi, bid);
limit = MFS_BMAP_SIZE_BITS(sbi, bid);
nblocks = MFS_BMAP_SIZE_BLOCKS(sbi, bid);
if (bid == BMAP_ZONE) {
search = &sbi->zsearch;
} else {
search = &sbi->isearch;
}
bits_per_block = sbi->block_size * 8;
block_t *b;
retry:
for (i = *search / bits_per_block; i < nblocks; ++i) {
r = block_get(&b, inst->service_id, i + start_block,
BLOCK_FLAGS_NONE);
if (r != EOK)
goto out;
unsigned tmp = *search % bits_per_block;
freebit = find_free_bit_and_set(b->data, sbi->block_size,
sbi->native, tmp);
if (freebit == -1) {
r = block_put(b);
if (r != EOK)
goto out;
continue;
}
*idx = freebit + bits_per_block * i;
if (*idx > limit) {
r = block_put(b);
if (r != EOK)
goto out;
break;
}
*search = *idx;
b->dirty = true;
r = block_put(b);
goto out;
}
if (*search > 0) {
*search = 0;
goto retry;
}
return ENOSPC;
out:
return r;
}
static int
find_free_bit_and_set(bitchunk_t *b, const int bsize,
const bool native, unsigned start_bit)
{
int r = -1;
unsigned i, j;
bitchunk_t chunk;
const size_t chunk_bits = sizeof(bitchunk_t) * 8;
for (i = start_bit / chunk_bits;
i < bsize / sizeof(bitchunk_t); ++i) {
if (!(~b[i])) {
continue;
}
chunk = conv32(native, b[i]);
for (j = 0; j < chunk_bits; ++j) {
if (!(chunk & (1 << j))) {
r = i * chunk_bits + j;
chunk |= 1 << j;
b[i] = conv32(native, chunk);
goto found;
}
}
}
found:
return r;
}
HelenOS homepage, sources at GitHub