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

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

Fix memory leak in mfs_destroy_node()

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