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

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

Currently MFS does not support minix filesystems where the size of a zone is not equal to the size
of a block.

Refuse to mount the filesystem if the "log2_zone_size" field of the superblock is not zero.

  • Property mode set to 100644
File size: 24.8 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>
[7413683]37#include "mfs.h"
[9e3dc95]38
[ee257b2]39#define OPEN_NODES_KEYS 2
[03bc76a]40#define OPEN_NODES_SERVICE_KEY 0
[ee257b2]41#define OPEN_NODES_INODE_KEY 1
42#define OPEN_NODES_BUCKETS 256
43
[8ceba1e]44static bool check_magic_number(uint16_t magic, bool *native,
[44c6091f]45 mfs_version_t *version, bool *longfilenames);
[44c0f5b]46static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
[44c6091f]47 fs_index_t index);
[096c8835]48
[41202a9]49static int mfs_node_put(fs_node_t *fsnode);
50static int mfs_node_open(fs_node_t *fsnode);
51static fs_index_t mfs_index_get(fs_node_t *fsnode);
52static unsigned mfs_lnkcnt_get(fs_node_t *fsnode);
[ac28650]53static bool mfs_is_directory(fs_node_t *fsnode);
54static bool mfs_is_file(fs_node_t *fsnode);
55static int mfs_has_children(bool *has_children, fs_node_t *fsnode);
[03bc76a]56static int mfs_root_get(fs_node_t **rfn, service_id_t service_id);
[b33870b]57static service_id_t mfs_service_get(fs_node_t *fsnode);
[ac28650]58static aoff64_t mfs_size_get(fs_node_t *node);
[bd64680]59static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
[03bc76a]60static int mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags);
[88ccd8b8]61static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name);
[53eb588]62static int mfs_unlink(fs_node_t *, fs_node_t *, const char *name);
[d8af1bd]63static int mfs_destroy_node(fs_node_t *fn);
[ee257b2]64static hash_index_t open_nodes_hash(unsigned long key[]);
65static int open_nodes_compare(unsigned long key[], hash_count_t keys,
66 link_t *item);
67static void open_nodes_remove_cb(link_t *link);
[ac28650]68
[03bc76a]69static int mfs_node_get(fs_node_t **rfn, service_id_t service_id,
[ac28650]70 fs_index_t index);
[03bc76a]71static int
72mfs_instance_get(service_id_t service_id, struct mfs_instance **instance);
[ac28650]73
[41202a9]74
[953a823]75static LIST_INITIALIZE(inst_list);
76static FIBRIL_MUTEX_INITIALIZE(inst_list_mutex);
[ee257b2]77static hash_table_t open_nodes;
78static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
[953a823]79
[e54ba607]80libfs_ops_t mfs_libfs_ops = {
[0d6ab10]81 .size_get = mfs_size_get,
[fe4ac35]82 .root_get = mfs_root_get,
[b33870b]83 .service_get = mfs_service_get,
[7d04324]84 .is_directory = mfs_is_directory,
[44c0f5b]85 .is_file = mfs_is_file,
[cfbcd86]86 .node_get = mfs_node_get,
[41202a9]87 .node_put = mfs_node_put,
88 .node_open = mfs_node_open,
89 .index_get = mfs_index_get,
[bd64680]90 .match = mfs_match,
[10eb754]91 .create = mfs_create_node,
[88ccd8b8]92 .link = mfs_link,
[53eb588]93 .unlink = mfs_unlink,
[d8af1bd]94 .destroy = mfs_destroy_node,
[41202a9]95 .has_children = mfs_has_children,
96 .lnkcnt_get = mfs_lnkcnt_get
[e54ba607]97};
[3b08178]98
[ee257b2]99/* Hash table interface for open nodes hash table */
100static hash_index_t open_nodes_hash(unsigned long key[])
101{
102 /* TODO: This is very simple and probably can be improved */
103 return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
104}
105
106static int open_nodes_compare(unsigned long key[], hash_count_t keys,
107 link_t *item)
108{
109 struct mfs_node *mnode = hash_table_get_instance(item, struct mfs_node, link);
110 assert(keys > 0);
[03bc76a]111 if (mnode->instance->service_id !=
112 ((service_id_t) key[OPEN_NODES_SERVICE_KEY])) {
[ee257b2]113 return false;
114 }
115 if (keys == 1) {
116 return true;
117 }
118 assert(keys == 2);
119 return (mnode->ino_i->index == key[OPEN_NODES_INODE_KEY]);
120}
121
122static void open_nodes_remove_cb(link_t *link)
123{
124 /* We don't use remove callback for this hash table */
125}
126
127static hash_table_operations_t open_nodes_ops = {
128 .hash = open_nodes_hash,
129 .compare = open_nodes_compare,
130 .remove_callback = open_nodes_remove_cb,
131};
132
133int mfs_global_init(void)
134{
135 if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
136 OPEN_NODES_KEYS, &open_nodes_ops)) {
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,
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
[953a823]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
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
[ee257b2]181 instance->open_nodes_cnt = 0;
182
[b438804]183 sb = malloc(MFS_SUPERBLOCK_SIZE);
[953a823]184 if (!sb) {
[f456ab2]185 rc = ENOMEM;
186 goto out_error;
[953a823]187 }
[92dd5c8]188
189 /* Read the superblock */
[e03d545]190 rc = block_read_direct(service_id, MFS_SUPERBLOCK << 1, 2, sb);
[f456ab2]191 if (rc != EOK)
192 goto out_error;
[096c8835]193
[953a823]194 sb3 = (struct mfs3_superblock *) sb;
195
196 if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
[7a96476]197 /*This is a V1 or V2 Minix filesystem*/
[953a823]198 magic = sb->s_magic;
[5222e746]199 } else if (check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
200 /*This is a V3 Minix filesystem*/
201 magic = sb3->s_magic;
202 } else {
203 /*Not recognized*/
[92dd5c8]204 mfsdebug("magic number not recognized\n");
[f456ab2]205 rc = ENOTSUP;
206 goto out_error;
[9e3dc95]207 }
[92dd5c8]208
[245eb02d]209 mfsdebug("magic number recognized = %04x\n", magic);
[953a823]210
211 /*Fill superblock info structure*/
212
213 sbi->fs_version = version;
214 sbi->long_names = longnames;
215 sbi->native = native;
216 sbi->magic = magic;
[ef76d72]217 sbi->isearch = 0;
218 sbi->zsearch = 0;
[953a823]219
220 if (version == MFS_VERSION_V3) {
221 sbi->ninodes = conv32(native, sb3->s_ninodes);
222 sbi->ibmap_blocks = conv16(native, sb3->s_ibmap_blocks);
223 sbi->zbmap_blocks = conv16(native, sb3->s_zbmap_blocks);
224 sbi->firstdatazone = conv16(native, sb3->s_first_data_zone);
225 sbi->log2_zone_size = conv16(native, sb3->s_log2_zone_size);
226 sbi->max_file_size = conv32(native, sb3->s_max_file_size);
227 sbi->nzones = conv32(native, sb3->s_nzones);
228 sbi->block_size = conv16(native, sb3->s_block_size);
[10eb754]229 sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
[a04b62d]230 sbi->dirsize = MFS3_DIRSIZE;
[bd64680]231 sbi->max_name_len = MFS3_MAX_NAME_LEN;
[953a823]232 } else {
233 sbi->ninodes = conv16(native, sb->s_ninodes);
234 sbi->ibmap_blocks = conv16(native, sb->s_ibmap_blocks);
235 sbi->zbmap_blocks = conv16(native, sb->s_zbmap_blocks);
236 sbi->firstdatazone = conv16(native, sb->s_first_data_zone);
237 sbi->log2_zone_size = conv16(native, sb->s_log2_zone_size);
238 sbi->max_file_size = conv32(native, sb->s_max_file_size);
[3b08178]239 sbi->block_size = MFS_BLOCKSIZE;
[5a841a4]240 if (version == MFS_VERSION_V2) {
[953a823]241 sbi->nzones = conv32(native, sb->s_nzones2);
[5a841a4]242 sbi->ino_per_block = V2_INODES_PER_BLOCK;
243 } else {
244 sbi->nzones = conv16(native, sb->s_nzones);
245 sbi->ino_per_block = V1_INODES_PER_BLOCK;
246 }
[a04b62d]247 sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
[bd64680]248 sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
[44c6091f]249 MFS_MAX_NAME_LEN;
[953a823]250 }
[85ff862]251
252 if (sbi->log2_zone_size != 0) {
253 /* In MFS, file space is allocated per zones.
254 * Zones are a collection of consecutive blocks on disk.
255 *
256 * The current MFS implementation supports only filesystems
257 * where the size of a zone is equal to the
258 * size of a block.
259 */
260 rc = ENOTSUP;
261 goto out_error;
262 }
263
[10eb754]264 sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
[44c6091f]265
[03bc76a]266 rc = block_cache_init(service_id, sbi->block_size, 0, cmode);
[3b08178]267 if (rc != EOK) {
268 mfsdebug("block cache initialization failed\n");
[f456ab2]269 block_cache_fini(service_id);
270 rc = EINVAL;
271 goto out_error;
[3b08178]272 }
273
[953a823]274 /*Initialize the instance structure and add it to the list*/
275 link_initialize(&instance->link);
[03bc76a]276 instance->service_id = service_id;
[953a823]277 instance->sbi = sbi;
278
279 fibril_mutex_lock(&inst_list_mutex);
280 list_append(&instance->link, &inst_list);
281 fibril_mutex_unlock(&inst_list_mutex);
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
[7accfac]326 /* Remove the instance from the list */
327 fibril_mutex_lock(&inst_list_mutex);
328 list_remove(&inst->link);
329 fibril_mutex_unlock(&inst_list_mutex);
330
331 free(inst->sbi);
332 free(inst);
[03bc76a]333 return EOK;
[51db5aeb]334}
335
[b33870b]336service_id_t mfs_service_get(fs_node_t *fsnode)
[e54ba607]337{
338 struct mfs_node *node = fsnode->data;
[03bc76a]339 return node->instance->service_id;
[e54ba607]340}
341
[03bc76a]342static int mfs_create_node(fs_node_t **rfn, service_id_t service_id, int flags)
[10eb754]343{
[88ccd8b8]344 int r;
345 struct mfs_instance *inst;
346 struct mfs_node *mnode;
347 fs_node_t *fsnode;
348 uint32_t inum;
[44c6091f]349
[ee257b2]350 mfsdebug("%s()\n", __FUNCTION__);
351
[03bc76a]352 r = mfs_instance_get(service_id, &inst);
[c699b0c]353 if (r != EOK)
354 return r;
[88ccd8b8]355
356 /*Alloc a new inode*/
[70ac0af]357 r = mfs_alloc_inode(inst, &inum);
[c699b0c]358 if (r != EOK)
359 return r;
[88ccd8b8]360
361 struct mfs_ino_info *ino_i;
362
363 ino_i = malloc(sizeof(*ino_i));
364 if (!ino_i) {
365 r = ENOMEM;
366 goto out_err;
367 }
368
369 mnode = malloc(sizeof(*mnode));
370 if (!mnode) {
371 r = ENOMEM;
372 goto out_err_1;
373 }
[44c6091f]374
[88ccd8b8]375 fsnode = malloc(sizeof(fs_node_t));
376 if (!fsnode) {
377 r = ENOMEM;
378 goto out_err_2;
379 }
380
[bbd4c72]381 if (flags & L_DIRECTORY) {
[13ecdac9]382 ino_i->i_mode = S_IFDIR;
[bbd4c72]383 ino_i->i_nlinks = 2; /*This accounts for the '.' dentry*/
384 } else {
[13ecdac9]385 ino_i->i_mode = S_IFREG;
[bbd4c72]386 ino_i->i_nlinks = 1;
387 }
[13ecdac9]388
[88ccd8b8]389 ino_i->i_uid = 0;
390 ino_i->i_gid = 0;
391 ino_i->i_size = 0;
392 ino_i->i_atime = 0;
393 ino_i->i_mtime = 0;
394 ino_i->i_ctime = 0;
395
396 memset(ino_i->i_dzone, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES);
397 memset(ino_i->i_izone, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES);
398
[58c36ac]399 mfsdebug("new node idx = %d\n", (int) inum);
400
[88ccd8b8]401 ino_i->index = inum;
402 ino_i->dirty = true;
403 mnode->ino_i = ino_i;
404 mnode->instance = inst;
[ee257b2]405 mnode->refcnt = 1;
406
407 link_initialize(&mnode->link);
[88ccd8b8]408
[ee257b2]409 unsigned long key[] = {
[03bc76a]410 [OPEN_NODES_SERVICE_KEY] = inst->service_id,
[ee257b2]411 [OPEN_NODES_INODE_KEY] = inum,
412 };
413
414 fibril_mutex_lock(&open_nodes_lock);
415 hash_table_insert(&open_nodes, key, &mnode->link);
416 fibril_mutex_unlock(&open_nodes_lock);
417 inst->open_nodes_cnt++;
418
419 mnode->ino_i->dirty = true;
[88ccd8b8]420
421 fs_node_initialize(fsnode);
422 fsnode->data = mnode;
[ee257b2]423 mnode->fsnode = fsnode;
[88ccd8b8]424 *rfn = fsnode;
425
426 return EOK;
427
428out_err_2:
429 free(mnode);
430out_err_1:
431 free(ino_i);
432out_err:
433 return r;
[10eb754]434}
435
[bd64680]436static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
437{
438 struct mfs_node *mnode = pfn->data;
439 struct mfs_ino_info *ino_i = mnode->ino_i;
[e80c2ff]440 struct mfs_dentry_info d_info;
[488f7ed]441 int r;
[bd64680]442
[ee257b2]443 mfsdebug("%s()\n", __FUNCTION__);
444
[bd64680]445 if (!S_ISDIR(ino_i->i_mode))
446 return ENOTDIR;
447
448 struct mfs_sb_info *sbi = mnode->instance->sbi;
449 const size_t comp_size = str_size(component);
450
[e80c2ff]451 unsigned i;
452 for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
[3a5ee6c]453 r = mfs_read_dentry(mnode, &d_info, i);
[c699b0c]454 if (r != EOK)
455 return r;
[488f7ed]456
[e80c2ff]457 if (!d_info.d_inum) {
[bd64680]458 /*This entry is not used*/
459 continue;
460 }
461
[367d67fe]462 const size_t dentry_name_size = str_size(d_info.d_name);
463
464 if (comp_size == dentry_name_size &&
465 !bcmp(component, d_info.d_name, dentry_name_size)) {
[bd64680]466 /*Hit!*/
467 mfs_node_core_get(rfn, mnode->instance,
[e80c2ff]468 d_info.d_inum);
[bd64680]469 goto found;
470 }
471 }
472 *rfn = NULL;
473found:
474 return EOK;
475}
476
[ac28650]477static aoff64_t mfs_size_get(fs_node_t *node)
[0d6ab10]478{
479 const struct mfs_node *mnode = node->data;
[155f792]480 return mnode->ino_i->i_size;
[0d6ab10]481}
482
[03bc76a]483static int
484mfs_node_get(fs_node_t **rfn, service_id_t service_id,
[44c0f5b]485 fs_index_t index)
486{
487 int rc;
488 struct mfs_instance *instance;
489
[ee257b2]490 mfsdebug("%s()\n", __FUNCTION__);
491
[03bc76a]492 rc = mfs_instance_get(service_id, &instance);
[c699b0c]493 if (rc != EOK)
494 return rc;
[44c0f5b]495
496 return mfs_node_core_get(rfn, instance, index);
497}
498
[03bc76a]499static int
500mfs_node_put(fs_node_t *fsnode)
[41202a9]501{
[ee257b2]502 int rc = EOK;
[41202a9]503 struct mfs_node *mnode = fsnode->data;
504
[ee257b2]505 mfsdebug("%s()\n", __FUNCTION__);
506
507 fibril_mutex_lock(&open_nodes_lock);
508
509 assert(mnode->refcnt > 0);
510 mnode->refcnt--;
511 if (mnode->refcnt == 0) {
512 unsigned long key[] = {
[03bc76a]513 [OPEN_NODES_SERVICE_KEY] = mnode->instance->service_id,
[ee257b2]514 [OPEN_NODES_INODE_KEY] = mnode->ino_i->index
515 };
516 hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
517 assert(mnode->instance->open_nodes_cnt > 0);
518 mnode->instance->open_nodes_cnt--;
[5f509cc]519 rc = mfs_put_inode(mnode);
[ee257b2]520 free(mnode->ino_i);
521 free(mnode);
522 free(fsnode);
523 }
[41202a9]524
[ee257b2]525 fibril_mutex_unlock(&open_nodes_lock);
526 return rc;
[41202a9]527}
528
529static int mfs_node_open(fs_node_t *fsnode)
530{
531 /*
532 * Opening a file is stateless, nothing
533 * to be done here.
534 */
535 return EOK;
536}
537
538static fs_index_t mfs_index_get(fs_node_t *fsnode)
539{
540 struct mfs_node *mnode = fsnode->data;
541 return mnode->ino_i->index;
542}
543
544static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
545{
546 struct mfs_node *mnode = fsnode->data;
547
[75e0f15]548 mfsdebug("%s() %d\n", __FUNCTION__, mnode->ino_i->i_nlinks);
[ee257b2]549
[bbd4c72]550 if (S_ISDIR(mnode->ino_i->i_mode)) {
551 if (mnode->ino_i->i_nlinks > 1)
552 return 1;
553 else
554 return 0;
[75e0f15]555 } else
556 return mnode->ino_i->i_nlinks;
[41202a9]557}
558
[44c0f5b]559static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
[44c6091f]560 fs_index_t index)
[44c0f5b]561{
562 fs_node_t *node = NULL;
563 struct mfs_node *mnode = NULL;
564 int rc;
565
[ee257b2]566 mfsdebug("%s()\n", __FUNCTION__);
567
568 fibril_mutex_lock(&open_nodes_lock);
569
570 /* Check if the node is not already open */
571 unsigned long key[] = {
[03bc76a]572 [OPEN_NODES_SERVICE_KEY] = inst->service_id,
[ee257b2]573 [OPEN_NODES_INODE_KEY] = index,
574 };
575 link_t *already_open = hash_table_find(&open_nodes, key);
576
577 if (already_open) {
578 mnode = hash_table_get_instance(already_open, struct mfs_node, link);
579 *rfn = mnode->fsnode;
580 mnode->refcnt++;
581
582 fibril_mutex_unlock(&open_nodes_lock);
583 return EOK;
584 }
585
[b438804]586 node = malloc(sizeof(fs_node_t));
[44c0f5b]587 if (!node) {
588 rc = ENOMEM;
589 goto out_err;
590 }
591
592 fs_node_initialize(node);
593
[b438804]594 mnode = malloc(sizeof(*mnode));
[44c0f5b]595 if (!mnode) {
596 rc = ENOMEM;
597 goto out_err;
598 }
599
[155f792]600 struct mfs_ino_info *ino_i;
601
[3a5ee6c]602 rc = mfs_get_inode(inst, &ino_i, index);
[c699b0c]603 if (rc != EOK)
604 goto out_err;
[155f792]605
[41202a9]606 ino_i->index = index;
[155f792]607 mnode->ino_i = ino_i;
[ee257b2]608 mnode->refcnt = 1;
609 link_initialize(&mnode->link);
[155f792]610
[44c0f5b]611 mnode->instance = inst;
612 node->data = mnode;
[ee257b2]613 mnode->fsnode = node;
[44c0f5b]614 *rfn = node;
615
[ee257b2]616 hash_table_insert(&open_nodes, key, &mnode->link);
617 inst->open_nodes_cnt++;
618
619 fibril_mutex_unlock(&open_nodes_lock);
620
[44c0f5b]621 return EOK;
622
623out_err:
624 if (node)
625 free(node);
626 if (mnode)
627 free(mnode);
[ee257b2]628 fibril_mutex_unlock(&open_nodes_lock);
[44c0f5b]629 return rc;
630}
631
[ac28650]632static bool mfs_is_directory(fs_node_t *fsnode)
[5a58ae2]633{
[44c0f5b]634 const struct mfs_node *node = fsnode->data;
[155f792]635 return S_ISDIR(node->ino_i->i_mode);
[5a58ae2]636}
637
[ac28650]638static bool mfs_is_file(fs_node_t *fsnode)
[7d04324]639{
640 struct mfs_node *node = fsnode->data;
[155f792]641 return S_ISREG(node->ino_i->i_mode);
[7d04324]642}
643
[03bc76a]644static int mfs_root_get(fs_node_t **rfn, service_id_t service_id)
[fe4ac35]645{
[03bc76a]646 int rc = mfs_node_get(rfn, service_id, MFS_ROOT_INO);
[41202a9]647 return rc;
[fe4ac35]648}
649
[88ccd8b8]650static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
651{
[afd9c3b]652 struct mfs_node *parent = pfn->data;
653 struct mfs_node *child = cfn->data;
[48de019]654 struct mfs_sb_info *sbi = parent->instance->sbi;
655
[ee257b2]656 mfsdebug("%s()\n", __FUNCTION__);
657
[48de019]658 if (str_size(name) > sbi->max_name_len)
659 return ENAMETOOLONG;
[afd9c3b]660
[3a5ee6c]661 int r = mfs_insert_dentry(parent, name, child->ino_i->index);
[c699b0c]662 if (r != EOK)
663 goto exit_error;
[13ecdac9]664
665 if (S_ISDIR(child->ino_i->i_mode)) {
[3a5ee6c]666 r = mfs_insert_dentry(child, ".", child->ino_i->index);
[c699b0c]667 if (r != EOK)
668 goto exit_error;
[bbd4c72]669
[3a5ee6c]670 r = mfs_insert_dentry(child, "..", parent->ino_i->index);
[c699b0c]671 if (r != EOK)
672 goto exit_error;
[bbd4c72]673
674 parent->ino_i->i_nlinks++;
675 parent->ino_i->dirty = true;
[13ecdac9]676 }
[afd9c3b]677
[13ecdac9]678exit_error:
[afd9c3b]679 return r;
[88ccd8b8]680}
681
[53eb588]682static int
683mfs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name)
684{
685 struct mfs_node *parent = pfn->data;
686 struct mfs_node *child = cfn->data;
687 bool has_children;
688 int r;
689
[ee257b2]690 mfsdebug("%s()\n", __FUNCTION__);
691
[53eb588]692 if (!parent)
693 return EBUSY;
694
695 r = mfs_has_children(&has_children, cfn);
[c699b0c]696 if (r != EOK)
697 return r;
[3f3e5b5]698
[53eb588]699 if (has_children)
700 return ENOTEMPTY;
701
[3a5ee6c]702 r = mfs_remove_dentry(parent, name);
[c699b0c]703 if (r != EOK)
704 return r;
[53eb588]705
706 struct mfs_ino_info *chino = child->ino_i;
707
708 assert(chino->i_nlinks >= 1);
[bbd4c72]709 chino->i_nlinks--;
710 mfsdebug("Links: %d\n", chino->i_nlinks);
711
712 if (chino->i_nlinks <= 1 && S_ISDIR(chino->i_mode)) {
713 /* The child directory will be destroyed, decrease the
714 * parent hard links counter.
715 */
[ee257b2]716 parent->ino_i->i_nlinks--;
717 parent->ino_i->dirty = true;
718 }
719
[53eb588]720 chino->dirty = true;
721
[ee257b2]722 return r;
[53eb588]723}
724
[ac28650]725static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
[54caa41b]726{
727 struct mfs_node *mnode = fsnode->data;
[e80c2ff]728 struct mfs_sb_info *sbi = mnode->instance->sbi;
[488f7ed]729 int r;
[54caa41b]730
731 *has_children = false;
732
733 if (!S_ISDIR(mnode->ino_i->i_mode))
734 goto out;
735
[e80c2ff]736 struct mfs_dentry_info d_info;
[44c6091f]737
[ac28650]738 /* The first two dentries are always . and .. */
[e80c2ff]739 unsigned i;
[3f3e5b5]740 for (i = 2; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
[3a5ee6c]741 r = mfs_read_dentry(mnode, &d_info, i);
[c699b0c]742 if (r != EOK)
743 return r;
[54caa41b]744
[e80c2ff]745 if (d_info.d_inum) {
[7a96476]746 /*A valid entry has been found*/
[54caa41b]747 *has_children = true;
748 break;
749 }
750 }
[41202a9]751out:
752
[54caa41b]753 return EOK;
754}
755
[03bc76a]756static int
757mfs_read(service_id_t service_id, fs_index_t index, aoff64_t pos,
758 size_t *rbytes)
[668f1949]759{
760 int rc;
761 fs_node_t *fn;
762
[03bc76a]763 rc = mfs_node_get(&fn, service_id, index);
764 if (rc != EOK)
765 return rc;
766 if (!fn)
767 return ENOENT;
[668f1949]768
769 struct mfs_node *mnode;
770 struct mfs_ino_info *ino_i;
771 size_t len, bytes = 0;
772 ipc_callid_t callid;
773
774 mnode = fn->data;
775 ino_i = mnode->ino_i;
776
777 if (!async_data_read_receive(&callid, &len)) {
[230229de]778 rc = EINVAL;
779 goto out_error;
[668f1949]780 }
781
782 if (S_ISDIR(ino_i->i_mode)) {
783 aoff64_t spos = pos;
[e80c2ff]784 struct mfs_dentry_info d_info;
785 struct mfs_sb_info *sbi = mnode->instance->sbi;
[668f1949]786
[e8b6b6a]787 if (pos < 2) {
788 /*Skip the first two dentries ('.' and '..')*/
789 pos = 2;
790 }
791
[3f3e5b5]792 for (; pos < mnode->ino_i->i_size / sbi->dirsize; ++pos) {
[3a5ee6c]793 rc = mfs_read_dentry(mnode, &d_info, pos);
[c699b0c]794 if (rc != EOK)
795 goto out_error;
[488f7ed]796
[e80c2ff]797 if (d_info.d_inum) {
[668f1949]798 /*Dentry found!*/
799 goto found;
800 }
801 }
802
803 rc = mfs_node_put(fn);
804 async_answer_0(callid, rc != EOK ? rc : ENOENT);
[03bc76a]805 return rc;
[668f1949]806found:
[e80c2ff]807 async_data_read_finalize(callid, d_info.d_name,
808 str_size(d_info.d_name) + 1);
[668f1949]809 bytes = ((pos - spos) + 1);
[230229de]810 } else {
811 struct mfs_sb_info *sbi = mnode->instance->sbi;
812
813 if (pos >= (size_t) ino_i->i_size) {
814 /*Trying to read beyond the end of file*/
815 bytes = 0;
816 (void) async_data_read_finalize(callid, NULL, 0);
817 goto out_success;
818 }
819
820 bytes = min(len, sbi->block_size - pos % sbi->block_size);
821 bytes = min(bytes, ino_i->i_size - pos);
822
823 uint32_t zone;
824 block_t *b;
[668f1949]825
[3a5ee6c]826 rc = mfs_read_map(&zone, mnode, pos);
[c699b0c]827 if (rc != EOK)
828 goto out_error;
[230229de]829
830 if (zone == 0) {
831 /*sparse file*/
832 uint8_t *buf = malloc(sbi->block_size);
833 if (!buf) {
834 rc = ENOMEM;
835 goto out_error;
836 }
[6fc5262]837 memset(buf, 0, sizeof(sbi->block_size));
[230229de]838 async_data_read_finalize(callid,
[44c6091f]839 buf + pos % sbi->block_size, bytes);
[230229de]840 free(buf);
841 goto out_success;
842 }
843
[03bc76a]844 rc = block_get(&b, service_id, zone, BLOCK_FLAGS_NONE);
[c699b0c]845 if (rc != EOK)
846 goto out_error;
[230229de]847
848 async_data_read_finalize(callid, b->data +
[44c6091f]849 pos % sbi->block_size, bytes);
[230229de]850
851 rc = block_put(b);
852 if (rc != EOK) {
853 mfs_node_put(fn);
[03bc76a]854 return rc;
[230229de]855 }
856 }
857out_success:
[668f1949]858 rc = mfs_node_put(fn);
[03bc76a]859 *rbytes = bytes;
860 return rc;
[44c6091f]861out_error:
862 ;
[230229de]863 int tmp = mfs_node_put(fn);
864 async_answer_0(callid, tmp != EOK ? tmp : rc);
[03bc76a]865 return tmp != EOK ? tmp : rc;
[668f1949]866}
867
[03bc76a]868static int
869mfs_write(service_id_t service_id, fs_index_t index, aoff64_t pos,
870 size_t *wbytes, aoff64_t *nsize)
[bb7e8382]871{
872 fs_node_t *fn;
873 int r;
874 int flags = BLOCK_FLAGS_NONE;
875
[03bc76a]876 r = mfs_node_get(&fn, service_id, index);
877 if (r != EOK)
878 return r;
879 if (!fn)
880 return ENOENT;
[bb7e8382]881
882 ipc_callid_t callid;
883 size_t len;
884
885 if (!async_data_write_receive(&callid, &len)) {
886 r = EINVAL;
887 goto out_err;
888 }
889
890 struct mfs_node *mnode = fn->data;
891 struct mfs_sb_info *sbi = mnode->instance->sbi;
892 struct mfs_ino_info *ino_i = mnode->ino_i;
893 const size_t bs = sbi->block_size;
894 size_t bytes = min(len, bs - pos % bs);
895 size_t boundary = ROUND_UP(ino_i->i_size, bs);
896 uint32_t block;
897
898 if (bytes == bs)
899 flags = BLOCK_FLAGS_NOREAD;
900
901 if (pos < boundary) {
[3a5ee6c]902 r = mfs_read_map(&block, mnode, pos);
[c699b0c]903 if (r != EOK)
904 goto out_err;
[bb7e8382]905
906 if (block == 0) {
907 /*Writing in a sparse block*/
[70ac0af]908 r = mfs_alloc_zone(mnode->instance, &block);
[c699b0c]909 if (r != EOK)
910 goto out_err;
[bb7e8382]911 flags = BLOCK_FLAGS_NOREAD;
912 }
913 } else {
914 uint32_t dummy;
915
[70ac0af]916 r = mfs_alloc_zone(mnode->instance, &block);
[c699b0c]917 if (r != EOK)
918 goto out_err;
[bb7e8382]919
[3a5ee6c]920 r = mfs_write_map(mnode, pos, block, &dummy);
[c699b0c]921 if (r != EOK)
922 goto out_err;
[bb7e8382]923 }
924
925 block_t *b;
[03bc76a]926 r = block_get(&b, service_id, block, flags);
[c699b0c]927 if (r != EOK)
928 goto out_err;
[bb7e8382]929
930 async_data_write_finalize(callid, b->data + pos % bs, bytes);
931 b->dirty = true;
932
933 r = block_put(b);
934 if (r != EOK) {
935 mfs_node_put(fn);
[03bc76a]936 return r;
[bb7e8382]937 }
938
939 ino_i->i_size = pos + bytes;
940 ino_i->dirty = true;
941 r = mfs_node_put(fn);
[03bc76a]942 *nsize = pos + bytes;
943 *wbytes = bytes;
944 return r;
[bb7e8382]945
946out_err:
947 mfs_node_put(fn);
948 async_answer_0(callid, r);
[03bc76a]949 return r;
[bb7e8382]950}
951
[03bc76a]952static int
953mfs_destroy(service_id_t service_id, fs_index_t index)
[d8af1bd]954{
955 fs_node_t *fn;
956 int r;
957
[03bc76a]958 r = mfs_node_get(&fn, service_id, index);
959 if (r != EOK)
960 return r;
961 if (!fn)
962 return ENOENT;
[d8af1bd]963
964 /*Destroy the inode*/
[e03d545]965 return mfs_destroy_node(fn);
[d8af1bd]966}
967
968static int
969mfs_destroy_node(fs_node_t *fn)
970{
971 struct mfs_node *mnode = fn->data;
972 bool has_children;
973 int r;
974
[a5bad72]975 mfsdebug("mfs_destroy_node %d\n", mnode->ino_i->index);
976
[d8af1bd]977 r = mfs_has_children(&has_children, fn);
[c699b0c]978 if (r != EOK)
979 goto out;
[d8af1bd]980
981 assert(!has_children);
982
983 /*Free the entire inode content*/
[3a5ee6c]984 r = mfs_inode_shrink(mnode, mnode->ino_i->i_size);
[c699b0c]985 if (r != EOK)
986 goto out;
[e03d545]987
988 /*Mark the inode as free in the bitmap*/
[70ac0af]989 r = mfs_free_inode(mnode->instance, mnode->ino_i->index);
[d8af1bd]990
[51db5aeb]991out:
[eefb653]992 mfs_node_put(fn);
[d8af1bd]993 return r;
994}
995
[03bc76a]996static int
997mfs_truncate(service_id_t service_id, fs_index_t index, aoff64_t size)
[8a49fed]998{
999 fs_node_t *fn;
1000 int r;
1001
[03bc76a]1002 r = mfs_node_get(&fn, service_id, index);
1003 if (r != EOK)
1004 return r;
1005 if (!fn)
1006 return r;
[8a49fed]1007
1008 struct mfs_node *mnode = fn->data;
1009 struct mfs_ino_info *ino_i = mnode->ino_i;
1010
1011 if (ino_i->i_size == size)
1012 r = EOK;
1013 else
[3a5ee6c]1014 r = mfs_inode_shrink(mnode, ino_i->i_size - size);
[8a49fed]1015
1016 mfs_node_put(fn);
[03bc76a]1017 return r;
[8a49fed]1018}
1019
[03bc76a]1020static int
1021mfs_instance_get(service_id_t service_id, struct mfs_instance **instance)
[3b08178]1022{
1023 struct mfs_instance *instance_ptr;
1024
1025 fibril_mutex_lock(&inst_list_mutex);
1026
[03bc76a]1027 if (list_empty(&inst_list)) {
1028 fibril_mutex_unlock(&inst_list_mutex);
1029 return EINVAL;
1030 }
1031
1032 list_foreach(inst_list, link) {
[bd64680]1033 instance_ptr = list_get_instance(link, struct mfs_instance,
[44c6091f]1034 link);
1035
[03bc76a]1036 if (instance_ptr->service_id == service_id) {
[3b08178]1037 *instance = instance_ptr;
1038 fibril_mutex_unlock(&inst_list_mutex);
1039 return EOK;
1040 }
1041 }
1042
1043 mfsdebug("Instance not found\n");
1044
1045 fibril_mutex_unlock(&inst_list_mutex);
1046 return EINVAL;
1047}
1048
[8ceba1e]1049static bool check_magic_number(uint16_t magic, bool *native,
[44c6091f]1050 mfs_version_t *version, bool *longfilenames)
[9e3dc95]1051{
[cfac897]1052 bool rc = true;
[8ceba1e]1053 *longfilenames = false;
1054
[57640e7]1055 if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
1056 *native = magic == MFS_MAGIC_V1;
[9e3dc95]1057 *version = MFS_VERSION_V1;
[8ceba1e]1058 } else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
1059 *native = magic == MFS_MAGIC_V1L;
1060 *version = MFS_VERSION_V1;
1061 *longfilenames = true;
[57640e7]1062 } else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
1063 *native = magic == MFS_MAGIC_V2;
[9e3dc95]1064 *version = MFS_VERSION_V2;
[8ceba1e]1065 } else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
1066 *native = magic == MFS_MAGIC_V2L;
1067 *version = MFS_VERSION_V2;
1068 *longfilenames = true;
[57640e7]1069 } else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
1070 *native = magic == MFS_MAGIC_V3;
[9e3dc95]1071 *version = MFS_VERSION_V3;
[cfac897]1072 } else
1073 rc = false;
[9e3dc95]1074
[7a96476]1075 return rc;
[096c8835]1076}
1077
[03bc76a]1078static int
1079mfs_close(service_id_t service_id, fs_index_t index)
[e700970]1080{
[03bc76a]1081 return 0;
[e700970]1082}
1083
[03bc76a]1084static int
1085mfs_sync(service_id_t service_id, fs_index_t index)
[51db5aeb]1086{
1087 fs_node_t *fn;
[03bc76a]1088 int rc = mfs_node_get(&fn, service_id, index);
1089 if (rc != EOK)
1090 return rc;
1091 if (!fn)
1092 return ENOENT;
[51db5aeb]1093
1094 struct mfs_node *mnode = fn->data;
1095 mnode->ino_i->dirty = true;
1096
[03bc76a]1097 return mfs_node_put(fn);
[51db5aeb]1098}
1099
[03bc76a]1100vfs_out_ops_t mfs_ops = {
1101 .mounted = mfs_mounted,
1102 .unmounted = mfs_unmounted,
1103 .read = mfs_read,
1104 .write = mfs_write,
1105 .truncate = mfs_truncate,
1106 .close = mfs_close,
1107 .destroy = mfs_destroy,
1108 .sync = mfs_sync,
1109};
1110
[096c8835]1111/**
1112 * @}
[44c6091f]1113 */
[096c8835]1114
Note: See TracBrowser for help on using the repository browser.