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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 049d68b was d0a1e9b6, checked in by Manuele Conti <conti.ma@…>, 12 years ago

Update implementation size, total, free block operations like new stucture statfs.

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