source: mainline/uspace/srv/fs/locfs/locfs_ops.c@ 7fa8589

Last change on this file since 7fa8589 was 7fa8589, checked in by Matthieu Riolo <matthieu.riolo@…>, 5 years ago

Removing unneeded casts from errno_t to errno_t

  • Property mode set to 100644
File size: 17.1 KB
Line 
1/*
2 * Copyright (c) 2009 Martin Decky
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 locfs
30 * @{
31 */
32
33/**
34 * @file locfs_ops.c
35 * @brief Implementation of VFS operations for the locfs file system server.
36 */
37
38#include <macros.h>
39#include <stdbool.h>
40#include <errno.h>
41#include <stdlib.h>
42#include <str.h>
43#include <libfs.h>
44#include <fibril_synch.h>
45#include <adt/hash_table.h>
46#include <ipc/loc.h>
47#include <assert.h>
48#include "locfs.h"
49#include "locfs_ops.h"
50
51typedef struct {
52 loc_object_type_t type;
53 service_id_t service_id;
54} locfs_node_t;
55
56/** Opened services structure */
57typedef struct {
58 service_id_t service_id;
59 async_sess_t *sess; /**< If NULL, the structure is incomplete. */
60 size_t refcount;
61 ht_link_t link;
62 fibril_condvar_t cv; /**< Broadcast when completed. */
63} service_t;
64
65/** Hash table of opened services */
66static hash_table_t services;
67
68/** Hash table mutex */
69static FIBRIL_MUTEX_INITIALIZE(services_mutex);
70
71/* Implementation of hash table interface for the nodes hash table. */
72
73static size_t services_key_hash(const void *key)
74{
75 const service_id_t *k = key;
76 return *k;
77}
78
79static size_t services_hash(const ht_link_t *item)
80{
81 service_t *dev = hash_table_get_inst(item, service_t, link);
82 return dev->service_id;
83}
84
85static bool services_key_equal(const void *key, const ht_link_t *item)
86{
87 const service_id_t *k = key;
88 service_t *dev = hash_table_get_inst(item, service_t, link);
89 return (dev->service_id == *k);
90}
91
92static void services_remove_callback(ht_link_t *item)
93{
94 free(hash_table_get_inst(item, service_t, link));
95}
96
97static hash_table_ops_t services_ops = {
98 .hash = services_hash,
99 .key_hash = services_key_hash,
100 .key_equal = services_key_equal,
101 .equal = NULL,
102 .remove_callback = services_remove_callback
103};
104
105static errno_t locfs_node_get_internal(fs_node_t **rfn, loc_object_type_t type,
106 service_id_t service_id)
107{
108 locfs_node_t *node = (locfs_node_t *) malloc(sizeof(locfs_node_t));
109 if (node == NULL) {
110 *rfn = NULL;
111 return ENOMEM;
112 }
113
114 *rfn = (fs_node_t *) malloc(sizeof(fs_node_t));
115 if (*rfn == NULL) {
116 free(node);
117 *rfn = NULL;
118 return ENOMEM;
119 }
120
121 fs_node_initialize(*rfn);
122 node->type = type;
123 node->service_id = service_id;
124
125 (*rfn)->data = node;
126 return EOK;
127}
128
129static errno_t locfs_root_get(fs_node_t **rfn, service_id_t service_id)
130{
131 return locfs_node_get_internal(rfn, LOC_OBJECT_NONE, 0);
132}
133
134static errno_t locfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
135{
136 locfs_node_t *node = (locfs_node_t *) pfn->data;
137 errno_t ret;
138
139 if (node->service_id == 0) {
140 /* Root directory */
141
142 loc_sdesc_t *nspaces;
143 size_t count = loc_get_namespaces(&nspaces);
144
145 if (count > 0) {
146 size_t pos;
147 for (pos = 0; pos < count; pos++) {
148 /* Ignore root namespace */
149 if (str_cmp(nspaces[pos].name, "") == 0)
150 continue;
151
152 if (str_cmp(nspaces[pos].name, component) == 0) {
153 ret = locfs_node_get_internal(rfn, LOC_OBJECT_NAMESPACE, nspaces[pos].id);
154 free(nspaces);
155 return ret;
156 }
157 }
158
159 free(nspaces);
160 }
161
162 /* Search root namespace */
163 service_id_t namespace;
164 loc_sdesc_t *svcs;
165 if (loc_namespace_get_id("", &namespace, 0) == EOK) {
166 count = loc_get_services(namespace, &svcs);
167
168 if (count > 0) {
169 size_t pos;
170 for (pos = 0; pos < count; pos++) {
171 if (str_cmp(svcs[pos].name, component) == 0) {
172 ret = locfs_node_get_internal(rfn, LOC_OBJECT_SERVICE, svcs[pos].id);
173 free(svcs);
174 return ret;
175 }
176 }
177
178 free(svcs);
179 }
180 }
181
182 *rfn = NULL;
183 return EOK;
184 }
185
186 if (node->type == LOC_OBJECT_NAMESPACE) {
187 /* Namespace directory */
188
189 loc_sdesc_t *svcs;
190 size_t count = loc_get_services(node->service_id, &svcs);
191 if (count > 0) {
192 size_t pos;
193 for (pos = 0; pos < count; pos++) {
194 if (str_cmp(svcs[pos].name, component) == 0) {
195 ret = locfs_node_get_internal(rfn, LOC_OBJECT_SERVICE, svcs[pos].id);
196 free(svcs);
197 return ret;
198 }
199 }
200
201 free(svcs);
202 }
203
204 *rfn = NULL;
205 return EOK;
206 }
207
208 *rfn = NULL;
209 return EOK;
210}
211
212static errno_t locfs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
213{
214 return locfs_node_get_internal(rfn, loc_id_probe(index), index);
215}
216
217static errno_t locfs_node_open(fs_node_t *fn)
218{
219 locfs_node_t *node = (locfs_node_t *) fn->data;
220
221 if (node->service_id == 0) {
222 /* Root directory */
223 return EOK;
224 }
225
226 loc_object_type_t type = loc_id_probe(node->service_id);
227
228 if (type == LOC_OBJECT_NAMESPACE) {
229 /* Namespace directory */
230 return EOK;
231 }
232
233 if (type == LOC_OBJECT_SERVICE) {
234 /* Device node */
235
236 fibril_mutex_lock(&services_mutex);
237 ht_link_t *lnk;
238 restart:
239 lnk = hash_table_find(&services, &node->service_id);
240 if (lnk == NULL) {
241 service_t *dev = (service_t *) malloc(sizeof(service_t));
242 if (dev == NULL) {
243 fibril_mutex_unlock(&services_mutex);
244 return ENOMEM;
245 }
246
247 dev->service_id = node->service_id;
248
249 /* Mark as incomplete */
250 dev->sess = NULL;
251 dev->refcount = 1;
252 fibril_condvar_initialize(&dev->cv);
253
254 /*
255 * Insert the incomplete device structure so that other
256 * fibrils will not race with us when we drop the mutex
257 * below.
258 */
259 hash_table_insert(&services, &dev->link);
260
261 /*
262 * Drop the mutex to allow recursive locfs requests.
263 */
264 fibril_mutex_unlock(&services_mutex);
265
266 async_sess_t *sess = loc_service_connect(node->service_id,
267 INTERFACE_FS, 0);
268
269 fibril_mutex_lock(&services_mutex);
270
271 /*
272 * Notify possible waiters about this device structure
273 * being completed (or destroyed).
274 */
275 fibril_condvar_broadcast(&dev->cv);
276
277 if (!sess) {
278 /*
279 * Connecting failed, need to remove the
280 * entry and free the device structure.
281 */
282 hash_table_remove(&services, &node->service_id);
283 fibril_mutex_unlock(&services_mutex);
284
285 return ENOENT;
286 }
287
288 /* Set the correct session. */
289 dev->sess = sess;
290 } else {
291 service_t *dev = hash_table_get_inst(lnk, service_t, link);
292
293 if (!dev->sess) {
294 /*
295 * Wait until the device structure is completed
296 * and start from the beginning as the device
297 * structure might have entirely disappeared
298 * while we were not holding the mutex in
299 * fibril_condvar_wait().
300 */
301 fibril_condvar_wait(&dev->cv, &services_mutex);
302 goto restart;
303 }
304
305 dev->refcount++;
306 }
307
308 fibril_mutex_unlock(&services_mutex);
309
310 return EOK;
311 }
312
313 return ENOENT;
314}
315
316static errno_t locfs_node_put(fs_node_t *fn)
317{
318 free(fn->data);
319 free(fn);
320 return EOK;
321}
322
323static errno_t locfs_create_node(fs_node_t **rfn, service_id_t service_id, int lflag)
324{
325 assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
326
327 *rfn = NULL;
328 return ENOTSUP;
329}
330
331static errno_t locfs_destroy_node(fs_node_t *fn)
332{
333 return ENOTSUP;
334}
335
336static errno_t locfs_link_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
337{
338 return ENOTSUP;
339}
340
341static errno_t locfs_unlink_node(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
342{
343 return ENOTSUP;
344}
345
346static errno_t locfs_has_children(bool *has_children, fs_node_t *fn)
347{
348 locfs_node_t *node = (locfs_node_t *) fn->data;
349
350 if (node->service_id == 0) {
351 size_t count = loc_count_namespaces();
352 if (count > 0) {
353 *has_children = true;
354 return EOK;
355 }
356
357 /* Root namespace */
358 service_id_t namespace;
359 if (loc_namespace_get_id("", &namespace, 0) == EOK) {
360 count = loc_count_services(namespace);
361 if (count > 0) {
362 *has_children = true;
363 return EOK;
364 }
365 }
366
367 *has_children = false;
368 return EOK;
369 }
370
371 if (node->type == LOC_OBJECT_NAMESPACE) {
372 size_t count = loc_count_services(node->service_id);
373 if (count > 0) {
374 *has_children = true;
375 return EOK;
376 }
377
378 *has_children = false;
379 return EOK;
380 }
381
382 *has_children = false;
383 return EOK;
384}
385
386static fs_index_t locfs_index_get(fs_node_t *fn)
387{
388 locfs_node_t *node = (locfs_node_t *) fn->data;
389 return node->service_id;
390}
391
392static aoff64_t locfs_size_get(fs_node_t *fn)
393{
394 return 0;
395}
396
397static unsigned int locfs_lnkcnt_get(fs_node_t *fn)
398{
399 locfs_node_t *node = (locfs_node_t *) fn->data;
400
401 if (node->service_id == 0)
402 return 0;
403
404 return 1;
405}
406
407static bool locfs_is_directory(fs_node_t *fn)
408{
409 locfs_node_t *node = (locfs_node_t *) fn->data;
410
411 return ((node->type == LOC_OBJECT_NONE) || (node->type == LOC_OBJECT_NAMESPACE));
412}
413
414static bool locfs_is_file(fs_node_t *fn)
415{
416 locfs_node_t *node = (locfs_node_t *) fn->data;
417
418 return (node->type == LOC_OBJECT_SERVICE);
419}
420
421static service_id_t locfs_service_get(fs_node_t *fn)
422{
423 locfs_node_t *node = (locfs_node_t *) fn->data;
424
425 if (node->type == LOC_OBJECT_SERVICE)
426 return node->service_id;
427
428 return 0;
429}
430
431/** libfs operations */
432libfs_ops_t locfs_libfs_ops = {
433 .root_get = locfs_root_get,
434 .match = locfs_match,
435 .node_get = locfs_node_get,
436 .node_open = locfs_node_open,
437 .node_put = locfs_node_put,
438 .create = locfs_create_node,
439 .destroy = locfs_destroy_node,
440 .link = locfs_link_node,
441 .unlink = locfs_unlink_node,
442 .has_children = locfs_has_children,
443 .index_get = locfs_index_get,
444 .size_get = locfs_size_get,
445 .lnkcnt_get = locfs_lnkcnt_get,
446 .is_directory = locfs_is_directory,
447 .is_file = locfs_is_file,
448 .service_get = locfs_service_get
449};
450
451bool locfs_init(void)
452{
453 if (!hash_table_create(&services, 0, 0, &services_ops))
454 return false;
455
456 return true;
457}
458
459static errno_t locfs_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
460{
461 return ENOTSUP;
462}
463
464static errno_t locfs_mounted(service_id_t service_id, const char *opts,
465 fs_index_t *index, aoff64_t *size)
466{
467 *index = 0;
468 *size = 0;
469 return EOK;
470}
471
472static errno_t locfs_unmounted(service_id_t service_id)
473{
474 return ENOTSUP;
475}
476
477static errno_t
478locfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
479 size_t *rbytes)
480{
481 if (index == 0) {
482 ipc_call_t call;
483 size_t size;
484 if (!async_data_read_receive(&call, &size)) {
485 async_answer_0(&call, EINVAL);
486 return EINVAL;
487 }
488
489 loc_sdesc_t *desc;
490 size_t count = loc_get_namespaces(&desc);
491
492 /* Get rid of root namespace */
493 size_t i;
494 for (i = 0; i < count; i++) {
495 if (str_cmp(desc[i].name, "") == 0) {
496 if (pos >= i)
497 pos++;
498
499 break;
500 }
501 }
502
503 if (pos < count) {
504 async_data_read_finalize(&call, desc[pos].name, str_size(desc[pos].name) + 1);
505 free(desc);
506 *rbytes = 1;
507 return EOK;
508 }
509
510 free(desc);
511 pos -= count;
512
513 /* Search root namespace */
514 service_id_t namespace;
515 if (loc_namespace_get_id("", &namespace, 0) == EOK) {
516 count = loc_get_services(namespace, &desc);
517
518 if (pos < count) {
519 async_data_read_finalize(&call, desc[pos].name, str_size(desc[pos].name) + 1);
520 free(desc);
521 *rbytes = 1;
522 return EOK;
523 }
524
525 free(desc);
526 }
527
528 async_answer_0(&call, ENOENT);
529 return ENOENT;
530 }
531
532 loc_object_type_t type = loc_id_probe(index);
533
534 if (type == LOC_OBJECT_NAMESPACE) {
535 /* Namespace directory */
536 ipc_call_t call;
537 size_t size;
538 if (!async_data_read_receive(&call, &size)) {
539 async_answer_0(&call, EINVAL);
540 return EINVAL;
541 }
542
543 loc_sdesc_t *desc;
544 size_t count = loc_get_services(index, &desc);
545
546 if (pos < count) {
547 async_data_read_finalize(&call, desc[pos].name, str_size(desc[pos].name) + 1);
548 free(desc);
549 *rbytes = 1;
550 return EOK;
551 }
552
553 free(desc);
554 async_answer_0(&call, ENOENT);
555 return ENOENT;
556 }
557
558 if (type == LOC_OBJECT_SERVICE) {
559 /* Device node */
560
561 fibril_mutex_lock(&services_mutex);
562 service_id_t service_index = index;
563 ht_link_t *lnk = hash_table_find(&services, &service_index);
564 if (lnk == NULL) {
565 fibril_mutex_unlock(&services_mutex);
566 return ENOENT;
567 }
568
569 service_t *dev = hash_table_get_inst(lnk, service_t, link);
570 assert(dev->sess);
571
572 ipc_call_t call;
573 if (!async_data_read_receive(&call, NULL)) {
574 fibril_mutex_unlock(&services_mutex);
575 async_answer_0(&call, EINVAL);
576 return EINVAL;
577 }
578
579 /* Make a request at the driver */
580 async_exch_t *exch = async_exchange_begin(dev->sess);
581
582 ipc_call_t answer;
583 aid_t msg = async_send_4(exch, VFS_OUT_READ, service_id,
584 index, LOWER32(pos), UPPER32(pos), &answer);
585
586 /* Forward the IPC_M_DATA_READ request to the driver */
587 async_forward_0(&call, exch, 0, IPC_FF_ROUTE_FROM_ME);
588
589 async_exchange_end(exch);
590
591 fibril_mutex_unlock(&services_mutex);
592
593 /* Wait for reply from the driver. */
594 errno_t rc;
595 async_wait_for(msg, &rc);
596
597 /* Do not propagate EHANGUP back to VFS. */
598 if (rc == EHANGUP)
599 rc = ENOTSUP;
600
601 *rbytes = ipc_get_arg1(&answer);
602 return rc;
603 }
604
605 return ENOENT;
606}
607
608static errno_t
609locfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
610 size_t *wbytes, aoff64_t *nsize)
611{
612 if (index == 0)
613 return ENOTSUP;
614
615 loc_object_type_t type = loc_id_probe(index);
616
617 if (type == LOC_OBJECT_NAMESPACE) {
618 /* Namespace directory */
619 return ENOTSUP;
620 }
621
622 if (type == LOC_OBJECT_SERVICE) {
623 /* Device node */
624
625 fibril_mutex_lock(&services_mutex);
626 service_id_t service_index = index;
627 ht_link_t *lnk = hash_table_find(&services, &service_index);
628 if (lnk == NULL) {
629 fibril_mutex_unlock(&services_mutex);
630 return ENOENT;
631 }
632
633 service_t *dev = hash_table_get_inst(lnk, service_t, link);
634 assert(dev->sess);
635
636 ipc_call_t call;
637 if (!async_data_write_receive(&call, NULL)) {
638 fibril_mutex_unlock(&services_mutex);
639 async_answer_0(&call, EINVAL);
640 return EINVAL;
641 }
642
643 /* Make a request at the driver */
644 async_exch_t *exch = async_exchange_begin(dev->sess);
645
646 ipc_call_t answer;
647 aid_t msg = async_send_4(exch, VFS_OUT_WRITE, service_id,
648 index, LOWER32(pos), UPPER32(pos), &answer);
649
650 /* Forward the IPC_M_DATA_WRITE request to the driver */
651 async_forward_0(&call, exch, 0, IPC_FF_ROUTE_FROM_ME);
652
653 async_exchange_end(exch);
654
655 fibril_mutex_unlock(&services_mutex);
656
657 /* Wait for reply from the driver. */
658 errno_t rc;
659 async_wait_for(msg, &rc);
660
661 /* Do not propagate EHANGUP back to VFS. */
662 if (rc == EHANGUP)
663 rc = ENOTSUP;
664
665 *wbytes = ipc_get_arg1(&answer);
666 *nsize = 0;
667 return rc;
668 }
669
670 return ENOENT;
671}
672
673static errno_t
674locfs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
675{
676 return ENOTSUP;
677}
678
679static errno_t locfs_close(service_id_t service_id, fs_index_t index)
680{
681 if (index == 0)
682 return EOK;
683
684 loc_object_type_t type = loc_id_probe(index);
685
686 if (type == LOC_OBJECT_NAMESPACE) {
687 /* Namespace directory */
688 return EOK;
689 }
690
691 if (type == LOC_OBJECT_SERVICE) {
692
693 fibril_mutex_lock(&services_mutex);
694 service_id_t service_index = index;
695 ht_link_t *lnk = hash_table_find(&services, &service_index);
696 if (lnk == NULL) {
697 fibril_mutex_unlock(&services_mutex);
698 return ENOENT;
699 }
700
701 service_t *dev = hash_table_get_inst(lnk, service_t, link);
702 assert(dev->sess);
703 dev->refcount--;
704
705 if (dev->refcount == 0) {
706 async_hangup(dev->sess);
707 service_id_t service_index = index;
708 hash_table_remove(&services, &service_index);
709 }
710
711 fibril_mutex_unlock(&services_mutex);
712
713 return EOK;
714 }
715
716 return ENOENT;
717}
718
719static errno_t locfs_sync(service_id_t service_id, fs_index_t index)
720{
721 if (index == 0)
722 return EOK;
723
724 loc_object_type_t type = loc_id_probe(index);
725
726 if (type == LOC_OBJECT_NAMESPACE) {
727 /* Namespace directory */
728 return EOK;
729 }
730
731 if (type == LOC_OBJECT_SERVICE) {
732
733 fibril_mutex_lock(&services_mutex);
734 service_id_t service_index = index;
735 ht_link_t *lnk = hash_table_find(&services, &service_index);
736 if (lnk == NULL) {
737 fibril_mutex_unlock(&services_mutex);
738 return ENOENT;
739 }
740
741 service_t *dev = hash_table_get_inst(lnk, service_t, link);
742 assert(dev->sess);
743
744 /* Make a request at the driver */
745 async_exch_t *exch = async_exchange_begin(dev->sess);
746
747 ipc_call_t answer;
748 aid_t msg = async_send_2(exch, VFS_OUT_SYNC, service_id,
749 index, &answer);
750
751 async_exchange_end(exch);
752
753 fibril_mutex_unlock(&services_mutex);
754
755 /* Wait for reply from the driver */
756 errno_t rc;
757 async_wait_for(msg, &rc);
758
759 return rc;
760 }
761
762 return ENOENT;
763}
764
765static errno_t locfs_destroy(service_id_t service_id, fs_index_t index)
766{
767 return ENOTSUP;
768}
769
770vfs_out_ops_t locfs_ops = {
771 .fsprobe = locfs_fsprobe,
772 .mounted = locfs_mounted,
773 .unmounted = locfs_unmounted,
774 .read = locfs_read,
775 .write = locfs_write,
776 .truncate = locfs_truncate,
777 .close = locfs_close,
778 .destroy = locfs_destroy,
779 .sync = locfs_sync,
780};
781
782/**
783 * @}
784 */
Note: See TracBrowser for help on using the repository browser.