source: mainline/uspace/srv/fs/ext4fs/ext4fs_ops.c@ 3711e7e

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3711e7e was 3711e7e, checked in by Frantisek Princ <frantisek.princ@…>, 14 years ago

Complete mounting skeleton (ported from ext2fs) - some filesystem checks during mount process still missing

  • Property mode set to 100644
File size: 12.5 KB
Line 
1/*
2 * Copyright (c) 2011 Frantisek Princ
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 ext4fs_ops.c
35 * @brief VFS operations for EXT4 filesystem.
36 */
37
38#include <errno.h>
39#include <fibril_synch.h>
40#include <libext4.h>
41#include <libfs.h>
42#include <malloc.h>
43#include <stdio.h>
44#include <adt/hash_table.h>
45#include <ipc/loc.h>
46#include "ext4fs.h"
47#include "../../vfs/vfs.h"
48
49#define EXT4FS_NODE(node) ((node) ? (ext4fs_node_t *) (node)->data : NULL)
50#define EXT4FS_DBG(format, ...) {if (true) printf("ext4fs: %s: " format "\n", __FUNCTION__, ##__VA_ARGS__);}
51
52#define OPEN_NODES_KEYS 2
53#define OPEN_NODES_DEV_HANDLE_KEY 0
54#define OPEN_NODES_INODE_KEY 1
55#define OPEN_NODES_BUCKETS 256
56
57typedef struct ext4fs_instance {
58 link_t link;
59 service_id_t service_id;
60 ext4_filesystem_t *filesystem;
61 unsigned int open_nodes_count;
62} ext4fs_instance_t;
63
64typedef struct ext4fs_node {
65 ext4fs_instance_t *instance;
66 ext4_inode_ref_t *inode_ref;
67 fs_node_t *fs_node;
68 link_t link;
69 unsigned int references;
70} ext4fs_node_t;
71
72/*
73 * Forward declarations of auxiliary functions
74 */
75static int ext4fs_instance_get(service_id_t, ext4fs_instance_t **);
76static int ext4fs_node_get_core(fs_node_t **, ext4fs_instance_t *, fs_index_t);
77static int ext4fs_node_put_core(ext4fs_node_t *);
78
79/*
80 * Forward declarations of EXT4 libfs operations.
81 */
82static int ext4fs_root_get(fs_node_t **, service_id_t);
83static int ext4fs_match(fs_node_t **, fs_node_t *, const char *);
84static int ext4fs_node_get(fs_node_t **, service_id_t, fs_index_t);
85static int ext4fs_node_open(fs_node_t *);
86static int ext4fs_node_put(fs_node_t *);
87static int ext4fs_create_node(fs_node_t **, service_id_t, int);
88static int ext4fs_destroy_node(fs_node_t *);
89static int ext4fs_link(fs_node_t *, fs_node_t *, const char *);
90static int ext4fs_unlink(fs_node_t *, fs_node_t *, const char *);
91static int ext4fs_has_children(bool *, fs_node_t *);
92static fs_index_t ext4fs_index_get(fs_node_t *);
93static aoff64_t ext4fs_size_get(fs_node_t *);
94static unsigned ext4fs_lnkcnt_get(fs_node_t *);
95static bool ext4fs_is_directory(fs_node_t *);
96static bool ext4fs_is_file(fs_node_t *node);
97static service_id_t ext4fs_service_get(fs_node_t *node);
98
99/*
100 * Static variables
101 */
102static LIST_INITIALIZE(instance_list);
103static FIBRIL_MUTEX_INITIALIZE(instance_list_mutex);
104static hash_table_t open_nodes;
105static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
106
107/* Hash table interface for open nodes hash table */
108static hash_index_t open_nodes_hash(unsigned long key[])
109{
110 /* TODO: This is very simple and probably can be improved */
111 return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
112}
113
114static int open_nodes_compare(unsigned long key[], hash_count_t keys,
115 link_t *item)
116{
117 ext4fs_node_t *enode = hash_table_get_instance(item, ext4fs_node_t, link);
118 assert(keys > 0);
119 if (enode->instance->service_id !=
120 ((service_id_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
121 return false;
122 }
123 if (keys == 1) {
124 return true;
125 }
126 assert(keys == 2);
127 return (enode->inode_ref->index == key[OPEN_NODES_INODE_KEY]);
128}
129
130static void open_nodes_remove_cb(link_t *link)
131{
132 /* We don't use remove callback for this hash table */
133}
134
135static hash_table_operations_t open_nodes_ops = {
136 .hash = open_nodes_hash,
137 .compare = open_nodes_compare,
138 .remove_callback = open_nodes_remove_cb,
139};
140
141
142int ext4fs_global_init(void)
143{
144 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
145 OPEN_NODES_KEYS, &open_nodes_ops)) {
146 return ENOMEM;
147 }
148 return EOK;
149}
150
151
152int ext4fs_global_fini(void)
153{
154 hash_table_destroy(&open_nodes);
155 return EOK;
156}
157
158
159/*
160 * EXT4 libfs operations.
161 */
162
163int ext4fs_instance_get(service_id_t service_id, ext4fs_instance_t **inst)
164{
165 EXT4FS_DBG("");
166
167 ext4fs_instance_t *tmp;
168
169 fibril_mutex_lock(&instance_list_mutex);
170
171 EXT4FS_DBG("Checking lists");
172
173 if (list_empty(&instance_list)) {
174 fibril_mutex_unlock(&instance_list_mutex);
175 return EINVAL;
176 }
177
178 EXT4FS_DBG("checked");
179
180 list_foreach(instance_list, link) {
181 tmp = list_get_instance(link, ext4fs_instance_t, link);
182
183 if (tmp->service_id == service_id) {
184 *inst = tmp;
185 fibril_mutex_unlock(&instance_list_mutex);
186 return EOK;
187 }
188 }
189
190 EXT4FS_DBG("Not found");
191
192 fibril_mutex_unlock(&instance_list_mutex);
193 return EINVAL;
194}
195
196
197int ext4fs_root_get(fs_node_t **rfn, service_id_t service_id)
198{
199 return ext4fs_node_get(rfn, service_id, EXT4_INODE_ROOT_INDEX);
200}
201
202
203int ext4fs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
204{
205 // TODO
206 return EOK;
207}
208
209
210int ext4fs_node_get(fs_node_t **rfn, service_id_t service_id, fs_index_t index)
211{
212 ext4fs_instance_t *inst = NULL;
213 int rc;
214
215 rc = ext4fs_instance_get(service_id, &inst);
216 if (rc != EOK) {
217 return rc;
218 }
219
220 return ext4fs_node_get_core(rfn, inst, index);
221}
222
223
224int ext4fs_node_get_core(fs_node_t **rfn, ext4fs_instance_t *inst,
225 fs_index_t index)
226{
227
228 int rc;
229 fs_node_t *node = NULL;
230 ext4fs_node_t *enode = NULL;
231
232 ext4_inode_ref_t *inode_ref = NULL;
233
234 fibril_mutex_lock(&open_nodes_lock);
235
236 /* Check if the node is not already open */
237 unsigned long key[] = {
238 [OPEN_NODES_DEV_HANDLE_KEY] = inst->service_id,
239 [OPEN_NODES_INODE_KEY] = index,
240 };
241 link_t *already_open = hash_table_find(&open_nodes, key);
242
243 if (already_open) {
244 enode = hash_table_get_instance(already_open, ext4fs_node_t, link);
245 *rfn = enode->fs_node;
246 enode->references++;
247
248 fibril_mutex_unlock(&open_nodes_lock);
249 return EOK;
250 }
251
252 enode = malloc(sizeof(ext4fs_node_t));
253 if (enode == NULL) {
254 fibril_mutex_unlock(&open_nodes_lock);
255 return ENOMEM;
256 }
257
258 node = malloc(sizeof(fs_node_t));
259 if (node == NULL) {
260 free(enode);
261 fibril_mutex_unlock(&open_nodes_lock);
262 return ENOMEM;
263 }
264 fs_node_initialize(node);
265
266 rc = ext4_filesystem_get_inode_ref(inst->filesystem, index, &inode_ref);
267 if (rc != EOK) {
268 free(enode);
269 free(node);
270 fibril_mutex_unlock(&open_nodes_lock);
271 return rc;
272 }
273
274 enode->inode_ref = inode_ref;
275 enode->instance = inst;
276 enode->references = 1;
277 enode->fs_node = node;
278 link_initialize(&enode->link);
279
280 node->data = enode;
281 *rfn = node;
282
283 hash_table_insert(&open_nodes, key, &enode->link);
284 inst->open_nodes_count++;
285
286 fibril_mutex_unlock(&open_nodes_lock);
287
288 return EOK;
289}
290
291
292int ext4fs_node_put_core(ext4fs_node_t *enode) {
293 // TODO
294 return EOK;
295}
296
297
298int ext4fs_node_open(fs_node_t *fn)
299{
300 // TODO stateless operation
301 return EOK;
302}
303
304int ext4fs_node_put(fs_node_t *fn)
305{
306 EXT4FS_DBG("");
307 int rc;
308 ext4fs_node_t *enode = EXT4FS_NODE(fn);
309
310 fibril_mutex_lock(&open_nodes_lock);
311
312 assert(enode->references > 0);
313 enode->references--;
314 if (enode->references == 0) {
315 rc = ext4fs_node_put_core(enode);
316 if (rc != EOK) {
317 fibril_mutex_unlock(&open_nodes_lock);
318 return rc;
319 }
320 }
321
322 fibril_mutex_unlock(&open_nodes_lock);
323
324 return EOK;
325}
326
327
328int ext4fs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
329{
330 // TODO
331 return ENOTSUP;
332}
333
334
335int ext4fs_destroy_node(fs_node_t *fn)
336{
337 // TODO
338 return ENOTSUP;
339}
340
341
342int ext4fs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
343{
344 // TODO
345 return ENOTSUP;
346}
347
348
349int ext4fs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
350{
351 // TODO
352 return ENOTSUP;
353}
354
355
356int ext4fs_has_children(bool *has_children, fs_node_t *fn)
357{
358 // TODO
359 return EOK;
360}
361
362
363fs_index_t ext4fs_index_get(fs_node_t *fn)
364{
365 // TODO
366 return 0;
367}
368
369
370aoff64_t ext4fs_size_get(fs_node_t *fn)
371{
372 // TODO
373 return 0;
374}
375
376
377unsigned ext4fs_lnkcnt_get(fs_node_t *fn)
378{
379 // TODO
380 return 0;
381}
382
383
384bool ext4fs_is_directory(fs_node_t *fn)
385{
386 // TODO
387 return false;
388}
389
390
391bool ext4fs_is_file(fs_node_t *fn)
392{
393 // TODO
394 return false;
395}
396
397
398service_id_t ext4fs_service_get(fs_node_t *fn)
399{
400 // TODO
401 return 0;
402}
403
404/*
405 * libfs operations.
406 */
407libfs_ops_t ext4fs_libfs_ops = {
408 .root_get = ext4fs_root_get,
409 .match = ext4fs_match,
410 .node_get = ext4fs_node_get,
411 .node_open = ext4fs_node_open,
412 .node_put = ext4fs_node_put,
413 .create = ext4fs_create_node,
414 .destroy = ext4fs_destroy_node,
415 .link = ext4fs_link,
416 .unlink = ext4fs_unlink,
417 .has_children = ext4fs_has_children,
418 .index_get = ext4fs_index_get,
419 .size_get = ext4fs_size_get,
420 .lnkcnt_get = ext4fs_lnkcnt_get,
421 .is_directory = ext4fs_is_directory,
422 .is_file = ext4fs_is_file,
423 .service_get = ext4fs_service_get
424};
425
426
427/*
428 * VFS operations.
429 */
430
431static int ext4fs_mounted(service_id_t service_id, const char *opts,
432 fs_index_t *index, aoff64_t *size, unsigned *lnkcnt)
433{
434
435 int rc;
436 ext4_filesystem_t *fs;
437 ext4fs_instance_t *inst;
438 bool read_only;
439
440 /* Allocate libext4 filesystem structure */
441 fs = (ext4_filesystem_t *) malloc(sizeof(ext4_filesystem_t));
442 if (fs == NULL) {
443 return ENOMEM;
444 }
445
446 /* Allocate instance structure */
447 inst = (ext4fs_instance_t *) malloc(sizeof(ext4fs_instance_t));
448 if (inst == NULL) {
449 free(fs);
450 return ENOMEM;
451 }
452
453 /* Initialize the filesystem */
454 rc = ext4_filesystem_init(fs, service_id);
455 if (rc != EOK) {
456 free(fs);
457 free(inst);
458 return rc;
459 }
460
461 /* Do some sanity checking */
462 rc = ext4_filesystem_check_sanity(fs);
463 if (rc != EOK) {
464 ext4_filesystem_fini(fs);
465 free(fs);
466 free(inst);
467 return rc;
468 }
469
470 /* Check flags */
471 rc = ext4_filesystem_check_features(fs, &read_only);
472 if (rc != EOK) {
473 ext4_filesystem_fini(fs);
474 free(fs);
475 free(inst);
476 return rc;
477 }
478
479 /* Initialize instance */
480 link_initialize(&inst->link);
481 inst->service_id = service_id;
482 inst->filesystem = fs;
483 inst->open_nodes_count = 0;
484
485 /* Read root node */
486 fs_node_t *root_node;
487 rc = ext4fs_node_get_core(&root_node, inst, EXT4_INODE_ROOT_INDEX);
488 if (rc != EOK) {
489 ext4_filesystem_fini(fs);
490 free(fs);
491 free(inst);
492 return rc;
493 }
494 ext4fs_node_t *enode = EXT4FS_NODE(root_node);
495
496 /* Add instance to the list */
497 fibril_mutex_lock(&instance_list_mutex);
498 list_append(&inst->link, &instance_list);
499 fibril_mutex_unlock(&instance_list_mutex);
500
501 *index = EXT4_INODE_ROOT_INDEX;
502 *size = 0;
503 *lnkcnt = ext4_inode_get_usage_count(enode->inode_ref->inode);
504
505 ext4fs_node_put(root_node);
506
507 return EOK;
508}
509
510
511static int ext4fs_unmounted(service_id_t service_id)
512{
513
514 int rc;
515 ext4fs_instance_t *inst;
516
517 rc = ext4fs_instance_get(service_id, &inst);
518
519 if (rc != EOK) {
520 return rc;
521 }
522
523 fibril_mutex_lock(&open_nodes_lock);
524
525 if (inst->open_nodes_count != 0) {
526 fibril_mutex_unlock(&open_nodes_lock);
527 return EBUSY;
528 }
529
530 /* Remove the instance from the list */
531 fibril_mutex_lock(&instance_list_mutex);
532 list_remove(&inst->link);
533 fibril_mutex_unlock(&instance_list_mutex);
534
535 fibril_mutex_unlock(&open_nodes_lock);
536
537 ext4_filesystem_fini(inst->filesystem);
538
539 return EOK;
540}
541
542
543static int
544ext4fs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
545 size_t *rbytes)
546{
547 // TODO
548 return 0;
549}
550
551
552static int
553ext4fs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
554 size_t *wbytes, aoff64_t *nsize)
555{
556 // TODO
557 return ENOTSUP;
558}
559
560
561static int
562ext4fs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
563{
564 // TODO
565 return ENOTSUP;
566}
567
568
569static int ext4fs_close(service_id_t service_id, fs_index_t index)
570{
571 // TODO
572 return EOK;
573}
574
575
576static int ext4fs_destroy(service_id_t service_id, fs_index_t index)
577{
578 //TODO
579 return ENOTSUP;
580}
581
582
583static int ext4fs_sync(service_id_t service_id, fs_index_t index)
584{
585 // TODO
586 return ENOTSUP;
587}
588
589vfs_out_ops_t ext4fs_ops = {
590 .mounted = ext4fs_mounted,
591 .unmounted = ext4fs_unmounted,
592 .read = ext4fs_read,
593 .write = ext4fs_write,
594 .truncate = ext4fs_truncate,
595 .close = ext4fs_close,
596 .destroy = ext4fs_destroy,
597 .sync = ext4fs_sync,
598};
599
600/**
601 * @}
602 */
Note: See TracBrowser for help on using the repository browser.