Subversion Repositories HelenOS

Compare Revisions

Ignore whitespace Rev 3539 → Rev 3540

/trunk/uspace/lib/libblock/libblock.c
262,7 → 262,7
if (!cache)
return ENOMEM;
futex_initialize(&cache->lock, 0);
futex_initialize(&cache->lock, 1);
list_initialize(&cache->free_head);
cache->block_size = size;
cache->block_count = blocks;
336,40 → 336,109
return EOK;
}
 
block_t *block_get(dev_handle_t dev_handle, off_t offset, size_t bs)
static bool cache_can_grow(cache_t *cache)
{
/* FIXME */
return true;
}
 
static void block_initialize(block_t *b)
{
futex_initialize(&b->lock, 1);
b->refcnt = 1;
b->dirty = false;
rwlock_initialize(&b->contents_lock);
link_initialize(&b->free_link);
link_initialize(&b->hash_link);
}
 
/** Instantiate a block in memory and get a reference to it.
*
* @param dev_handle Device handle of the block device.
* @param boff Block offset.
*
* @return Block structure.
*/
block_t *block_get(dev_handle_t dev_handle, off_t boff, size_t bs)
{
devcon_t *devcon;
cache_t *cache;
block_t *b;
off_t bufpos = 0;
size_t buflen = 0;
off_t pos = offset * bs;
link_t *l;
unsigned long key = boff;
devcon = devcon_search(dev_handle);
 
b = malloc(sizeof(block_t));
if (!b)
return NULL;
assert(devcon);
assert(devcon->cache);
b->data = malloc(bs);
if (!b->data) {
free(b);
return NULL;
}
b->size = bs;
cache = devcon->cache;
futex_down(&cache->lock);
l = hash_table_find(&cache->block_hash, &key);
if (l) {
/*
* We found the block in the cache.
*/
b = hash_table_get_instance(l, block_t, hash_link);
futex_down(&b->lock);
if (b->refcnt++ == 0)
list_remove(&b->free_link);
futex_up(&b->lock);
} else {
/*
* The block was not found in the cache.
*/
int rc;
off_t bufpos = 0;
size_t buflen = 0;
off_t pos = boff * cache->block_size;
 
if (block_read(dev_handle, &bufpos, &buflen, &pos, b->data,
bs, bs) != EOK) {
free(b->data);
free(b);
return NULL;
if (cache_can_grow(cache)) {
/*
* We can grow the cache by allocating new blocks.
* Should the allocation fail, we fail over and try to
* recycle a block from the cache.
*/
b = malloc(sizeof(block_t));
if (!b)
goto recycle;
b->data = malloc(cache->block_size);
if (!b->data) {
free(b);
goto recycle;
}
} else {
/*
* Try to recycle a block from the free list.
*/
unsigned long temp_key;
recycle:
assert(!list_empty(&cache->free_head));
l = cache->free_head.next;
list_remove(l);
b = hash_table_get_instance(l, block_t, hash_link);
assert(!b->dirty);
temp_key = b->boff;
hash_table_remove(&cache->block_hash, &temp_key, 1);
}
 
block_initialize(b);
b->dev_handle = dev_handle;
b->size = cache->block_size;
b->boff = boff;
/* read block from the device */
rc = block_read(dev_handle, &bufpos, &buflen, &pos, b->data,
cache->block_size, cache->block_size);
assert(rc == EOK);
hash_table_insert(&cache->block_hash, &key, &b->hash_link);
}
 
futex_up(&cache->lock);
return b;
}
 
void block_put(block_t *block)
{
/* FIXME */
free(block->data);
free(block);
}
 
/** @}