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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since f9d8c3a was 5bf76c1, checked in by Jakub Jermar <jakub@…>, 14 years ago

Move the fs instance managing logic out of mfs to libfs.

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