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

serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5de852c was f783081, checked in by jxsvoboda <5887334+jxsvoboda@…>, 4 years ago

libfs's service_get() returns service ID for service-special files

Not the service ID of the owning file system. Any file-system except
locfs should return zero.

  • Property mode set to 100644
File size: 27.4 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{
[f783081]394 return 0;
[e54ba607]395}
396
[b7fd2a0]397static errno_t
[6d4d883]398mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[10eb754]399{
[b7fd2a0]400 errno_t r;
[88ccd8b8]401 struct mfs_instance *inst;
402 struct mfs_node *mnode;
403 fs_node_t *fsnode;
404 uint32_t inum;
[44c6091f]405
[03bc76a]406 r = mfs_instance_get(service_id, &inst);
[c699b0c]407 if (r != EOK)
408 return r;
[88ccd8b8]409
[6d4d883]410 /* Alloc a new inode */
[70ac0af]411 r = mfs_alloc_inode(inst, &inum);
[c699b0c]412 if (r != EOK)
413 return r;
[88ccd8b8]414
415 struct mfs_ino_info *ino_i;
416
417 ino_i = malloc(sizeof(*ino_i));
418 if (!ino_i) {
419 r = ENOMEM;
420 goto out_err;
421 }
422
423 mnode = malloc(sizeof(*mnode));
424 if (!mnode) {
425 r = ENOMEM;
426 goto out_err_1;
427 }
[44c6091f]428
[88ccd8b8]429 fsnode = malloc(sizeof(fs_node_t));
430 if (!fsnode) {
431 r = ENOMEM;
432 goto out_err_2;
433 }
434
[bbd4c72]435 if (flags & L_DIRECTORY) {
[13ecdac9]436 ino_i->i_mode = S_IFDIR;
[4c3ad56]437 ino_i->i_nlinks = 1; /* This accounts for the '.' dentry */
[1ba6651]438 } else {
[13ecdac9]439 ino_i->i_mode = S_IFREG;
[1ba6651]440 ino_i->i_nlinks = 0;
441 }
[13ecdac9]442
[88ccd8b8]443 ino_i->i_uid = 0;
444 ino_i->i_gid = 0;
445 ino_i->i_size = 0;
446 ino_i->i_atime = 0;
447 ino_i->i_mtime = 0;
448 ino_i->i_ctime = 0;
449
450 memset(ino_i->i_dzone, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES);
451 memset(ino_i->i_izone, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES);
452
[58c36ac]453 mfsdebug("new node idx = %d\n", (int) inum);
454
[88ccd8b8]455 ino_i->index = inum;
456 ino_i->dirty = true;
457 mnode->ino_i = ino_i;
458 mnode->instance = inst;
[ee257b2]459 mnode->refcnt = 1;
460
461 fibril_mutex_lock(&open_nodes_lock);
[062d900]462 hash_table_insert(&open_nodes, &mnode->link);
[ee257b2]463 fibril_mutex_unlock(&open_nodes_lock);
464 inst->open_nodes_cnt++;
465
466 mnode->ino_i->dirty = true;
[88ccd8b8]467
468 fs_node_initialize(fsnode);
469 fsnode->data = mnode;
[ee257b2]470 mnode->fsnode = fsnode;
[88ccd8b8]471 *rfn = fsnode;
472
473 return EOK;
474
475out_err_2:
476 free(mnode);
477out_err_1:
478 free(ino_i);
479out_err:
[64e63ce1]480 mfs_free_inode(inst, inum);
[88ccd8b8]481 return r;
[10eb754]482}
483
[b7fd2a0]484static errno_t
[6d4d883]485mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
[bd64680]486{
487 struct mfs_node *mnode = pfn->data;
488 struct mfs_ino_info *ino_i = mnode->ino_i;
[e80c2ff]489 struct mfs_dentry_info d_info;
[b7fd2a0]490 errno_t r;
[bd64680]491
492 if (!S_ISDIR(ino_i->i_mode))
493 return ENOTDIR;
494
495 struct mfs_sb_info *sbi = mnode->instance->sbi;
496 const size_t comp_size = str_size(component);
497
[e80c2ff]498 unsigned i;
499 for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
[3a5ee6c]500 r = mfs_read_dentry(mnode, &d_info, i);
[c699b0c]501 if (r != EOK)
502 return r;
[488f7ed]503
[e80c2ff]504 if (!d_info.d_inum) {
[6d4d883]505 /* This entry is not used */
[bd64680]506 continue;
507 }
508
[367d67fe]509 const size_t dentry_name_size = str_size(d_info.d_name);
510
511 if (comp_size == dentry_name_size &&
[44ecf89]512 memcmp(component, d_info.d_name, dentry_name_size) == 0) {
[6d4d883]513 /* Hit! */
[bd64680]514 mfs_node_core_get(rfn, mnode->instance,
[6d4d883]515 d_info.d_inum);
[bd64680]516 goto found;
517 }
518 }
519 *rfn = NULL;
520found:
521 return EOK;
522}
523
[6d4d883]524static aoff64_t
525mfs_size_get(fs_node_t *node)
[0d6ab10]526{
527 const struct mfs_node *mnode = node->data;
[155f792]528 return mnode->ino_i->i_size;
[0d6ab10]529}
530
[b7fd2a0]531static errno_t
[03bc76a]532mfs_node_get(fs_node_t **rfn, service_id_t service_id,
[6d4d883]533 fs_index_t index)
[44c0f5b]534{
[b7fd2a0]535 errno_t rc;
[44c0f5b]536 struct mfs_instance *instance;
537
[03bc76a]538 rc = mfs_instance_get(service_id, &instance);
[c699b0c]539 if (rc != EOK)
540 return rc;
[44c0f5b]541
542 return mfs_node_core_get(rfn, instance, index);
543}
544
[b7fd2a0]545static errno_t
[03bc76a]546mfs_node_put(fs_node_t *fsnode)
[41202a9]547{
[b7fd2a0]548 errno_t rc = EOK;
[41202a9]549 struct mfs_node *mnode = fsnode->data;
550
[ee257b2]551 fibril_mutex_lock(&open_nodes_lock);
552
553 assert(mnode->refcnt > 0);
554 mnode->refcnt--;
555 if (mnode->refcnt == 0) {
[062d900]556 hash_table_remove_item(&open_nodes, &mnode->link);
[ee257b2]557 assert(mnode->instance->open_nodes_cnt > 0);
558 mnode->instance->open_nodes_cnt--;
[5f509cc]559 rc = mfs_put_inode(mnode);
[ee257b2]560 free(mnode->ino_i);
561 free(mnode);
562 free(fsnode);
563 }
[41202a9]564
[ee257b2]565 fibril_mutex_unlock(&open_nodes_lock);
566 return rc;
[41202a9]567}
568
[b7fd2a0]569static errno_t
[6d4d883]570mfs_node_open(fs_node_t *fsnode)
[41202a9]571{
572 /*
573 * Opening a file is stateless, nothing
574 * to be done here.
575 */
576 return EOK;
577}
578
[6d4d883]579static fs_index_t
580mfs_index_get(fs_node_t *fsnode)
[41202a9]581{
582 struct mfs_node *mnode = fsnode->data;
583 return mnode->ino_i->index;
584}
585
[6d4d883]586static unsigned
587mfs_lnkcnt_get(fs_node_t *fsnode)
[41202a9]588{
589 struct mfs_node *mnode = fsnode->data;
590
[75e0f15]591 mfsdebug("%s() %d\n", __FUNCTION__, mnode->ino_i->i_nlinks);
[ee257b2]592
[bbd4c72]593 if (S_ISDIR(mnode->ino_i->i_mode)) {
594 if (mnode->ino_i->i_nlinks > 1)
595 return 1;
596 else
597 return 0;
[75e0f15]598 } else
599 return mnode->ino_i->i_nlinks;
[41202a9]600}
601
[b7fd2a0]602static errno_t
[6d4d883]603mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
604 fs_index_t index)
[44c0f5b]605{
606 fs_node_t *node = NULL;
607 struct mfs_node *mnode = NULL;
[b7fd2a0]608 errno_t rc;
[44c0f5b]609
[ee257b2]610 fibril_mutex_lock(&open_nodes_lock);
611
612 /* Check if the node is not already open */
[062d900]613 node_key_t key = {
614 .service_id = inst->service_id,
615 .index = index
[ee257b2]616 };
[a35b458]617
[062d900]618 ht_link_t *already_open = hash_table_find(&open_nodes, &key);
[ee257b2]619
620 if (already_open) {
[062d900]621 mnode = hash_table_get_inst(already_open, struct mfs_node, link);
[4c53333]622
[ee257b2]623 *rfn = mnode->fsnode;
624 mnode->refcnt++;
625
626 fibril_mutex_unlock(&open_nodes_lock);
627 return EOK;
628 }
629
[b438804]630 node = malloc(sizeof(fs_node_t));
[44c0f5b]631 if (!node) {
632 rc = ENOMEM;
633 goto out_err;
634 }
635
636 fs_node_initialize(node);
637
[b438804]638 mnode = malloc(sizeof(*mnode));
[44c0f5b]639 if (!mnode) {
640 rc = ENOMEM;
641 goto out_err;
642 }
643
[155f792]644 struct mfs_ino_info *ino_i;
645
[3a5ee6c]646 rc = mfs_get_inode(inst, &ino_i, index);
[c699b0c]647 if (rc != EOK)
648 goto out_err;
[155f792]649
[41202a9]650 ino_i->index = index;
[155f792]651 mnode->ino_i = ino_i;
[ee257b2]652 mnode->refcnt = 1;
[155f792]653
[44c0f5b]654 mnode->instance = inst;
655 node->data = mnode;
[ee257b2]656 mnode->fsnode = node;
[44c0f5b]657 *rfn = node;
658
[062d900]659 hash_table_insert(&open_nodes, &mnode->link);
[ee257b2]660 inst->open_nodes_cnt++;
661
662 fibril_mutex_unlock(&open_nodes_lock);
663
[44c0f5b]664 return EOK;
665
666out_err:
667 if (node)
668 free(node);
669 if (mnode)
670 free(mnode);
[ee257b2]671 fibril_mutex_unlock(&open_nodes_lock);
[44c0f5b]672 return rc;
673}
674
[6d4d883]675static bool
676mfs_is_directory(fs_node_t *fsnode)
[5a58ae2]677{
[44c0f5b]678 const struct mfs_node *node = fsnode->data;
[155f792]679 return S_ISDIR(node->ino_i->i_mode);
[5a58ae2]680}
681
[6d4d883]682static bool
683mfs_is_file(fs_node_t *fsnode)
[7d04324]684{
685 struct mfs_node *node = fsnode->data;
[155f792]686 return S_ISREG(node->ino_i->i_mode);
[7d04324]687}
688
[b7fd2a0]689static errno_t
[6d4d883]690mfs_root_get(fs_node_t **rfn, service_id_t service_id)
[fe4ac35]691{
[b7fd2a0]692 errno_t rc = mfs_node_get(rfn, service_id, MFS_ROOT_INO);
[41202a9]693 return rc;
[fe4ac35]694}
695
[b7fd2a0]696static errno_t
[6d4d883]697mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
[88ccd8b8]698{
[afd9c3b]699 struct mfs_node *parent = pfn->data;
700 struct mfs_node *child = cfn->data;
[48de019]701 struct mfs_sb_info *sbi = parent->instance->sbi;
[48902fa]702 bool destroy_dentry = false;
[48de019]703
704 if (str_size(name) > sbi->max_name_len)
705 return ENAMETOOLONG;
[afd9c3b]706
[b7fd2a0]707 errno_t r = mfs_insert_dentry(parent, name, child->ino_i->index);
[c699b0c]708 if (r != EOK)
[48902fa]709 return r;
[4c3ad56]710
[13ecdac9]711 if (S_ISDIR(child->ino_i->i_mode)) {
[48902fa]712 if (child->ino_i->i_nlinks != 1) {
713 /* It's not possible to hardlink directories in MFS */
714 destroy_dentry = true;
715 r = EMLINK;
716 goto exit;
717 }
[3a5ee6c]718 r = mfs_insert_dentry(child, ".", child->ino_i->index);
[48902fa]719 if (r != EOK) {
720 destroy_dentry = true;
721 goto exit;
722 }
[bbd4c72]723
[3a5ee6c]724 r = mfs_insert_dentry(child, "..", parent->ino_i->index);
[48902fa]725 if (r != EOK) {
[64e63ce1]726 mfs_remove_dentry(child, ".");
[48902fa]727 destroy_dentry = true;
728 goto exit;
729 }
[bbd4c72]730
731 parent->ino_i->i_nlinks++;
732 parent->ino_i->dirty = true;
[13ecdac9]733 }
[afd9c3b]734
[48902fa]735exit:
736 if (destroy_dentry) {
[b7fd2a0]737 errno_t r2 = mfs_remove_dentry(parent, name);
[48902fa]738 if (r2 != EOK)
739 r = r2;
740 } else {
741 child->ino_i->i_nlinks++;
742 child->ino_i->dirty = true;
743 }
[afd9c3b]744 return r;
[88ccd8b8]745}
746
[b7fd2a0]747static errno_t
[53eb588]748mfs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name)
749{
750 struct mfs_node *parent = pfn->data;
751 struct mfs_node *child = cfn->data;
752 bool has_children;
[b7fd2a0]753 errno_t r;
[53eb588]754
755 if (!parent)
756 return EBUSY;
757
758 r = mfs_has_children(&has_children, cfn);
[c699b0c]759 if (r != EOK)
760 return r;
[3f3e5b5]761
[53eb588]762 if (has_children)
763 return ENOTEMPTY;
764
[3a5ee6c]765 r = mfs_remove_dentry(parent, name);
[c699b0c]766 if (r != EOK)
767 return r;
[53eb588]768
769 struct mfs_ino_info *chino = child->ino_i;
770
771 assert(chino->i_nlinks >= 1);
[bbd4c72]772 chino->i_nlinks--;
773 mfsdebug("Links: %d\n", chino->i_nlinks);
774
775 if (chino->i_nlinks <= 1 && S_ISDIR(chino->i_mode)) {
[7c3fb9b]776 /*
777 * The child directory will be destroyed, decrease the
[bbd4c72]778 * parent hard links counter.
779 */
[ee257b2]780 parent->ino_i->i_nlinks--;
781 parent->ino_i->dirty = true;
782 }
783
[53eb588]784 chino->dirty = true;
785
[ee257b2]786 return r;
[53eb588]787}
788
[b7fd2a0]789static errno_t
[6d4d883]790mfs_has_children(bool *has_children, fs_node_t *fsnode)
[54caa41b]791{
792 struct mfs_node *mnode = fsnode->data;
[e80c2ff]793 struct mfs_sb_info *sbi = mnode->instance->sbi;
[b7fd2a0]794 errno_t r;
[54caa41b]795
796 *has_children = false;
797
798 if (!S_ISDIR(mnode->ino_i->i_mode))
799 goto out;
800
[e80c2ff]801 struct mfs_dentry_info d_info;
[44c6091f]802
[ac28650]803 /* The first two dentries are always . and .. */
[e80c2ff]804 unsigned i;
[3f3e5b5]805 for (i = 2; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
[3a5ee6c]806 r = mfs_read_dentry(mnode, &d_info, i);
[c699b0c]807 if (r != EOK)
808 return r;
[54caa41b]809
[e80c2ff]810 if (d_info.d_inum) {
[6d4d883]811 /* A valid entry has been found */
[54caa41b]812 *has_children = true;
813 break;
814 }
815 }
[41202a9]816out:
817
[54caa41b]818 return EOK;
819}
820
[b7fd2a0]821static errno_t
[03bc76a]822mfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
[6d4d883]823 size_t *rbytes)
[668f1949]824{
[b7fd2a0]825 errno_t rc;
[84239b1]826 errno_t tmp;
[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;
[984a9ba]838 ipc_call_t call;
[668f1949]839
840 mnode = fn->data;
841 ino_i = mnode->ino_i;
842
[984a9ba]843 if (!async_data_read_receive(&call, &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);
[984a9ba]870 async_answer_0(&call, rc != EOK ? rc : ENOENT);
[03bc76a]871 return rc;
[18b6a88]872 found:
[984a9ba]873 async_data_read_finalize(&call, 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;
[984a9ba]882 (void) async_data_read_finalize(&call, NULL, 0);
[230229de]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));
[984a9ba]904 async_data_read_finalize(&call,
[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
[984a9ba]914 async_data_read_finalize(&call, 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:
[84239b1]928 tmp = mfs_node_put(fn);
[984a9ba]929 async_answer_0(&call, tmp != EOK ? tmp : rc);
[03bc76a]930 return tmp != EOK ? tmp : rc;
[668f1949]931}
932
[b7fd2a0]933static errno_t
[03bc76a]934mfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
[6d4d883]935 size_t *wbytes, aoff64_t *nsize)
[bb7e8382]936{
937 fs_node_t *fn;
[b7fd2a0]938 errno_t r;
[bb7e8382]939 int flags = BLOCK_FLAGS_NONE;
940
[03bc76a]941 r = mfs_node_get(&fn, service_id, index);
942 if (r != EOK)
943 return r;
944 if (!fn)
945 return ENOENT;
[bb7e8382]946
[984a9ba]947 ipc_call_t call;
[bb7e8382]948 size_t len;
949
[984a9ba]950 if (!async_data_write_receive(&call, &len)) {
[bb7e8382]951 r = EINVAL;
952 goto out_err;
953 }
954
955 struct mfs_node *mnode = fn->data;
956 struct mfs_sb_info *sbi = mnode->instance->sbi;
957 struct mfs_ino_info *ino_i = mnode->ino_i;
958 const size_t bs = sbi->block_size;
[36cb22f]959 size_t bytes = min(len, bs - (pos % bs));
[bb7e8382]960 uint32_t block;
961
962 if (bytes == bs)
963 flags = BLOCK_FLAGS_NOREAD;
964
[36cb22f]965 r = mfs_read_map(&block, mnode, pos);
966 if (r != EOK)
967 goto out_err;
[bb7e8382]968
[36cb22f]969 if (block == 0) {
[bb7e8382]970 uint32_t dummy;
971
[70ac0af]972 r = mfs_alloc_zone(mnode->instance, &block);
[c699b0c]973 if (r != EOK)
974 goto out_err;
[a35b458]975
[3a5ee6c]976 r = mfs_write_map(mnode, pos, block, &dummy);
[64e63ce1]977 if (r != EOK) {
978 mfs_free_zone(mnode->instance, block);
[c699b0c]979 goto out_err;
[64e63ce1]980 }
[36cb22f]981
982 flags = BLOCK_FLAGS_NOREAD;
[bb7e8382]983 }
984
985 block_t *b;
[03bc76a]986 r = block_get(&b, service_id, block, flags);
[c699b0c]987 if (r != EOK)
988 goto out_err;
[bb7e8382]989
[36cb22f]990 if (flags == BLOCK_FLAGS_NOREAD)
991 memset(b->data, 0, sbi->block_size);
992
[984a9ba]993 async_data_write_finalize(&call, b->data + (pos % bs), bytes);
[bb7e8382]994 b->dirty = true;
995
996 r = block_put(b);
997 if (r != EOK) {
998 mfs_node_put(fn);
[03bc76a]999 return r;
[bb7e8382]1000 }
1001
[36cb22f]1002 if (pos + bytes > ino_i->i_size) {
1003 ino_i->i_size = pos + bytes;
1004 ino_i->dirty = true;
1005 }
[bb7e8382]1006 r = mfs_node_put(fn);
[36cb22f]1007 *nsize = ino_i->i_size;
[03bc76a]1008 *wbytes = bytes;
1009 return r;
[bb7e8382]1010
1011out_err:
1012 mfs_node_put(fn);
[984a9ba]1013 async_answer_0(&call, r);
[03bc76a]1014 return r;
[bb7e8382]1015}
1016
[b7fd2a0]1017static errno_t
[03bc76a]1018mfs_destroy(service_id_t service_id, fs_index_t index)
[d8af1bd]1019{
[1ba6651]1020 fs_node_t *fn = NULL;
[b7fd2a0]1021 errno_t r;
[d8af1bd]1022
[03bc76a]1023 r = mfs_node_get(&fn, service_id, index);
1024 if (r != EOK)
1025 return r;
1026 if (!fn)
1027 return ENOENT;
[d8af1bd]1028
[6d4d883]1029 /* Destroy the inode */
[e03d545]1030 return mfs_destroy_node(fn);
[d8af1bd]1031}
1032
[b7fd2a0]1033static errno_t
[d8af1bd]1034mfs_destroy_node(fs_node_t *fn)
1035{
1036 struct mfs_node *mnode = fn->data;
1037 bool has_children;
[b7fd2a0]1038 errno_t r;
[d8af1bd]1039
[a5bad72]1040 mfsdebug("mfs_destroy_node %d\n", mnode->ino_i->index);
1041
[d8af1bd]1042 r = mfs_has_children(&has_children, fn);
[c699b0c]1043 if (r != EOK)
1044 goto out;
[d8af1bd]1045
1046 assert(!has_children);
1047
[6d4d883]1048 /* Free the entire inode content */
[3a5ee6c]1049 r = mfs_inode_shrink(mnode, mnode->ino_i->i_size);
[c699b0c]1050 if (r != EOK)
1051 goto out;
[e03d545]1052
[6d4d883]1053 /* Mark the inode as free in the bitmap */
[70ac0af]1054 r = mfs_free_inode(mnode->instance, mnode->ino_i->index);
[d8af1bd]1055
[51db5aeb]1056out:
[eefb653]1057 mfs_node_put(fn);
[d8af1bd]1058 return r;
1059}
1060
[b7fd2a0]1061static errno_t
[03bc76a]1062mfs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
[8a49fed]1063{
1064 fs_node_t *fn;
[b7fd2a0]1065 errno_t r;
[8a49fed]1066
[03bc76a]1067 r = mfs_node_get(&fn, service_id, index);
1068 if (r != EOK)
1069 return r;
1070 if (!fn)
1071 return r;
[8a49fed]1072
1073 struct mfs_node *mnode = fn->data;
1074 struct mfs_ino_info *ino_i = mnode->ino_i;
1075
1076 if (ino_i->i_size == size)
1077 r = EOK;
1078 else
[3a5ee6c]1079 r = mfs_inode_shrink(mnode, ino_i->i_size - size);
[8a49fed]1080
1081 mfs_node_put(fn);
[03bc76a]1082 return r;
[8a49fed]1083}
1084
[b7fd2a0]1085static errno_t
[03bc76a]1086mfs_instance_get(service_id_t service_id, struct mfs_instance **instance)
[3b08178]1087{
[5bf76c1]1088 void *data;
[b7fd2a0]1089 errno_t rc;
[44c6091f]1090
[5bf76c1]1091 rc = fs_instance_get(service_id, &data);
[6d4d883]1092 if (rc == EOK)
[5bf76c1]1093 *instance = (struct mfs_instance *) data;
[6d4d883]1094 else {
[5bf76c1]1095 mfsdebug("instance not found\n");
[3b08178]1096 }
1097
[5bf76c1]1098 return rc;
[3b08178]1099}
1100
[6d4d883]1101static bool
1102check_magic_number(uint16_t magic, bool *native,
[18b6a88]1103 mfs_version_t *version, bool *longfilenames)
[9e3dc95]1104{
[cfac897]1105 bool rc = true;
[8ceba1e]1106 *longfilenames = false;
1107
[57640e7]1108 if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
1109 *native = magic == MFS_MAGIC_V1;
[9e3dc95]1110 *version = MFS_VERSION_V1;
[8ceba1e]1111 } else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
1112 *native = magic == MFS_MAGIC_V1L;
1113 *version = MFS_VERSION_V1;
1114 *longfilenames = true;
[57640e7]1115 } else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
1116 *native = magic == MFS_MAGIC_V2;
[9e3dc95]1117 *version = MFS_VERSION_V2;
[8ceba1e]1118 } else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
1119 *native = magic == MFS_MAGIC_V2L;
1120 *version = MFS_VERSION_V2;
1121 *longfilenames = true;
[57640e7]1122 } else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
1123 *native = magic == MFS_MAGIC_V3;
[9e3dc95]1124 *version = MFS_VERSION_V3;
[cfac897]1125 } else
1126 rc = false;
[9e3dc95]1127
[7a96476]1128 return rc;
[096c8835]1129}
1130
[df3caec5]1131/** Filesystem sanity check
1132 *
1133 * @param Pointer to the MFS superblock.
1134 *
1135 * @return EOK on success, ENOTSUP otherwise.
1136 */
[b7fd2a0]1137static errno_t
[df3caec5]1138mfs_check_sanity(struct mfs_sb_info *sbi)
1139{
1140 if (!is_power_of_two(sbi->block_size) ||
1141 sbi->block_size < MFS_MIN_BLOCKSIZE ||
1142 sbi->block_size > MFS_MAX_BLOCKSIZE)
1143 return ENOTSUP;
1144 else if (sbi->ibmap_blocks == 0 || sbi->zbmap_blocks == 0)
1145 return ENOTSUP;
1146 else if (sbi->ninodes == 0 || sbi->nzones == 0)
1147 return ENOTSUP;
1148 else if (sbi->firstdatazone == 0)
1149 return ENOTSUP;
1150
1151 return EOK;
1152}
1153
[b7fd2a0]1154static errno_t
[03bc76a]1155mfs_close(service_id_t service_id, fs_index_t index)
[e700970]1156{
[03bc76a]1157 return 0;
[e700970]1158}
1159
[b7fd2a0]1160static errno_t
[03bc76a]1161mfs_sync(service_id_t service_id, fs_index_t index)
[51db5aeb]1162{
[5b56dc7]1163 fs_node_t *fn = NULL;
[b7fd2a0]1164 errno_t rc = mfs_node_get(&fn, service_id, index);
[03bc76a]1165 if (rc != EOK)
1166 return rc;
1167 if (!fn)
1168 return ENOENT;
[51db5aeb]1169
1170 struct mfs_node *mnode = fn->data;
1171 mnode->ino_i->dirty = true;
1172
[03bc76a]1173 return mfs_node_put(fn);
[51db5aeb]1174}
1175
[df3caec5]1176/** Check if a given number is a power of two.
1177 *
1178 * @param n The number to check.
1179 *
1180 * @return true if it is a power of two, false otherwise.
1181 */
1182static bool
1183is_power_of_two(uint32_t n)
1184{
1185 if (n == 0)
1186 return false;
1187
1188 return (n & (n - 1)) == 0;
1189}
1190
[b7fd2a0]1191static errno_t
[3dd148d]1192mfs_size_block(service_id_t service_id, uint32_t *size)
[66366470]1193{
[9dc6083]1194 struct mfs_instance *inst;
[b7fd2a0]1195 errno_t rc;
[3dd148d]1196
1197 rc = mfs_instance_get(service_id, &inst);
[9dc6083]1198 if (rc != EOK)
1199 return rc;
[3dd148d]1200
[9dc6083]1201 if (NULL == inst)
1202 return ENOENT;
[a35b458]1203
[3dd148d]1204 *size = inst->sbi->block_size;
[67632f7]1205
[3dd148d]1206 return EOK;
[66366470]1207}
1208
[b7fd2a0]1209static errno_t
[3dd148d]1210mfs_total_block_count(service_id_t service_id, uint64_t *count)
[67632f7]1211{
1212 struct mfs_instance *inst;
[b7fd2a0]1213 errno_t rc;
[a35b458]1214
[3dd148d]1215 rc = mfs_instance_get(service_id, &inst);
[67632f7]1216 if (rc != EOK)
1217 return rc;
1218
1219 if (NULL == inst)
1220 return ENOENT;
[a35b458]1221
[3dd148d]1222 *count = (uint64_t) MFS_BMAP_SIZE_BITS(inst->sbi, BMAP_ZONE);
[67632f7]1223
[3dd148d]1224 return EOK;
[67632f7]1225}
1226
[b7fd2a0]1227static errno_t
[3dd148d]1228mfs_free_block_count(service_id_t service_id, uint64_t *count)
[67632f7]1229{
1230 uint32_t block_free;
[a35b458]1231
[67632f7]1232 struct mfs_instance *inst;
[b7fd2a0]1233 errno_t rc = mfs_instance_get(service_id, &inst);
[67632f7]1234 if (rc != EOK)
1235 return rc;
1236
[1eaa3cf]1237 struct mfs_sb_info *sbi = inst->sbi;
1238
1239 if (!sbi->nfree_zones_valid) {
[7c3fb9b]1240 /*
1241 * The cached number of free zones is not valid,
[1eaa3cf]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 */
Note: See TracBrowser for help on using the repository browser.