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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c898236 was eb40d86, checked in by Maurizio Lombardi <m.lombardi85@…>, 12 years ago

merge mainline changes

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