source: mainline/uspace/srv/fs/ext2fs/ext2fs_ops.c@ 3bb732b

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3bb732b was 0ca7286, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

Added resizing to user space (single-threaded) hash_table. Resizes in a way to mitigate effects of bad hash functions. Change of interface affected many files.

  • Property mode set to 100644
File size: 22.6 KB
RevLine 
[796c276]1/*
2 * Copyright (c) 2011 Martin Sucha
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 ext2fs_ops.c
35 * @brief Implementation of VFS operations for the EXT2 file system server.
36 */
37
38#include "ext2fs.h"
39#include "../../vfs/vfs.h"
40#include <libfs.h>
41#include <libblock.h>
42#include <libext2.h>
43#include <ipc/services.h>
[15f3c3f]44#include <ipc/loc.h>
[796c276]45#include <macros.h>
46#include <async.h>
47#include <errno.h>
48#include <str.h>
49#include <byteorder.h>
50#include <adt/hash_table.h>
51#include <adt/list.h>
52#include <assert.h>
53#include <fibril_synch.h>
54#include <sys/mman.h>
55#include <align.h>
56#include <adt/hash_table.h>
[7ea69a6]57#include <sys/typefmt.h>
[0e26444]58#include <malloc.h>
59#include <stdio.h>
[f6fece9]60#include <inttypes.h>
[796c276]61
[4dc6a32]62#define EXT2FS_NODE(node) ((node) ? (ext2fs_node_t *) (node)->data : NULL)
63#define EXT2FS_DBG(format, ...) {if (false) printf("ext2fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
[d1ac0d7]64#define OPEN_NODES_KEYS 2
65#define OPEN_NODES_DEV_HANDLE_KEY 0
66#define OPEN_NODES_INODE_KEY 1
[796c276]67
[4dc6a32]68typedef struct ext2fs_instance {
69 link_t link;
[15f3c3f]70 service_id_t service_id;
[4dc6a32]71 ext2_filesystem_t *filesystem;
[d1ac0d7]72 unsigned int open_nodes_count;
[4dc6a32]73} ext2fs_instance_t;
74
75typedef struct ext2fs_node {
76 ext2fs_instance_t *instance;
77 ext2_inode_ref_t *inode_ref;
[d1ac0d7]78 fs_node_t *fs_node;
79 link_t link;
80 unsigned int references;
[4dc6a32]81} ext2fs_node_t;
82
[e2abab03]83/*
84 * Forward declarations of auxiliary functions
85 */
[15f3c3f]86static int ext2fs_instance_get(service_id_t, ext2fs_instance_t **);
[efcebe1]87static int ext2fs_read_directory(ipc_callid_t, aoff64_t, size_t,
88 ext2fs_instance_t *, ext2_inode_ref_t *, size_t *);
89static int ext2fs_read_file(ipc_callid_t, aoff64_t, size_t, ext2fs_instance_t *,
90 ext2_inode_ref_t *, size_t *);
[84226f0]91static bool ext2fs_is_dots(const uint8_t *, size_t);
[e2abab03]92static int ext2fs_node_get_core(fs_node_t **, ext2fs_instance_t *, fs_index_t);
[d1ac0d7]93static int ext2fs_node_put_core(ext2fs_node_t *);
[796c276]94
95/*
96 * Forward declarations of EXT2 libfs operations.
97 */
[15f3c3f]98static int ext2fs_root_get(fs_node_t **, service_id_t);
[796c276]99static int ext2fs_match(fs_node_t **, fs_node_t *, const char *);
[15f3c3f]100static int ext2fs_node_get(fs_node_t **, service_id_t, fs_index_t);
[796c276]101static int ext2fs_node_open(fs_node_t *);
102static int ext2fs_node_put(fs_node_t *);
[15f3c3f]103static int ext2fs_create_node(fs_node_t **, service_id_t, int);
[796c276]104static int ext2fs_destroy_node(fs_node_t *);
105static int ext2fs_link(fs_node_t *, fs_node_t *, const char *);
106static int ext2fs_unlink(fs_node_t *, fs_node_t *, const char *);
107static int ext2fs_has_children(bool *, fs_node_t *);
108static fs_index_t ext2fs_index_get(fs_node_t *);
109static aoff64_t ext2fs_size_get(fs_node_t *);
110static unsigned ext2fs_lnkcnt_get(fs_node_t *);
111static bool ext2fs_is_directory(fs_node_t *);
112static bool ext2fs_is_file(fs_node_t *node);
[b33870b]113static service_id_t ext2fs_service_get(fs_node_t *node);
[796c276]114
115/*
116 * Static variables
117 */
[4dc6a32]118static LIST_INITIALIZE(instance_list);
[a210bc7]119static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
[d1ac0d7]120static hash_table_t open_nodes;
121static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
122
123/* Hash table interface for open nodes hash table */
[0ca7286]124static size_t open_nodes_key_hash(unsigned long key[])
[d1ac0d7]125{
[0ca7286]126 /* Hash construction recommended in Effective Java, 2nd Edition. */
127 size_t hash = 17;
128 hash = 31 * hash + key[OPEN_NODES_DEV_HANDLE_KEY];
129 hash = 31 * hash + key[OPEN_NODES_INODE_KEY];
130 return hash;
[d1ac0d7]131}
132
[0ca7286]133static size_t open_nodes_hash(const link_t *item)
134{
135 ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
136
137 assert(enode->instance);
138 assert(enode->inode_ref);
139
140 unsigned long key[] = {
141 [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
142 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
143 };
144
145 return open_nodes_key_hash(key);
146}
147
148static bool open_nodes_match(unsigned long key[], size_t keys,
149 const link_t *item)
[d1ac0d7]150{
151 ext2fs_node_t *enode = hash_table_get_instance(item, ext2fs_node_t, link);
152 assert(keys > 0);
[15f3c3f]153 if (enode->instance->service_id !=
154 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
[d1ac0d7]155 return false;
156 }
157 if (keys == 1) {
158 return true;
159 }
160 assert(keys == 2);
161 return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
162}
163
[0ca7286]164static hash_table_ops_t open_nodes_ops = {
[d1ac0d7]165 .hash = open_nodes_hash,
[0ca7286]166 .key_hash = open_nodes_key_hash,
167 .match = open_nodes_match,
168 .equal = 0,
169 .remove_callback = 0,
[d1ac0d7]170};
[796c276]171
172/**
173 *
174 */
175int ext2fs_global_init(void)
176{
[0ca7286]177 if (!hash_table_create(&open_nodes, 0, OPEN_NODES_KEYS, &open_nodes_ops)) {
[d1ac0d7]178 return ENOMEM;
179 }
[4dc6a32]180 return EOK;
181}
182
183int ext2fs_global_fini(void)
184{
[d1ac0d7]185 hash_table_destroy(&open_nodes);
[796c276]186 return EOK;
187}
188
189
190/*
191 * EXT2 libfs operations.
192 */
193
[4dc6a32]194/**
[15f3c3f]195 * Find an instance of filesystem for the given service_id
[4dc6a32]196 */
[15f3c3f]197int ext2fs_instance_get(service_id_t service_id, ext2fs_instance_t **inst)
[4dc6a32]198{
[15f3c3f]199 EXT2FS_DBG("(%" PRIun ", -)", service_id);
[4dc6a32]200 ext2fs_instance_t *tmp;
[a210bc7]201
202 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]203
204 if (list_empty(&instance_list)) {
205 EXT2FS_DBG("list empty");
[a210bc7]206 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]207 return EINVAL;
208 }
209
[b72efe8]210 list_foreach(instance_list, link) {
[4dc6a32]211 tmp = list_get_instance(link, ext2fs_instance_t, link);
212
[15f3c3f]213 if (tmp->service_id == service_id) {
[4dc6a32]214 *inst = tmp;
[a210bc7]215 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]216 return EOK;
217 }
218 }
219
220 EXT2FS_DBG("not found");
[a210bc7]221
222 fibril_mutex_unlock(&instance_list_mutex);
[4dc6a32]223 return EINVAL;
224}
225
226
227
[15f3c3f]228int ext2fs_root_get(fs_node_t **rfn, service_id_t service_id)
[796c276]229{
[15f3c3f]230 EXT2FS_DBG("(-, %" PRIun ")", service_id);
231 return ext2fs_node_get(rfn, service_id, EXT2_INODE_ROOT_INDEX);
[796c276]232}
233
234int ext2fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
235{
[4dc6a32]236 EXT2FS_DBG("(-,-,%s)", component);
237 ext2fs_node_t *eparent = EXT2FS_NODE(pfn);
238 ext2_filesystem_t *fs;
239 ext2_directory_iterator_t it;
240 int rc;
241 size_t name_size;
242 size_t component_size;
243 bool found = false;
[82a3b31f]244 uint32_t inode;
[4dc6a32]245
246 fs = eparent->instance->filesystem;
247
248 if (!ext2_inode_is_type(fs->superblock, eparent->inode_ref->inode,
249 EXT2_INODE_MODE_DIRECTORY)) {
250 return ENOTDIR;
251 }
252
[4e36219]253 rc = ext2_directory_iterator_init(&it, fs, eparent->inode_ref, 0);
[4dc6a32]254 if (rc != EOK) {
255 return rc;
256 }
257
[1a86c50]258 /* Find length of component in bytes
259 * TODO: check for library function call that does this
260 */
[4dc6a32]261 component_size = 0;
262 while (*(component+component_size) != 0) {
263 component_size++;
264 }
265
266 while (it.current != NULL) {
[82a3b31f]267 inode = ext2_directory_entry_ll_get_inode(it.current);
268
[1a86c50]269 /* ignore empty directory entries */
[82a3b31f]270 if (inode != 0) {
[4dc6a32]271 name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
272 it.current);
273
274 if (name_size == component_size && bcmp(component, &it.current->name,
275 name_size) == 0) {
[e2abab03]276 rc = ext2fs_node_get_core(rfn, eparent->instance,
[82a3b31f]277 inode);
[4dc6a32]278 if (rc != EOK) {
279 ext2_directory_iterator_fini(&it);
280 return rc;
281 }
282 found = true;
283 break;
284 }
285 }
286
287 rc = ext2_directory_iterator_next(&it);
288 if (rc != EOK) {
289 ext2_directory_iterator_fini(&it);
290 return rc;
291 }
292 }
293
294 ext2_directory_iterator_fini(&it);
295
296 if (!found) {
297 return ENOENT;
298 }
299
300 return EOK;
[796c276]301}
302
303/** Instantiate a EXT2 in-core node. */
[15f3c3f]304int ext2fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
[796c276]305{
[15f3c3f]306 EXT2FS_DBG("(-,%" PRIun ",%u)", service_id, index);
[e2abab03]307
308 ext2fs_instance_t *inst = NULL;
309 int rc;
310
[15f3c3f]311 rc = ext2fs_instance_get(service_id, &inst);
[e2abab03]312 if (rc != EOK) {
313 return rc;
314 }
315
316 return ext2fs_node_get_core(rfn, inst, index);
317}
318
319int ext2fs_node_get_core(fs_node_t **rfn, ext2fs_instance_t *inst,
320 fs_index_t index)
321{
[4dc6a32]322 int rc;
323 fs_node_t *node = NULL;
324 ext2fs_node_t *enode = NULL;
[e2abab03]325
[4dc6a32]326 ext2_inode_ref_t *inode_ref = NULL;
327
[d1ac0d7]328 fibril_mutex_lock(&open_nodes_lock);
329
330 /* Check if the node is not already open */
331 unsigned long key[] = {
[15f3c3f]332 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
[d1ac0d7]333 [OPEN_NODES_INODE_KEY] = index,
334 };
335 link_t *already_open = hash_table_find(&open_nodes, key);
336
337 if (already_open) {
338 enode = hash_table_get_instance(already_open, ext2fs_node_t, link);
339 *rfn = enode->fs_node;
340 enode->references++;
341
342 fibril_mutex_unlock(&open_nodes_lock);
343 return EOK;
344 }
345
[4dc6a32]346 enode = malloc(sizeof(ext2fs_node_t));
347 if (enode == NULL) {
[d1ac0d7]348 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]349 return ENOMEM;
350 }
351
352 node = malloc(sizeof(fs_node_t));
353 if (node == NULL) {
354 free(enode);
[d1ac0d7]355 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]356 return ENOMEM;
[e2abab03]357 }
[4dc6a32]358 fs_node_initialize(node);
359
360 rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
361 if (rc != EOK) {
362 free(enode);
363 free(node);
[d1ac0d7]364 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]365 return rc;
366 }
367
368 enode->inode_ref = inode_ref;
369 enode->instance = inst;
[d1ac0d7]370 enode->references = 1;
371 enode->fs_node = node;
372 link_initialize(&enode->link);
373
[4dc6a32]374 node->data = enode;
375 *rfn = node;
376
[0ca7286]377 hash_table_insert(&open_nodes, &enode->link);
[d1ac0d7]378 inst->open_nodes_count++;
379
[4dc6a32]380 EXT2FS_DBG("inode: %u", inode_ref->index);
381
382 EXT2FS_DBG("EOK");
383
[d1ac0d7]384 fibril_mutex_unlock(&open_nodes_lock);
[4dc6a32]385 return EOK;
[796c276]386}
387
388int ext2fs_node_open(fs_node_t *fn)
389{
[4dc6a32]390 EXT2FS_DBG("");
[796c276]391 /*
392 * Opening a file is stateless, nothing
393 * to be done here.
394 */
395 return EOK;
396}
397
398int ext2fs_node_put(fs_node_t *fn)
399{
[4dc6a32]400 EXT2FS_DBG("");
401 int rc;
402 ext2fs_node_t *enode = EXT2FS_NODE(fn);
[d1ac0d7]403
404 fibril_mutex_lock(&open_nodes_lock);
405
406 assert(enode->references > 0);
407 enode->references--;
408 if (enode->references == 0) {
409 rc = ext2fs_node_put_core(enode);
410 if (rc != EOK) {
411 fibril_mutex_unlock(&open_nodes_lock);
412 return rc;
413 }
414 }
415
416 fibril_mutex_unlock(&open_nodes_lock);
417
418 return EOK;
419}
420
421int ext2fs_node_put_core(ext2fs_node_t *enode)
422{
423 int rc;
424
425 unsigned long key[] = {
[15f3c3f]426 [OPEN_NODES_DEV_HANDLE_KEY] = enode->instance->service_id,
[d1ac0d7]427 [OPEN_NODES_INODE_KEY] = enode->inode_ref->index,
428 };
429 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
430 assert(enode->instance->open_nodes_count > 0);
431 enode->instance->open_nodes_count--;
432
[4dc6a32]433 rc = ext2_filesystem_put_inode_ref(enode->inode_ref);
434 if (rc != EOK) {
435 EXT2FS_DBG("ext2_filesystem_put_inode_ref failed");
[d1ac0d7]436 return rc;
[4dc6a32]437 }
[d1ac0d7]438
439 free(enode->fs_node);
440 free(enode);
441 return EOK;
[796c276]442}
443
[15f3c3f]444int ext2fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[796c276]445{
[4dc6a32]446 EXT2FS_DBG("");
[796c276]447 // TODO
448 return ENOTSUP;
449}
450
451int ext2fs_destroy_node(fs_node_t *fn)
452{
[4dc6a32]453 EXT2FS_DBG("");
[796c276]454 // TODO
455 return ENOTSUP;
456}
457
458int ext2fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
459{
[4dc6a32]460 EXT2FS_DBG("");
[796c276]461 // TODO
462 return ENOTSUP;
463}
464
465int ext2fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
466{
[4dc6a32]467 EXT2FS_DBG("");
[796c276]468 // TODO
469 return ENOTSUP;
470}
471
472int ext2fs_has_children(bool *has_children, fs_node_t *fn)
473{
[4dc6a32]474 EXT2FS_DBG("");
475 ext2fs_node_t *enode = EXT2FS_NODE(fn);
476 ext2_directory_iterator_t it;
477 ext2_filesystem_t *fs;
478 int rc;
479 bool found = false;
[84226f0]480 size_t name_size;
[4dc6a32]481
482 fs = enode->instance->filesystem;
483
484 if (!ext2_inode_is_type(fs->superblock, enode->inode_ref->inode,
485 EXT2_INODE_MODE_DIRECTORY)) {
486 *has_children = false;
487 EXT2FS_DBG("EOK - false");
488 return EOK;
489 }
490
[4e36219]491 rc = ext2_directory_iterator_init(&it, fs, enode->inode_ref, 0);
[4dc6a32]492 if (rc != EOK) {
493 EXT2FS_DBG("error %u", rc);
494 return rc;
495 }
496
[1a86c50]497 /* Find a non-empty directory entry */
[4dc6a32]498 while (it.current != NULL) {
499 if (it.current->inode != 0) {
[84226f0]500 name_size = ext2_directory_entry_ll_get_name_length(fs->superblock,
501 it.current);
502 if (!ext2fs_is_dots(&it.current->name, name_size)) {
503 found = true;
504 break;
505 }
[4dc6a32]506 }
507
508 rc = ext2_directory_iterator_next(&it);
509 if (rc != EOK) {
510 ext2_directory_iterator_fini(&it);
511 EXT2FS_DBG("error %u", rc);
512 return rc;
513 }
514 }
515
516 rc = ext2_directory_iterator_fini(&it);
517 if (rc != EOK) {
518 EXT2FS_DBG("error %u", rc);
519 return rc;
520 }
521
522 *has_children = found;
523 EXT2FS_DBG("EOK");
524
525 return EOK;
[796c276]526}
527
528
529fs_index_t ext2fs_index_get(fs_node_t *fn)
530{
[4dc6a32]531 ext2fs_node_t *enode = EXT2FS_NODE(fn);
532 EXT2FS_DBG("%u", enode->inode_ref->index);
533 return enode->inode_ref->index;
[796c276]534}
535
536aoff64_t ext2fs_size_get(fs_node_t *fn)
537{
[4dc6a32]538 ext2fs_node_t *enode = EXT2FS_NODE(fn);
539 aoff64_t size = ext2_inode_get_size(enode->instance->filesystem->superblock,
540 enode->inode_ref->inode);
541 EXT2FS_DBG("%" PRIu64, size);
542 return size;
[796c276]543}
544
545unsigned ext2fs_lnkcnt_get(fs_node_t *fn)
546{
[4dc6a32]547 ext2fs_node_t *enode = EXT2FS_NODE(fn);
548 unsigned count = ext2_inode_get_usage_count(enode->inode_ref->inode);
549 EXT2FS_DBG("%u", count);
550 return count;
[796c276]551}
552
553bool ext2fs_is_directory(fs_node_t *fn)
554{
[4dc6a32]555 ext2fs_node_t *enode = EXT2FS_NODE(fn);
556 bool is_dir = ext2_inode_is_type(enode->instance->filesystem->superblock,
557 enode->inode_ref->inode, EXT2_INODE_MODE_DIRECTORY);
558 EXT2FS_DBG("%s", is_dir ? "true" : "false");
559 EXT2FS_DBG("%u", enode->inode_ref->index);
560 return is_dir;
[796c276]561}
562
563bool ext2fs_is_file(fs_node_t *fn)
564{
[4dc6a32]565 ext2fs_node_t *enode = EXT2FS_NODE(fn);
566 bool is_file = ext2_inode_is_type(enode->instance->filesystem->superblock,
567 enode->inode_ref->inode, EXT2_INODE_MODE_FILE);
568 EXT2FS_DBG("%s", is_file ? "true" : "false");
569 return is_file;
[796c276]570}
571
[b33870b]572service_id_t ext2fs_service_get(fs_node_t *fn)
[796c276]573{
[4dc6a32]574 EXT2FS_DBG("");
575 ext2fs_node_t *enode = EXT2FS_NODE(fn);
[15f3c3f]576 return enode->instance->service_id;
[796c276]577}
578
579/** libfs operations */
580libfs_ops_t ext2fs_libfs_ops = {
581 .root_get = ext2fs_root_get,
582 .match = ext2fs_match,
583 .node_get = ext2fs_node_get,
584 .node_open = ext2fs_node_open,
585 .node_put = ext2fs_node_put,
586 .create = ext2fs_create_node,
587 .destroy = ext2fs_destroy_node,
588 .link = ext2fs_link,
589 .unlink = ext2fs_unlink,
590 .has_children = ext2fs_has_children,
591 .index_get = ext2fs_index_get,
592 .size_get = ext2fs_size_get,
593 .lnkcnt_get = ext2fs_lnkcnt_get,
594 .is_directory = ext2fs_is_directory,
595 .is_file = ext2fs_is_file,
[b33870b]596 .service_get = ext2fs_service_get
[796c276]597};
598
599/*
600 * VFS operations.
601 */
602
[86ffa27f]603static int ext2fs_mounted(service_id_t service_id, const char *opts,
[efcebe1]604 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
[796c276]605{
[4dc6a32]606 EXT2FS_DBG("");
[796c276]607 int rc;
608 ext2_filesystem_t *fs;
[4dc6a32]609 ext2fs_instance_t *inst;
[eef306c]610 bool read_only;
[4dc6a32]611
[796c276]612 /* Allocate libext2 filesystem structure */
613 fs = (ext2_filesystem_t *) malloc(sizeof(ext2_filesystem_t));
[efcebe1]614 if (fs == NULL)
615 return ENOMEM;
[796c276]616
[4dc6a32]617 /* Allocate instance structure */
618 inst = (ext2fs_instance_t *) malloc(sizeof(ext2fs_instance_t));
619 if (inst == NULL) {
620 free(fs);
[efcebe1]621 return ENOMEM;
[4dc6a32]622 }
623
[796c276]624 /* Initialize the filesystem */
[15f3c3f]625 rc = ext2_filesystem_init(fs, service_id);
[796c276]626 if (rc != EOK) {
[4dc6a32]627 free(fs);
628 free(inst);
[efcebe1]629 return rc;
[796c276]630 }
631
632 /* Do some sanity checking */
633 rc = ext2_filesystem_check_sanity(fs);
634 if (rc != EOK) {
635 ext2_filesystem_fini(fs);
[4dc6a32]636 free(fs);
637 free(inst);
[efcebe1]638 return rc;
[796c276]639 }
640
[eef306c]641 /* Check flags */
642 rc = ext2_filesystem_check_flags(fs, &read_only);
643 if (rc != EOK) {
644 ext2_filesystem_fini(fs);
645 free(fs);
646 free(inst);
[efcebe1]647 return rc;
[eef306c]648 }
649
[d1ac0d7]650 /* Initialize instance */
[4dc6a32]651 link_initialize(&inst->link);
[15f3c3f]652 inst->service_id = service_id;
[4dc6a32]653 inst->filesystem = fs;
[d1ac0d7]654 inst->open_nodes_count = 0;
[a210bc7]655
[d1ac0d7]656 /* Read root node */
657 fs_node_t *root_node;
658 rc = ext2fs_node_get_core(&root_node, inst, EXT2_INODE_ROOT_INDEX);
659 if (rc != EOK) {
660 ext2_filesystem_fini(fs);
661 free(fs);
662 free(inst);
[efcebe1]663 return rc;
[d1ac0d7]664 }
665 ext2fs_node_t *enode = EXT2FS_NODE(root_node);
666
667 /* Add instance to the list */
[a210bc7]668 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]669 list_append(&inst->link, &instance_list);
[a210bc7]670 fibril_mutex_unlock(&instance_list_mutex);
[796c276]671
[efcebe1]672 *index = EXT2_INODE_ROOT_INDEX;
673 *size = 0;
674 *lnkcnt = ext2_inode_get_usage_count(enode->inode_ref->inode);
[d1ac0d7]675
676 ext2fs_node_put(root_node);
[796c276]677
[efcebe1]678 return EOK;
[796c276]679}
680
[86ffa27f]681static int ext2fs_unmounted(service_id_t service_id)
[796c276]682{
[4dc6a32]683 EXT2FS_DBG("");
684 ext2fs_instance_t *inst;
685 int rc;
686
[15f3c3f]687 rc = ext2fs_instance_get(service_id, &inst);
[4dc6a32]688
[efcebe1]689 if (rc != EOK)
690 return rc;
[4dc6a32]691
[d1ac0d7]692 fibril_mutex_lock(&open_nodes_lock);
693
694 EXT2FS_DBG("open_nodes_count = %d", inst->open_nodes_count)
695 if (inst->open_nodes_count != 0) {
696 fibril_mutex_unlock(&open_nodes_lock);
[efcebe1]697 return EBUSY;
[d1ac0d7]698 }
[4dc6a32]699
[1a86c50]700 /* Remove the instance from the list */
[a210bc7]701 fibril_mutex_lock(&instance_list_mutex);
[4dc6a32]702 list_remove(&inst->link);
[a210bc7]703 fibril_mutex_unlock(&instance_list_mutex);
[d1ac0d7]704
705 fibril_mutex_unlock(&open_nodes_lock);
[a210bc7]706
[4dc6a32]707 ext2_filesystem_fini(inst->filesystem);
708
[efcebe1]709 return EOK;
[796c276]710}
711
[efcebe1]712static int
[86ffa27f]713ext2fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]714 size_t *rbytes)
[796c276]715{
[4dc6a32]716 EXT2FS_DBG("");
[796c276]717
[4dc6a32]718 ext2fs_instance_t *inst;
719 ext2_inode_ref_t *inode_ref;
720 int rc;
[b83e16ff]721
[4dc6a32]722 /*
723 * Receive the read request.
724 */
725 ipc_callid_t callid;
726 size_t size;
727 if (!async_data_read_receive(&callid, &size)) {
728 async_answer_0(callid, EINVAL);
[efcebe1]729 return EINVAL;
[4dc6a32]730 }
731
[15f3c3f]732 rc = ext2fs_instance_get(service_id, &inst);
[4dc6a32]733 if (rc != EOK) {
734 async_answer_0(callid, rc);
[efcebe1]735 return rc;
[4dc6a32]736 }
737
738 rc = ext2_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
739 if (rc != EOK) {
740 async_answer_0(callid, rc);
[efcebe1]741 return rc;
[4dc6a32]742 }
743
744 if (ext2_inode_is_type(inst->filesystem->superblock, inode_ref->inode,
[efcebe1]745 EXT2_INODE_MODE_FILE)) {
746 rc = ext2fs_read_file(callid, pos, size, inst, inode_ref,
747 rbytes);
748 } else if (ext2_inode_is_type(inst->filesystem->superblock,
749 inode_ref->inode, EXT2_INODE_MODE_DIRECTORY)) {
750 rc = ext2fs_read_directory(callid, pos, size, inst, inode_ref,
751 rbytes);
752 } else {
[1a86c50]753 /* Other inode types not supported */
[df38657]754 async_answer_0(callid, ENOTSUP);
[efcebe1]755 rc = ENOTSUP;
[df38657]756 }
757
758 ext2_filesystem_put_inode_ref(inode_ref);
[b83e16ff]759
[efcebe1]760 return rc;
[b83e16ff]761}
762
[84226f0]763/**
764 * Determine whether given directory entry name is . or ..
765 */
766bool ext2fs_is_dots(const uint8_t *name, size_t name_size) {
767 if (name_size == 1 && name[0] == '.') {
768 return true;
769 }
770
771 if (name_size == 2 && name[0] == '.' && name[1] == '.') {
772 return true;
773 }
774
775 return false;
776}
777
[efcebe1]778int ext2fs_read_directory(ipc_callid_t callid, aoff64_t pos, size_t size,
779 ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
[b83e16ff]780{
781 ext2_directory_iterator_t it;
[4e36219]782 aoff64_t next;
[b83e16ff]783 uint8_t *buf;
784 size_t name_size;
785 int rc;
[df38657]786 bool found = false;
[b83e16ff]787
[4e36219]788 rc = ext2_directory_iterator_init(&it, inst->filesystem, inode_ref, pos);
[b83e16ff]789 if (rc != EOK) {
790 async_answer_0(callid, rc);
[efcebe1]791 return rc;
[b83e16ff]792 }
793
[4e36219]794 /* Find next interesting directory entry.
795 * We want to skip . and .. entries
[1a86c50]796 * as these are not used in HelenOS
797 */
[b83e16ff]798 while (it.current != NULL) {
[df38657]799 if (it.current->inode == 0) {
800 goto skip;
801 }
802
803 name_size = ext2_directory_entry_ll_get_name_length(
[efcebe1]804 inst->filesystem->superblock, it.current);
[df38657]805
[1a86c50]806 /* skip . and .. */
[84226f0]807 if (ext2fs_is_dots(&it.current->name, name_size)) {
808 goto skip;
[4dc6a32]809 }
810
[4e36219]811 /* The on-disk entry does not contain \0 at the end
[efcebe1]812 * end of entry name, so we copy it to new buffer
813 * and add the \0 at the end
814 */
[4e36219]815 buf = malloc(name_size+1);
816 if (buf == NULL) {
817 ext2_directory_iterator_fini(&it);
818 async_answer_0(callid, ENOMEM);
[efcebe1]819 return ENOMEM;
[df38657]820 }
[4e36219]821 memcpy(buf, &it.current->name, name_size);
[efcebe1]822 *(buf + name_size) = 0;
[4e36219]823 found = true;
[efcebe1]824 (void) async_data_read_finalize(callid, buf, name_size + 1);
[4e36219]825 free(buf);
826 break;
[df38657]827
828skip:
[b83e16ff]829 rc = ext2_directory_iterator_next(&it);
[4dc6a32]830 if (rc != EOK) {
[b83e16ff]831 ext2_directory_iterator_fini(&it);
832 async_answer_0(callid, rc);
[efcebe1]833 return rc;
[4dc6a32]834 }
835 }
836
[4e36219]837 if (found) {
838 rc = ext2_directory_iterator_next(&it);
[efcebe1]839 if (rc != EOK)
840 return rc;
[4e36219]841 next = it.current_offset;
[b83e16ff]842 }
843
844 rc = ext2_directory_iterator_fini(&it);
[efcebe1]845 if (rc != EOK)
846 return rc;
[b83e16ff]847
[df38657]848 if (found) {
[efcebe1]849 *rbytes = next - pos;
850 return EOK;
851 } else {
[df38657]852 async_answer_0(callid, ENOENT);
[efcebe1]853 return ENOENT;
[df38657]854 }
[796c276]855}
856
[efcebe1]857int ext2fs_read_file(ipc_callid_t callid, aoff64_t pos, size_t size,
858 ext2fs_instance_t *inst, ext2_inode_ref_t *inode_ref, size_t *rbytes)
[529edc66]859{
860 int rc;
861 uint32_t block_size;
862 aoff64_t file_block;
863 uint64_t file_size;
864 uint32_t fs_block;
865 size_t offset_in_block;
866 size_t bytes;
867 block_t *block;
[7ea69a6]868 uint8_t *buffer;
[529edc66]869
870 file_size = ext2_inode_get_size(inst->filesystem->superblock,
871 inode_ref->inode);
872
873 if (pos >= file_size) {
[1a86c50]874 /* Read 0 bytes successfully */
[529edc66]875 async_data_read_finalize(callid, NULL, 0);
[efcebe1]876 *rbytes = 0;
877 return EOK;
[529edc66]878 }
879
[1a86c50]880 /* For now, we only read data from one block at a time */
[529edc66]881 block_size = ext2_superblock_get_block_size(inst->filesystem->superblock);
882 file_block = pos / block_size;
883 offset_in_block = pos % block_size;
884 bytes = min(block_size - offset_in_block, size);
885
[1a86c50]886 /* Handle end of file */
[7ea69a6]887 if (pos + bytes > file_size) {
888 bytes = file_size - pos;
889 }
890
[1a86c50]891 /* Get the real block number */
[529edc66]892 rc = ext2_filesystem_get_inode_data_block_index(inst->filesystem,
893 inode_ref->inode, file_block, &fs_block);
894 if (rc != EOK) {
895 async_answer_0(callid, rc);
[efcebe1]896 return rc;
[529edc66]897 }
898
[1a86c50]899 /* Check for sparse file
900 * If ext2_filesystem_get_inode_data_block_index returned
901 * fs_block == 0, it means that the given block is not allocated for the
902 * file and we need to return a buffer of zeros
903 */
[7ea69a6]904 if (fs_block == 0) {
905 buffer = malloc(bytes);
906 if (buffer == NULL) {
907 async_answer_0(callid, ENOMEM);
[efcebe1]908 return ENOMEM;
[7ea69a6]909 }
910
911 memset(buffer, 0, bytes);
912
913 async_data_read_finalize(callid, buffer, bytes);
[efcebe1]914 *rbytes = bytes;
[7ea69a6]915
916 free(buffer);
917
[efcebe1]918 return EOK;
[7ea69a6]919 }
920
[1a86c50]921 /* Usual case - we need to read a block from device */
[15f3c3f]922 rc = block_get(&block, inst->service_id, fs_block, BLOCK_FLAGS_NONE);
[529edc66]923 if (rc != EOK) {
924 async_answer_0(callid, rc);
[efcebe1]925 return rc;
[529edc66]926 }
927
[7ea69a6]928 assert(offset_in_block + bytes <= block_size);
929 async_data_read_finalize(callid, block->data + offset_in_block, bytes);
[529edc66]930
931 rc = block_put(block);
[efcebe1]932 if (rc != EOK)
933 return rc;
[796c276]934
[efcebe1]935 *rbytes = bytes;
936 return EOK;
[796c276]937}
938
[efcebe1]939static int
[86ffa27f]940ext2fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[efcebe1]941 size_t *wbytes, aoff64_t *nsize)
[796c276]942{
[4dc6a32]943 EXT2FS_DBG("");
[efcebe1]944 return ENOTSUP;
[796c276]945}
946
[efcebe1]947static int
[86ffa27f]948ext2fs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
[796c276]949{
[4dc6a32]950 EXT2FS_DBG("");
[efcebe1]951 return ENOTSUP;
[796c276]952}
953
[86ffa27f]954static int ext2fs_close(service_id_t service_id, fs_index_t index)
[796c276]955{
[4dc6a32]956 EXT2FS_DBG("");
[efcebe1]957 return EOK;
[796c276]958}
959
[86ffa27f]960static int ext2fs_destroy(service_id_t service_id, fs_index_t index)
[796c276]961{
[4dc6a32]962 EXT2FS_DBG("");
[efcebe1]963 return ENOTSUP;
[796c276]964}
965
[86ffa27f]966static int ext2fs_sync(service_id_t service_id, fs_index_t index)
[796c276]967{
[4dc6a32]968 EXT2FS_DBG("");
[efcebe1]969 return ENOTSUP;
[796c276]970}
971
[efcebe1]972vfs_out_ops_t ext2fs_ops = {
973 .mounted = ext2fs_mounted,
974 .unmounted = ext2fs_unmounted,
975 .read = ext2fs_read,
976 .write = ext2fs_write,
977 .truncate = ext2fs_truncate,
978 .close = ext2fs_close,
979 .destroy = ext2fs_destroy,
980 .sync = ext2fs_sync,
981};
[796c276]982
983/**
984 * @}
985 */
[efcebe1]986
Note: See TracBrowser for help on using the repository browser.