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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 69a60c4 was 69a60c4, checked in by Martin Decky <martin@…>, 15 years ago

implement sync

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