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
;
219 if (version
== MFS_VERSION_V3
) {
220 sbi
->ninodes
= conv32(native
, sb3
->s_ninodes
);
221 sbi
->ibmap_blocks
= conv16(native
, sb3
->s_ibmap_blocks
);
222 sbi
->zbmap_blocks
= conv16(native
, sb3
->s_zbmap_blocks
);
223 sbi
->firstdatazone
= conv16(native
, sb3
->s_first_data_zone
);
224 sbi
->log2_zone_size
= conv16(native
, sb3
->s_log2_zone_size
);
225 sbi
->max_file_size
= conv32(native
, sb3
->s_max_file_size
);
226 sbi
->nzones
= conv32(native
, sb3
->s_nzones
);
227 sbi
->block_size
= conv16(native
, sb3
->s_block_size
);
228 sbi
->ino_per_block
= V3_INODES_PER_BLOCK(sbi
->block_size
);
229 sbi
->dirsize
= MFS3_DIRSIZE
;
230 sbi
->max_name_len
= MFS3_MAX_NAME_LEN
;
232 sbi
->ninodes
= conv16(native
, sb
->s_ninodes
);
233 sbi
->ibmap_blocks
= conv16(native
, sb
->s_ibmap_blocks
);
234 sbi
->zbmap_blocks
= conv16(native
, sb
->s_zbmap_blocks
);
235 sbi
->firstdatazone
= conv16(native
, sb
->s_first_data_zone
);
236 sbi
->log2_zone_size
= conv16(native
, sb
->s_log2_zone_size
);
237 sbi
->max_file_size
= conv32(native
, sb
->s_max_file_size
);
238 sbi
->block_size
= MFS_BLOCKSIZE
;
239 if (version
== MFS_VERSION_V2
) {
240 sbi
->nzones
= conv32(native
, sb
->s_nzones2
);
241 sbi
->ino_per_block
= V2_INODES_PER_BLOCK
;
243 sbi
->nzones
= conv16(native
, sb
->s_nzones
);
244 sbi
->ino_per_block
= V1_INODES_PER_BLOCK
;
246 sbi
->dirsize
= longnames
? MFSL_DIRSIZE
: MFS_DIRSIZE
;
247 sbi
->max_name_len
= longnames
? MFS_L_MAX_NAME_LEN
:
251 if (sbi
->log2_zone_size
!= 0) {
252 /* In MFS, file space is allocated per zones.
253 * Zones are a collection of consecutive blocks on disk.
255 * The current MFS implementation supports only filesystems
256 * where the size of a zone is equal to the
263 sbi
->itable_off
= 2 + sbi
->ibmap_blocks
+ sbi
->zbmap_blocks
;
264 if ((rc
= mfs_check_sanity(sbi
)) != EOK
) {
265 fprintf(stderr
, "Filesystem corrupted, invalid superblock");
269 rc
= block_cache_init(service_id
, sbi
->block_size
, 0, cmode
);
271 mfsdebug("block cache initialization failed\n");
276 /* Initialize the instance structure and remember it */
277 instance
->service_id
= service_id
;
279 instance
->open_nodes_cnt
= 0;
280 rc
= fs_instance_create(service_id
, instance
);
282 block_cache_fini(service_id
);
283 mfsdebug("fs instance creation failed\n");
287 mfsdebug("mount successful\n");
290 mfs_node_get(&fn
, service_id
, MFS_ROOT_INO
);
292 struct mfs_node
*mroot
= fn
->data
;
294 *index
= mroot
->ino_i
->index
;
295 *size
= mroot
->ino_i
->i_size
;
300 return mfs_node_put(fn
);
303 block_fini(service_id
);
314 mfs_unmounted(service_id_t service_id
)
316 struct mfs_instance
*inst
;
318 mfsdebug("%s()\n", __FUNCTION__
);
320 int r
= mfs_instance_get(service_id
, &inst
);
324 if (inst
->open_nodes_cnt
!= 0)
327 (void) block_cache_fini(service_id
);
328 block_fini(service_id
);
330 /* Remove and destroy the instance */
331 (void) fs_instance_destroy(service_id
);
338 mfs_service_get(fs_node_t
*fsnode
)
340 struct mfs_node
*node
= fsnode
->data
;
341 return node
->instance
->service_id
;
345 mfs_create_node(fs_node_t
**rfn
, service_id_t service_id
, int flags
)
348 struct mfs_instance
*inst
;
349 struct mfs_node
*mnode
;
353 r
= mfs_instance_get(service_id
, &inst
);
357 /* Alloc a new inode */
358 r
= mfs_alloc_inode(inst
, &inum
);
362 struct mfs_ino_info
*ino_i
;
364 ino_i
= malloc(sizeof(*ino_i
));
370 mnode
= malloc(sizeof(*mnode
));
376 fsnode
= malloc(sizeof(fs_node_t
));
382 if (flags
& L_DIRECTORY
) {
383 ino_i
->i_mode
= S_IFDIR
;
384 ino_i
->i_nlinks
= 1; /* This accounts for the '.' dentry */
386 ino_i
->i_mode
= S_IFREG
;
397 memset(ino_i
->i_dzone
, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES
);
398 memset(ino_i
->i_izone
, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES
);
400 mfsdebug("new node idx = %d\n", (int) inum
);
404 mnode
->ino_i
= ino_i
;
405 mnode
->instance
= inst
;
408 fibril_mutex_lock(&open_nodes_lock
);
409 hash_table_insert(&open_nodes
, &mnode
->link
);
410 fibril_mutex_unlock(&open_nodes_lock
);
411 inst
->open_nodes_cnt
++;
413 mnode
->ino_i
->dirty
= true;
415 fs_node_initialize(fsnode
);
416 fsnode
->data
= mnode
;
417 mnode
->fsnode
= fsnode
;
427 mfs_free_inode(inst
, inum
);
432 mfs_match(fs_node_t
**rfn
, fs_node_t
*pfn
, const char *component
)
434 struct mfs_node
*mnode
= pfn
->data
;
435 struct mfs_ino_info
*ino_i
= mnode
->ino_i
;
436 struct mfs_dentry_info d_info
;
439 if (!S_ISDIR(ino_i
->i_mode
))
442 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
443 const size_t comp_size
= str_size(component
);
446 for (i
= 0; i
< mnode
->ino_i
->i_size
/ sbi
->dirsize
; ++i
) {
447 r
= mfs_read_dentry(mnode
, &d_info
, i
);
451 if (!d_info
.d_inum
) {
452 /* This entry is not used */
456 const size_t dentry_name_size
= str_size(d_info
.d_name
);
458 if (comp_size
== dentry_name_size
&&
459 memcmp(component
, d_info
.d_name
, dentry_name_size
) == 0) {
461 mfs_node_core_get(rfn
, mnode
->instance
,
472 mfs_size_get(fs_node_t
*node
)
474 const struct mfs_node
*mnode
= node
->data
;
475 return mnode
->ino_i
->i_size
;
479 mfs_node_get(fs_node_t
**rfn
, service_id_t service_id
,
483 struct mfs_instance
*instance
;
485 rc
= mfs_instance_get(service_id
, &instance
);
489 return mfs_node_core_get(rfn
, instance
, index
);
493 mfs_node_put(fs_node_t
*fsnode
)
496 struct mfs_node
*mnode
= fsnode
->data
;
498 fibril_mutex_lock(&open_nodes_lock
);
500 assert(mnode
->refcnt
> 0);
502 if (mnode
->refcnt
== 0) {
503 hash_table_remove_item(&open_nodes
, &mnode
->link
);
504 assert(mnode
->instance
->open_nodes_cnt
> 0);
505 mnode
->instance
->open_nodes_cnt
--;
506 rc
= mfs_put_inode(mnode
);
512 fibril_mutex_unlock(&open_nodes_lock
);
517 mfs_node_open(fs_node_t
*fsnode
)
520 * Opening a file is stateless, nothing
527 mfs_index_get(fs_node_t
*fsnode
)
529 struct mfs_node
*mnode
= fsnode
->data
;
530 return mnode
->ino_i
->index
;
534 mfs_lnkcnt_get(fs_node_t
*fsnode
)
536 struct mfs_node
*mnode
= fsnode
->data
;
538 mfsdebug("%s() %d\n", __FUNCTION__
, mnode
->ino_i
->i_nlinks
);
540 if (S_ISDIR(mnode
->ino_i
->i_mode
)) {
541 if (mnode
->ino_i
->i_nlinks
> 1)
546 return mnode
->ino_i
->i_nlinks
;
550 mfs_node_core_get(fs_node_t
**rfn
, struct mfs_instance
*inst
,
553 fs_node_t
*node
= NULL
;
554 struct mfs_node
*mnode
= NULL
;
557 fibril_mutex_lock(&open_nodes_lock
);
559 /* Check if the node is not already open */
561 .service_id
= inst
->service_id
,
565 ht_link_t
*already_open
= hash_table_find(&open_nodes
, &key
);
568 mnode
= hash_table_get_inst(already_open
, struct mfs_node
, link
);
570 *rfn
= mnode
->fsnode
;
573 fibril_mutex_unlock(&open_nodes_lock
);
577 node
= malloc(sizeof(fs_node_t
));
583 fs_node_initialize(node
);
585 mnode
= malloc(sizeof(*mnode
));
591 struct mfs_ino_info
*ino_i
;
593 rc
= mfs_get_inode(inst
, &ino_i
, index
);
597 ino_i
->index
= index
;
598 mnode
->ino_i
= ino_i
;
601 mnode
->instance
= inst
;
603 mnode
->fsnode
= node
;
606 hash_table_insert(&open_nodes
, &mnode
->link
);
607 inst
->open_nodes_cnt
++;
609 fibril_mutex_unlock(&open_nodes_lock
);
618 fibril_mutex_unlock(&open_nodes_lock
);
623 mfs_is_directory(fs_node_t
*fsnode
)
625 const struct mfs_node
*node
= fsnode
->data
;
626 return S_ISDIR(node
->ino_i
->i_mode
);
630 mfs_is_file(fs_node_t
*fsnode
)
632 struct mfs_node
*node
= fsnode
->data
;
633 return S_ISREG(node
->ino_i
->i_mode
);
637 mfs_root_get(fs_node_t
**rfn
, service_id_t service_id
)
639 int rc
= mfs_node_get(rfn
, service_id
, MFS_ROOT_INO
);
644 mfs_link(fs_node_t
*pfn
, fs_node_t
*cfn
, const char *name
)
646 struct mfs_node
*parent
= pfn
->data
;
647 struct mfs_node
*child
= cfn
->data
;
648 struct mfs_sb_info
*sbi
= parent
->instance
->sbi
;
649 bool destroy_dentry
= false;
651 if (str_size(name
) > sbi
->max_name_len
)
654 int r
= mfs_insert_dentry(parent
, name
, child
->ino_i
->index
);
658 if (S_ISDIR(child
->ino_i
->i_mode
)) {
659 if (child
->ino_i
->i_nlinks
!= 1) {
660 /* It's not possible to hardlink directories in MFS */
661 destroy_dentry
= true;
665 r
= mfs_insert_dentry(child
, ".", child
->ino_i
->index
);
667 destroy_dentry
= true;
671 r
= mfs_insert_dentry(child
, "..", parent
->ino_i
->index
);
673 mfs_remove_dentry(child
, ".");
674 destroy_dentry
= true;
678 parent
->ino_i
->i_nlinks
++;
679 parent
->ino_i
->dirty
= true;
683 if (destroy_dentry
) {
684 int r2
= mfs_remove_dentry(parent
, name
);
688 child
->ino_i
->i_nlinks
++;
689 child
->ino_i
->dirty
= true;
695 mfs_unlink(fs_node_t
*pfn
, fs_node_t
*cfn
, const char *name
)
697 struct mfs_node
*parent
= pfn
->data
;
698 struct mfs_node
*child
= cfn
->data
;
705 r
= mfs_has_children(&has_children
, cfn
);
712 r
= mfs_remove_dentry(parent
, name
);
716 struct mfs_ino_info
*chino
= child
->ino_i
;
718 assert(chino
->i_nlinks
>= 1);
720 mfsdebug("Links: %d\n", chino
->i_nlinks
);
722 if (chino
->i_nlinks
<= 1 && S_ISDIR(chino
->i_mode
)) {
723 /* The child directory will be destroyed, decrease the
724 * parent hard links counter.
726 parent
->ino_i
->i_nlinks
--;
727 parent
->ino_i
->dirty
= true;
736 mfs_has_children(bool *has_children
, fs_node_t
*fsnode
)
738 struct mfs_node
*mnode
= fsnode
->data
;
739 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
742 *has_children
= false;
744 if (!S_ISDIR(mnode
->ino_i
->i_mode
))
747 struct mfs_dentry_info d_info
;
749 /* The first two dentries are always . and .. */
751 for (i
= 2; i
< mnode
->ino_i
->i_size
/ sbi
->dirsize
; ++i
) {
752 r
= mfs_read_dentry(mnode
, &d_info
, i
);
757 /* A valid entry has been found */
758 *has_children
= true;
768 mfs_read(service_id_t service_id
, fs_index_t index
, aoff64_t pos
,
772 fs_node_t
*fn
= NULL
;
774 rc
= mfs_node_get(&fn
, service_id
, index
);
780 struct mfs_node
*mnode
;
781 struct mfs_ino_info
*ino_i
;
782 size_t len
, bytes
= 0;
786 ino_i
= mnode
->ino_i
;
788 if (!async_data_read_receive(&callid
, &len
)) {
793 if (S_ISDIR(ino_i
->i_mode
)) {
795 struct mfs_dentry_info d_info
;
796 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
799 /* Skip the first two dentries ('.' and '..') */
803 for (; pos
< mnode
->ino_i
->i_size
/ sbi
->dirsize
; ++pos
) {
804 rc
= mfs_read_dentry(mnode
, &d_info
, pos
);
814 rc
= mfs_node_put(fn
);
815 async_answer_0(callid
, rc
!= EOK
? rc
: ENOENT
);
818 async_data_read_finalize(callid
, d_info
.d_name
,
819 str_size(d_info
.d_name
) + 1);
820 bytes
= ((pos
- spos
) + 1);
822 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
824 if (pos
>= (size_t) ino_i
->i_size
) {
825 /* Trying to read beyond the end of file */
827 (void) async_data_read_finalize(callid
, NULL
, 0);
831 bytes
= min(len
, sbi
->block_size
- pos
% sbi
->block_size
);
832 bytes
= min(bytes
, ino_i
->i_size
- pos
);
837 rc
= mfs_read_map(&zone
, mnode
, pos
);
843 uint8_t *buf
= malloc(sbi
->block_size
);
848 memset(buf
, 0, sizeof(sbi
->block_size
));
849 async_data_read_finalize(callid
,
850 buf
+ pos
% sbi
->block_size
, bytes
);
855 rc
= block_get(&b
, service_id
, zone
, BLOCK_FLAGS_NONE
);
859 async_data_read_finalize(callid
, b
->data
+
860 pos
% sbi
->block_size
, bytes
);
869 rc
= mfs_node_put(fn
);
874 int tmp
= mfs_node_put(fn
);
875 async_answer_0(callid
, tmp
!= EOK
? tmp
: rc
);
876 return tmp
!= EOK
? tmp
: rc
;
880 mfs_write(service_id_t service_id
, fs_index_t index
, aoff64_t pos
,
881 size_t *wbytes
, aoff64_t
*nsize
)
885 int flags
= BLOCK_FLAGS_NONE
;
887 r
= mfs_node_get(&fn
, service_id
, index
);
896 if (!async_data_write_receive(&callid
, &len
)) {
901 struct mfs_node
*mnode
= fn
->data
;
902 struct mfs_sb_info
*sbi
= mnode
->instance
->sbi
;
903 struct mfs_ino_info
*ino_i
= mnode
->ino_i
;
904 const size_t bs
= sbi
->block_size
;
905 size_t bytes
= min(len
, bs
- (pos
% bs
));
909 flags
= BLOCK_FLAGS_NOREAD
;
911 r
= mfs_read_map(&block
, mnode
, pos
);
918 r
= mfs_alloc_zone(mnode
->instance
, &block
);
922 r
= mfs_write_map(mnode
, pos
, block
, &dummy
);
924 mfs_free_zone(mnode
->instance
, block
);
928 flags
= BLOCK_FLAGS_NOREAD
;
932 r
= block_get(&b
, service_id
, block
, flags
);
936 if (flags
== BLOCK_FLAGS_NOREAD
)
937 memset(b
->data
, 0, sbi
->block_size
);
939 async_data_write_finalize(callid
, b
->data
+ (pos
% bs
), bytes
);
948 if (pos
+ bytes
> ino_i
->i_size
) {
949 ino_i
->i_size
= pos
+ bytes
;
952 r
= mfs_node_put(fn
);
953 *nsize
= ino_i
->i_size
;
959 async_answer_0(callid
, r
);
964 mfs_destroy(service_id_t service_id
, fs_index_t index
)
966 fs_node_t
*fn
= NULL
;
969 r
= mfs_node_get(&fn
, service_id
, index
);
975 /* Destroy the inode */
976 return mfs_destroy_node(fn
);
980 mfs_destroy_node(fs_node_t
*fn
)
982 struct mfs_node
*mnode
= fn
->data
;
986 mfsdebug("mfs_destroy_node %d\n", mnode
->ino_i
->index
);
988 r
= mfs_has_children(&has_children
, fn
);
992 assert(!has_children
);
994 /* Free the entire inode content */
995 r
= mfs_inode_shrink(mnode
, mnode
->ino_i
->i_size
);
999 /* Mark the inode as free in the bitmap */
1000 r
= mfs_free_inode(mnode
->instance
, mnode
->ino_i
->index
);
1008 mfs_truncate(service_id_t service_id
, fs_index_t index
, aoff64_t size
)
1013 r
= mfs_node_get(&fn
, service_id
, index
);
1019 struct mfs_node
*mnode
= fn
->data
;
1020 struct mfs_ino_info
*ino_i
= mnode
->ino_i
;
1022 if (ino_i
->i_size
== size
)
1025 r
= mfs_inode_shrink(mnode
, ino_i
->i_size
- size
);
1032 mfs_instance_get(service_id_t service_id
, struct mfs_instance
**instance
)
1037 rc
= fs_instance_get(service_id
, &data
);
1039 *instance
= (struct mfs_instance
*) data
;
1041 mfsdebug("instance not found\n");
1048 check_magic_number(uint16_t magic
, bool *native
,
1049 mfs_version_t
*version
, bool *longfilenames
)
1052 *longfilenames
= false;
1054 if (magic
== MFS_MAGIC_V1
|| magic
== MFS_MAGIC_V1R
) {
1055 *native
= magic
== MFS_MAGIC_V1
;
1056 *version
= MFS_VERSION_V1
;
1057 } else if (magic
== MFS_MAGIC_V1L
|| magic
== MFS_MAGIC_V1LR
) {
1058 *native
= magic
== MFS_MAGIC_V1L
;
1059 *version
= MFS_VERSION_V1
;
1060 *longfilenames
= true;
1061 } else if (magic
== MFS_MAGIC_V2
|| magic
== MFS_MAGIC_V2R
) {
1062 *native
= magic
== MFS_MAGIC_V2
;
1063 *version
= MFS_VERSION_V2
;
1064 } else if (magic
== MFS_MAGIC_V2L
|| magic
== MFS_MAGIC_V2LR
) {
1065 *native
= magic
== MFS_MAGIC_V2L
;
1066 *version
= MFS_VERSION_V2
;
1067 *longfilenames
= true;
1068 } else if (magic
== MFS_MAGIC_V3
|| magic
== MFS_MAGIC_V3R
) {
1069 *native
= magic
== MFS_MAGIC_V3
;
1070 *version
= MFS_VERSION_V3
;
1077 /** Filesystem sanity check
1079 * @param Pointer to the MFS superblock.
1081 * @return EOK on success, ENOTSUP otherwise.
1084 mfs_check_sanity(struct mfs_sb_info
*sbi
)
1086 if (!is_power_of_two(sbi
->block_size
) ||
1087 sbi
->block_size
< MFS_MIN_BLOCKSIZE
||
1088 sbi
->block_size
> MFS_MAX_BLOCKSIZE
)
1090 else if (sbi
->ibmap_blocks
== 0 || sbi
->zbmap_blocks
== 0)
1092 else if (sbi
->ninodes
== 0 || sbi
->nzones
== 0)
1094 else if (sbi
->firstdatazone
== 0)
1101 mfs_close(service_id_t service_id
, fs_index_t index
)
1107 mfs_sync(service_id_t service_id
, fs_index_t index
)
1109 fs_node_t
*fn
= NULL
;
1110 int rc
= mfs_node_get(&fn
, service_id
, index
);
1116 struct mfs_node
*mnode
= fn
->data
;
1117 mnode
->ino_i
->dirty
= true;
1119 return mfs_node_put(fn
);
1122 /** Check if a given number is a power of two.
1124 * @param n The number to check.
1126 * @return true if it is a power of two, false otherwise.
1129 is_power_of_two(uint32_t n
)
1134 return (n
& (n
- 1)) == 0;
1138 mfs_size_block(service_id_t service_id
, uint32_t *size
)
1140 struct mfs_instance
*inst
;
1143 rc
= mfs_instance_get(service_id
, &inst
);
1150 *size
= inst
->sbi
->block_size
;
1156 mfs_total_block_count(service_id_t service_id
, uint64_t *count
)
1158 struct mfs_instance
*inst
;
1161 rc
= mfs_instance_get(service_id
, &inst
);
1168 *count
= (uint64_t) MFS_BMAP_SIZE_BITS(inst
->sbi
, BMAP_ZONE
);
1174 mfs_free_block_count(service_id_t service_id
, uint64_t *count
)
1176 uint32_t block_free
;
1178 struct mfs_instance
*inst
;
1179 int rc
= mfs_instance_get(service_id
, &inst
);
1183 rc
= mfs_count_free_zones(inst
, &block_free
);
1184 *count
= block_free
;
1189 vfs_out_ops_t mfs_ops
= {
1190 .mounted
= mfs_mounted
,
1191 .unmounted
= mfs_unmounted
,
1194 .truncate
= mfs_truncate
,
1196 .destroy
= mfs_destroy
,