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

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

cstyle

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