source: mainline/uspace/srv/fs/mfs/mfs_ops.c@ 40a2af3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 40a2af3 was 40a2af3, checked in by Maurizio Lombardi <m.lombardi85@…>, 14 years ago

remove a lot of useless asserts

  • Property mode set to 100644
File size: 24.5 KB
Line 
1/*
2 * Copyright (c) 2011 Maurizio Lombardi
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#include <stdlib.h>
34#include <fibril_synch.h>
35#include <align.h>
36#include <adt/hash_table.h>
37#include "mfs.h"
38
39#define OPEN_NODES_KEYS 2
40#define OPEN_NODES_SERVICE_KEY 0
41#define OPEN_NODES_INODE_KEY 1
42#define OPEN_NODES_BUCKETS 256
43
44static bool check_magic_number(uint16_t magic, bool *native,
45 mfs_version_t *version, bool *longfilenames);
46static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
47 fs_index_t index);
48
49static int mfs_node_put(fs_node_t *fsnode);
50static int mfs_node_open(fs_node_t *fsnode);
51static fs_index_t mfs_index_get(fs_node_t *fsnode);
52static unsigned mfs_lnkcnt_get(fs_node_t *fsnode);
53static bool mfs_is_directory(fs_node_t *fsnode);
54static bool mfs_is_file(fs_node_t *fsnode);
55static int mfs_has_children(bool *has_children, fs_node_t *fsnode);
56static int mfs_root_get(fs_node_t **rfn, service_id_t service_id);
57static service_id_t mfs_service_get(fs_node_t *fsnode);
58static aoff64_t mfs_size_get(fs_node_t *node);
59static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
60static int mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags);
61static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name);
62static int mfs_unlink(fs_node_t *, fs_node_t *, const char *name);
63static int mfs_destroy_node(fs_node_t *fn);
64static hash_index_t open_nodes_hash(unsigned long key[]);
65static int open_nodes_compare(unsigned long key[], hash_count_t keys,
66 link_t *item);
67static void open_nodes_remove_cb(link_t *link);
68
69static int mfs_node_get(fs_node_t **rfn, service_id_t service_id,
70 fs_index_t index);
71static int
72mfs_instance_get(service_id_t service_id, struct mfs_instance **instance);
73
74
75static LIST_INITIALIZE(inst_list);
76static FIBRIL_MUTEX_INITIALIZE(inst_list_mutex);
77static hash_table_t open_nodes;
78static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
79
80libfs_ops_t mfs_libfs_ops = {
81 .size_get = mfs_size_get,
82 .root_get = mfs_root_get,
83 .service_get = mfs_service_get,
84 .is_directory = mfs_is_directory,
85 .is_file = mfs_is_file,
86 .node_get = mfs_node_get,
87 .node_put = mfs_node_put,
88 .node_open = mfs_node_open,
89 .index_get = mfs_index_get,
90 .match = mfs_match,
91 .create = mfs_create_node,
92 .link = mfs_link,
93 .unlink = mfs_unlink,
94 .destroy = mfs_destroy_node,
95 .has_children = mfs_has_children,
96 .lnkcnt_get = mfs_lnkcnt_get
97};
98
99/* Hash table interface for open nodes hash table */
100static hash_index_t open_nodes_hash(unsigned long key[])
101{
102 /* TODO: This is very simple and probably can be improved */
103 return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
104}
105
106static int open_nodes_compare(unsigned long key[], hash_count_t keys,
107 link_t *item)
108{
109 struct mfs_node *mnode = hash_table_get_instance(item, struct mfs_node, link);
110 assert(keys > 0);
111 if (mnode->instance->service_id !=
112 ((service_id_t) key[OPEN_NODES_SERVICE_KEY])) {
113 return false;
114 }
115 if (keys == 1) {
116 return true;
117 }
118 assert(keys == 2);
119 return (mnode->ino_i->index == key[OPEN_NODES_INODE_KEY]);
120}
121
122static void open_nodes_remove_cb(link_t *link)
123{
124 /* We don't use remove callback for this hash table */
125}
126
127static hash_table_operations_t open_nodes_ops = {
128 .hash = open_nodes_hash,
129 .compare = open_nodes_compare,
130 .remove_callback = open_nodes_remove_cb,
131};
132
133int mfs_global_init(void)
134{
135 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
136 OPEN_NODES_KEYS, &open_nodes_ops)) {
137 return ENOMEM;
138 }
139 return EOK;
140}
141
142static int
143mfs_mounted(service_id_t service_id, const char *opts, fs_index_t *index,
144 aoff64_t *size, unsigned *linkcnt)
145{
146 enum cache_mode cmode;
147 struct mfs_superblock *sb;
148 struct mfs3_superblock *sb3;
149 struct mfs_sb_info *sbi;
150 struct mfs_instance *instance;
151 bool native, longnames;
152 mfs_version_t version;
153 uint16_t magic;
154 int rc;
155
156 /* Check for option enabling write through. */
157 if (str_cmp(opts, "wtcache") == 0)
158 cmode = CACHE_MODE_WT;
159 else
160 cmode = CACHE_MODE_WB;
161
162 /* initialize libblock */
163 rc = block_init(EXCHANGE_SERIALIZE, service_id, 4096);
164 if (rc != EOK)
165 return rc;
166
167 /*Allocate space for generic MFS superblock*/
168 sbi = malloc(sizeof(*sbi));
169 if (!sbi) {
170 block_fini(service_id);
171 return ENOMEM;
172 }
173
174 /*Allocate space for filesystem instance*/
175 instance = malloc(sizeof(*instance));
176 if (!instance) {
177 free(sbi);
178 block_fini(service_id);
179 return ENOMEM;
180 }
181
182 instance->open_nodes_cnt = 0;
183
184 sb = malloc(MFS_SUPERBLOCK_SIZE);
185 if (!sb) {
186 free(instance);
187 free(sbi);
188 block_fini(service_id);
189 return ENOMEM;
190 }
191
192 /* Read the superblock */
193 rc = block_read_direct(service_id, MFS_SUPERBLOCK << 1, 2, sb);
194 if (rc != EOK) {
195 free(instance);
196 free(sbi);
197 free(sb);
198 block_fini(service_id);
199 return rc;
200 }
201
202 sb3 = (struct mfs3_superblock *) sb;
203
204 if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
205 /*This is a V1 or V2 Minix filesystem*/
206 magic = sb->s_magic;
207 } else if (check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
208 /*This is a V3 Minix filesystem*/
209 magic = sb3->s_magic;
210 } else {
211 /*Not recognized*/
212 mfsdebug("magic number not recognized\n");
213 free(instance);
214 free(sbi);
215 free(sb);
216 block_fini(service_id);
217 return ENOTSUP;
218 }
219
220 mfsdebug("magic number recognized = %04x\n", magic);
221
222 /*Fill superblock info structure*/
223
224 sbi->fs_version = version;
225 sbi->long_names = longnames;
226 sbi->native = native;
227 sbi->magic = magic;
228 sbi->isearch = 0;
229 sbi->zsearch = 0;
230
231 if (version == MFS_VERSION_V3) {
232 sbi->ninodes = conv32(native, sb3->s_ninodes);
233 sbi->ibmap_blocks = conv16(native, sb3->s_ibmap_blocks);
234 sbi->zbmap_blocks = conv16(native, sb3->s_zbmap_blocks);
235 sbi->firstdatazone = conv16(native, sb3->s_first_data_zone);
236 sbi->log2_zone_size = conv16(native, sb3->s_log2_zone_size);
237 sbi->max_file_size = conv32(native, sb3->s_max_file_size);
238 sbi->nzones = conv32(native, sb3->s_nzones);
239 sbi->block_size = conv16(native, sb3->s_block_size);
240 sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
241 sbi->dirsize = MFS3_DIRSIZE;
242 sbi->max_name_len = MFS3_MAX_NAME_LEN;
243 } else {
244 sbi->ninodes = conv16(native, sb->s_ninodes);
245 sbi->ibmap_blocks = conv16(native, sb->s_ibmap_blocks);
246 sbi->zbmap_blocks = conv16(native, sb->s_zbmap_blocks);
247 sbi->firstdatazone = conv16(native, sb->s_first_data_zone);
248 sbi->log2_zone_size = conv16(native, sb->s_log2_zone_size);
249 sbi->max_file_size = conv32(native, sb->s_max_file_size);
250 sbi->block_size = MFS_BLOCKSIZE;
251 if (version == MFS_VERSION_V2) {
252 sbi->nzones = conv32(native, sb->s_nzones2);
253 sbi->ino_per_block = V2_INODES_PER_BLOCK;
254 } else {
255 sbi->nzones = conv16(native, sb->s_nzones);
256 sbi->ino_per_block = V1_INODES_PER_BLOCK;
257 }
258 sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
259 sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
260 MFS_MAX_NAME_LEN;
261 }
262 sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
263
264 free(sb);
265
266 rc = block_cache_init(service_id, sbi->block_size, 0, cmode);
267 if (rc != EOK) {
268 free(instance);
269 free(sbi);
270 free(sb);
271 block_cache_fini(service_id);
272 block_fini(service_id);
273 mfsdebug("block cache initialization failed\n");
274 return EINVAL;
275 }
276
277 /*Initialize the instance structure and add it to the list*/
278 link_initialize(&instance->link);
279 instance->service_id = service_id;
280 instance->sbi = sbi;
281
282 fibril_mutex_lock(&inst_list_mutex);
283 list_append(&instance->link, &inst_list);
284 fibril_mutex_unlock(&inst_list_mutex);
285
286 mfsdebug("mount successful\n");
287
288 fs_node_t *fn;
289 mfs_node_get(&fn, service_id, MFS_ROOT_INO);
290
291 struct mfs_node *mroot = fn->data;
292
293 *index = mroot->ino_i->index;
294 *size = mroot->ino_i->i_size;
295 *linkcnt = 1;
296
297 return mfs_node_put(fn);
298}
299
300static int
301mfs_unmounted(service_id_t service_id)
302{
303 struct mfs_instance *inst;
304
305 mfsdebug("%s()\n", __FUNCTION__);
306
307 int r = mfs_instance_get(service_id, &inst);
308 if (r != EOK)
309 return r;
310
311 if (inst->open_nodes_cnt != 0)
312 return EBUSY;
313
314 (void) block_cache_fini(service_id);
315 block_fini(service_id);
316
317 /* Remove the instance from the list */
318 fibril_mutex_lock(&inst_list_mutex);
319 list_remove(&inst->link);
320 fibril_mutex_unlock(&inst_list_mutex);
321
322 free(inst->sbi);
323 free(inst);
324 return EOK;
325}
326
327service_id_t mfs_service_get(fs_node_t *fsnode)
328{
329 struct mfs_node *node = fsnode->data;
330 return node->instance->service_id;
331}
332
333static int mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
334{
335 int r;
336 struct mfs_instance *inst;
337 struct mfs_node *mnode;
338 fs_node_t *fsnode;
339 uint32_t inum;
340
341 mfsdebug("%s()\n", __FUNCTION__);
342
343 r = mfs_instance_get(service_id, &inst);
344 if (r != EOK)
345 return r;
346
347 /*Alloc a new inode*/
348 r = mfs_alloc_inode(inst, &inum);
349 if (r != EOK)
350 return r;
351
352 struct mfs_ino_info *ino_i;
353
354 ino_i = malloc(sizeof(*ino_i));
355 if (!ino_i) {
356 r = ENOMEM;
357 goto out_err;
358 }
359
360 mnode = malloc(sizeof(*mnode));
361 if (!mnode) {
362 r = ENOMEM;
363 goto out_err_1;
364 }
365
366 fsnode = malloc(sizeof(fs_node_t));
367 if (!fsnode) {
368 r = ENOMEM;
369 goto out_err_2;
370 }
371
372 if (flags & L_DIRECTORY) {
373 ino_i->i_mode = S_IFDIR;
374 ino_i->i_nlinks = 2; /*This accounts for the '.' dentry*/
375 } else {
376 ino_i->i_mode = S_IFREG;
377 ino_i->i_nlinks = 1;
378 }
379
380 ino_i->i_uid = 0;
381 ino_i->i_gid = 0;
382 ino_i->i_size = 0;
383 ino_i->i_atime = 0;
384 ino_i->i_mtime = 0;
385 ino_i->i_ctime = 0;
386
387 memset(ino_i->i_dzone, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES);
388 memset(ino_i->i_izone, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES);
389
390 mfsdebug("new node idx = %d\n", (int) inum);
391
392 ino_i->index = inum;
393 ino_i->dirty = true;
394 mnode->ino_i = ino_i;
395 mnode->instance = inst;
396 mnode->refcnt = 1;
397
398 link_initialize(&mnode->link);
399
400 unsigned long key[] = {
401 [OPEN_NODES_SERVICE_KEY] = inst->service_id,
402 [OPEN_NODES_INODE_KEY] = inum,
403 };
404
405 fibril_mutex_lock(&open_nodes_lock);
406 hash_table_insert(&open_nodes, key, &mnode->link);
407 fibril_mutex_unlock(&open_nodes_lock);
408 inst->open_nodes_cnt++;
409
410 mnode->ino_i->dirty = true;
411
412 fs_node_initialize(fsnode);
413 fsnode->data = mnode;
414 mnode->fsnode = fsnode;
415 *rfn = fsnode;
416
417 return EOK;
418
419out_err_2:
420 free(mnode);
421out_err_1:
422 free(ino_i);
423out_err:
424 return r;
425}
426
427static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
428{
429 struct mfs_node *mnode = pfn->data;
430 struct mfs_ino_info *ino_i = mnode->ino_i;
431 struct mfs_dentry_info d_info;
432 int r;
433
434 mfsdebug("%s()\n", __FUNCTION__);
435
436 if (!S_ISDIR(ino_i->i_mode))
437 return ENOTDIR;
438
439 struct mfs_sb_info *sbi = mnode->instance->sbi;
440 const size_t comp_size = str_size(component);
441
442 unsigned i;
443 for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
444 r = mfs_read_dentry(mnode, &d_info, i);
445 if (r != EOK)
446 return r;
447
448 if (!d_info.d_inum) {
449 /*This entry is not used*/
450 continue;
451 }
452
453 const size_t dentry_name_size = str_size(d_info.d_name);
454
455 if (comp_size == dentry_name_size &&
456 !bcmp(component, d_info.d_name, dentry_name_size)) {
457 /*Hit!*/
458 mfs_node_core_get(rfn, mnode->instance,
459 d_info.d_inum);
460 goto found;
461 }
462 }
463 *rfn = NULL;
464found:
465 return EOK;
466}
467
468static aoff64_t mfs_size_get(fs_node_t *node)
469{
470 const struct mfs_node *mnode = node->data;
471 return mnode->ino_i->i_size;
472}
473
474static int
475mfs_node_get(fs_node_t **rfn, service_id_t service_id,
476 fs_index_t index)
477{
478 int rc;
479 struct mfs_instance *instance;
480
481 mfsdebug("%s()\n", __FUNCTION__);
482
483 rc = mfs_instance_get(service_id, &instance);
484 if (rc != EOK)
485 return rc;
486
487 return mfs_node_core_get(rfn, instance, index);
488}
489
490static int
491mfs_node_put(fs_node_t *fsnode)
492{
493 int rc = EOK;
494 struct mfs_node *mnode = fsnode->data;
495
496 mfsdebug("%s()\n", __FUNCTION__);
497
498 fibril_mutex_lock(&open_nodes_lock);
499
500 assert(mnode->refcnt > 0);
501 mnode->refcnt--;
502 if (mnode->refcnt == 0) {
503 unsigned long key[] = {
504 [OPEN_NODES_SERVICE_KEY] = mnode->instance->service_id,
505 [OPEN_NODES_INODE_KEY] = mnode->ino_i->index
506 };
507 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
508 assert(mnode->instance->open_nodes_cnt > 0);
509 mnode->instance->open_nodes_cnt--;
510 rc = mfs_put_inode(mnode);
511 free(mnode->ino_i);
512 free(mnode);
513 free(fsnode);
514 }
515
516 fibril_mutex_unlock(&open_nodes_lock);
517 return rc;
518}
519
520static int mfs_node_open(fs_node_t *fsnode)
521{
522 /*
523 * Opening a file is stateless, nothing
524 * to be done here.
525 */
526 return EOK;
527}
528
529static fs_index_t mfs_index_get(fs_node_t *fsnode)
530{
531 struct mfs_node *mnode = fsnode->data;
532 return mnode->ino_i->index;
533}
534
535static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
536{
537 struct mfs_node *mnode = fsnode->data;
538
539 mfsdebug("%s() %d\n", __FUNCTION__, mnode->ino_i->i_nlinks);
540
541 if (S_ISDIR(mnode->ino_i->i_mode)) {
542 if (mnode->ino_i->i_nlinks > 1)
543 return 1;
544 else
545 return 0;
546 } else
547 return mnode->ino_i->i_nlinks;
548}
549
550static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
551 fs_index_t index)
552{
553 fs_node_t *node = NULL;
554 struct mfs_node *mnode = NULL;
555 int rc;
556
557 mfsdebug("%s()\n", __FUNCTION__);
558
559 fibril_mutex_lock(&open_nodes_lock);
560
561 /* Check if the node is not already open */
562 unsigned long key[] = {
563 [OPEN_NODES_SERVICE_KEY] = inst->service_id,
564 [OPEN_NODES_INODE_KEY] = index,
565 };
566 link_t *already_open = hash_table_find(&open_nodes, key);
567
568 if (already_open) {
569 mnode = hash_table_get_instance(already_open, struct mfs_node, link);
570 *rfn = mnode->fsnode;
571 mnode->refcnt++;
572
573 fibril_mutex_unlock(&open_nodes_lock);
574 return EOK;
575 }
576
577 node = malloc(sizeof(fs_node_t));
578 if (!node) {
579 rc = ENOMEM;
580 goto out_err;
581 }
582
583 fs_node_initialize(node);
584
585 mnode = malloc(sizeof(*mnode));
586 if (!mnode) {
587 rc = ENOMEM;
588 goto out_err;
589 }
590
591 struct mfs_ino_info *ino_i;
592
593 rc = mfs_get_inode(inst, &ino_i, index);
594 if (rc != EOK)
595 goto out_err;
596
597 ino_i->index = index;
598 mnode->ino_i = ino_i;
599 mnode->refcnt = 1;
600 link_initialize(&mnode->link);
601
602 mnode->instance = inst;
603 node->data = mnode;
604 mnode->fsnode = node;
605 *rfn = node;
606
607 hash_table_insert(&open_nodes, key, &mnode->link);
608 inst->open_nodes_cnt++;
609
610 fibril_mutex_unlock(&open_nodes_lock);
611
612 return EOK;
613
614out_err:
615 if (node)
616 free(node);
617 if (mnode)
618 free(mnode);
619 fibril_mutex_unlock(&open_nodes_lock);
620 return rc;
621}
622
623static bool mfs_is_directory(fs_node_t *fsnode)
624{
625 const struct mfs_node *node = fsnode->data;
626 return S_ISDIR(node->ino_i->i_mode);
627}
628
629static bool mfs_is_file(fs_node_t *fsnode)
630{
631 struct mfs_node *node = fsnode->data;
632 return S_ISREG(node->ino_i->i_mode);
633}
634
635static int mfs_root_get(fs_node_t **rfn, service_id_t service_id)
636{
637 int rc = mfs_node_get(rfn, service_id, MFS_ROOT_INO);
638 return rc;
639}
640
641static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
642{
643 struct mfs_node *parent = pfn->data;
644 struct mfs_node *child = cfn->data;
645 struct mfs_sb_info *sbi = parent->instance->sbi;
646
647 mfsdebug("%s()\n", __FUNCTION__);
648
649 if (str_size(name) > sbi->max_name_len)
650 return ENAMETOOLONG;
651
652 int r = mfs_insert_dentry(parent, name, child->ino_i->index);
653 if (r != EOK)
654 goto exit_error;
655
656 if (S_ISDIR(child->ino_i->i_mode)) {
657 r = mfs_insert_dentry(child, ".", child->ino_i->index);
658 if (r != EOK)
659 goto exit_error;
660
661 r = mfs_insert_dentry(child, "..", parent->ino_i->index);
662 if (r != EOK)
663 goto exit_error;
664
665 parent->ino_i->i_nlinks++;
666 parent->ino_i->dirty = true;
667 }
668
669exit_error:
670 return r;
671}
672
673static int
674mfs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name)
675{
676 struct mfs_node *parent = pfn->data;
677 struct mfs_node *child = cfn->data;
678 bool has_children;
679 int r;
680
681 mfsdebug("%s()\n", __FUNCTION__);
682
683 if (!parent)
684 return EBUSY;
685
686 r = mfs_has_children(&has_children, cfn);
687 if (r != EOK)
688 return r;
689
690 if (has_children)
691 return ENOTEMPTY;
692
693 r = mfs_remove_dentry(parent, name);
694 if (r != EOK)
695 return r;
696
697 struct mfs_ino_info *chino = child->ino_i;
698
699 assert(chino->i_nlinks >= 1);
700 chino->i_nlinks--;
701 mfsdebug("Links: %d\n", chino->i_nlinks);
702
703 if (chino->i_nlinks <= 1 && S_ISDIR(chino->i_mode)) {
704 /* The child directory will be destroyed, decrease the
705 * parent hard links counter.
706 */
707 parent->ino_i->i_nlinks--;
708 parent->ino_i->dirty = true;
709 }
710
711 chino->dirty = true;
712
713 return r;
714}
715
716static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
717{
718 struct mfs_node *mnode = fsnode->data;
719 struct mfs_sb_info *sbi = mnode->instance->sbi;
720 int r;
721
722 *has_children = false;
723
724 if (!S_ISDIR(mnode->ino_i->i_mode))
725 goto out;
726
727 struct mfs_dentry_info d_info;
728
729 /* The first two dentries are always . and .. */
730 unsigned i;
731 for (i = 2; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
732 r = mfs_read_dentry(mnode, &d_info, i);
733 if (r != EOK)
734 return r;
735
736 if (d_info.d_inum) {
737 /*A valid entry has been found*/
738 *has_children = true;
739 break;
740 }
741 }
742out:
743
744 return EOK;
745}
746
747static int
748mfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
749 size_t *rbytes)
750{
751 int rc;
752 fs_node_t *fn;
753
754 rc = mfs_node_get(&fn, service_id, index);
755 if (rc != EOK)
756 return rc;
757 if (!fn)
758 return ENOENT;
759
760 struct mfs_node *mnode;
761 struct mfs_ino_info *ino_i;
762 size_t len, bytes = 0;
763 ipc_callid_t callid;
764
765 mnode = fn->data;
766 ino_i = mnode->ino_i;
767
768 if (!async_data_read_receive(&callid, &len)) {
769 rc = EINVAL;
770 goto out_error;
771 }
772
773 if (S_ISDIR(ino_i->i_mode)) {
774 aoff64_t spos = pos;
775 struct mfs_dentry_info d_info;
776 struct mfs_sb_info *sbi = mnode->instance->sbi;
777
778 if (pos < 2) {
779 /*Skip the first two dentries ('.' and '..')*/
780 pos = 2;
781 }
782
783 for (; pos < mnode->ino_i->i_size / sbi->dirsize; ++pos) {
784 rc = mfs_read_dentry(mnode, &d_info, pos);
785 if (rc != EOK)
786 goto out_error;
787
788 if (d_info.d_inum) {
789 /*Dentry found!*/
790 goto found;
791 }
792 }
793
794 rc = mfs_node_put(fn);
795 async_answer_0(callid, rc != EOK ? rc : ENOENT);
796 return rc;
797found:
798 async_data_read_finalize(callid, d_info.d_name,
799 str_size(d_info.d_name) + 1);
800 bytes = ((pos - spos) + 1);
801 } else {
802 struct mfs_sb_info *sbi = mnode->instance->sbi;
803
804 if (pos >= (size_t) ino_i->i_size) {
805 /*Trying to read beyond the end of file*/
806 bytes = 0;
807 (void) async_data_read_finalize(callid, NULL, 0);
808 goto out_success;
809 }
810
811 bytes = min(len, sbi->block_size - pos % sbi->block_size);
812 bytes = min(bytes, ino_i->i_size - pos);
813
814 uint32_t zone;
815 block_t *b;
816
817 rc = mfs_read_map(&zone, mnode, pos);
818 if (rc != EOK)
819 goto out_error;
820
821 if (zone == 0) {
822 /*sparse file*/
823 uint8_t *buf = malloc(sbi->block_size);
824 if (!buf) {
825 rc = ENOMEM;
826 goto out_error;
827 }
828 memset(buf, 0, sizeof(sbi->block_size));
829 async_data_read_finalize(callid,
830 buf + pos % sbi->block_size, bytes);
831 free(buf);
832 goto out_success;
833 }
834
835 rc = block_get(&b, service_id, zone, BLOCK_FLAGS_NONE);
836 if (rc != EOK)
837 goto out_error;
838
839 async_data_read_finalize(callid, b->data +
840 pos % sbi->block_size, bytes);
841
842 rc = block_put(b);
843 if (rc != EOK) {
844 mfs_node_put(fn);
845 return rc;
846 }
847 }
848out_success:
849 rc = mfs_node_put(fn);
850 *rbytes = bytes;
851 return rc;
852out_error:
853 ;
854 int tmp = mfs_node_put(fn);
855 async_answer_0(callid, tmp != EOK ? tmp : rc);
856 return tmp != EOK ? tmp : rc;
857}
858
859static int
860mfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
861 size_t *wbytes, aoff64_t *nsize)
862{
863 fs_node_t *fn;
864 int r;
865 int flags = BLOCK_FLAGS_NONE;
866
867 r = mfs_node_get(&fn, service_id, index);
868 if (r != EOK)
869 return r;
870 if (!fn)
871 return ENOENT;
872
873 ipc_callid_t callid;
874 size_t len;
875
876 if (!async_data_write_receive(&callid, &len)) {
877 r = EINVAL;
878 goto out_err;
879 }
880
881 struct mfs_node *mnode = fn->data;
882 struct mfs_sb_info *sbi = mnode->instance->sbi;
883 struct mfs_ino_info *ino_i = mnode->ino_i;
884 const size_t bs = sbi->block_size;
885 size_t bytes = min(len, bs - pos % bs);
886 size_t boundary = ROUND_UP(ino_i->i_size, bs);
887 uint32_t block;
888
889 if (bytes == bs)
890 flags = BLOCK_FLAGS_NOREAD;
891
892 if (pos < boundary) {
893 r = mfs_read_map(&block, mnode, pos);
894 if (r != EOK)
895 goto out_err;
896
897 if (block == 0) {
898 /*Writing in a sparse block*/
899 r = mfs_alloc_zone(mnode->instance, &block);
900 if (r != EOK)
901 goto out_err;
902 flags = BLOCK_FLAGS_NOREAD;
903 }
904 } else {
905 uint32_t dummy;
906
907 r = mfs_alloc_zone(mnode->instance, &block);
908 if (r != EOK)
909 goto out_err;
910
911 r = mfs_write_map(mnode, pos, block, &dummy);
912 if (r != EOK)
913 goto out_err;
914 }
915
916 block_t *b;
917 r = block_get(&b, service_id, block, flags);
918 if (r != EOK)
919 goto out_err;
920
921 async_data_write_finalize(callid, b->data + pos % bs, bytes);
922 b->dirty = true;
923
924 r = block_put(b);
925 if (r != EOK) {
926 mfs_node_put(fn);
927 return r;
928 }
929
930 ino_i->i_size = pos + bytes;
931 ino_i->dirty = true;
932 r = mfs_node_put(fn);
933 *nsize = pos + bytes;
934 *wbytes = bytes;
935 return r;
936
937out_err:
938 mfs_node_put(fn);
939 async_answer_0(callid, r);
940 return r;
941}
942
943static int
944mfs_destroy(service_id_t service_id, fs_index_t index)
945{
946 fs_node_t *fn;
947 int r;
948
949 r = mfs_node_get(&fn, service_id, index);
950 if (r != EOK)
951 return r;
952 if (!fn)
953 return ENOENT;
954
955 /*Destroy the inode*/
956 return mfs_destroy_node(fn);
957}
958
959static int
960mfs_destroy_node(fs_node_t *fn)
961{
962 struct mfs_node *mnode = fn->data;
963 bool has_children;
964 int r;
965
966 mfsdebug("mfs_destroy_node %d\n", mnode->ino_i->index);
967
968 r = mfs_has_children(&has_children, fn);
969 if (r != EOK)
970 goto out;
971
972 assert(!has_children);
973
974 /*Free the entire inode content*/
975 r = mfs_inode_shrink(mnode, mnode->ino_i->i_size);
976 if (r != EOK)
977 goto out;
978
979 /*Mark the inode as free in the bitmap*/
980 r = mfs_free_inode(mnode->instance, mnode->ino_i->index);
981
982out:
983 mfs_node_put(fn);
984 return r;
985}
986
987static int
988mfs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
989{
990 fs_node_t *fn;
991 int r;
992
993 r = mfs_node_get(&fn, service_id, index);
994 if (r != EOK)
995 return r;
996 if (!fn)
997 return r;
998
999 struct mfs_node *mnode = fn->data;
1000 struct mfs_ino_info *ino_i = mnode->ino_i;
1001
1002 if (ino_i->i_size == size)
1003 r = EOK;
1004 else
1005 r = mfs_inode_shrink(mnode, ino_i->i_size - size);
1006
1007 mfs_node_put(fn);
1008 return r;
1009}
1010
1011static int
1012mfs_instance_get(service_id_t service_id, struct mfs_instance **instance)
1013{
1014 struct mfs_instance *instance_ptr;
1015
1016 fibril_mutex_lock(&inst_list_mutex);
1017
1018 if (list_empty(&inst_list)) {
1019 fibril_mutex_unlock(&inst_list_mutex);
1020 return EINVAL;
1021 }
1022
1023 list_foreach(inst_list, link) {
1024 instance_ptr = list_get_instance(link, struct mfs_instance,
1025 link);
1026
1027 if (instance_ptr->service_id == service_id) {
1028 *instance = instance_ptr;
1029 fibril_mutex_unlock(&inst_list_mutex);
1030 return EOK;
1031 }
1032 }
1033
1034 mfsdebug("Instance not found\n");
1035
1036 fibril_mutex_unlock(&inst_list_mutex);
1037 return EINVAL;
1038}
1039
1040static bool check_magic_number(uint16_t magic, bool *native,
1041 mfs_version_t *version, bool *longfilenames)
1042{
1043 bool rc = true;
1044 *longfilenames = false;
1045
1046 if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
1047 *native = magic == MFS_MAGIC_V1;
1048 *version = MFS_VERSION_V1;
1049 } else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
1050 *native = magic == MFS_MAGIC_V1L;
1051 *version = MFS_VERSION_V1;
1052 *longfilenames = true;
1053 } else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
1054 *native = magic == MFS_MAGIC_V2;
1055 *version = MFS_VERSION_V2;
1056 } else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
1057 *native = magic == MFS_MAGIC_V2L;
1058 *version = MFS_VERSION_V2;
1059 *longfilenames = true;
1060 } else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
1061 *native = magic == MFS_MAGIC_V3;
1062 *version = MFS_VERSION_V3;
1063 } else
1064 rc = false;
1065
1066 return rc;
1067}
1068
1069static int
1070mfs_close(service_id_t service_id, fs_index_t index)
1071{
1072 return 0;
1073}
1074
1075static int
1076mfs_sync(service_id_t service_id, fs_index_t index)
1077{
1078 fs_node_t *fn;
1079 int rc = mfs_node_get(&fn, service_id, index);
1080 if (rc != EOK)
1081 return rc;
1082 if (!fn)
1083 return ENOENT;
1084
1085 struct mfs_node *mnode = fn->data;
1086 mnode->ino_i->dirty = true;
1087
1088 return mfs_node_put(fn);
1089}
1090
1091vfs_out_ops_t mfs_ops = {
1092 .mounted = mfs_mounted,
1093 .unmounted = mfs_unmounted,
1094 .read = mfs_read,
1095 .write = mfs_write,
1096 .truncate = mfs_truncate,
1097 .close = mfs_close,
1098 .destroy = mfs_destroy,
1099 .sync = mfs_sync,
1100};
1101
1102/**
1103 * @}
1104 */
1105
Note: See TracBrowser for help on using the repository browser.