74,6 → 74,32 |
/** List of unused structures. */ |
static LIST_INITIALIZE(unused_head); |
|
static void unused_initialize(unused_t *u, dev_handle_t dev_handle) |
{ |
link_initialize(&u->link); |
u->dev_handle = dev_handle; |
u->next = 0; |
u->remaining = ((uint64_t)((fs_index_t)-1)) + 1; |
list_initialize(&u->freed_head); |
} |
|
static unused_t *unused_find(dev_handle_t dev_handle, bool lock) |
{ |
unused_t *u; |
link_t *l; |
|
if (lock) |
futex_down(&unused_futex); |
for (l = unused_head.next; l != &unused_head; l = l->next) { |
u = list_get_instance(l, unused_t, link); |
if (u->dev_handle == dev_handle) |
return u; |
} |
if (lock) |
futex_up(&unused_futex); |
return NULL; |
} |
|
/** Futex protecting the up_hash and ui_hash. */ |
static futex_t used_futex = FUTEX_INITIALIZER; |
|
188,24 → 214,15 |
}; |
|
/** Allocate a VFS index which is not currently in use. */ |
static bool fat_idx_alloc(dev_handle_t dev_handle, fs_index_t *index) |
static bool fat_index_alloc(dev_handle_t dev_handle, fs_index_t *index) |
{ |
link_t *l; |
unused_t *u; |
|
assert(index); |
futex_down(&unused_futex); |
for (l = unused_head.next; l != &unused_head; l = l->next) { |
u = list_get_instance(l, unused_t, link); |
if (u->dev_handle == dev_handle) |
goto hit; |
} |
futex_up(&unused_futex); |
|
/* dev_handle not found */ |
return false; |
u = unused_find(dev_handle, true); |
if (!u) |
return false; |
|
hit: |
if (list_empty(&u->freed_head)) { |
if (u->remaining) { |
/* |
259,23 → 276,13 |
} |
|
/** Free a VFS index, which is no longer in use. */ |
static void fat_idx_free(dev_handle_t dev_handle, fs_index_t index) |
static void fat_index_free(dev_handle_t dev_handle, fs_index_t index) |
{ |
link_t *l; |
unused_t *u; |
|
futex_down(&unused_futex); |
for (l = unused_head.next; l != &unused_head; l = l->next) { |
u = list_get_instance(l, unused_t, link); |
if (u->dev_handle == dev_handle) |
goto hit; |
} |
futex_up(&unused_futex); |
u = unused_find(dev_handle, true); |
assert(u); |
|
/* should not happen */ |
assert(0); |
|
hit: |
if (u->next == index + 1) { |
/* The index can be returned directly to the counter. */ |
u->next--; |
331,6 → 338,52 |
futex_up(&unused_futex); |
} |
|
static fat_idx_t *fat_idx_create(dev_handle_t dev_handle) |
{ |
fat_idx_t *fidx; |
|
fidx = (fat_idx_t *) malloc(sizeof(fat_idx_t)); |
if (!fidx) |
return NULL; |
if (!fat_index_alloc(dev_handle, &fidx->index)) { |
free(fidx); |
return NULL; |
} |
|
link_initialize(&fidx->uph_link); |
link_initialize(&fidx->uih_link); |
futex_initialize(&fidx->lock, 1); |
fidx->dev_handle = dev_handle; |
fidx->pfc = FAT_CLST_RES0; /* no parent yet */ |
fidx->pdi = 0; |
fidx->nodep = NULL; |
|
return fidx; |
} |
|
fat_idx_t *fat_idx_get_new(dev_handle_t dev_handle) |
{ |
fat_idx_t *fidx; |
|
futex_down(&used_futex); |
fidx = fat_idx_create(dev_handle); |
if (!fidx) { |
futex_up(&used_futex); |
return NULL; |
} |
|
unsigned long ikey[] = { |
[UIH_DH_KEY] = dev_handle, |
[UIH_INDEX_KEY] = fidx->index, |
}; |
|
hash_table_insert(&ui_hash, ikey, &fidx->uih_link); |
futex_down(&fidx->lock); |
futex_up(&used_futex); |
|
return fidx; |
} |
|
fat_idx_t * |
fat_idx_get_by_pos(dev_handle_t dev_handle, fat_cluster_t pfc, unsigned pdi) |
{ |
347,16 → 400,11 |
if (l) { |
fidx = hash_table_get_instance(l, fat_idx_t, uph_link); |
} else { |
fidx = (fat_idx_t *) malloc(sizeof(fat_idx_t)); |
fidx = fat_idx_create(dev_handle); |
if (!fidx) { |
futex_up(&used_futex); |
return NULL; |
} |
if (!fat_idx_alloc(dev_handle, &fidx->index)) { |
free(fidx); |
futex_up(&used_futex); |
return NULL; |
} |
|
unsigned long ikey[] = { |
[UIH_DH_KEY] = dev_handle, |
363,13 → 411,8 |
[UIH_INDEX_KEY] = fidx->index, |
}; |
|
link_initialize(&fidx->uph_link); |
link_initialize(&fidx->uih_link); |
futex_initialize(&fidx->lock, 1); |
fidx->dev_handle = dev_handle; |
fidx->pfc = pfc; |
fidx->pdi = pdi; |
fidx->nodep = NULL; |
|
hash_table_insert(&up_hash, pkey, &fidx->uph_link); |
hash_table_insert(&ui_hash, ikey, &fidx->uih_link); |
380,6 → 423,32 |
return fidx; |
} |
|
void fat_idx_hashin(fat_idx_t *idx) |
{ |
unsigned long pkey[] = { |
[UPH_DH_KEY] = idx->dev_handle, |
[UPH_PFC_KEY] = idx->pfc, |
[UPH_PDI_KEY] = idx->pdi, |
}; |
|
futex_down(&used_futex); |
hash_table_insert(&up_hash, pkey, &idx->uph_link); |
futex_up(&used_futex); |
} |
|
void fat_idx_hashout(fat_idx_t *idx) |
{ |
unsigned long pkey[] = { |
[UPH_DH_KEY] = idx->dev_handle, |
[UPH_PFC_KEY] = idx->pfc, |
[UPH_PDI_KEY] = idx->pdi, |
}; |
|
futex_down(&used_futex); |
hash_table_remove(&up_hash, pkey, 3); |
futex_up(&used_futex); |
} |
|
fat_idx_t * |
fat_idx_get_by_index(dev_handle_t dev_handle, fs_index_t index) |
{ |
401,3 → 470,87 |
return fidx; |
} |
|
/** Destroy the index structure. |
* |
* @param idx The index structure to be destroyed. |
*/ |
void fat_idx_destroy(fat_idx_t *idx) |
{ |
unsigned long ikey[] = { |
[UIH_DH_KEY] = idx->dev_handle, |
[UIH_INDEX_KEY] = idx->index, |
}; |
|
assert(idx->pfc == FAT_CLST_RES0); |
|
futex_down(&used_futex); |
/* |
* Since we can only free unlinked nodes, the index structure is not |
* present in the position hash (uph). We therefore hash it out from |
* the index hash only. |
*/ |
hash_table_remove(&ui_hash, ikey, 2); |
futex_up(&used_futex); |
/* Release the VFS index. */ |
fat_index_free(idx->dev_handle, idx->index); |
/* Deallocate the structure. */ |
free(idx); |
} |
|
int fat_idx_init(void) |
{ |
if (!hash_table_create(&up_hash, UPH_BUCKETS, 3, &uph_ops)) |
return ENOMEM; |
if (!hash_table_create(&ui_hash, UIH_BUCKETS, 2, &uih_ops)) { |
hash_table_destroy(&up_hash); |
return ENOMEM; |
} |
return EOK; |
} |
|
void fat_idx_fini(void) |
{ |
/* We assume the hash tables are empty. */ |
hash_table_destroy(&up_hash); |
hash_table_destroy(&ui_hash); |
} |
|
int fat_idx_init_by_dev_handle(dev_handle_t dev_handle) |
{ |
unused_t *u; |
int rc = EOK; |
|
u = (unused_t *) malloc(sizeof(unused_t)); |
if (!u) |
return ENOMEM; |
unused_initialize(u, dev_handle); |
futex_down(&unused_futex); |
if (!unused_find(dev_handle, false)) |
list_append(&u->link, &unused_head); |
else |
rc = EEXIST; |
futex_up(&unused_futex); |
return rc; |
} |
|
void fat_idx_fini_by_dev_handle(dev_handle_t dev_handle) |
{ |
unused_t *u; |
|
u = unused_find(dev_handle, true); |
assert(u); |
list_remove(&u->link); |
futex_up(&unused_futex); |
|
while (!list_empty(&u->freed_head)) { |
freed_t *f; |
f = list_get_instance(u->freed_head.next, freed_t, link); |
list_remove(&f->link); |
free(f); |
} |
free(u); |
} |
|
/** |
* @} |
*/ |