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

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

Cleaning error path in mfs_mounted()

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