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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 83e69b9 was 1558d85, checked in by Jakub Jermar <jakub@…>, 10 years ago

Remove duplicate includes

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