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

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

mfs: initialize the inode field "i_nlinks" to 0 when creating a new node; remove some debug messages and fix a warning.

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