source: mainline/uspace/srv/fs/mfs/mfs_ops.c@ 3061bc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3061bc1 was 1d6dd2a, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Remove unnecessary includes from <stdio.h>.

  • 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
29/** @addtogroup fs
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
[ee257b2]41
[8ceba1e]42static bool check_magic_number(uint16_t magic, bool *native,
[6d4d883]43 mfs_version_t *version, bool *longfilenames);
[b7fd2a0]44static errno_t mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
[6d4d883]45 fs_index_t index);
[b7fd2a0]46static errno_t mfs_node_put(fs_node_t *fsnode);
47static errno_t mfs_node_open(fs_node_t *fsnode);
[41202a9]48static fs_index_t mfs_index_get(fs_node_t *fsnode);
49static unsigned mfs_lnkcnt_get(fs_node_t *fsnode);
[ac28650]50static bool mfs_is_directory(fs_node_t *fsnode);
51static bool mfs_is_file(fs_node_t *fsnode);
[b7fd2a0]52static errno_t mfs_has_children(bool *has_children, fs_node_t *fsnode);
53static errno_t mfs_root_get(fs_node_t **rfn, service_id_t service_id);
[b33870b]54static service_id_t mfs_service_get(fs_node_t *fsnode);
[ac28650]55static aoff64_t mfs_size_get(fs_node_t *node);
[b7fd2a0]56static errno_t mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
57static errno_t mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags);
58static errno_t mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name);
59static errno_t mfs_unlink(fs_node_t *, fs_node_t *, const char *name);
60static errno_t mfs_destroy_node(fs_node_t *fn);
61static errno_t mfs_node_get(fs_node_t **rfn, service_id_t service_id,
[6d4d883]62 fs_index_t index);
[b7fd2a0]63static errno_t mfs_instance_get(service_id_t service_id,
[6d4d883]64 struct mfs_instance **instance);
[b7fd2a0]65static errno_t mfs_check_sanity(struct mfs_sb_info *sbi);
[df3caec5]66static bool is_power_of_two(uint32_t n);
[b7fd2a0]67static errno_t mfs_size_block(service_id_t service_id, uint32_t *size);
68static errno_t mfs_total_block_count(service_id_t service_id, uint64_t *count);
69static errno_t mfs_free_block_count(service_id_t service_id, uint64_t *count);
[41202a9]70
[ee257b2]71static hash_table_t open_nodes;
72static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
[953a823]73
[e54ba607]74libfs_ops_t mfs_libfs_ops = {
[0d6ab10]75 .size_get = mfs_size_get,
[fe4ac35]76 .root_get = mfs_root_get,
[b33870b]77 .service_get = mfs_service_get,
[7d04324]78 .is_directory = mfs_is_directory,
[44c0f5b]79 .is_file = mfs_is_file,
[cfbcd86]80 .node_get = mfs_node_get,
[41202a9]81 .node_put = mfs_node_put,
82 .node_open = mfs_node_open,
83 .index_get = mfs_index_get,
[bd64680]84 .match = mfs_match,
[10eb754]85 .create = mfs_create_node,
[88ccd8b8]86 .link = mfs_link,
[53eb588]87 .unlink = mfs_unlink,
[d8af1bd]88 .destroy = mfs_destroy_node,
[41202a9]89 .has_children = mfs_has_children,
[66366470]90 .lnkcnt_get = mfs_lnkcnt_get,
[67632f7]91 .size_block = mfs_size_block,
[c84146d3]92 .total_block_count = mfs_total_block_count,
93 .free_block_count = mfs_free_block_count
[e54ba607]94};
[3b08178]95
[ee257b2]96/* Hash table interface for open nodes hash table */
[062d900]97typedef struct {
98 service_id_t service_id;
99 fs_index_t index;
100} node_key_t;
101
102static size_t
103open_nodes_key_hash(void *key)
[ee257b2]104{
[062d900]105 node_key_t *node_key = (node_key_t*)key;
106 return hash_combine(node_key->service_id, node_key->index);
[ee257b2]107}
108
[062d900]109static size_t
110open_nodes_hash(const ht_link_t *item)
[ee257b2]111{
[062d900]112 struct mfs_node *m = hash_table_get_inst(item, struct mfs_node, link);
113 return hash_combine(m->instance->service_id, m->ino_i->index);
[ee257b2]114}
115
[062d900]116static bool
117open_nodes_key_equal(void *key, const ht_link_t *item)
[ee257b2]118{
[062d900]119 node_key_t *node_key = (node_key_t*)key;
120 struct mfs_node *mnode = hash_table_get_inst(item, struct mfs_node, link);
121
122 return node_key->service_id == mnode->instance->service_id
123 && node_key->index == mnode->ino_i->index;
[ee257b2]124}
125
[062d900]126static hash_table_ops_t open_nodes_ops = {
[ee257b2]127 .hash = open_nodes_hash,
[062d900]128 .key_hash = open_nodes_key_hash,
129 .key_equal = open_nodes_key_equal,
[4e00f87]130 .equal = NULL,
131 .remove_callback = NULL,
[ee257b2]132};
133
[b7fd2a0]134errno_t
[6d4d883]135mfs_global_init(void)
[ee257b2]136{
[062d900]137 if (!hash_table_create(&open_nodes, 0, 0, &open_nodes_ops)) {
[ee257b2]138 return ENOMEM;
139 }
140 return EOK;
141}
142
[d2c8533]143/** Read the superblock.
144 */
[b7fd2a0]145static errno_t mfs_read_sb(service_id_t service_id, struct mfs_sb_info **rsbi)
[096c8835]146{
[f456ab2]147 struct mfs_superblock *sb = NULL;
148 struct mfs3_superblock *sb3 = NULL;
[d2c8533]149 struct mfs_sb_info *sbi;
150 size_t bsize;
[8ceba1e]151 bool native, longnames;
[9e3dc95]152 mfs_version_t version;
[245eb02d]153 uint16_t magic;
[b7fd2a0]154 errno_t rc;
[096c8835]155
[6d4d883]156 /* Allocate space for generic MFS superblock */
[b438804]157 sbi = malloc(sizeof(*sbi));
[953a823]158 if (!sbi) {
[f456ab2]159 rc = ENOMEM;
160 goto out_error;
[953a823]161 }
162
[d2c8533]163 sb = malloc(MFS_SUPERBLOCK_SIZE);
164 if (!sb) {
[f456ab2]165 rc = ENOMEM;
166 goto out_error;
[953a823]167 }
168
[d2c8533]169 rc = block_get_bsize(service_id, &bsize);
170 if (rc != EOK) {
171 rc = EIO;
172 goto out_error;
173 }
174
175 /* We don't support other block size than 512 */
176 if (bsize != 512) {
177 rc = ENOTSUP;
[f456ab2]178 goto out_error;
[953a823]179 }
[92dd5c8]180
181 /* Read the superblock */
[e03d545]182 rc = block_read_direct(service_id, MFS_SUPERBLOCK << 1, 2, sb);
[f456ab2]183 if (rc != EOK)
184 goto out_error;
[096c8835]185
[953a823]186 sb3 = (struct mfs3_superblock *) sb;
187
188 if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
[6d4d883]189 /* This is a V1 or V2 Minix filesystem */
[953a823]190 magic = sb->s_magic;
[7769ec9]191 } else if (check_magic_number(sb3->s_magic, &native,
192 &version, &longnames)) {
[6d4d883]193 /* This is a V3 Minix filesystem */
[5222e746]194 magic = sb3->s_magic;
195 } else {
[6d4d883]196 /* Not recognized */
[92dd5c8]197 mfsdebug("magic number not recognized\n");
[f456ab2]198 rc = ENOTSUP;
199 goto out_error;
[9e3dc95]200 }
[92dd5c8]201
[245eb02d]202 mfsdebug("magic number recognized = %04x\n", magic);
[953a823]203
[6d4d883]204 /* Fill superblock info structure */
[953a823]205
206 sbi->fs_version = version;
207 sbi->long_names = longnames;
208 sbi->native = native;
209 sbi->magic = magic;
[ef76d72]210 sbi->isearch = 0;
211 sbi->zsearch = 0;
[1eaa3cf]212 sbi->nfree_zones_valid = false;
213 sbi->nfree_zones = 0;
[953a823]214
215 if (version == MFS_VERSION_V3) {
216 sbi->ninodes = conv32(native, sb3->s_ninodes);
217 sbi->ibmap_blocks = conv16(native, sb3->s_ibmap_blocks);
218 sbi->zbmap_blocks = conv16(native, sb3->s_zbmap_blocks);
219 sbi->firstdatazone = conv16(native, sb3->s_first_data_zone);
220 sbi->log2_zone_size = conv16(native, sb3->s_log2_zone_size);
221 sbi->max_file_size = conv32(native, sb3->s_max_file_size);
222 sbi->nzones = conv32(native, sb3->s_nzones);
223 sbi->block_size = conv16(native, sb3->s_block_size);
[10eb754]224 sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
[a04b62d]225 sbi->dirsize = MFS3_DIRSIZE;
[bd64680]226 sbi->max_name_len = MFS3_MAX_NAME_LEN;
[953a823]227 } else {
228 sbi->ninodes = conv16(native, sb->s_ninodes);
229 sbi->ibmap_blocks = conv16(native, sb->s_ibmap_blocks);
230 sbi->zbmap_blocks = conv16(native, sb->s_zbmap_blocks);
231 sbi->firstdatazone = conv16(native, sb->s_first_data_zone);
232 sbi->log2_zone_size = conv16(native, sb->s_log2_zone_size);
233 sbi->max_file_size = conv32(native, sb->s_max_file_size);
[3b08178]234 sbi->block_size = MFS_BLOCKSIZE;
[5a841a4]235 if (version == MFS_VERSION_V2) {
[953a823]236 sbi->nzones = conv32(native, sb->s_nzones2);
[5a841a4]237 sbi->ino_per_block = V2_INODES_PER_BLOCK;
238 } else {
239 sbi->nzones = conv16(native, sb->s_nzones);
240 sbi->ino_per_block = V1_INODES_PER_BLOCK;
241 }
[a04b62d]242 sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
[bd64680]243 sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
[6d4d883]244 MFS_MAX_NAME_LEN;
[953a823]245 }
[85ff862]246
247 if (sbi->log2_zone_size != 0) {
248 /* In MFS, file space is allocated per zones.
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
279
[b7fd2a0]280static errno_t mfs_fsprobe(service_id_t service_id, vfs_fs_probe_info_t *info)
[d2c8533]281{
282 struct mfs_sb_info *sbi = NULL;
[b7fd2a0]283 errno_t rc;
[d2c8533]284
285 /* Initialize libblock */
286 rc = block_init(service_id, 4096);
287 if (rc != EOK)
288 return rc;
289
290 /* Read the superblock */
291 rc = mfs_read_sb(service_id, &sbi);
292 block_fini(service_id);
293
294 return rc;
295}
296
[b7fd2a0]297static errno_t
[d2c8533]298mfs_mounted(service_id_t service_id, const char *opts, fs_index_t *index,
[4f30222]299 aoff64_t *size)
[d2c8533]300{
301 enum cache_mode cmode;
302 struct mfs_sb_info *sbi = NULL;
303 struct mfs_instance *instance = NULL;
[b7fd2a0]304 errno_t rc;
[d2c8533]305
306 /* Check for option enabling write through. */
307 if (str_cmp(opts, "wtcache") == 0)
308 cmode = CACHE_MODE_WT;
309 else
310 cmode = CACHE_MODE_WB;
311
312 /* Initialize libblock */
313 rc = block_init(service_id, 4096);
314 if (rc != EOK)
315 return rc;
316
317 /* Allocate space for filesystem instance */
318 instance = malloc(sizeof(*instance));
319 if (!instance) {
320 rc = ENOMEM;
321 goto out_error;
322 }
323
324 /* Read the superblock */
325 rc = mfs_read_sb(service_id, &sbi);
326 if (rc != EOK)
327 goto out_error;
328
[03bc76a]329 rc = block_cache_init(service_id, sbi->block_size, 0, cmode);
[3b08178]330 if (rc != EOK) {
331 mfsdebug("block cache initialization failed\n");
[f456ab2]332 rc = EINVAL;
333 goto out_error;
[3b08178]334 }
335
[6d4d883]336 /* Initialize the instance structure and remember it */
[03bc76a]337 instance->service_id = service_id;
[953a823]338 instance->sbi = sbi;
[5bf76c1]339 instance->open_nodes_cnt = 0;
340 rc = fs_instance_create(service_id, instance);
341 if (rc != EOK) {
342 block_cache_fini(service_id);
343 mfsdebug("fs instance creation failed\n");
[bf08ff0]344 goto out_error;
[5bf76c1]345 }
[953a823]346
347 mfsdebug("mount successful\n");
348
[99e846f0]349 fs_node_t *fn;
[03bc76a]350 mfs_node_get(&fn, service_id, MFS_ROOT_INO);
[99e846f0]351
[03bc76a]352 struct mfs_node *mroot = fn->data;
[99e846f0]353
[03bc76a]354 *index = mroot->ino_i->index;
355 *size = mroot->ino_i->i_size;
[99e846f0]356
[03bc76a]357 return mfs_node_put(fn);
[f456ab2]358
359out_error:
360 block_fini(service_id);
361 if (sbi)
362 free(sbi);
363 if(instance)
364 free(instance);
365 return rc;
[3b08178]366}
367
[b7fd2a0]368static errno_t
[03bc76a]369mfs_unmounted(service_id_t service_id)
[51db5aeb]370{
[7accfac]371 struct mfs_instance *inst;
372
[bbd4c72]373 mfsdebug("%s()\n", __FUNCTION__);
374
[b7fd2a0]375 errno_t r = mfs_instance_get(service_id, &inst);
[03bc76a]376 if (r != EOK)
377 return r;
[51db5aeb]378
[03bc76a]379 if (inst->open_nodes_cnt != 0)
380 return EBUSY;
[ee257b2]381
[03bc76a]382 (void) block_cache_fini(service_id);
383 block_fini(service_id);
[51db5aeb]384
[5bf76c1]385 /* Remove and destroy the instance */
386 (void) fs_instance_destroy(service_id);
[7accfac]387 free(inst->sbi);
388 free(inst);
[03bc76a]389 return EOK;
[51db5aeb]390}
391
[6d4d883]392service_id_t
393mfs_service_get(fs_node_t *fsnode)
[e54ba607]394{
395 struct mfs_node *node = fsnode->data;
[03bc76a]396 return node->instance->service_id;
[e54ba607]397}
398
[b7fd2a0]399static errno_t
[6d4d883]400mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[10eb754]401{
[b7fd2a0]402 errno_t r;
[88ccd8b8]403 struct mfs_instance *inst;
404 struct mfs_node *mnode;
405 fs_node_t *fsnode;
406 uint32_t inum;
[44c6091f]407
[03bc76a]408 r = mfs_instance_get(service_id, &inst);
[c699b0c]409 if (r != EOK)
410 return r;
[88ccd8b8]411
[6d4d883]412 /* Alloc a new inode */
[70ac0af]413 r = mfs_alloc_inode(inst, &inum);
[c699b0c]414 if (r != EOK)
415 return r;
[88ccd8b8]416
417 struct mfs_ino_info *ino_i;
418
419 ino_i = malloc(sizeof(*ino_i));
420 if (!ino_i) {
421 r = ENOMEM;
422 goto out_err;
423 }
424
425 mnode = malloc(sizeof(*mnode));
426 if (!mnode) {
427 r = ENOMEM;
428 goto out_err_1;
429 }
[44c6091f]430
[88ccd8b8]431 fsnode = malloc(sizeof(fs_node_t));
432 if (!fsnode) {
433 r = ENOMEM;
434 goto out_err_2;
435 }
436
[bbd4c72]437 if (flags & L_DIRECTORY) {
[13ecdac9]438 ino_i->i_mode = S_IFDIR;
[4c3ad56]439 ino_i->i_nlinks = 1; /* This accounts for the '.' dentry */
[1ba6651]440 } else {
[13ecdac9]441 ino_i->i_mode = S_IFREG;
[1ba6651]442 ino_i->i_nlinks = 0;
443 }
[13ecdac9]444
[88ccd8b8]445 ino_i->i_uid = 0;
446 ino_i->i_gid = 0;
447 ino_i->i_size = 0;
448 ino_i->i_atime = 0;
449 ino_i->i_mtime = 0;
450 ino_i->i_ctime = 0;
451
452 memset(ino_i->i_dzone, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES);
453 memset(ino_i->i_izone, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES);
454
[58c36ac]455 mfsdebug("new node idx = %d\n", (int) inum);
456
[88ccd8b8]457 ino_i->index = inum;
458 ino_i->dirty = true;
459 mnode->ino_i = ino_i;
460 mnode->instance = inst;
[ee257b2]461 mnode->refcnt = 1;
462
463 fibril_mutex_lock(&open_nodes_lock);
[062d900]464 hash_table_insert(&open_nodes, &mnode->link);
[ee257b2]465 fibril_mutex_unlock(&open_nodes_lock);
466 inst->open_nodes_cnt++;
467
468 mnode->ino_i->dirty = true;
[88ccd8b8]469
470 fs_node_initialize(fsnode);
471 fsnode->data = mnode;
[ee257b2]472 mnode->fsnode = fsnode;
[88ccd8b8]473 *rfn = fsnode;
474
475 return EOK;
476
477out_err_2:
478 free(mnode);
479out_err_1:
480 free(ino_i);
481out_err:
[64e63ce1]482 mfs_free_inode(inst, inum);
[88ccd8b8]483 return r;
[10eb754]484}
485
[b7fd2a0]486static errno_t
[6d4d883]487mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
[bd64680]488{
489 struct mfs_node *mnode = pfn->data;
490 struct mfs_ino_info *ino_i = mnode->ino_i;
[e80c2ff]491 struct mfs_dentry_info d_info;
[b7fd2a0]492 errno_t r;
[bd64680]493
494 if (!S_ISDIR(ino_i->i_mode))
495 return ENOTDIR;
496
497 struct mfs_sb_info *sbi = mnode->instance->sbi;
498 const size_t comp_size = str_size(component);
499
[e80c2ff]500 unsigned i;
501 for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
[3a5ee6c]502 r = mfs_read_dentry(mnode, &d_info, i);
[c699b0c]503 if (r != EOK)
504 return r;
[488f7ed]505
[e80c2ff]506 if (!d_info.d_inum) {
[6d4d883]507 /* This entry is not used */
[bd64680]508 continue;
509 }
510
[367d67fe]511 const size_t dentry_name_size = str_size(d_info.d_name);
512
513 if (comp_size == dentry_name_size &&
[44ecf89]514 memcmp(component, d_info.d_name, dentry_name_size) == 0) {
[6d4d883]515 /* Hit! */
[bd64680]516 mfs_node_core_get(rfn, mnode->instance,
[6d4d883]517 d_info.d_inum);
[bd64680]518 goto found;
519 }
520 }
521 *rfn = NULL;
522found:
523 return EOK;
524}
525
[6d4d883]526static aoff64_t
527mfs_size_get(fs_node_t *node)
[0d6ab10]528{
529 const struct mfs_node *mnode = node->data;
[155f792]530 return mnode->ino_i->i_size;
[0d6ab10]531}
532
[b7fd2a0]533static errno_t
[03bc76a]534mfs_node_get(fs_node_t **rfn, service_id_t service_id,
[6d4d883]535 fs_index_t index)
[44c0f5b]536{
[b7fd2a0]537 errno_t rc;
[44c0f5b]538 struct mfs_instance *instance;
539
[03bc76a]540 rc = mfs_instance_get(service_id, &instance);
[c699b0c]541 if (rc != EOK)
542 return rc;
[44c0f5b]543
544 return mfs_node_core_get(rfn, instance, index);
545}
546
[b7fd2a0]547static errno_t
[03bc76a]548mfs_node_put(fs_node_t *fsnode)
[41202a9]549{
[b7fd2a0]550 errno_t rc = EOK;
[41202a9]551 struct mfs_node *mnode = fsnode->data;
552
[ee257b2]553 fibril_mutex_lock(&open_nodes_lock);
554
555 assert(mnode->refcnt > 0);
556 mnode->refcnt--;
557 if (mnode->refcnt == 0) {
[062d900]558 hash_table_remove_item(&open_nodes, &mnode->link);
[ee257b2]559 assert(mnode->instance->open_nodes_cnt > 0);
560 mnode->instance->open_nodes_cnt--;
[5f509cc]561 rc = mfs_put_inode(mnode);
[ee257b2]562 free(mnode->ino_i);
563 free(mnode);
564 free(fsnode);
565 }
[41202a9]566
[ee257b2]567 fibril_mutex_unlock(&open_nodes_lock);
568 return rc;
[41202a9]569}
570
[b7fd2a0]571static errno_t
[6d4d883]572mfs_node_open(fs_node_t *fsnode)
[41202a9]573{
574 /*
575 * Opening a file is stateless, nothing
576 * to be done here.
577 */
578 return EOK;
579}
580
[6d4d883]581static fs_index_t
582mfs_index_get(fs_node_t *fsnode)
[41202a9]583{
584 struct mfs_node *mnode = fsnode->data;
585 return mnode->ino_i->index;
586}
587
[6d4d883]588static unsigned
589mfs_lnkcnt_get(fs_node_t *fsnode)
[41202a9]590{
591 struct mfs_node *mnode = fsnode->data;
592
[75e0f15]593 mfsdebug("%s() %d\n", __FUNCTION__, mnode->ino_i->i_nlinks);
[ee257b2]594
[bbd4c72]595 if (S_ISDIR(mnode->ino_i->i_mode)) {
596 if (mnode->ino_i->i_nlinks > 1)
597 return 1;
598 else
599 return 0;
[75e0f15]600 } else
601 return mnode->ino_i->i_nlinks;
[41202a9]602}
603
[b7fd2a0]604static errno_t
[6d4d883]605mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
606 fs_index_t index)
[44c0f5b]607{
608 fs_node_t *node = NULL;
609 struct mfs_node *mnode = NULL;
[b7fd2a0]610 errno_t rc;
[44c0f5b]611
[ee257b2]612 fibril_mutex_lock(&open_nodes_lock);
613
614 /* Check if the node is not already open */
[062d900]615 node_key_t key = {
616 .service_id = inst->service_id,
617 .index = index
[ee257b2]618 };
[062d900]619
620 ht_link_t *already_open = hash_table_find(&open_nodes, &key);
[ee257b2]621
622 if (already_open) {
[062d900]623 mnode = hash_table_get_inst(already_open, struct mfs_node, link);
[4c53333]624
[ee257b2]625 *rfn = mnode->fsnode;
626 mnode->refcnt++;
627
628 fibril_mutex_unlock(&open_nodes_lock);
629 return EOK;
630 }
631
[b438804]632 node = malloc(sizeof(fs_node_t));
[44c0f5b]633 if (!node) {
634 rc = ENOMEM;
635 goto out_err;
636 }
637
638 fs_node_initialize(node);
639
[b438804]640 mnode = malloc(sizeof(*mnode));
[44c0f5b]641 if (!mnode) {
642 rc = ENOMEM;
643 goto out_err;
644 }
645
[155f792]646 struct mfs_ino_info *ino_i;
647
[3a5ee6c]648 rc = mfs_get_inode(inst, &ino_i, index);
[c699b0c]649 if (rc != EOK)
650 goto out_err;
[155f792]651
[41202a9]652 ino_i->index = index;
[155f792]653 mnode->ino_i = ino_i;
[ee257b2]654 mnode->refcnt = 1;
[155f792]655
[44c0f5b]656 mnode->instance = inst;
657 node->data = mnode;
[ee257b2]658 mnode->fsnode = node;
[44c0f5b]659 *rfn = node;
660
[062d900]661 hash_table_insert(&open_nodes, &mnode->link);
[ee257b2]662 inst->open_nodes_cnt++;
663
664 fibril_mutex_unlock(&open_nodes_lock);
665
[44c0f5b]666 return EOK;
667
668out_err:
669 if (node)
670 free(node);
671 if (mnode)
672 free(mnode);
[ee257b2]673 fibril_mutex_unlock(&open_nodes_lock);
[44c0f5b]674 return rc;
675}
676
[6d4d883]677static bool
678mfs_is_directory(fs_node_t *fsnode)
[5a58ae2]679{
[44c0f5b]680 const struct mfs_node *node = fsnode->data;
[155f792]681 return S_ISDIR(node->ino_i->i_mode);
[5a58ae2]682}
683
[6d4d883]684static bool
685mfs_is_file(fs_node_t *fsnode)
[7d04324]686{
687 struct mfs_node *node = fsnode->data;
[155f792]688 return S_ISREG(node->ino_i->i_mode);
[7d04324]689}
690
[b7fd2a0]691static errno_t
[6d4d883]692mfs_root_get(fs_node_t **rfn, service_id_t service_id)
[fe4ac35]693{
[b7fd2a0]694 errno_t rc = mfs_node_get(rfn, service_id, MFS_ROOT_INO);
[41202a9]695 return rc;
[fe4ac35]696}
697
[b7fd2a0]698static errno_t
[6d4d883]699mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
[88ccd8b8]700{
[afd9c3b]701 struct mfs_node *parent = pfn->data;
702 struct mfs_node *child = cfn->data;
[48de019]703 struct mfs_sb_info *sbi = parent->instance->sbi;
[48902fa]704 bool destroy_dentry = false;
[48de019]705
706 if (str_size(name) > sbi->max_name_len)
707 return ENAMETOOLONG;
[afd9c3b]708
[b7fd2a0]709 errno_t r = mfs_insert_dentry(parent, name, child->ino_i->index);
[c699b0c]710 if (r != EOK)
[48902fa]711 return r;
[4c3ad56]712
[13ecdac9]713 if (S_ISDIR(child->ino_i->i_mode)) {
[48902fa]714 if (child->ino_i->i_nlinks != 1) {
715 /* It's not possible to hardlink directories in MFS */
716 destroy_dentry = true;
717 r = EMLINK;
718 goto exit;
719 }
[3a5ee6c]720 r = mfs_insert_dentry(child, ".", child->ino_i->index);
[48902fa]721 if (r != EOK) {
722 destroy_dentry = true;
723 goto exit;
724 }
[bbd4c72]725
[3a5ee6c]726 r = mfs_insert_dentry(child, "..", parent->ino_i->index);
[48902fa]727 if (r != EOK) {
[64e63ce1]728 mfs_remove_dentry(child, ".");
[48902fa]729 destroy_dentry = true;
730 goto exit;
731 }
[bbd4c72]732
733 parent->ino_i->i_nlinks++;
734 parent->ino_i->dirty = true;
[13ecdac9]735 }
[afd9c3b]736
[48902fa]737exit:
738 if (destroy_dentry) {
[b7fd2a0]739 errno_t r2 = mfs_remove_dentry(parent, name);
[48902fa]740 if (r2 != EOK)
741 r = r2;
742 } else {
743 child->ino_i->i_nlinks++;
744 child->ino_i->dirty = true;
745 }
[afd9c3b]746 return r;
[88ccd8b8]747}
748
[b7fd2a0]749static errno_t
[53eb588]750mfs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name)
751{
752 struct mfs_node *parent = pfn->data;
753 struct mfs_node *child = cfn->data;
754 bool has_children;
[b7fd2a0]755 errno_t r;
[53eb588]756
757 if (!parent)
758 return EBUSY;
759
760 r = mfs_has_children(&has_children, cfn);
[c699b0c]761 if (r != EOK)
762 return r;
[3f3e5b5]763
[53eb588]764 if (has_children)
765 return ENOTEMPTY;
766
[3a5ee6c]767 r = mfs_remove_dentry(parent, name);
[c699b0c]768 if (r != EOK)
769 return r;
[53eb588]770
771 struct mfs_ino_info *chino = child->ino_i;
772
773 assert(chino->i_nlinks >= 1);
[bbd4c72]774 chino->i_nlinks--;
775 mfsdebug("Links: %d\n", chino->i_nlinks);
776
777 if (chino->i_nlinks <= 1 && S_ISDIR(chino->i_mode)) {
778 /* The child directory will be destroyed, decrease the
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;
[5b56dc7]827 fs_node_t *fn = NULL;
[668f1949]828
[03bc76a]829 rc = mfs_node_get(&fn, service_id, index);
830 if (rc != EOK)
831 return rc;
832 if (!fn)
833 return ENOENT;
[668f1949]834
835 struct mfs_node *mnode;
836 struct mfs_ino_info *ino_i;
837 size_t len, bytes = 0;
838 ipc_callid_t callid;
839
840 mnode = fn->data;
841 ino_i = mnode->ino_i;
842
843 if (!async_data_read_receive(&callid, &len)) {
[230229de]844 rc = EINVAL;
845 goto out_error;
[668f1949]846 }
847
848 if (S_ISDIR(ino_i->i_mode)) {
849 aoff64_t spos = pos;
[e80c2ff]850 struct mfs_dentry_info d_info;
851 struct mfs_sb_info *sbi = mnode->instance->sbi;
[668f1949]852
[e8b6b6a]853 if (pos < 2) {
[6d4d883]854 /* Skip the first two dentries ('.' and '..') */
[e8b6b6a]855 pos = 2;
856 }
857
[3f3e5b5]858 for (; pos < mnode->ino_i->i_size / sbi->dirsize; ++pos) {
[3a5ee6c]859 rc = mfs_read_dentry(mnode, &d_info, pos);
[c699b0c]860 if (rc != EOK)
861 goto out_error;
[488f7ed]862
[e80c2ff]863 if (d_info.d_inum) {
[6d4d883]864 /* Dentry found! */
[668f1949]865 goto found;
866 }
867 }
868
869 rc = mfs_node_put(fn);
870 async_answer_0(callid, rc != EOK ? rc : ENOENT);
[03bc76a]871 return rc;
[668f1949]872found:
[e80c2ff]873 async_data_read_finalize(callid, d_info.d_name,
[c2e50d7]874 str_size(d_info.d_name) + 1);
[668f1949]875 bytes = ((pos - spos) + 1);
[230229de]876 } else {
877 struct mfs_sb_info *sbi = mnode->instance->sbi;
878
879 if (pos >= (size_t) ino_i->i_size) {
[6d4d883]880 /* Trying to read beyond the end of file */
[230229de]881 bytes = 0;
882 (void) async_data_read_finalize(callid, NULL, 0);
883 goto out_success;
884 }
885
886 bytes = min(len, sbi->block_size - pos % sbi->block_size);
887 bytes = min(bytes, ino_i->i_size - pos);
888
889 uint32_t zone;
890 block_t *b;
[668f1949]891
[3a5ee6c]892 rc = mfs_read_map(&zone, mnode, pos);
[c699b0c]893 if (rc != EOK)
894 goto out_error;
[230229de]895
896 if (zone == 0) {
[6d4d883]897 /* sparse file */
[230229de]898 uint8_t *buf = malloc(sbi->block_size);
899 if (!buf) {
900 rc = ENOMEM;
901 goto out_error;
902 }
[6fc5262]903 memset(buf, 0, sizeof(sbi->block_size));
[230229de]904 async_data_read_finalize(callid,
[6d4d883]905 buf + pos % sbi->block_size, bytes);
[230229de]906 free(buf);
907 goto out_success;
908 }
909
[03bc76a]910 rc = block_get(&b, service_id, zone, BLOCK_FLAGS_NONE);
[c699b0c]911 if (rc != EOK)
912 goto out_error;
[230229de]913
914 async_data_read_finalize(callid, b->data +
[6d4d883]915 pos % sbi->block_size, bytes);
[230229de]916
917 rc = block_put(b);
918 if (rc != EOK) {
919 mfs_node_put(fn);
[03bc76a]920 return rc;
[230229de]921 }
922 }
923out_success:
[668f1949]924 rc = mfs_node_put(fn);
[03bc76a]925 *rbytes = bytes;
926 return rc;
[44c6091f]927out_error:
928 ;
[b7fd2a0]929 errno_t tmp = mfs_node_put(fn);
[230229de]930 async_answer_0(callid, 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
948 ipc_callid_t callid;
949 size_t len;
950
951 if (!async_data_write_receive(&callid, &len)) {
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;
[36cb22f]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
994 async_data_write_finalize(callid, 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);
1014 async_answer_0(callid, 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,
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;
[67632f7]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;
[3dd148d]1215
1216 rc = mfs_instance_get(service_id, &inst);
[67632f7]1217 if (rc != EOK)
1218 return rc;
1219
1220 if (NULL == inst)
1221 return ENOENT;
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;
1232
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) {
1241 /* The cached number of free zones is not valid,
1242 * we need to scan the bitmap to retrieve the
1243 * current value.
1244 */
1245
1246 rc = mfs_count_free_zones(inst, &block_free);
1247 if (rc != EOK)
1248 return rc;
1249
1250 sbi->nfree_zones = block_free;
1251 sbi->nfree_zones_valid = true;
1252 }
[67632f7]1253
[1eaa3cf]1254 *count = sbi->nfree_zones;
[67632f7]1255
[cc8044e]1256 return rc;
[67632f7]1257}
1258
[03bc76a]1259vfs_out_ops_t mfs_ops = {
[d2c8533]1260 .fsprobe = mfs_fsprobe,
[03bc76a]1261 .mounted = mfs_mounted,
1262 .unmounted = mfs_unmounted,
1263 .read = mfs_read,
1264 .write = mfs_write,
1265 .truncate = mfs_truncate,
1266 .close = mfs_close,
1267 .destroy = mfs_destroy,
1268 .sync = mfs_sync,
1269};
1270
[096c8835]1271/**
1272 * @}
[44c6091f]1273 */
[096c8835]1274
Note: See TracBrowser for help on using the repository browser.