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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since fafb8e5 was fafb8e5, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Mechanically lowercase IPC_SET_*/IPC_GET_*

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