/branches/dynload/uspace/srv/fs/fat/fat_idx.c |
---|
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; |
190,22 → 216,13 |
/** Allocate a VFS index which is not currently in use. */ |
static bool fat_idx_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) { |
/* |
261,21 → 278,11 |
/** Free a VFS index, which is no longer in use. */ |
static void fat_idx_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--; |
401,3 → 408,60 |
return fidx; |
} |
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); |
} |
/** |
* @} |
*/ |
/branches/dynload/uspace/srv/fs/fat/fat.h |
---|
40,7 → 40,9 |
#include <bool.h> |
#include "../../vfs/vfs.h" |
#ifndef dprintf |
#define dprintf(...) printf(__VA_ARGS__) |
#endif |
typedef struct { |
uint8_t ji[3]; /**< Jump instruction. */ |
217,11 → 219,18 |
extern fs_reg_t fat_reg; |
extern void fat_mounted(ipc_callid_t, ipc_call_t *); |
extern void fat_mount(ipc_callid_t, ipc_call_t *); |
extern void fat_lookup(ipc_callid_t, ipc_call_t *); |
extern fat_idx_t *fat_idx_get_by_pos(dev_handle_t, fat_cluster_t, unsigned); |
extern fat_idx_t *fat_idx_get_by_index(dev_handle_t, fs_index_t); |
extern int fat_idx_init(void); |
extern void fat_idx_fini(void); |
extern int fat_idx_init_by_dev_handle(dev_handle_t); |
extern void fat_idx_fini_by_dev_handle(dev_handle_t); |
#endif |
/** |
/branches/dynload/uspace/srv/fs/fat/fat.c |
---|
55,6 → 55,7 |
[IPC_METHOD_TO_VFS_OP(VFS_WRITE)] = VFS_OP_NULL, |
[IPC_METHOD_TO_VFS_OP(VFS_TRUNCATE)] = VFS_OP_NULL, |
[IPC_METHOD_TO_VFS_OP(VFS_MOUNT)] = VFS_OP_NULL, |
[IPC_METHOD_TO_VFS_OP(VFS_MOUNTED)] = VFS_OP_DEFINED, |
[IPC_METHOD_TO_VFS_OP(VFS_UNMOUNT)] = VFS_OP_NULL, |
} |
}; |
97,6 → 98,12 |
callid = async_get_call(&call); |
switch (IPC_GET_METHOD(call)) { |
case VFS_MOUNTED: |
fat_mounted(callid, &call); |
break; |
case VFS_MOUNT: |
fat_mount(callid, &call); |
break; |
case VFS_LOOKUP: |
fat_lookup(callid, &call); |
break; |
110,9 → 117,14 |
int main(int argc, char **argv) |
{ |
int vfs_phone; |
int rc; |
printf("FAT: HelenOS FAT file system server.\n"); |
rc = fat_idx_init(); |
if (rc != EOK) |
goto err; |
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0); |
while (vfs_phone < EOK) { |
usleep(10000); |
119,11 → 131,10 |
vfs_phone = ipc_connect_me_to(PHONE_NS, SERVICE_VFS, 0, 0); |
} |
int rc; |
rc = fs_register(vfs_phone, &fat_reg, &fat_vfs_info, fat_connection); |
if (rc != EOK) { |
printf("Failed to register the FAT file system (%d)\n", rc); |
return rc; |
fat_idx_fini(); |
goto err; |
} |
dprintf("FAT filesystem registered, fs_handle=%d.\n", |
132,6 → 143,10 |
async_manager(); |
/* not reached */ |
return 0; |
err: |
printf("Failed to register the FAT file system (%d)\n", rc); |
return rc; |
} |
/** |
/branches/dynload/uspace/srv/fs/fat/fat_ops.c |
---|
112,12 → 112,17 |
#define FAT_BS(b) ((fat_bs_t *)((b)->data)) |
#define FAT_CLST_RES0 0x0000 |
#define FAT_CLST_RES1 0x0001 /* internally used to mark root directory */ |
#define FAT_CLST_RES1 0x0001 |
#define FAT_CLST_FIRST 0x0002 |
#define FAT_CLST_BAD 0xfff7 |
#define FAT_CLST_LAST1 0xfff8 |
#define FAT_CLST_LAST8 0xffff |
/* internally used to mark root directory's parent */ |
#define FAT_CLST_ROOTPAR FAT_CLST_RES0 |
/* internally used to mark root directory */ |
#define FAT_CLST_ROOT FAT_CLST_RES1 |
#define fat_block_get(np, off) \ |
_fat_block_get((np)->idx->dev_handle, (np)->firstc, (off)) |
151,7 → 156,7 |
rds += ((sizeof(fat_dentry_t) * rde) % bps != 0); |
ssa = rscnt + fatcnt * sf + rds; |
if (firstc == FAT_CLST_RES1) { |
if (firstc == FAT_CLST_ROOT) { |
/* root directory special case */ |
assert(offset < rds); |
b = block_get(dev_handle, rscnt + fatcnt * sf + offset); |
521,7 → 526,7 |
static void *fat_root_get(dev_handle_t dev_handle) |
{ |
return NULL; /* TODO */ |
return fat_node_get(dev_handle, 0); |
} |
static char fat_plb_get_char(unsigned pos) |
558,6 → 563,60 |
.is_file = fat_is_file |
}; |
void fat_mounted(ipc_callid_t rid, ipc_call_t *request) |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
block_t *bb; |
uint16_t rde; |
int rc; |
/* Read the number of root directory entries. */ |
bb = block_get(dev_handle, BS_BLOCK); |
rde = uint16_t_le2host(FAT_BS(bb)->root_ent_max); |
block_put(bb); |
rc = fat_idx_init_by_dev_handle(dev_handle); |
if (rc != EOK) { |
ipc_answer_0(rid, rc); |
return; |
} |
/* Initialize the root node. */ |
fat_node_t *rootp = (fat_node_t *)malloc(sizeof(fat_node_t)); |
if (!rootp) { |
fat_idx_fini_by_dev_handle(dev_handle); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
fat_node_initialize(rootp); |
fat_idx_t *ridxp = fat_idx_get_by_pos(dev_handle, FAT_CLST_ROOTPAR, 0); |
if (!ridxp) { |
free(rootp); |
fat_idx_fini_by_dev_handle(dev_handle); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
assert(ridxp->index == 0); |
/* ridxp->lock held */ |
rootp->type = FAT_DIRECTORY; |
rootp->firstc = FAT_CLST_ROOT; |
rootp->refcnt = 1; |
rootp->size = rde * sizeof(fat_dentry_t); |
rootp->idx = ridxp; |
ridxp->nodep = rootp; |
futex_up(&ridxp->lock); |
ipc_answer_0(rid, EOK); |
} |
void fat_mount(ipc_callid_t rid, ipc_call_t *request) |
{ |
ipc_answer_0(rid, ENOTSUP); |
} |
void fat_lookup(ipc_callid_t rid, ipc_call_t *request) |
{ |
libfs_lookup(&fat_libfs_ops, fat_reg.fs_handle, rid, request); |