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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • 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 };
[a35b458]619
[062d900]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;
[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
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;
[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) {
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.