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

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

Merge mainline changes

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