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

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

cstyle

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