source: mainline/uspace/srv/fs/tmpfs/tmpfs_ops.c@ f1fae414

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f1fae414 was b72efe8, checked in by Jiri Svoboda <jiri@…>, 14 years ago

Separate list_t typedef from link_t (user-space part).

  • list_t represents lists
  • Use list_first(), list_last(), list_empty() where appropriate
  • Use list_foreach() where possible
  • assert_link_not_used()
  • usb_hid_report_path_free() shall not unlink the path, caller must do it
  • Property mode set to 100644
File size: 17.7 KB
Line 
1/*
2 * Copyright (c) 2008 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup fs
30 * @{
31 */
32
33/**
34 * @file tmpfs_ops.c
35 * @brief Implementation of VFS operations for the TMPFS file system
36 * server.
37 */
38
39#include "tmpfs.h"
40#include "../../vfs/vfs.h"
41#include <macros.h>
42#include <stdint.h>
43#include <async.h>
44#include <errno.h>
45#include <atomic.h>
46#include <stdlib.h>
47#include <str.h>
48#include <stdio.h>
49#include <assert.h>
50#include <sys/types.h>
51#include <adt/hash_table.h>
52#include <as.h>
53#include <libfs.h>
54
55#define min(a, b) ((a) < (b) ? (a) : (b))
56#define max(a, b) ((a) > (b) ? (a) : (b))
57
58#define NODES_BUCKETS 256
59
60/** All root nodes have index 0. */
61#define TMPFS_SOME_ROOT 0
62/** Global counter for assigning node indices. Shared by all instances. */
63fs_index_t tmpfs_next_index = 1;
64
65/*
66 * Implementation of the libfs interface.
67 */
68
69/* Forward declarations of static functions. */
70static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
71static int tmpfs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
72static int tmpfs_node_open(fs_node_t *);
73static int tmpfs_node_put(fs_node_t *);
74static int tmpfs_create_node(fs_node_t **, devmap_handle_t, int);
75static int tmpfs_destroy_node(fs_node_t *);
76static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
77static int tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
78
79/* Implementation of helper functions. */
80static int tmpfs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
81{
82 return tmpfs_node_get(rfn, devmap_handle, TMPFS_SOME_ROOT);
83}
84
85static int tmpfs_has_children(bool *has_children, fs_node_t *fn)
86{
87 *has_children = !list_empty(&TMPFS_NODE(fn)->cs_list);
88 return EOK;
89}
90
91static fs_index_t tmpfs_index_get(fs_node_t *fn)
92{
93 return TMPFS_NODE(fn)->index;
94}
95
96static aoff64_t tmpfs_size_get(fs_node_t *fn)
97{
98 return TMPFS_NODE(fn)->size;
99}
100
101static unsigned tmpfs_lnkcnt_get(fs_node_t *fn)
102{
103 return TMPFS_NODE(fn)->lnkcnt;
104}
105
106static char tmpfs_plb_get_char(unsigned pos)
107{
108 return tmpfs_reg.plb_ro[pos % PLB_SIZE];
109}
110
111static bool tmpfs_is_directory(fs_node_t *fn)
112{
113 return TMPFS_NODE(fn)->type == TMPFS_DIRECTORY;
114}
115
116static bool tmpfs_is_file(fs_node_t *fn)
117{
118 return TMPFS_NODE(fn)->type == TMPFS_FILE;
119}
120
121static devmap_handle_t tmpfs_device_get(fs_node_t *fn)
122{
123 return 0;
124}
125
126/** libfs operations */
127libfs_ops_t tmpfs_libfs_ops = {
128 .root_get = tmpfs_root_get,
129 .match = tmpfs_match,
130 .node_get = tmpfs_node_get,
131 .node_open = tmpfs_node_open,
132 .node_put = tmpfs_node_put,
133 .create = tmpfs_create_node,
134 .destroy = tmpfs_destroy_node,
135 .link = tmpfs_link_node,
136 .unlink = tmpfs_unlink_node,
137 .has_children = tmpfs_has_children,
138 .index_get = tmpfs_index_get,
139 .size_get = tmpfs_size_get,
140 .lnkcnt_get = tmpfs_lnkcnt_get,
141 .plb_get_char = tmpfs_plb_get_char,
142 .is_directory = tmpfs_is_directory,
143 .is_file = tmpfs_is_file,
144 .device_get = tmpfs_device_get
145};
146
147/** Hash table of all TMPFS nodes. */
148hash_table_t nodes;
149
150#define NODES_KEY_DEV 0
151#define NODES_KEY_INDEX 1
152
153/* Implementation of hash table interface for the nodes hash table. */
154static hash_index_t nodes_hash(unsigned long key[])
155{
156 return key[NODES_KEY_INDEX] % NODES_BUCKETS;
157}
158
159static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
160{
161 tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
162 nh_link);
163
164 switch (keys) {
165 case 1:
166 return (nodep->devmap_handle == key[NODES_KEY_DEV]);
167 case 2:
168 return ((nodep->devmap_handle == key[NODES_KEY_DEV]) &&
169 (nodep->index == key[NODES_KEY_INDEX]));
170 default:
171 assert((keys == 1) || (keys == 2));
172 }
173
174 return 0;
175}
176
177static void nodes_remove_callback(link_t *item)
178{
179 tmpfs_node_t *nodep = hash_table_get_instance(item, tmpfs_node_t,
180 nh_link);
181
182 while (!list_empty(&nodep->cs_list)) {
183 tmpfs_dentry_t *dentryp = list_get_instance(
184 list_first(&nodep->cs_list), tmpfs_dentry_t, link);
185
186 assert(nodep->type == TMPFS_DIRECTORY);
187 list_remove(&dentryp->link);
188 free(dentryp);
189 }
190
191 if (nodep->data) {
192 assert(nodep->type == TMPFS_FILE);
193 free(nodep->data);
194 }
195 free(nodep->bp);
196 free(nodep);
197}
198
199/** TMPFS nodes hash table operations. */
200hash_table_operations_t nodes_ops = {
201 .hash = nodes_hash,
202 .compare = nodes_compare,
203 .remove_callback = nodes_remove_callback
204};
205
206static void tmpfs_node_initialize(tmpfs_node_t *nodep)
207{
208 nodep->bp = NULL;
209 nodep->index = 0;
210 nodep->devmap_handle = 0;
211 nodep->type = TMPFS_NONE;
212 nodep->lnkcnt = 0;
213 nodep->size = 0;
214 nodep->data = NULL;
215 link_initialize(&nodep->nh_link);
216 list_initialize(&nodep->cs_list);
217}
218
219static void tmpfs_dentry_initialize(tmpfs_dentry_t *dentryp)
220{
221 link_initialize(&dentryp->link);
222 dentryp->name = NULL;
223 dentryp->node = NULL;
224}
225
226bool tmpfs_init(void)
227{
228 if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
229 return false;
230
231 return true;
232}
233
234static bool tmpfs_instance_init(devmap_handle_t devmap_handle)
235{
236 fs_node_t *rfn;
237 int rc;
238
239 rc = tmpfs_create_node(&rfn, devmap_handle, L_DIRECTORY);
240 if (rc != EOK || !rfn)
241 return false;
242 TMPFS_NODE(rfn)->lnkcnt = 0; /* FS root is not linked */
243 return true;
244}
245
246static void tmpfs_instance_done(devmap_handle_t devmap_handle)
247{
248 unsigned long key[] = {
249 [NODES_KEY_DEV] = devmap_handle
250 };
251 /*
252 * Here we are making use of one special feature of our hash table
253 * implementation, which allows to remove more items based on a partial
254 * key match. In the following, we are going to remove all nodes
255 * matching our device handle. The nodes_remove_callback() function will
256 * take care of resource deallocation.
257 */
258 hash_table_remove(&nodes, key, 1);
259}
260
261int tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
262{
263 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
264
265 list_foreach(parentp->cs_list, lnk) {
266 tmpfs_dentry_t *dentryp;
267 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
268 if (!str_cmp(dentryp->name, component)) {
269 *rfn = FS_NODE(dentryp->node);
270 return EOK;
271 }
272 }
273
274 *rfn = NULL;
275 return EOK;
276}
277
278int tmpfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
279{
280 unsigned long key[] = {
281 [NODES_KEY_DEV] = devmap_handle,
282 [NODES_KEY_INDEX] = index
283 };
284 link_t *lnk = hash_table_find(&nodes, key);
285 if (lnk) {
286 tmpfs_node_t *nodep;
287 nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
288 *rfn = FS_NODE(nodep);
289 } else {
290 *rfn = NULL;
291 }
292 return EOK;
293}
294
295int tmpfs_node_open(fs_node_t *fn)
296{
297 /* nothing to do */
298 return EOK;
299}
300
301int tmpfs_node_put(fs_node_t *fn)
302{
303 /* nothing to do */
304 return EOK;
305}
306
307int tmpfs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
308{
309 fs_node_t *rootfn;
310 int rc;
311
312 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
313
314 tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
315 if (!nodep)
316 return ENOMEM;
317 tmpfs_node_initialize(nodep);
318 nodep->bp = malloc(sizeof(fs_node_t));
319 if (!nodep->bp) {
320 free(nodep);
321 return ENOMEM;
322 }
323 fs_node_initialize(nodep->bp);
324 nodep->bp->data = nodep; /* link the FS and TMPFS nodes */
325
326 rc = tmpfs_root_get(&rootfn, devmap_handle);
327 assert(rc == EOK);
328 if (!rootfn)
329 nodep->index = TMPFS_SOME_ROOT;
330 else
331 nodep->index = tmpfs_next_index++;
332 nodep->devmap_handle = devmap_handle;
333 if (lflag & L_DIRECTORY)
334 nodep->type = TMPFS_DIRECTORY;
335 else
336 nodep->type = TMPFS_FILE;
337
338 /* Insert the new node into the nodes hash table. */
339 unsigned long key[] = {
340 [NODES_KEY_DEV] = nodep->devmap_handle,
341 [NODES_KEY_INDEX] = nodep->index
342 };
343 hash_table_insert(&nodes, key, &nodep->nh_link);
344 *rfn = FS_NODE(nodep);
345 return EOK;
346}
347
348int tmpfs_destroy_node(fs_node_t *fn)
349{
350 tmpfs_node_t *nodep = TMPFS_NODE(fn);
351
352 assert(!nodep->lnkcnt);
353 assert(list_empty(&nodep->cs_list));
354
355 unsigned long key[] = {
356 [NODES_KEY_DEV] = nodep->devmap_handle,
357 [NODES_KEY_INDEX] = nodep->index
358 };
359 hash_table_remove(&nodes, key, 2);
360
361 /*
362 * The nodes_remove_callback() function takes care of the actual
363 * resource deallocation.
364 */
365 return EOK;
366}
367
368int tmpfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
369{
370 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
371 tmpfs_node_t *childp = TMPFS_NODE(cfn);
372 tmpfs_dentry_t *dentryp;
373
374 assert(parentp->type == TMPFS_DIRECTORY);
375
376 /* Check for duplicit entries. */
377 list_foreach(parentp->cs_list, lnk) {
378 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
379 if (!str_cmp(dentryp->name, nm))
380 return EEXIST;
381 }
382
383 /* Allocate and initialize the dentry. */
384 dentryp = malloc(sizeof(tmpfs_dentry_t));
385 if (!dentryp)
386 return ENOMEM;
387 tmpfs_dentry_initialize(dentryp);
388
389 /* Populate and link the new dentry. */
390 size_t size = str_size(nm);
391 dentryp->name = malloc(size + 1);
392 if (!dentryp->name) {
393 free(dentryp);
394 return ENOMEM;
395 }
396 str_cpy(dentryp->name, size + 1, nm);
397 dentryp->node = childp;
398 childp->lnkcnt++;
399 list_append(&dentryp->link, &parentp->cs_list);
400
401 return EOK;
402}
403
404int tmpfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
405{
406 tmpfs_node_t *parentp = TMPFS_NODE(pfn);
407 tmpfs_node_t *childp = NULL;
408 tmpfs_dentry_t *dentryp;
409
410 if (!parentp)
411 return EBUSY;
412
413 list_foreach(parentp->cs_list, lnk) {
414 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
415 if (!str_cmp(dentryp->name, nm)) {
416 childp = dentryp->node;
417 assert(FS_NODE(childp) == cfn);
418 break;
419 }
420 }
421
422 if (!childp)
423 return ENOENT;
424
425 if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_list))
426 return ENOTEMPTY;
427
428 list_remove(&dentryp->link);
429 free(dentryp);
430 childp->lnkcnt--;
431
432 return EOK;
433}
434
435void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request)
436{
437 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
438 fs_node_t *rootfn;
439 int rc;
440
441 /* Accept the mount options. */
442 char *opts;
443 rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
444 if (rc != EOK) {
445 async_answer_0(rid, rc);
446 return;
447 }
448
449 /* Check if this device is not already mounted. */
450 rc = tmpfs_root_get(&rootfn, devmap_handle);
451 if ((rc == EOK) && (rootfn)) {
452 (void) tmpfs_node_put(rootfn);
453 free(opts);
454 async_answer_0(rid, EEXIST);
455 return;
456 }
457
458 /* Initialize TMPFS instance. */
459 if (!tmpfs_instance_init(devmap_handle)) {
460 free(opts);
461 async_answer_0(rid, ENOMEM);
462 return;
463 }
464
465 rc = tmpfs_root_get(&rootfn, devmap_handle);
466 assert(rc == EOK);
467 tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
468 if (str_cmp(opts, "restore") == 0) {
469 if (tmpfs_restore(devmap_handle))
470 async_answer_3(rid, EOK, rootp->index, rootp->size,
471 rootp->lnkcnt);
472 else
473 async_answer_0(rid, ELIMIT);
474 } else {
475 async_answer_3(rid, EOK, rootp->index, rootp->size,
476 rootp->lnkcnt);
477 }
478 free(opts);
479}
480
481void tmpfs_mount(ipc_callid_t rid, ipc_call_t *request)
482{
483 libfs_mount(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
484}
485
486void tmpfs_unmounted(ipc_callid_t rid, ipc_call_t *request)
487{
488 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
489
490 tmpfs_instance_done(devmap_handle);
491 async_answer_0(rid, EOK);
492}
493
494void tmpfs_unmount(ipc_callid_t rid, ipc_call_t *request)
495{
496 libfs_unmount(&tmpfs_libfs_ops, rid, request);
497}
498
499void tmpfs_lookup(ipc_callid_t rid, ipc_call_t *request)
500{
501 libfs_lookup(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
502}
503
504void tmpfs_read(ipc_callid_t rid, ipc_call_t *request)
505{
506 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
507 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
508 aoff64_t pos =
509 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
510
511 /*
512 * Lookup the respective TMPFS node.
513 */
514 link_t *hlp;
515 unsigned long key[] = {
516 [NODES_KEY_DEV] = devmap_handle,
517 [NODES_KEY_INDEX] = index
518 };
519 hlp = hash_table_find(&nodes, key);
520 if (!hlp) {
521 async_answer_0(rid, ENOENT);
522 return;
523 }
524 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
525 nh_link);
526
527 /*
528 * Receive the read request.
529 */
530 ipc_callid_t callid;
531 size_t size;
532 if (!async_data_read_receive(&callid, &size)) {
533 async_answer_0(callid, EINVAL);
534 async_answer_0(rid, EINVAL);
535 return;
536 }
537
538 size_t bytes;
539 if (nodep->type == TMPFS_FILE) {
540 bytes = min(nodep->size - pos, size);
541 (void) async_data_read_finalize(callid, nodep->data + pos,
542 bytes);
543 } else {
544 tmpfs_dentry_t *dentryp;
545 link_t *lnk;
546
547 assert(nodep->type == TMPFS_DIRECTORY);
548
549 /*
550 * Yes, we really use O(n) algorithm here.
551 * If it bothers someone, it could be fixed by introducing a
552 * hash table.
553 */
554 lnk = list_nth(&nodep->cs_list, pos);
555
556 if (lnk == NULL) {
557 async_answer_0(callid, ENOENT);
558 async_answer_1(rid, ENOENT, 0);
559 return;
560 }
561
562 dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
563
564 (void) async_data_read_finalize(callid, dentryp->name,
565 str_size(dentryp->name) + 1);
566 bytes = 1;
567 }
568
569 /*
570 * Answer the VFS_READ call.
571 */
572 async_answer_1(rid, EOK, bytes);
573}
574
575void tmpfs_write(ipc_callid_t rid, ipc_call_t *request)
576{
577 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
578 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
579 aoff64_t pos =
580 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
581
582 /*
583 * Lookup the respective TMPFS node.
584 */
585 link_t *hlp;
586 unsigned long key[] = {
587 [NODES_KEY_DEV] = devmap_handle,
588 [NODES_KEY_INDEX] = index
589 };
590 hlp = hash_table_find(&nodes, key);
591 if (!hlp) {
592 async_answer_0(rid, ENOENT);
593 return;
594 }
595 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
596 nh_link);
597
598 /*
599 * Receive the write request.
600 */
601 ipc_callid_t callid;
602 size_t size;
603 if (!async_data_write_receive(&callid, &size)) {
604 async_answer_0(callid, EINVAL);
605 async_answer_0(rid, EINVAL);
606 return;
607 }
608
609 /*
610 * Check whether the file needs to grow.
611 */
612 if (pos + size <= nodep->size) {
613 /* The file size is not changing. */
614 (void) async_data_write_finalize(callid, nodep->data + pos, size);
615 async_answer_2(rid, EOK, size, nodep->size);
616 return;
617 }
618 size_t delta = (pos + size) - nodep->size;
619 /*
620 * At this point, we are deliberately extremely straightforward and
621 * simply realloc the contents of the file on every write that grows the
622 * file. In the end, the situation might not be as bad as it may look:
623 * our heap allocator can save us and just grow the block whenever
624 * possible.
625 */
626 void *newdata = realloc(nodep->data, nodep->size + delta);
627 if (!newdata) {
628 async_answer_0(callid, ENOMEM);
629 async_answer_2(rid, EOK, 0, nodep->size);
630 return;
631 }
632 /* Clear any newly allocated memory in order to emulate gaps. */
633 memset(newdata + nodep->size, 0, delta);
634 nodep->size += delta;
635 nodep->data = newdata;
636 (void) async_data_write_finalize(callid, nodep->data + pos, size);
637 async_answer_2(rid, EOK, size, nodep->size);
638}
639
640void tmpfs_truncate(ipc_callid_t rid, ipc_call_t *request)
641{
642 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
643 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
644 aoff64_t size =
645 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
646
647 /*
648 * Lookup the respective TMPFS node.
649 */
650 unsigned long key[] = {
651 [NODES_KEY_DEV] = devmap_handle,
652 [NODES_KEY_INDEX] = index
653 };
654 link_t *hlp = hash_table_find(&nodes, key);
655 if (!hlp) {
656 async_answer_0(rid, ENOENT);
657 return;
658 }
659 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
660 nh_link);
661
662 if (size == nodep->size) {
663 async_answer_0(rid, EOK);
664 return;
665 }
666
667 if (size > SIZE_MAX) {
668 async_answer_0(rid, ENOMEM);
669 return;
670 }
671
672 void *newdata = realloc(nodep->data, size);
673 if (!newdata) {
674 async_answer_0(rid, ENOMEM);
675 return;
676 }
677
678 if (size > nodep->size) {
679 size_t delta = size - nodep->size;
680 memset(newdata + nodep->size, 0, delta);
681 }
682
683 nodep->size = size;
684 nodep->data = newdata;
685 async_answer_0(rid, EOK);
686}
687
688void tmpfs_close(ipc_callid_t rid, ipc_call_t *request)
689{
690 async_answer_0(rid, EOK);
691}
692
693void tmpfs_destroy(ipc_callid_t rid, ipc_call_t *request)
694{
695 devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
696 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
697 int rc;
698
699 link_t *hlp;
700 unsigned long key[] = {
701 [NODES_KEY_DEV] = devmap_handle,
702 [NODES_KEY_INDEX] = index
703 };
704 hlp = hash_table_find(&nodes, key);
705 if (!hlp) {
706 async_answer_0(rid, ENOENT);
707 return;
708 }
709 tmpfs_node_t *nodep = hash_table_get_instance(hlp, tmpfs_node_t,
710 nh_link);
711 rc = tmpfs_destroy_node(FS_NODE(nodep));
712 async_answer_0(rid, rc);
713}
714
715void tmpfs_open_node(ipc_callid_t rid, ipc_call_t *request)
716{
717 libfs_open_node(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
718}
719
720void tmpfs_stat(ipc_callid_t rid, ipc_call_t *request)
721{
722 libfs_stat(&tmpfs_libfs_ops, tmpfs_reg.fs_handle, rid, request);
723}
724
725void tmpfs_sync(ipc_callid_t rid, ipc_call_t *request)
726{
727 /*
728 * TMPFS keeps its data structures always consistent,
729 * thus the sync operation is a no-op.
730 */
731 async_answer_0(rid, EOK);
732}
733
734/**
735 * @}
736 */
Note: See TracBrowser for help on using the repository browser.