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