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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6d5e378 was 086290d, checked in by Jakub Jermar <jakub@…>, 14 years ago

locfs should not propagate EHANGUP to VFS.

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