58,14 → 58,11 |
|
#define NAMES_BUCKETS 4 |
|
/* |
* For now, we don't distinguish between different dev_handles/instances. All |
* requests resolve to the only instance, rooted in the following variable. |
*/ |
static tmpfs_dentry_t *root; |
/** All root nodes have index 0. */ |
#define TMPFS_SOME_ROOT 0 |
/** Global counter for assigning node indices. Shared by all instances. */ |
fs_index_t tmpfs_next_index = 1; |
|
#define TMPFS_DEV 0 /**< Dummy device handle for TMPFS */ |
|
/* |
* Implementation of the libfs interface. |
*/ |
102,7 → 99,7 |
|
static void *tmpfs_root_get(dev_handle_t dev_handle) |
{ |
return root; |
return tmpfs_node_get(dev_handle, TMPFS_SOME_ROOT); |
} |
|
static char tmpfs_plb_get_char(unsigned pos) |
142,18 → 139,22 |
/** Hash table of all directory entries. */ |
hash_table_t dentries; |
|
#define DENTRIES_KEY_INDEX 0 |
#define DENTRIES_KEY_DEV 1 |
|
/* Implementation of hash table interface for the dentries hash table. */ |
static hash_index_t dentries_hash(unsigned long *key) |
static hash_index_t dentries_hash(unsigned long key[]) |
{ |
return *key % DENTRIES_BUCKETS; |
return key[DENTRIES_KEY_INDEX] % DENTRIES_BUCKETS; |
} |
|
static int dentries_compare(unsigned long *key, hash_count_t keys, |
static int dentries_compare(unsigned long key[], hash_count_t keys, |
link_t *item) |
{ |
tmpfs_dentry_t *dentry = hash_table_get_instance(item, tmpfs_dentry_t, |
dh_link); |
return dentry->index == *key; |
return (dentry->index == key[DENTRIES_KEY_INDEX] && |
dentry->dev_handle == key[DENTRIES_KEY_DEV]); |
} |
|
static void dentries_remove_callback(link_t *item) |
167,8 → 168,6 |
.remove_callback = dentries_remove_callback |
}; |
|
fs_index_t tmpfs_next_index = 1; |
|
typedef struct { |
char *name; |
tmpfs_dentry_t *parent; |
215,6 → 214,7 |
static bool tmpfs_dentry_initialize(tmpfs_dentry_t *dentry) |
{ |
dentry->index = 0; |
dentry->dev_handle = 0; |
dentry->sibling = NULL; |
dentry->child = NULL; |
dentry->type = TMPFS_NONE; |
226,15 → 226,21 |
&names_ops); |
} |
|
static bool tmpfs_init(void) |
bool tmpfs_init(void) |
{ |
if (!hash_table_create(&dentries, DENTRIES_BUCKETS, 1, &dentries_ops)) |
if (!hash_table_create(&dentries, DENTRIES_BUCKETS, 2, &dentries_ops)) |
return false; |
root = (tmpfs_dentry_t *) tmpfs_create_node(TMPFS_DEV, L_DIRECTORY); |
if (!root) { |
hash_table_destroy(&dentries); |
|
return true; |
} |
|
static bool tmpfs_instance_init(dev_handle_t dev_handle) |
{ |
tmpfs_dentry_t *root; |
|
root = (tmpfs_dentry_t *) tmpfs_create_node(dev_handle, L_DIRECTORY); |
if (!root) |
return false; |
} |
root->lnkcnt = 0; /* FS root is not linked */ |
return true; |
} |
255,7 → 261,7 |
link_t *hlp = hash_table_find(&childp->names, &key); |
assert(hlp); |
tmpfs_name_t *namep = hash_table_get_instance(hlp, tmpfs_name_t, link); |
return !strcmp(namep->name, component); |
return !str_cmp(namep->name, component); |
} |
|
void *tmpfs_match(void *prnt, const char *component) |
272,8 → 278,11 |
void * |
tmpfs_node_get(dev_handle_t dev_handle, fs_index_t index) |
{ |
unsigned long key = index; |
link_t *lnk = hash_table_find(&dentries, &key); |
unsigned long key[] = { |
[DENTRIES_KEY_INDEX] = index, |
[DENTRIES_KEY_DEV] = dev_handle |
}; |
link_t *lnk = hash_table_find(&dentries, key); |
if (!lnk) |
return NULL; |
return hash_table_get_instance(lnk, tmpfs_dentry_t, dh_link); |
296,7 → 305,11 |
free(node); |
return NULL; |
} |
node->index = tmpfs_next_index++; |
if (!tmpfs_root_get(dev_handle)) |
node->index = TMPFS_SOME_ROOT; |
else |
node->index = tmpfs_next_index++; |
node->dev_handle = dev_handle; |
if (lflag & L_DIRECTORY) |
node->type = TMPFS_DIRECTORY; |
else |
303,8 → 316,11 |
node->type = TMPFS_FILE; |
|
/* Insert the new node into the dentry hash table. */ |
unsigned long key = node->index; |
hash_table_insert(&dentries, &key, &node->dh_link); |
unsigned long key[] = { |
[DENTRIES_KEY_INDEX] = node->index, |
[DENTRIES_KEY_DEV] = node->dev_handle |
}; |
hash_table_insert(&dentries, key, &node->dh_link); |
return (void *) node; |
} |
|
319,13 → 335,13 |
if (!namep) |
return ENOMEM; |
tmpfs_name_initialize(namep); |
size_t len = strlen(nm); |
namep->name = malloc(len + 1); |
size_t size = str_size(nm); |
namep->name = malloc(size + 1); |
if (!namep->name) { |
free(namep); |
return ENOMEM; |
} |
strcpy(namep->name, nm); |
str_cpy(namep->name, size + 1, nm); |
namep->parent = parentp; |
|
childp->lnkcnt++; |
384,8 → 400,11 |
assert(!dentry->child); |
assert(!dentry->sibling); |
|
unsigned long key = dentry->index; |
hash_table_remove(&dentries, &key, 1); |
unsigned long key[] = { |
[DENTRIES_KEY_INDEX] = dentry->index, |
[DENTRIES_KEY_DEV] = dentry->dev_handle |
}; |
hash_table_remove(&dentries, key, 2); |
|
hash_table_destroy(&dentry->names); |
|
399,13 → 418,36 |
{ |
dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request); |
|
/* Initialize TMPFS. */ |
if (!root && !tmpfs_init()) { |
/* accept the mount options */ |
ipc_callid_t callid; |
size_t size; |
if (!ipc_data_write_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
} |
char *opts = malloc(size + 1); |
if (!opts) { |
ipc_answer_0(callid, ENOMEM); |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
ipcarg_t retval = ipc_data_write_finalize(callid, opts, size); |
if (retval != EOK) { |
ipc_answer_0(rid, retval); |
free(opts); |
return; |
} |
opts[size] = '\0'; |
|
if (dev_handle >= 0) { |
/* Initialize TMPFS instance. */ |
if (!tmpfs_instance_init(dev_handle)) { |
ipc_answer_0(rid, ENOMEM); |
return; |
} |
|
tmpfs_dentry_t *root = tmpfs_root_get(dev_handle); |
if (str_cmp(opts, "restore") == 0) { |
if (tmpfs_restore(dev_handle)) |
ipc_answer_3(rid, EOK, root->index, root->size, |
root->lnkcnt); |
441,8 → 483,11 |
* Lookup the respective dentry. |
*/ |
link_t *hlp; |
unsigned long key = index; |
hlp = hash_table_find(&dentries, &key); |
unsigned long key[] = { |
[DENTRIES_KEY_INDEX] = index, |
[DENTRIES_KEY_DEV] = dev_handle, |
}; |
hlp = hash_table_find(&dentries, key); |
if (!hlp) { |
ipc_answer_0(rid, ENOENT); |
return; |
454,8 → 499,8 |
* Receive the read request. |
*/ |
ipc_callid_t callid; |
size_t len; |
if (!ipc_data_read_receive(&callid, &len)) { |
size_t size; |
if (!ipc_data_read_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
463,7 → 508,7 |
|
size_t bytes; |
if (dentry->type == TMPFS_FILE) { |
bytes = max(0, min(dentry->size - pos, len)); |
bytes = max(0, min(dentry->size - pos, size)); |
(void) ipc_data_read_finalize(callid, dentry->data + pos, |
bytes); |
} else { |
494,7 → 539,7 |
link); |
|
(void) ipc_data_read_finalize(callid, namep->name, |
strlen(namep->name) + 1); |
str_size(namep->name) + 1); |
bytes = 1; |
} |
|
514,8 → 559,11 |
* Lookup the respective dentry. |
*/ |
link_t *hlp; |
unsigned long key = index; |
hlp = hash_table_find(&dentries, &key); |
unsigned long key[] = { |
[DENTRIES_KEY_INDEX] = index, |
[DENTRIES_KEY_DEV] = dev_handle |
}; |
hlp = hash_table_find(&dentries, key); |
if (!hlp) { |
ipc_answer_0(rid, ENOENT); |
return; |
527,8 → 575,8 |
* Receive the write request. |
*/ |
ipc_callid_t callid; |
size_t len; |
if (!ipc_data_write_receive(&callid, &len)) { |
size_t size; |
if (!ipc_data_write_receive(&callid, &size)) { |
ipc_answer_0(callid, EINVAL); |
ipc_answer_0(rid, EINVAL); |
return; |
537,13 → 585,13 |
/* |
* Check whether the file needs to grow. |
*/ |
if (pos + len <= dentry->size) { |
if (pos + size <= dentry->size) { |
/* The file size is not changing. */ |
(void) ipc_data_write_finalize(callid, dentry->data + pos, len); |
ipc_answer_2(rid, EOK, len, dentry->size); |
(void) ipc_data_write_finalize(callid, dentry->data + pos, size); |
ipc_answer_2(rid, EOK, size, dentry->size); |
return; |
} |
size_t delta = (pos + len) - dentry->size; |
size_t delta = (pos + size) - dentry->size; |
/* |
* At this point, we are deliberately extremely straightforward and |
* simply realloc the contents of the file on every write that grows the |
561,8 → 609,8 |
memset(newdata + dentry->size, 0, delta); |
dentry->size += delta; |
dentry->data = newdata; |
(void) ipc_data_write_finalize(callid, dentry->data + pos, len); |
ipc_answer_2(rid, EOK, len, dentry->size); |
(void) ipc_data_write_finalize(callid, dentry->data + pos, size); |
ipc_answer_2(rid, EOK, size, dentry->size); |
} |
|
void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request) |
575,8 → 623,11 |
* Lookup the respective dentry. |
*/ |
link_t *hlp; |
unsigned long key = index; |
hlp = hash_table_find(&dentries, &key); |
unsigned long key[] = { |
[DENTRIES_KEY_INDEX] = index, |
[DENTRIES_KEY_DEV] = dev_handle |
}; |
hlp = hash_table_find(&dentries, key); |
if (!hlp) { |
ipc_answer_0(rid, ENOENT); |
return; |
610,8 → 661,11 |
int rc; |
|
link_t *hlp; |
unsigned long key = index; |
hlp = hash_table_find(&dentries, &key); |
unsigned long key[] = { |
[DENTRIES_KEY_INDEX] = index, |
[DENTRIES_KEY_DEV] = dev_handle |
}; |
hlp = hash_table_find(&dentries, key); |
if (!hlp) { |
ipc_answer_0(rid, ENOENT); |
return; |