source: mainline/uspace/srv/fs/minixfs/mfs_ops.c@ e03d545

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

Minor fixes to minixfs:

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