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

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

merge mainline changes

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