00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00039 #include "tmpfs.h"
00040 #include "../../vfs/vfs.h"
00041 #include <macros.h>
00042 #include <stdint.h>
00043 #include <async.h>
00044 #include <errno.h>
00045 #include <atomic.h>
00046 #include <stdlib.h>
00047 #include <str.h>
00048 #include <stdio.h>
00049 #include <assert.h>
00050 #include <sys/types.h>
00051 #include <adt/hash_table.h>
00052 #include <as.h>
00053 #include <libfs.h>
00054
00055 #define min(a, b) ((a) < (b) ? (a) : (b))
00056 #define max(a, b) ((a) > (b) ? (a) : (b))
00057
00058 #define NODES_BUCKETS 256
00059
00061 #define TMPFS_SOME_ROOT 0
00062
00063 fs_index_t tmpfs_next_index = 1;
00064
00065
00066
00067
00068
00069
00070 static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
00071 static int tmpfs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
00072 static int tmpfs_node_open(fs_node_t *);
00073 static int tmpfs_node_put(fs_node_t *);
00074 static int tmpfs_create_node(fs_node_t **, devmap_handle_t, int);
00075 static int tmpfs_destroy_node(fs_node_t *);
00076 static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
00077 static int tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
00078
00079
00080 static int tmpfs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
00081 {
00082 return tmpfs_node_get(rfn, devmap_handle, TMPFS_SOME_ROOT);
00083 }
00084
00085 static int tmpfs_has_children(bool *has_children, fs_node_t *fn)
00086 {
00087 *has_children = !list_empty(&TMPFS_NODE(fn)->cs_head);
00088 return EOK;
00089 }
00090
00091 static fs_index_t tmpfs_index_get(fs_node_t *fn)
00092 {
00093 return TMPFS_NODE(fn)->index;
00094 }
00095
00096 static aoff64_t tmpfs_size_get(fs_node_t *fn)
00097 {
00098 return TMPFS_NODE(fn)->size;
00099 }
00100
00101 static unsigned tmpfs_lnkcnt_get(fs_node_t *fn)
00102 {
00103 return TMPFS_NODE(fn)->lnkcnt;
00104 }
00105
00106 static char tmpfs_plb_get_char(unsigned pos)
00107 {
00108 return tmpfs_reg.plb_ro[pos % PLB_SIZE];
00109 }
00110
00111 static bool tmpfs_is_directory(fs_node_t *fn)
00112 {
00113 return TMPFS_NODE(fn)->type == TMPFS_DIRECTORY;
00114 }
00115
00116 static bool tmpfs_is_file(fs_node_t *fn)
00117 {
00118 return TMPFS_NODE(fn)->type == TMPFS_FILE;
00119 }
00120
00121 static devmap_handle_t tmpfs_device_get(fs_node_t *fn)
00122 {
00123 return 0;
00124 }
00125
00127 libfs_ops_t tmpfs_libfs_ops = {
00128 .root_get = tmpfs_root_get,
00129 .match = tmpfs_match,
00130 .node_get = tmpfs_node_get,
00131 .node_open = tmpfs_node_open,
00132 .node_put = tmpfs_node_put,
00133 .create = tmpfs_create_node,
00134 .destroy = tmpfs_destroy_node,
00135 .link = tmpfs_link_node,
00136 .unlink = tmpfs_unlink_node,
00137 .has_children = tmpfs_has_children,
00138 .index_get = tmpfs_index_get,
00139 .size_get = tmpfs_size_get,
00140 .lnkcnt_get = tmpfs_lnkcnt_get,
00141 .plb_get_char = tmpfs_plb_get_char,
00142 .is_directory = tmpfs_is_directory,
00143 .is_file = tmpfs_is_file,
00144 .device_get = tmpfs_device_get
00145 };
00146
00148 hash_table_t nodes;
00149
00150 #define NODES_KEY_DEV 0
00151 #define NODES_KEY_INDEX 1
00152
00153
00154 static hash_index_t nodes_hash(unsigned long key[])
00155 {
00156 return key[NODES_KEY_INDEX] % NODES_BUCKETS;
00157 }
00158
00159 static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
00160 {
00161 tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
00162 nh_link);
00163
00164 switch (keys) {
00165 case 1:
00166 return (nodep->devmap_handle == key[NODES_KEY_DEV]);
00167 case 2:
00168 return ((nodep->devmap_handle == key[NODES_KEY_DEV]) &&
00169 (nodep->index == key[NODES_KEY_INDEX]));
00170 default:
00171 assert((keys == 1) || (keys == 2));
00172 }
00173
00174 return 0;
00175 }
00176
00177 static void nodes_remove_callback(link_t *item)
00178 {
00179 tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
00180 nh_link);
00181
00182 while (!list_empty(&nodep->cs_head)) {
00183 tmpfs_dentry_t *dentryp = list_get_instance(nodep->cs_head.next,
00184 tmpfs_dentry_t, link);
00185
00186 assert(nodep->type == TMPFS_DIRECTORY);
00187 list_remove(&dentryp->link);
00188 free(dentryp);
00189 }
00190
00191 if (nodep->data) {
00192 assert(nodep->type == TMPFS_FILE);
00193 free(nodep->data);
00194 }
00195 free(nodep->bp);
00196 free(nodep);
00197 }
00198
00200 hash_table_operations_t nodes_ops = {
00201 .hash = nodes_hash,
00202 .compare = nodes_compare,
00203 .remove_callback = nodes_remove_callback
00204 };
00205
00206 static void tmpfs_node_initialize(tmpfs_node_t *nodep)
00207 {
00208 nodep->bp = NULL;
00209 nodep->index = 0;
00210 nodep->devmap_handle = 0;
00211 nodep->type = TMPFS_NONE;
00212 nodep->lnkcnt = 0;
00213 nodep->size = 0;
00214 nodep->data = NULL;
00215 link_initialize(&nodep->nh_link);
00216 list_initialize(&nodep->cs_head);
00217 }
00218
00219 static void tmpfs_dentry_initialize(tmpfs_dentry_t *dentryp)
00220 {
00221 link_initialize(&dentryp->link);
00222 dentryp->name = NULL;
00223 dentryp->node = NULL;
00224 }
00225
00226 bool tmpfs_init(void)
00227 {
00228 if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
00229 return false;
00230
00231 return true;
00232 }
00233
00234 static bool tmpfs_instance_init(devmap_handle_t devmap_handle)
00235 {
00236 fs_node_t *rfn;
00237 int rc;
00238
00239 rc = tmpfs_create_node(&rfn, devmap_handle, L_DIRECTORY);
00240 if (rc != EOK || !rfn)
00241 return false;
00242 TMPFS_NODE(rfn)->lnkcnt = 0;
00243 return true;
00244 }
00245
00246 static void tmpfs_instance_done(devmap_handle_t devmap_handle)
00247 {
00248 unsigned long key[] = {
00249 [NODES_KEY_DEV] = devmap_handle
00250 };
00251
00252
00253
00254
00255
00256
00257
00258 hash_table_remove(&nodes, key, 1);
00259 }
00260
00261 int tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
00262 {
00263 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
00264 link_t *lnk;
00265
00266 for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
00267 lnk = lnk->next) {
00268 tmpfs_dentry_t *dentryp;
00269 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
00270 if (!str_cmp(dentryp->name, component)) {
00271 *rfn = FS_NODE(dentryp->node);
00272 return EOK;
00273 }
00274 }
00275
00276 *rfn = NULL;
00277 return EOK;
00278 }
00279
00280 int tmpfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
00281 {
00282 unsigned long key[] = {
00283 [NODES_KEY_DEV] = devmap_handle,
00284 [NODES_KEY_INDEX] = index
00285 };
00286 link_t *lnk = hash_table_find(&nodes, key);
00287 if (lnk) {
00288 tmpfs_node_t *nodep;
00289 nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
00290 *rfn = FS_NODE(nodep);
00291 } else {
00292 *rfn = NULL;
00293 }
00294 return EOK;
00295 }
00296
00297 int tmpfs_node_open(fs_node_t *fn)
00298 {
00299
00300 return EOK;
00301 }
00302
00303 int tmpfs_node_put(fs_node_t *fn)
00304 {
00305
00306 return EOK;
00307 }
00308
00309 int tmpfs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
00310 {
00311 fs_node_t *rootfn;
00312 int rc;
00313
00314 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
00315
00316 tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
00317 if (!nodep)
00318 return ENOMEM;
00319 tmpfs_node_initialize(nodep);
00320 nodep->bp = malloc(sizeof(fs_node_t));
00321 if (!nodep->bp) {
00322 free(nodep);
00323 return ENOMEM;
00324 }
00325 fs_node_initialize(nodep->bp);
00326 nodep->bp->data = nodep;
00327
00328 rc = tmpfs_root_get(&rootfn, devmap_handle);
00329 assert(rc == EOK);
00330 if (!rootfn)
00331 nodep->index = TMPFS_SOME_ROOT;
00332 else
00333 nodep->index = tmpfs_next_index++;
00334 nodep->devmap_handle = devmap_handle;
00335 if (lflag & L_DIRECTORY)
00336 nodep->type = TMPFS_DIRECTORY;
00337 else
00338 nodep->type = TMPFS_FILE;
00339
00340
00341 unsigned long key[] = {
00342 [NODES_KEY_DEV] = nodep->devmap_handle,
00343 [NODES_KEY_INDEX] = nodep->index
00344 };
00345 hash_table_insert(&nodes, key, &nodep->nh_link);
00346 *rfn = FS_NODE(nodep);
00347 return EOK;
00348 }
00349
00350 int tmpfs_destroy_node(fs_node_t *fn)
00351 {
00352 tmpfs_node_t *nodep = TMPFS_NODE(fn);
00353
00354 assert(!nodep->lnkcnt);
00355 assert(list_empty(&nodep->cs_head));
00356
00357 unsigned long key[] = {
00358 [NODES_KEY_DEV] = nodep->devmap_handle,
00359 [NODES_KEY_INDEX] = nodep->index
00360 };
00361 hash_table_remove(&nodes, key, 2);
00362
00363
00364
00365
00366
00367 return EOK;
00368 }
00369
00370 int tmpfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00371 {
00372 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
00373 tmpfs_node_t *childp = TMPFS_NODE(cfn);
00374 tmpfs_dentry_t *dentryp;
00375 link_t *lnk;
00376
00377 assert(parentp->type == TMPFS_DIRECTORY);
00378
00379
00380 for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
00381 lnk = lnk->next) {
00382 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
00383 if (!str_cmp(dentryp->name, nm))
00384 return EEXIST;
00385 }
00386
00387
00388 dentryp = malloc(sizeof(tmpfs_dentry_t));
00389 if (!dentryp)
00390 return ENOMEM;
00391 tmpfs_dentry_initialize(dentryp);
00392
00393
00394 size_t size = str_size(nm);
00395 dentryp->name = malloc(size + 1);
00396 if (!dentryp->name) {
00397 free(dentryp);
00398 return ENOMEM;
00399 }
00400 str_cpy(dentryp->name, size + 1, nm);
00401 dentryp->node = childp;
00402 childp->lnkcnt++;
00403 list_append(&dentryp->link, &parentp->cs_head);
00404
00405 return EOK;
00406 }
00407
00408 int tmpfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
00409 {
00410 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
00411 tmpfs_node_t *childp = NULL;
00412 tmpfs_dentry_t *dentryp;
00413 link_t *lnk;
00414
00415 if (!parentp)
00416 return EBUSY;
00417
00418 for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
00419 lnk = lnk->next) {
00420 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
00421 if (!str_cmp(dentryp->name, nm)) {
00422 childp = dentryp->node;
00423 assert(FS_NODE(childp) == cfn);
00424 break;
00425 }
00426 }
00427
00428 if (!childp)
00429 return ENOENT;
00430
00431 if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_head))
00432 return ENOTEMPTY;
00433
00434 list_remove(&dentryp->link);
00435 free(dentryp);
00436 childp->lnkcnt--;
00437
00438 return EOK;
00439 }
00440
00441 void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request)
00442 {
00443 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00444 fs_node_t *rootfn;
00445 int rc;
00446
00447
00448 char *opts;
00449 rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
00450 if (rc != EOK) {
00451 async_answer_0(rid, rc);
00452 return;
00453 }
00454
00455
00456 rc = tmpfs_root_get(&rootfn, devmap_handle);
00457 if ((rc == EOK) && (rootfn)) {
00458 (void) tmpfs_node_put(rootfn);
00459 free(opts);
00460 async_answer_0(rid, EEXIST);
00461 return;
00462 }
00463
00464
00465 if (!tmpfs_instance_init(devmap_handle)) {
00466 free(opts);
00467 async_answer_0(rid, ENOMEM);
00468 return;
00469 }
00470
00471 rc = tmpfs_root_get(&rootfn, devmap_handle);
00472 assert(rc == EOK);
00473 tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
00474 if (str_cmp(opts, "restore") == 0) {
00475 if (tmpfs_restore(devmap_handle))
00476 async_answer_3(rid, EOK, rootp->index, rootp->size,
00477 rootp->lnkcnt);
00478 else
00479 async_answer_0(rid, ELIMIT);
00480 } else {
00481 async_answer_3(rid, EOK, rootp->index, rootp->size,
00482 rootp->lnkcnt);
00483 }
00484 free(opts);
00485 }
00486
00487 void tmpfs_mount(ipc_callid_t rid, ipc_call_t *request)
00488 {
00489 libfs_mount(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00490 }
00491
00492 void tmpfs_unmounted(ipc_callid_t rid, ipc_call_t *request)
00493 {
00494 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00495
00496 tmpfs_instance_done(devmap_handle);
00497 async_answer_0(rid, EOK);
00498 }
00499
00500 void tmpfs_unmount(ipc_callid_t rid, ipc_call_t *request)
00501 {
00502 libfs_unmount(&tmpfs_libfs_ops, rid, request);
00503 }
00504
00505 void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request)
00506 {
00507 libfs_lookup(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00508 }
00509
00510 void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
00511 {
00512 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00513 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00514 aoff64_t pos =
00515 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
00516
00517
00518
00519
00520 link_t *hlp;
00521 unsigned long key[] = {
00522 [NODES_KEY_DEV] = devmap_handle,
00523 [NODES_KEY_INDEX] = index
00524 };
00525 hlp = hash_table_find(&nodes, key);
00526 if (!hlp) {
00527 async_answer_0(rid, ENOENT);
00528 return;
00529 }
00530 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00531 nh_link);
00532
00533
00534
00535
00536 ipc_callid_t callid;
00537 size_t size;
00538 if (!async_data_read_receive(&callid, &size)) {
00539 async_answer_0(callid, EINVAL);
00540 async_answer_0(rid, EINVAL);
00541 return;
00542 }
00543
00544 size_t bytes;
00545 if (nodep->type == TMPFS_FILE) {
00546 bytes = min(nodep->size - pos, size);
00547 (void) async_data_read_finalize(callid, nodep->data + pos,
00548 bytes);
00549 } else {
00550 tmpfs_dentry_t *dentryp;
00551 link_t *lnk;
00552 aoff64_t i;
00553
00554 assert(nodep->type == TMPFS_DIRECTORY);
00555
00556
00557
00558
00559
00560
00561 for (i = 0, lnk = nodep->cs_head.next;
00562 (i < pos) && (lnk != &nodep->cs_head);
00563 i++, lnk = lnk->next)
00564 ;
00565
00566 if (lnk == &nodep->cs_head) {
00567 async_answer_0(callid, ENOENT);
00568 async_answer_1(rid, ENOENT, 0);
00569 return;
00570 }
00571
00572 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
00573
00574 (void) async_data_read_finalize(callid, dentryp->name,
00575 str_size(dentryp->name) + 1);
00576 bytes = 1;
00577 }
00578
00579
00580
00581
00582 async_answer_1(rid, EOK, bytes);
00583 }
00584
00585 void tmpfs_write(ipc_callid_t rid, ipc_call_t *request)
00586 {
00587 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00588 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00589 aoff64_t pos =
00590 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
00591
00592
00593
00594
00595 link_t *hlp;
00596 unsigned long key[] = {
00597 [NODES_KEY_DEV] = devmap_handle,
00598 [NODES_KEY_INDEX] = index
00599 };
00600 hlp = hash_table_find(&nodes, key);
00601 if (!hlp) {
00602 async_answer_0(rid, ENOENT);
00603 return;
00604 }
00605 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00606 nh_link);
00607
00608
00609
00610
00611 ipc_callid_t callid;
00612 size_t size;
00613 if (!async_data_write_receive(&callid, &size)) {
00614 async_answer_0(callid, EINVAL);
00615 async_answer_0(rid, EINVAL);
00616 return;
00617 }
00618
00619
00620
00621
00622 if (pos + size <= nodep->size) {
00623
00624 (void) async_data_write_finalize(callid, nodep->data + pos, size);
00625 async_answer_2(rid, EOK, size, nodep->size);
00626 return;
00627 }
00628 size_t delta = (pos + size) - nodep->size;
00629
00630
00631
00632
00633
00634
00635
00636 void *newdata = realloc(nodep->data, nodep->size + delta);
00637 if (!newdata) {
00638 async_answer_0(callid, ENOMEM);
00639 async_answer_2(rid, EOK, 0, nodep->size);
00640 return;
00641 }
00642
00643 memset(newdata + nodep->size, 0, delta);
00644 nodep->size += delta;
00645 nodep->data = newdata;
00646 (void) async_data_write_finalize(callid, nodep->data + pos, size);
00647 async_answer_2(rid, EOK, size, nodep->size);
00648 }
00649
00650 void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request)
00651 {
00652 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
00653 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
00654 aoff64_t size =
00655 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
00656
00657
00658
00659
00660 unsigned long key[] = {
00661 [NODES_KEY_DEV] = devmap_handle,
00662 [NODES_KEY_INDEX] = index
00663 };
00664 link_t *hlp = hash_table_find(&nodes, key);
00665 if (!hlp) {
00666 async_answer_0(rid, ENOENT);
00667 return;
00668 }
00669 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00670 nh_link);
00671
00672 if (size == nodep->size) {
00673 async_answer_0(rid, EOK);
00674 return;
00675 }
00676
00677 if (size > SIZE_MAX) {
00678 async_answer_0(rid, ENOMEM);
00679 return;
00680 }
00681
00682 void *newdata = realloc(nodep->data, size);
00683 if (!newdata) {
00684 async_answer_0(rid, ENOMEM);
00685 return;
00686 }
00687
00688 if (size > nodep->size) {
00689 size_t delta = size - nodep->size;
00690 memset(newdata + nodep->size, 0, delta);
00691 }
00692
00693 nodep->size = size;
00694 nodep->data = newdata;
00695 async_answer_0(rid, EOK);
00696 }
00697
00698 void tmpfs_close(ipc_callid_t rid, ipc_call_t *request)
00699 {
00700 async_answer_0(rid, EOK);
00701 }
00702
00703 void tmpfs_destroy(ipc_callid_t rid, ipc_call_t *request)
00704 {
00705 devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
00706 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
00707 int rc;
00708
00709 link_t *hlp;
00710 unsigned long key[] = {
00711 [NODES_KEY_DEV] = devmap_handle,
00712 [NODES_KEY_INDEX] = index
00713 };
00714 hlp = hash_table_find(&nodes, key);
00715 if (!hlp) {
00716 async_answer_0(rid, ENOENT);
00717 return;
00718 }
00719 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
00720 nh_link);
00721 rc = tmpfs_destroy_node(FS_NODE(nodep));
00722 async_answer_0(rid, rc);
00723 }
00724
00725 void tmpfs_open_node(ipc_callid_t rid, ipc_call_t *request)
00726 {
00727 libfs_open_node(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00728 }
00729
00730 void tmpfs_stat(ipc_callid_t rid, ipc_call_t *request)
00731 {
00732 libfs_stat(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
00733 }
00734
00735 void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request)
00736 {
00737
00738
00739
00740
00741 async_answer_0(rid, EOK);
00742 }
00743