source: mainline/uspace/srv/fs/pipefs/pipefs_ops.c@ a49c4002

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a49c4002 was 8d1aab7, checked in by Martin Sucha <sucha14@…>, 15 years ago

Changes for simple pipefs behaviour. Currently it does not support waiting for data.

  • Property mode set to 100644
File size: 18.8 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 pipefs_ops.c
35 * @brief Implementation of VFS operations for the PIPEFS file system
36 * server.
37 */
38
39#include "pipefs.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 PIPEFS_SOME_ROOT 0
63/** Global counter for assigning node indices. Shared by all instances. */
64fs_index_t pipefs_next_index = 1;
65
66/*
67 * Implementation of the libfs interface.
68 */
69
70/* Forward declarations of static functions. */
71static int pipefs_match(fs_node_t **, fs_node_t *, const char *);
72static int pipefs_node_get(fs_node_t **, devmap_handle_t, fs_index_t);
73static int pipefs_node_open(fs_node_t *);
74static int pipefs_node_put(fs_node_t *);
75static int pipefs_create_node(fs_node_t **, devmap_handle_t, int);
76static int pipefs_destroy_node(fs_node_t *);
77static int pipefs_link_node(fs_node_t *, fs_node_t *, const char *);
78static int pipefs_unlink_node(fs_node_t *, fs_node_t *, const char *);
79
80/* Implementation of helper functions. */
81static int pipefs_root_get(fs_node_t **rfn, devmap_handle_t devmap_handle)
82{
83 return pipefs_node_get(rfn, devmap_handle, PIPEFS_SOME_ROOT);
84}
85
86static int pipefs_has_children(bool *has_children, fs_node_t *fn)
87{
88 *has_children = !list_empty(&PIPEFS_NODE(fn)->cs_head);
89 return EOK;
90}
91
92static fs_index_t pipefs_index_get(fs_node_t *fn)
93{
94 return PIPEFS_NODE(fn)->index;
95}
96
97static aoff64_t pipefs_size_get(fs_node_t *fn)
98{
99 return PIPEFS_NODE(fn)->size;
100}
101
102static unsigned pipefs_lnkcnt_get(fs_node_t *fn)
103{
104 return PIPEFS_NODE(fn)->lnkcnt;
105}
106
107static char pipefs_plb_get_char(unsigned pos)
108{
109 return pipefs_reg.plb_ro[pos % PLB_SIZE];
110}
111
112static bool pipefs_is_directory(fs_node_t *fn)
113{
114 return PIPEFS_NODE(fn)->type == PIPEFS_DIRECTORY;
115}
116
117static bool pipefs_is_file(fs_node_t *fn)
118{
119 return PIPEFS_NODE(fn)->type == PIPEFS_FILE;
120}
121
122static devmap_handle_t pipefs_device_get(fs_node_t *fn)
123{
124 return 0;
125}
126
127/** libfs operations */
128libfs_ops_t pipefs_libfs_ops = {
129 .root_get = pipefs_root_get,
130 .match = pipefs_match,
131 .node_get = pipefs_node_get,
132 .node_open = pipefs_node_open,
133 .node_put = pipefs_node_put,
134 .create = pipefs_create_node,
135 .destroy = pipefs_destroy_node,
136 .link = pipefs_link_node,
137 .unlink = pipefs_unlink_node,
138 .has_children = pipefs_has_children,
139 .index_get = pipefs_index_get,
140 .size_get = pipefs_size_get,
141 .lnkcnt_get = pipefs_lnkcnt_get,
142 .plb_get_char = pipefs_plb_get_char,
143 .is_directory = pipefs_is_directory,
144 .is_file = pipefs_is_file,
145 .device_get = pipefs_device_get
146};
147
148/** Hash table of all PIPEFS 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 pipefs_node_t *nodep = hash_table_get_instance(item, pipefs_node_t,
163 nh_link);
164
165 switch (keys) {
166 case 1:
167 return (nodep->devmap_handle == key[NODES_KEY_DEV]);
168 case 2:
169 return ((nodep->devmap_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 pipefs_node_t *nodep = hash_table_get_instance(item, pipefs_node_t,
181 nh_link);
182
183 while (!list_empty(&nodep->cs_head)) {
184 pipefs_dentry_t *dentryp = list_get_instance(nodep->cs_head.next,
185 pipefs_dentry_t, link);
186
187 assert(nodep->type == PIPEFS_DIRECTORY);
188 list_remove(&dentryp->link);
189 free(dentryp);
190 }
191
192 while (!list_empty(&nodep->data_head)) {
193 assert(nodep->type == PIPEFS_FILE);
194
195 pipefs_data_block_t *data_block = list_get_instance(nodep->data_head.next,
196 pipefs_data_block_t, link);
197
198 list_remove(&data_block->link);
199 free(data_block->data);
200 free(data_block);
201 }
202 free(nodep->bp);
203 free(nodep);
204}
205
206/** PIPEFS nodes hash table operations. */
207hash_table_operations_t nodes_ops = {
208 .hash = nodes_hash,
209 .compare = nodes_compare,
210 .remove_callback = nodes_remove_callback
211};
212
213static void pipefs_node_initialize(pipefs_node_t *nodep)
214{
215 nodep->bp = NULL;
216 nodep->index = 0;
217 nodep->devmap_handle = 0;
218 nodep->type = PIPEFS_NONE;
219 nodep->lnkcnt = 0;
220 nodep->start = 0;
221 nodep->size = 0;
222 list_initialize(&nodep->data_head);
223 link_initialize(&nodep->nh_link);
224 list_initialize(&nodep->cs_head);
225}
226
227static void pipefs_dentry_initialize(pipefs_dentry_t *dentryp)
228{
229 link_initialize(&dentryp->link);
230 dentryp->name = NULL;
231 dentryp->node = NULL;
232}
233
234bool pipefs_init(void)
235{
236 if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
237 return false;
238
239 return true;
240}
241
242static bool pipefs_instance_init(devmap_handle_t devmap_handle)
243{
244 fs_node_t *rfn;
245 int rc;
246
247 rc = pipefs_create_node(&rfn, devmap_handle, L_DIRECTORY);
248 if (rc != EOK || !rfn)
249 return false;
250 PIPEFS_NODE(rfn)->lnkcnt = 0; /* FS root is not linked */
251 return true;
252}
253
254static void pipefs_instance_done(devmap_handle_t devmap_handle)
255{
256 unsigned long key[] = {
257 [NODES_KEY_DEV] = devmap_handle
258 };
259 /*
260 * Here we are making use of one special feature of our hash table
261 * implementation, which allows to remove more items based on a partial
262 * key match. In the following, we are going to remove all nodes
263 * matching our device handle. The nodes_remove_callback() function will
264 * take care of resource deallocation.
265 */
266 hash_table_remove(&nodes, key, 1);
267}
268
269int pipefs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
270{
271 pipefs_node_t *parentp = PIPEFS_NODE(pfn);
272 link_t *lnk;
273
274 for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
275 lnk = lnk->next) {
276 pipefs_dentry_t *dentryp;
277 dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
278 if (!str_cmp(dentryp->name, component)) {
279 *rfn = FS_NODE(dentryp->node);
280 return EOK;
281 }
282 }
283
284 *rfn = NULL;
285 return EOK;
286}
287
288int pipefs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle, fs_index_t index)
289{
290 unsigned long key[] = {
291 [NODES_KEY_DEV] = devmap_handle,
292 [NODES_KEY_INDEX] = index
293 };
294 link_t *lnk = hash_table_find(&nodes, key);
295 if (lnk) {
296 pipefs_node_t *nodep;
297 nodep = hash_table_get_instance(lnk, pipefs_node_t, nh_link);
298 *rfn = FS_NODE(nodep);
299 } else {
300 *rfn = NULL;
301 }
302 return EOK;
303}
304
305int pipefs_node_open(fs_node_t *fn)
306{
307 /* nothing to do */
308 return EOK;
309}
310
311int pipefs_node_put(fs_node_t *fn)
312{
313 /* nothing to do */
314 return EOK;
315}
316
317int pipefs_create_node(fs_node_t **rfn, devmap_handle_t devmap_handle, int lflag)
318{
319 fs_node_t *rootfn;
320 int rc;
321
322 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
323
324 pipefs_node_t *nodep = malloc(sizeof(pipefs_node_t));
325 if (!nodep)
326 return ENOMEM;
327 pipefs_node_initialize(nodep);
328 nodep->bp = malloc(sizeof(fs_node_t));
329 if (!nodep->bp) {
330 free(nodep);
331 return ENOMEM;
332 }
333 fs_node_initialize(nodep->bp);
334 nodep->bp->data = nodep; /* link the FS and PIPEFS nodes */
335
336 rc = pipefs_root_get(&rootfn, devmap_handle);
337 assert(rc == EOK);
338 if (!rootfn)
339 nodep->index = PIPEFS_SOME_ROOT;
340 else
341 nodep->index = pipefs_next_index++;
342 nodep->devmap_handle = devmap_handle;
343 if (lflag & L_DIRECTORY)
344 nodep->type = PIPEFS_DIRECTORY;
345 else
346 nodep->type = PIPEFS_FILE;
347
348 /* Insert the new node into the nodes hash table. */
349 unsigned long key[] = {
350 [NODES_KEY_DEV] = nodep->devmap_handle,
351 [NODES_KEY_INDEX] = nodep->index
352 };
353 hash_table_insert(&nodes, key, &nodep->nh_link);
354 *rfn = FS_NODE(nodep);
355 return EOK;
356}
357
358int pipefs_destroy_node(fs_node_t *fn)
359{
360 pipefs_node_t *nodep = PIPEFS_NODE(fn);
361
362 assert(!nodep->lnkcnt);
363 assert(list_empty(&nodep->cs_head));
364
365 unsigned long key[] = {
366 [NODES_KEY_DEV] = nodep->devmap_handle,
367 [NODES_KEY_INDEX] = nodep->index
368 };
369 hash_table_remove(&nodes, key, 2);
370
371 /*
372 * The nodes_remove_callback() function takes care of the actual
373 * resource deallocation.
374 */
375 return EOK;
376}
377
378int pipefs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
379{
380 pipefs_node_t *parentp = PIPEFS_NODE(pfn);
381 pipefs_node_t *childp = PIPEFS_NODE(cfn);
382 pipefs_dentry_t *dentryp;
383 link_t *lnk;
384
385 assert(parentp->type == PIPEFS_DIRECTORY);
386
387 /* Check for duplicit entries. */
388 for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
389 lnk = lnk->next) {
390 dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
391 if (!str_cmp(dentryp->name, nm))
392 return EEXIST;
393 }
394
395 /* Allocate and initialize the dentry. */
396 dentryp = malloc(sizeof(pipefs_dentry_t));
397 if (!dentryp)
398 return ENOMEM;
399 pipefs_dentry_initialize(dentryp);
400
401 /* Populate and link the new dentry. */
402 size_t size = str_size(nm);
403 dentryp->name = malloc(size + 1);
404 if (!dentryp->name) {
405 free(dentryp);
406 return ENOMEM;
407 }
408 str_cpy(dentryp->name, size + 1, nm);
409 dentryp->node = childp;
410 childp->lnkcnt++;
411 list_append(&dentryp->link, &parentp->cs_head);
412
413 return EOK;
414}
415
416int pipefs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
417{
418 pipefs_node_t *parentp = PIPEFS_NODE(pfn);
419 pipefs_node_t *childp = NULL;
420 pipefs_dentry_t *dentryp;
421 link_t *lnk;
422
423 if (!parentp)
424 return EBUSY;
425
426 for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
427 lnk = lnk->next) {
428 dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
429 if (!str_cmp(dentryp->name, nm)) {
430 childp = dentryp->node;
431 assert(FS_NODE(childp) == cfn);
432 break;
433 }
434 }
435
436 if (!childp)
437 return ENOENT;
438
439 if ((childp->lnkcnt == 1) && !list_empty(&childp->cs_head))
440 return ENOTEMPTY;
441
442 list_remove(&dentryp->link);
443 free(dentryp);
444 childp->lnkcnt--;
445
446 return EOK;
447}
448
449void pipefs_mounted(ipc_callid_t rid, ipc_call_t *request)
450{
451 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
452 fs_node_t *rootfn;
453 int rc;
454
455 /* Accept the mount options. */
456 char *opts;
457 rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
458 if (rc != EOK) {
459 ipc_answer_0(rid, rc);
460 return;
461 }
462
463 /* Check if this device is not already mounted. */
464 rc = pipefs_root_get(&rootfn, devmap_handle);
465 if ((rc == EOK) && (rootfn)) {
466 (void) pipefs_node_put(rootfn);
467 free(opts);
468 ipc_answer_0(rid, EEXIST);
469 return;
470 }
471
472 /* Initialize PIPEFS instance. */
473 if (!pipefs_instance_init(devmap_handle)) {
474 free(opts);
475 ipc_answer_0(rid, ENOMEM);
476 return;
477 }
478
479 rc = pipefs_root_get(&rootfn, devmap_handle);
480 assert(rc == EOK);
481 pipefs_node_t *rootp = PIPEFS_NODE(rootfn);
482 ipc_answer_3(rid, EOK, rootp->index, rootp->size, rootp->lnkcnt);
483 free(opts);
484}
485
486void pipefs_mount(ipc_callid_t rid, ipc_call_t *request)
487{
488 libfs_mount(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
489}
490
491void pipefs_unmounted(ipc_callid_t rid, ipc_call_t *request)
492{
493 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
494
495 pipefs_instance_done(devmap_handle);
496 ipc_answer_0(rid, EOK);
497}
498
499void pipefs_unmount(ipc_callid_t rid, ipc_call_t *request)
500{
501 libfs_unmount(&pipefs_libfs_ops, rid, request);
502}
503
504void pipefs_lookup(ipc_callid_t rid, ipc_call_t *request)
505{
506 libfs_lookup(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
507}
508
509void pipefs_read(ipc_callid_t rid, ipc_call_t *request)
510{
511 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
512 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
513 aoff64_t pos =
514 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
515
516 /*
517 * Lookup the respective PIPEFS node.
518 */
519 link_t *hlp;
520 unsigned long key[] = {
521 [NODES_KEY_DEV] = devmap_handle,
522 [NODES_KEY_INDEX] = index
523 };
524 hlp = hash_table_find(&nodes, key);
525 if (!hlp) {
526 ipc_answer_0(rid, ENOENT);
527 return;
528 }
529 pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
530 nh_link);
531
532 /*
533 * Receive the read request.
534 */
535 ipc_callid_t callid;
536 size_t size;
537 if (!async_data_read_receive(&callid, &size)) {
538 ipc_answer_0(callid, EINVAL);
539 ipc_answer_0(rid, EINVAL);
540 return;
541 }
542
543 size_t bytes;
544 if (nodep->type == PIPEFS_FILE) {
545 /*
546 * Check if we still have the requested data.
547 * This may happen if the client seeked backwards
548 */
549 if (pos < nodep->start) {
550 ipc_answer_0(callid, ENOTSUP);
551 ipc_answer_0(rid, ENOTSUP);
552 return;
553 }
554
555 /*
556 * Free all data blocks that end before pos.
557 * This is in case the client seeked forward
558 */
559 while (!list_empty(&nodep->data_head)) {
560 pipefs_data_block_t *data_block =
561 list_get_instance(nodep->data_head.next,
562 pipefs_data_block_t, link);
563
564 aoff64_t block_end = nodep->start + data_block->size;
565
566 if (block_end > pos) {
567 break;
568 }
569
570 list_remove(&data_block->link);
571 free(data_block->data);
572 free(data_block);
573 nodep->start = block_end;
574 }
575
576 if (!list_empty(&nodep->data_head)) {
577 /* We have data block, so let's return its portion after pos */
578 pipefs_data_block_t *data_block =
579 list_get_instance(nodep->data_head.next,
580 pipefs_data_block_t, link);
581
582 assert(nodep->start <= pos);
583
584 aoff64_t block_end = nodep->start + data_block->size;
585 size_t block_offset = pos - nodep->start;
586
587 assert(block_end > pos);
588
589 bytes = min(block_end - pos, size);
590 (void) async_data_read_finalize(callid,
591 data_block->data + block_offset,
592 bytes);
593
594 if (nodep->start + block_offset + bytes == block_end) {
595 /* Free the data block - it was fully read */
596 list_remove(&data_block->link);
597 free(data_block->data);
598 free(data_block);
599 nodep->start = block_end;
600 }
601 }
602 else {
603 /*
604 * there is no data
605 * TODO implement waiting for the data
606 * and remove this else clause
607 */
608 ipc_answer_0(callid, ENOTSUP);
609 ipc_answer_1(rid, ENOTSUP, 0);
610 return;
611 }
612 } else {
613 pipefs_dentry_t *dentryp;
614 link_t *lnk;
615 aoff64_t i;
616
617 assert(nodep->type == PIPEFS_DIRECTORY);
618
619 /*
620 * Yes, we really use O(n) algorithm here.
621 * If it bothers someone, it could be fixed by introducing a
622 * hash table.
623 */
624 for (i = 0, lnk = nodep->cs_head.next;
625 (i < pos) && (lnk != &nodep->cs_head);
626 i++, lnk = lnk->next)
627 ;
628
629 if (lnk == &nodep->cs_head) {
630 ipc_answer_0(callid, ENOENT);
631 ipc_answer_1(rid, ENOENT, 0);
632 return;
633 }
634
635 dentryp = list_get_instance(lnk, pipefs_dentry_t, link);
636
637 (void) async_data_read_finalize(callid, dentryp->name,
638 str_size(dentryp->name) + 1);
639 bytes = 1;
640 }
641
642 /*
643 * Answer the VFS_READ call.
644 */
645 ipc_answer_1(rid, EOK, bytes);
646}
647
648void pipefs_write(ipc_callid_t rid, ipc_call_t *request)
649{
650 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
651 fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
652 aoff64_t pos =
653 (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request), IPC_GET_ARG4(*request));
654
655 /*
656 * Lookup the respective PIPEFS node.
657 */
658 link_t *hlp;
659 unsigned long key[] = {
660 [NODES_KEY_DEV] = devmap_handle,
661 [NODES_KEY_INDEX] = index
662 };
663 hlp = hash_table_find(&nodes, key);
664 if (!hlp) {
665 ipc_answer_0(rid, ENOENT);
666 return;
667 }
668 pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
669 nh_link);
670
671 /*
672 * Receive the write request.
673 */
674 ipc_callid_t callid;
675 size_t size;
676 if (!async_data_write_receive(&callid, &size)) {
677 ipc_answer_0(callid, EINVAL);
678 ipc_answer_0(rid, EINVAL);
679 return;
680 }
681
682 /*
683 * Check whether we are writing to the end
684 */
685 if (pos != nodep->size) {
686 ipc_answer_0(callid, ENOTSUP);
687 ipc_answer_2(rid, EOK, 0, nodep->size);
688 return;
689 }
690
691 /*
692 * Allocate a buffer for the new data.
693 * Currently we accept any size, create a data block from this
694 * and append it to the end of a file
695 */
696 void *newdata = malloc(size);
697 if (!newdata) {
698 ipc_answer_0(callid, ENOMEM);
699 ipc_answer_2(rid, EOK, 0, nodep->size);
700 return;
701 }
702
703 pipefs_data_block_t *newblock = malloc(sizeof(pipefs_data_block_t));
704
705 if (!newblock) {
706 free(newdata);
707 ipc_answer_0(callid, ENOMEM);
708 ipc_answer_2(rid, EOK, 0, nodep->size);
709 return;
710 }
711
712 int rc = async_data_write_finalize(callid, newdata, size);
713
714 if (rc != EOK) {
715 free(newblock);
716 free(newdata);
717 ipc_answer_0(callid, rc);
718 ipc_answer_2(rid, EOK, 0, nodep->size);
719 return;
720 }
721
722 link_initialize(&newblock->link);
723 newblock->size = size;
724 newblock->data = newdata;
725 list_append(&newblock->link, &nodep->data_head);
726
727 nodep->size += size;
728
729 ipc_answer_2(rid, EOK, size, nodep->size);
730}
731
732void pipefs_truncate(ipc_callid_t rid, ipc_call_t *request)
733{
734 /*
735 * PIPEFS does not support resizing of files
736 */
737 ipc_answer_0(rid, ENOTSUP);
738}
739
740void pipefs_close(ipc_callid_t rid, ipc_call_t *request)
741{
742 ipc_answer_0(rid, EOK);
743}
744
745void pipefs_destroy(ipc_callid_t rid, ipc_call_t *request)
746{
747 devmap_handle_t devmap_handle = (devmap_handle_t)IPC_GET_ARG1(*request);
748 fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
749 int rc;
750
751 link_t *hlp;
752 unsigned long key[] = {
753 [NODES_KEY_DEV] = devmap_handle,
754 [NODES_KEY_INDEX] = index
755 };
756 hlp = hash_table_find(&nodes, key);
757 if (!hlp) {
758 ipc_answer_0(rid, ENOENT);
759 return;
760 }
761 pipefs_node_t *nodep = hash_table_get_instance(hlp, pipefs_node_t,
762 nh_link);
763 rc = pipefs_destroy_node(FS_NODE(nodep));
764 ipc_answer_0(rid, rc);
765}
766
767void pipefs_open_node(ipc_callid_t rid, ipc_call_t *request)
768{
769 libfs_open_node(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
770}
771
772void pipefs_stat(ipc_callid_t rid, ipc_call_t *request)
773{
774 libfs_stat(&pipefs_libfs_ops, pipefs_reg.fs_handle, rid, request);
775}
776
777void pipefs_sync(ipc_callid_t rid, ipc_call_t *request)
778{
779 /*
780 * PIPEFS keeps its data structures always consistent,
781 * thus the sync operation is a no-op.
782 */
783 ipc_answer_0(rid, EOK);
784}
785
786/**
787 * @}
788 */
Note: See TracBrowser for help on using the repository browser.