2 * Copyright (c) 2011 Maurizio Lombardi
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
34 #include <fibril_synch.h>
36 #include <adt/hash_table.h>
41 static bool check_magic_number(uint16_t magic
, bool *native
,
42 mfs_version_t
*version
, bool *longfilenames
);
43 static int mfs_node_core_get(fs_node_t
**rfn
, struct mfs_instance
*inst
,
45 static int mfs_node_put(fs_node_t
*fsnode
);
46 static int mfs_node_open(fs_node_t
*fsnode
);
47 static fs_index_t
mfs_index_get(fs_node_t
*fsnode
);
48 static unsigned mfs_lnkcnt_get(fs_node_t
*fsnode
);
49 static bool mfs_is_directory(fs_node_t
*fsnode
);
50 static bool mfs_is_file(fs_node_t
*fsnode
);
51 static int mfs_has_children(bool *has_children
, fs_node_t
*fsnode
);
52 static int mfs_root_get(fs_node_t
**rfn
, service_id_t service_id
);
53 static service_id_t
mfs_service_get(fs_node_t
*fsnode
);
54 static aoff64_t
mfs_size_get(fs_node_t
*node
);
55 static int mfs_match(fs_node_t
**rfn
, fs_node_t
*pfn
, const char *component
);
56 static int mfs_create_node(fs_node_t
**rfn
, service_id_t service_id
, int flags
);
57 static int mfs_link(fs_node_t
*pfn
, fs_node_t
*cfn
, const char *name
);
58 static int mfs_unlink(fs_node_t
*, fs_node_t
*, const char *name
);
59 static int mfs_destroy_node(fs_node_t
*fn
);
60 static int mfs_node_get(fs_node_t
**rfn
, service_id_t service_id
,
62 static int mfs_instance_get(service_id_t service_id
,
63 struct mfs_instance
**instance
);
64 static int mfs_check_sanity(struct mfs_sb_info
*sbi
);
65 static bool is_power_of_two(uint32_t n
);
66 static int mfs_size_block(service_id_t service_id
, uint32_t *size
);
67 static int mfs_total_block_count(service_id_t service_id
, uint64_t *count
);
68 static int mfs_free_block_count(service_id_t service_id
, uint64_t *count
);
70 static hash_table_t open_nodes
;
71 static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock
);
73 libfs_ops_t mfs_libfs_ops
= {
74 .size_get
= mfs_size_get
,
75 .root_get
= mfs_root_get
,
76 .service_get
= mfs_service_get
,
77 .is_directory
= mfs_is_directory
,
78 .is_file
= mfs_is_file
,
79 .node_get
= mfs_node_get
,
80 .node_put
= mfs_node_put
,
81 .node_open
= mfs_node_open
,
82 .index_get
= mfs_index_get
,
84 .create
= mfs_create_node
,
87 .destroy
= mfs_destroy_node
,
88 .has_children
= mfs_has_children
,
89 .lnkcnt_get
= mfs_lnkcnt_get
,
90 .size_block
= mfs_size_block
,
91 .total_block_count
= mfs_total_block_count
,
92 .free_block_count
= mfs_free_block_count
95 /* Hash table interface for open nodes hash table */
97 service_id_t service_id
;
102 open_nodes_key_hash(void *key
)
104 node_key_t
*node_key
= (node_key_t
*)key
;
105 return hash_combine(node_key
->service_id
, node_key
->index
);
109 open_nodes_hash(const ht_link_t
*item
)
111 struct mfs_node
*m
= hash_table_get_inst(item
, struct mfs_node
, link
);
112 return hash_combine(m
->instance
->service_id
, m
->ino_i
->index
);
116 open_nodes_key_equal(void *key
, const ht_link_t
*item
)
118 node_key_t
*node_key
= (node_key_t
*)key
;
119 struct mfs_node
*mnode
= hash_table_get_inst(item
, struct mfs_node
, link
);
121 return node_key
->service_id
== mnode
->instance
->service_id
122 && node_key
->index
== mnode
->ino_i
->index
;
125 static hash_table_ops_t open_nodes_ops
= {
126 .hash
= open_nodes_hash
,
127 .key_hash
= open_nodes_key_hash
,
128 .key_equal
= open_nodes_key_equal
,
130 .remove_callback
= NULL
,
134 mfs_global_init(void)
136 if (!hash_table_create(&open_nodes
, 0, 0, &open_nodes_ops
)) {
143 mfs_mounted(service_id_t service_id
, const char *opts
, fs_index_t
*index
,
144 aoff64_t
*size
, unsigned *linkcnt
)
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
;
156 /* Check for option enabling write through. */
157 if (str_cmp(opts
, "wtcache") == 0)
158 cmode
= CACHE_MODE_WT
;
160 cmode
= CACHE_MODE_WB
;
162 /* initialize libblock */
163 rc
= block_init(EXCHANGE_SERIALIZE
, service_id
, 4096);
167 /* Allocate space for generic MFS superblock */
168 sbi
= malloc(sizeof(*sbi
));
174 /* Allocate space for filesystem instance */
175 instance
= malloc(sizeof(*instance
));
181 sb
= malloc(MFS_SUPERBLOCK_SIZE
);
187 /* Read the superblock */
188 rc
= block_read_direct(service_id
, MFS_SUPERBLOCK
<< 1, 2, sb
);
192 sb3
= (struct mfs3_superblock
*) sb
;
194 if (check_magic_number(sb
->s_magic
, &native
, &version
, &longnames
)) {
195 /* This is a V1 or V2 Minix filesystem */
197 } else if (check_magic_number(sb3
->s_magic
, &native
,
198 &version
, &longnames
)) {
199 /* This is a V3 Minix filesystem */
200 magic
= sb3
->s_magic
;
203 mfsdebug("magic number not recognized\n");
208 mfsdebug("magic number recognized = %04x\n", magic
);
210 /* Fill superblock info structure */
212 sbi
->fs_version
= version
;
213 sbi
->long_names
= longnames
;
214 sbi
->native
= native
;
218 sbi
->nfree_zones_valid
= false;
219 sbi
->nfree_zones
= 0;
221 if (version
== MFS_VERSION_V3
) {
222 sbi
->ninodes
= conv32(native
, sb3
->s_ninodes
);
223 sbi
->ibmap_blocks
= conv16(native
, sb3
->s_ibmap_blocks
);
224 sbi
->zbmap_blocks
= conv16(native
, sb3
->s_zbmap_blocks
);
225 sbi
->firstdatazone
= conv16(native
, sb3
->s_first_data_zone
);
226 sbi
->log2_zone_size
= conv16(native
, sb3
->s_log2_zone_size
);
227 sbi
->max_file_size
= conv32(native
, sb3
->s_max_file_size
);
228 sbi
->nzones
= conv32(native
, sb3
->s_nzones
);
229 sbi
->block_size
= conv16(native
, sb3
->s_block_size
);
230 sbi
->ino_per_block
= V3_INODES_PER_BLOCK(sbi
->block_size
);
231 sbi
->dirsize
= MFS3_DIRSIZE
;
232 sbi
->max_name_len
= MFS3_MAX_NAME_LEN
;
234 sbi
->ninodes
= conv16(native
, sb
->s_ninodes
);
235 sbi
->ibmap_blocks
= conv16(native
, sb
->s_ibmap_blocks
);
236 sbi
->zbmap_blocks
= conv16(native
, sb
->s_zbmap_blocks
);
237 sbi
->firstdatazone
= conv16(native
, sb
->s_first_data_zone
);
238 sbi
->log2_zone_size
= conv16(native
, sb
->s_log2_zone_size
);
239 sbi
->max_file_size
= conv32(native
, sb
->s_max_file_size
);
240 sbi
->block_size
= MFS_BLOCKSIZE
;
241 if (version
== MFS_VERSION_V2
) {
242 sbi
->nzones
= conv32(native
, sb
->s_nzones2
);
243 sbi
->ino_per_block
= V2_INODES_PER_BLOCK
;
245 sbi
->nzones
= conv16(native
, sb
->s_nzones
);
246 sbi
->ino_per_block
= V1_INODES_PER_BLOCK
;
248 sbi
->dirsize
= longnames
? MFSL_DIRSIZE
: MFS_DIRSIZE
;
249 sbi
->max_name_len
= longnames
? MFS_L_MAX_NAME_LEN
:
253 if (sbi
->log2_zone_size
!= 0) {
254 /* In MFS, file space is allocated per zones.
255 * Zones are a collection of consecutive blocks on disk.
257 * The current MFS implementation supports only filesystems
258 * where the size of a zone is equal to the
265 sbi
->itable_off
= 2 + sbi
->ibmap_blocks
+ sbi
->zbmap_blocks
;
266 if ((rc
= mfs_check_sanity(sbi
)) != EOK
) {
267 fprintf(stderr
, "Filesystem corrupted, invalid superblock");
271 rc
= block_cache_init(service_id
, sbi
->block_size
, 0, cmode
);
273 mfsdebug("block cache initialization failed\n");
278 /* Initialize the instance structure and remember it */
279 instance
->service_id
= service_id
;
281 instance
->open_nodes_cnt
= 0;
282 rc
= fs_instance_create(service_id
, instance
);
284 block_cache_fini(service_id
);
285 mfsdebug("fs instance creation failed\n");
289 mfsdebug("mount successful\n");
292 mfs_node_get(&fn
, service_id
, MFS_ROOT_INO
);
294 struct mfs_node
*mroot
= fn
->data
;
296 *index
= mroot
->ino_i
->index
;
297 *size
= mroot
->ino_i
->i_size
;
302 return mfs_node_put(fn
);
305 block_fini(service_id
);
316 mfs_unmounted(service_id_t service_id
)
318 struct mfs_instance
*inst
;
320 mfsdebug("%s()\n", __FUNCTION__
);
322 int r
= mfs_instance_get(service_id
, &inst
);
326 if (inst
->open_nodes_cnt
!= 0)
329 (void) block_cache_fini(service_id
);
330 block_fini(service_id
);
332 /* Remove and destroy the instance */
333 (void) fs_instance_destroy(service_id
);
340 mfs_service_get(fs_node_t
*fsnode
)
342 struct mfs_node
*node
= fsnode
->data
;
343 return node
->instance
->service_id
;
347 mfs_create_node(fs_node_t
**rfn
, service_id_t service_id
, int flags
)
350 struct mfs_instance
*inst
;
351 struct mfs_node
*mnode
;
355 r
= mfs_instance_get(service_id
, &inst
);
359 /* Alloc a new inode */
360 r
= mfs_alloc_inode(inst
, &inum
);
364 struct mfs_ino_info
*ino_i
;
366 ino_i
= malloc(sizeof(*ino_i
));
372 mnode
= malloc(sizeof(*mnode
));
378 fsnode
= malloc(sizeof(fs_node_t
));
384 if (flags
& L_DIRECTORY
) {
385 ino_i
->i_mode
= S_IFDIR
;
386 ino_i
->i_nlinks
= 1; /* This accounts for the '.' dentry */
388 ino_i
->i_mode
= S_IFREG
;
399 memset(ino_i
->i_dzone
, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES
);
400 memset(ino_i
->i_izone
, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES
);
402 mfsdebug("new node idx = %d\n", (int) inum
);
406 mnode
->ino_i
= ino_i
;
407 mnode
->instance
= inst
;
410 fibril_mutex_lock(&open_nodes_lock
);
411 hash_table_insert(&open_nodes
, &mnode
->link
);
412 fibril_mutex_unlock(&open_nodes_lock
);
413 inst
->open_nodes_cnt
++;
415 mnode
->ino_i
->dirty
= true;
417 fs_node_initialize(fsnode
);
418 fsnode
->data
= mnode
;
419 mnode
->fsnode
= fsnode
;
429 mfs_free_inode(inst
, inum
);
434 mfs_match(fs_node_t
**rfn
, fs_node_t
*pfn
, const char *component
)
436 struct mfs_node
*mnode
= pfn
->data
;
437 struct mfs_ino_info
*ino_i
= mnode
->ino_i
;
438 struct mfs_dentry_info d_info
;
441 if (!S_ISDIR(ino_i
->i_mode
))
444 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
445 const size_t comp_size
= str_size(component
);
448 for (i
= 0; i
< mnode
->ino_i
->i_size
/ sbi
->dirsize
; ++i
) {
449 r
= mfs_read_dentry(mnode
, &d_info
, i
);
453 if (!d_info
.d_inum
) {
454 /* This entry is not used */
458 const size_t dentry_name_size
= str_size(d_info
.d_name
);
460 if (comp_size
== dentry_name_size
&&
461 memcmp(component
, d_info
.d_name
, dentry_name_size
) == 0) {
463 mfs_node_core_get(rfn
, mnode
->instance
,
474 mfs_size_get(fs_node_t
*node
)
476 const struct mfs_node
*mnode
= node
->data
;
477 return mnode
->ino_i
->i_size
;
481 mfs_node_get(fs_node_t
**rfn
, service_id_t service_id
,
485 struct mfs_instance
*instance
;
487 rc
= mfs_instance_get(service_id
, &instance
);
491 return mfs_node_core_get(rfn
, instance
, index
);
495 mfs_node_put(fs_node_t
*fsnode
)
498 struct mfs_node
*mnode
= fsnode
->data
;
500 fibril_mutex_lock(&open_nodes_lock
);
502 assert(mnode
->refcnt
> 0);
504 if (mnode
->refcnt
== 0) {
505 hash_table_remove_item(&open_nodes
, &mnode
->link
);
506 assert(mnode
->instance
->open_nodes_cnt
> 0);
507 mnode
->instance
->open_nodes_cnt
--;
508 rc
= mfs_put_inode(mnode
);
514 fibril_mutex_unlock(&open_nodes_lock
);
519 mfs_node_open(fs_node_t
*fsnode
)
522 * Opening a file is stateless, nothing
529 mfs_index_get(fs_node_t
*fsnode
)
531 struct mfs_node
*mnode
= fsnode
->data
;
532 return mnode
->ino_i
->index
;
536 mfs_lnkcnt_get(fs_node_t
*fsnode
)
538 struct mfs_node
*mnode
= fsnode
->data
;
540 mfsdebug("%s() %d\n", __FUNCTION__
, mnode
->ino_i
->i_nlinks
);
542 if (S_ISDIR(mnode
->ino_i
->i_mode
)) {
543 if (mnode
->ino_i
->i_nlinks
> 1)
548 return mnode
->ino_i
->i_nlinks
;
552 mfs_node_core_get(fs_node_t
**rfn
, struct mfs_instance
*inst
,
555 fs_node_t
*node
= NULL
;
556 struct mfs_node
*mnode
= NULL
;
559 fibril_mutex_lock(&open_nodes_lock
);
561 /* Check if the node is not already open */
563 .service_id
= inst
->service_id
,
567 ht_link_t
*already_open
= hash_table_find(&open_nodes
, &key
);
570 mnode
= hash_table_get_inst(already_open
, struct mfs_node
, link
);
572 *rfn
= mnode
->fsnode
;
575 fibril_mutex_unlock(&open_nodes_lock
);
579 node
= malloc(sizeof(fs_node_t
));
585 fs_node_initialize(node
);
587 mnode
= malloc(sizeof(*mnode
));
593 struct mfs_ino_info
*ino_i
;
595 rc
= mfs_get_inode(inst
, &ino_i
, index
);
599 ino_i
->index
= index
;
600 mnode
->ino_i
= ino_i
;
603 mnode
->instance
= inst
;
605 mnode
->fsnode
= node
;
608 hash_table_insert(&open_nodes
, &mnode
->link
);
609 inst
->open_nodes_cnt
++;
611 fibril_mutex_unlock(&open_nodes_lock
);
620 fibril_mutex_unlock(&open_nodes_lock
);
625 mfs_is_directory(fs_node_t
*fsnode
)
627 const struct mfs_node
*node
= fsnode
->data
;
628 return S_ISDIR(node
->ino_i
->i_mode
);
632 mfs_is_file(fs_node_t
*fsnode
)
634 struct mfs_node
*node
= fsnode
->data
;
635 return S_ISREG(node
->ino_i
->i_mode
);
639 mfs_root_get(fs_node_t
**rfn
, service_id_t service_id
)
641 int rc
= mfs_node_get(rfn
, service_id
, MFS_ROOT_INO
);
646 mfs_link(fs_node_t
*pfn
, fs_node_t
*cfn
, const char *name
)
648 struct mfs_node
*parent
= pfn
->data
;
649 struct mfs_node
*child
= cfn
->data
;
650 struct mfs_sb_info
*sbi
= parent
->instance
->sbi
;
651 bool destroy_dentry
= false;
653 if (str_size(name
) > sbi
->max_name_len
)
656 int r
= mfs_insert_dentry(parent
, name
, child
->ino_i
->index
);
660 if (S_ISDIR(child
->ino_i
->i_mode
)) {
661 if (child
->ino_i
->i_nlinks
!= 1) {
662 /* It's not possible to hardlink directories in MFS */
663 destroy_dentry
= true;
667 r
= mfs_insert_dentry(child
, ".", child
->ino_i
->index
);
669 destroy_dentry
= true;
673 r
= mfs_insert_dentry(child
, "..", parent
->ino_i
->index
);
675 mfs_remove_dentry(child
, ".");
676 destroy_dentry
= true;
680 parent
->ino_i
->i_nlinks
++;
681 parent
->ino_i
->dirty
= true;
685 if (destroy_dentry
) {
686 int r2
= mfs_remove_dentry(parent
, name
);
690 child
->ino_i
->i_nlinks
++;
691 child
->ino_i
->dirty
= true;
697 mfs_unlink(fs_node_t
*pfn
, fs_node_t
*cfn
, const char *name
)
699 struct mfs_node
*parent
= pfn
->data
;
700 struct mfs_node
*child
= cfn
->data
;
707 r
= mfs_has_children(&has_children
, cfn
);
714 r
= mfs_remove_dentry(parent
, name
);
718 struct mfs_ino_info
*chino
= child
->ino_i
;
720 assert(chino
->i_nlinks
>= 1);
722 mfsdebug("Links: %d\n", chino
->i_nlinks
);
724 if (chino
->i_nlinks
<= 1 && S_ISDIR(chino
->i_mode
)) {
725 /* The child directory will be destroyed, decrease the
726 * parent hard links counter.
728 parent
->ino_i
->i_nlinks
--;
729 parent
->ino_i
->dirty
= true;
738 mfs_has_children(bool *has_children
, fs_node_t
*fsnode
)
740 struct mfs_node
*mnode
= fsnode
->data
;
741 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
744 *has_children
= false;
746 if (!S_ISDIR(mnode
->ino_i
->i_mode
))
749 struct mfs_dentry_info d_info
;
751 /* The first two dentries are always . and .. */
753 for (i
= 2; i
< mnode
->ino_i
->i_size
/ sbi
->dirsize
; ++i
) {
754 r
= mfs_read_dentry(mnode
, &d_info
, i
);
759 /* A valid entry has been found */
760 *has_children
= true;
770 mfs_read(service_id_t service_id
, fs_index_t index
, aoff64_t pos
,
774 fs_node_t
*fn
= NULL
;
776 rc
= mfs_node_get(&fn
, service_id
, index
);
782 struct mfs_node
*mnode
;
783 struct mfs_ino_info
*ino_i
;
784 size_t len
, bytes
= 0;
788 ino_i
= mnode
->ino_i
;
790 if (!async_data_read_receive(&callid
, &len
)) {
795 if (S_ISDIR(ino_i
->i_mode
)) {
797 struct mfs_dentry_info d_info
;
798 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
801 /* Skip the first two dentries ('.' and '..') */
805 for (; pos
< mnode
->ino_i
->i_size
/ sbi
->dirsize
; ++pos
) {
806 rc
= mfs_read_dentry(mnode
, &d_info
, pos
);
816 rc
= mfs_node_put(fn
);
817 async_answer_0(callid
, rc
!= EOK
? rc
: ENOENT
);
820 async_data_read_finalize(callid
, d_info
.d_name
,
821 str_size(d_info
.d_name
) + 1);
822 bytes
= ((pos
- spos
) + 1);
824 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
826 if (pos
>= (size_t) ino_i
->i_size
) {
827 /* Trying to read beyond the end of file */
829 (void) async_data_read_finalize(callid
, NULL
, 0);
833 bytes
= min(len
, sbi
->block_size
- pos
% sbi
->block_size
);
834 bytes
= min(bytes
, ino_i
->i_size
- pos
);
839 rc
= mfs_read_map(&zone
, mnode
, pos
);
845 uint8_t *buf
= malloc(sbi
->block_size
);
850 memset(buf
, 0, sizeof(sbi
->block_size
));
851 async_data_read_finalize(callid
,
852 buf
+ pos
% sbi
->block_size
, bytes
);
857 rc
= block_get(&b
, service_id
, zone
, BLOCK_FLAGS_NONE
);
861 async_data_read_finalize(callid
, b
->data
+
862 pos
% sbi
->block_size
, bytes
);
871 rc
= mfs_node_put(fn
);
876 int tmp
= mfs_node_put(fn
);
877 async_answer_0(callid
, tmp
!= EOK
? tmp
: rc
);
878 return tmp
!= EOK
? tmp
: rc
;
882 mfs_write(service_id_t service_id
, fs_index_t index
, aoff64_t pos
,
883 size_t *wbytes
, aoff64_t
*nsize
)
887 int flags
= BLOCK_FLAGS_NONE
;
889 r
= mfs_node_get(&fn
, service_id
, index
);
898 if (!async_data_write_receive(&callid
, &len
)) {
903 struct mfs_node
*mnode
= fn
->data
;
904 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
905 struct mfs_ino_info
*ino_i
= mnode
->ino_i
;
906 const size_t bs
= sbi
->block_size
;
907 size_t bytes
= min(len
, bs
- (pos
% bs
));
911 flags
= BLOCK_FLAGS_NOREAD
;
913 r
= mfs_read_map(&block
, mnode
, pos
);
920 r
= mfs_alloc_zone(mnode
->instance
, &block
);
924 r
= mfs_write_map(mnode
, pos
, block
, &dummy
);
926 mfs_free_zone(mnode
->instance
, block
);
930 flags
= BLOCK_FLAGS_NOREAD
;
934 r
= block_get(&b
, service_id
, block
, flags
);
938 if (flags
== BLOCK_FLAGS_NOREAD
)
939 memset(b
->data
, 0, sbi
->block_size
);
941 async_data_write_finalize(callid
, b
->data
+ (pos
% bs
), bytes
);
950 if (pos
+ bytes
> ino_i
->i_size
) {
951 ino_i
->i_size
= pos
+ bytes
;
954 r
= mfs_node_put(fn
);
955 *nsize
= ino_i
->i_size
;
961 async_answer_0(callid
, r
);
966 mfs_destroy(service_id_t service_id
, fs_index_t index
)
968 fs_node_t
*fn
= NULL
;
971 r
= mfs_node_get(&fn
, service_id
, index
);
977 /* Destroy the inode */
978 return mfs_destroy_node(fn
);
982 mfs_destroy_node(fs_node_t
*fn
)
984 struct mfs_node
*mnode
= fn
->data
;
988 mfsdebug("mfs_destroy_node %d\n", mnode
->ino_i
->index
);
990 r
= mfs_has_children(&has_children
, fn
);
994 assert(!has_children
);
996 /* Free the entire inode content */
997 r
= mfs_inode_shrink(mnode
, mnode
->ino_i
->i_size
);
1001 /* Mark the inode as free in the bitmap */
1002 r
= mfs_free_inode(mnode
->instance
, mnode
->ino_i
->index
);
1010 mfs_truncate(service_id_t service_id
, fs_index_t index
, aoff64_t size
)
1015 r
= mfs_node_get(&fn
, service_id
, index
);
1021 struct mfs_node
*mnode
= fn
->data
;
1022 struct mfs_ino_info
*ino_i
= mnode
->ino_i
;
1024 if (ino_i
->i_size
== size
)
1027 r
= mfs_inode_shrink(mnode
, ino_i
->i_size
- size
);
1034 mfs_instance_get(service_id_t service_id
, struct mfs_instance
**instance
)
1039 rc
= fs_instance_get(service_id
, &data
);
1041 *instance
= (struct mfs_instance
*) data
;
1043 mfsdebug("instance not found\n");
1050 check_magic_number(uint16_t magic
, bool *native
,
1051 mfs_version_t
*version
, bool *longfilenames
)
1054 *longfilenames
= false;
1056 if (magic
== MFS_MAGIC_V1
|| magic
== MFS_MAGIC_V1R
) {
1057 *native
= magic
== MFS_MAGIC_V1
;
1058 *version
= MFS_VERSION_V1
;
1059 } else if (magic
== MFS_MAGIC_V1L
|| magic
== MFS_MAGIC_V1LR
) {
1060 *native
= magic
== MFS_MAGIC_V1L
;
1061 *version
= MFS_VERSION_V1
;
1062 *longfilenames
= true;
1063 } else if (magic
== MFS_MAGIC_V2
|| magic
== MFS_MAGIC_V2R
) {
1064 *native
= magic
== MFS_MAGIC_V2
;
1065 *version
= MFS_VERSION_V2
;
1066 } else if (magic
== MFS_MAGIC_V2L
|| magic
== MFS_MAGIC_V2LR
) {
1067 *native
= magic
== MFS_MAGIC_V2L
;
1068 *version
= MFS_VERSION_V2
;
1069 *longfilenames
= true;
1070 } else if (magic
== MFS_MAGIC_V3
|| magic
== MFS_MAGIC_V3R
) {
1071 *native
= magic
== MFS_MAGIC_V3
;
1072 *version
= MFS_VERSION_V3
;
1079 /** Filesystem sanity check
1081 * @param Pointer to the MFS superblock.
1083 * @return EOK on success, ENOTSUP otherwise.
1086 mfs_check_sanity(struct mfs_sb_info
*sbi
)
1088 if (!is_power_of_two(sbi
->block_size
) ||
1089 sbi
->block_size
< MFS_MIN_BLOCKSIZE
||
1090 sbi
->block_size
> MFS_MAX_BLOCKSIZE
)
1092 else if (sbi
->ibmap_blocks
== 0 || sbi
->zbmap_blocks
== 0)
1094 else if (sbi
->ninodes
== 0 || sbi
->nzones
== 0)
1096 else if (sbi
->firstdatazone
== 0)
1103 mfs_close(service_id_t service_id
, fs_index_t index
)
1109 mfs_sync(service_id_t service_id
, fs_index_t index
)
1111 fs_node_t
*fn
= NULL
;
1112 int rc
= mfs_node_get(&fn
, service_id
, index
);
1118 struct mfs_node
*mnode
= fn
->data
;
1119 mnode
->ino_i
->dirty
= true;
1121 return mfs_node_put(fn
);
1124 /** Check if a given number is a power of two.
1126 * @param n The number to check.
1128 * @return true if it is a power of two, false otherwise.
1131 is_power_of_two(uint32_t n
)
1136 return (n
& (n
- 1)) == 0;
1140 mfs_size_block(service_id_t service_id
, uint32_t *size
)
1142 struct mfs_instance
*inst
;
1145 rc
= mfs_instance_get(service_id
, &inst
);
1152 *size
= inst
->sbi
->block_size
;
1158 mfs_total_block_count(service_id_t service_id
, uint64_t *count
)
1160 struct mfs_instance
*inst
;
1163 rc
= mfs_instance_get(service_id
, &inst
);
1170 *count
= (uint64_t) MFS_BMAP_SIZE_BITS(inst
->sbi
, BMAP_ZONE
);
1176 mfs_free_block_count(service_id_t service_id
, uint64_t *count
)
1178 uint32_t block_free
;
1180 struct mfs_instance
*inst
;
1181 int rc
= mfs_instance_get(service_id
, &inst
);
1185 struct mfs_sb_info
*sbi
= inst
->sbi
;
1187 if (!sbi
->nfree_zones_valid
) {
1188 /* The cached number of free zones is not valid,
1189 * we need to scan the bitmap to retrieve the
1193 rc
= mfs_count_free_zones(inst
, &block_free
);
1197 sbi
->nfree_zones
= block_free
;
1198 sbi
->nfree_zones_valid
= true;
1201 *count
= sbi
->nfree_zones
;
1206 vfs_out_ops_t mfs_ops
= {
1207 .mounted
= mfs_mounted
,
1208 .unmounted
= mfs_unmounted
,
1211 .truncate
= mfs_truncate
,
1213 .destroy
= mfs_destroy
,