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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5e801dc was 5e801dc, checked in by GitHub <noreply@…>, 6 years ago

Indicate and enforce constness of hash table key in certain functions (#158)

The assumption here is that modifying key in the hash/equal functions in something completely unexpected, and not something you would ever want to do intentionally, so it makes sense to disallow it entirely to get that extra level of checking.

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