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
Line 
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
33#include <stdlib.h>
34#include <fibril_synch.h>
35#include <align.h>
36#include <adt/hash_table.h>
37#include "mfs.h"
38
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
44static bool check_magic_number(uint16_t magic, bool *native,
45 mfs_version_t *version, bool *longfilenames);
46static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
47 fs_index_t index);
48
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);
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);
60static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
61static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags);
62static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name);
63static int mfs_unlink(fs_node_t *, fs_node_t *, const char *name);
64static int mfs_destroy_node(fs_node_t *fn);
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);
69
70static int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
71 fs_index_t index);
72
73
74static LIST_INITIALIZE(inst_list);
75static FIBRIL_MUTEX_INITIALIZE(inst_list_mutex);
76static hash_table_t open_nodes;
77static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
78
79libfs_ops_t mfs_libfs_ops = {
80 .size_get = mfs_size_get,
81 .root_get = mfs_root_get,
82 .device_get = mfs_device_get,
83 .is_directory = mfs_is_directory,
84 .is_file = mfs_is_file,
85 .node_get = mfs_node_get,
86 .node_put = mfs_node_put,
87 .node_open = mfs_node_open,
88 .index_get = mfs_index_get,
89 .match = mfs_match,
90 .create = mfs_create_node,
91 .link = mfs_link,
92 .unlink = mfs_unlink,
93 .destroy = mfs_destroy_node,
94 .plb_get_char = mfs_plb_get_char,
95 .has_children = mfs_has_children,
96 .lnkcnt_get = mfs_lnkcnt_get
97};
98
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
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);
145 enum cache_mode cmode;
146 struct mfs_superblock *sb;
147 struct mfs3_superblock *sb3;
148 struct mfs_sb_info *sbi;
149 struct mfs_instance *instance;
150 bool native, longnames;
151 mfs_version_t version;
152 uint16_t magic;
153
154 /* Accept the mount options */
155 char *opts;
156 int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
157
158 if (rc != EOK) {
159 mfsdebug("Can't accept async data write\n");
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 */
173 rc = block_init(EXCHANGE_SERIALIZE, devmap_handle, 1024);
174 if (rc != EOK) {
175 mfsdebug("libblock initialization failed\n");
176 async_answer_0(rid, rc);
177 return;
178 }
179
180 /*Allocate space for generic MFS superblock*/
181 sbi = malloc(sizeof(*sbi));
182
183 if (!sbi) {
184 async_answer_0(rid, ENOMEM);
185 return;
186 }
187
188 /*Allocate space for filesystem instance*/
189 instance = malloc(sizeof(*instance));
190
191 if (!instance) {
192 async_answer_0(rid, ENOMEM);
193 return;
194 }
195
196 instance->open_nodes_cnt = 0;
197
198 sb = malloc(MFS_SUPERBLOCK_SIZE);
199
200 if (!sb) {
201 async_answer_0(rid, ENOMEM);
202 return;
203 }
204
205 /* Read the superblock */
206 rc = block_read_direct(devmap_handle, MFS_SUPERBLOCK << 1, 1, sb);
207 if (rc != EOK) {
208 block_fini(devmap_handle);
209 async_answer_0(rid, rc);
210 return;
211 }
212
213 sb3 = (struct mfs3_superblock *) sb;
214
215 if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
216 /*This is a V1 or V2 Minix filesystem*/
217 magic = sb->s_magic;
218 goto recognized;
219 }
220
221 if (!check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
222 mfsdebug("magic number not recognized\n");
223 block_fini(devmap_handle);
224 async_answer_0(rid, ENOTSUP);
225 return;
226 }
227
228 /*This is a V3 Minix filesystem*/
229
230 magic = sb3->s_magic;
231
232recognized:
233
234 mfsdebug("magic number recognized = %04x\n", magic);
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;
242 sbi->isearch = 0;
243 sbi->zsearch = 0;
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);
254 sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
255 sbi->dirsize = MFS3_DIRSIZE;
256 sbi->max_name_len = MFS3_MAX_NAME_LEN;
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);
264 sbi->block_size = MFS_BLOCKSIZE;
265 if (version == MFS_VERSION_V2) {
266 sbi->nzones = conv32(native, sb->s_nzones2);
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 }
272 sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
273 sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
274 MFS_MAX_NAME_LEN;
275 }
276 sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
277
278 free(sb);
279
280 rc = block_cache_init(devmap_handle, sbi->block_size, 0, cmode);
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
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);
301}
302
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
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);
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 }
323
324 if (inst->open_nodes_cnt != 0) {
325 async_answer_0(rid, EBUSY);
326 return;
327 }
328
329 (void) block_cache_fini(devmap);
330 block_fini(devmap);
331
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
340 async_answer_0(rid, EOK);
341}
342
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
349static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags)
350{
351 int r;
352 struct mfs_instance *inst;
353 struct mfs_node *mnode;
354 fs_node_t *fsnode;
355 uint32_t inum;
356
357 mfsdebug("%s()\n", __FUNCTION__);
358
359 r = mfs_instance_get(handle, &inst);
360 on_error(r, return r);
361
362 /*Alloc a new inode*/
363 r = mfs_alloc_inode(inst, &inum);
364 on_error(r, return r);
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 }
379
380 fsnode = malloc(sizeof(fs_node_t));
381 if (!fsnode) {
382 r = ENOMEM;
383 goto out_err_2;
384 }
385
386 if (flags & L_DIRECTORY)
387 ino_i->i_mode = S_IFDIR;
388 else
389 ino_i->i_mode = S_IFREG;
390
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
402 mfsdebug("new node idx = %d\n", (int) inum);
403
404 ino_i->index = inum;
405 ino_i->dirty = true;
406 mnode->ino_i = ino_i;
407 mnode->instance = inst;
408 mnode->refcnt = 1;
409
410 link_initialize(&mnode->link);
411
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;
423
424 fs_node_initialize(fsnode);
425 fsnode->data = mnode;
426 mnode->fsnode = fsnode;
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;
437}
438
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;
443 struct mfs_dentry_info d_info;
444 int r;
445
446 mfsdebug("%s()\n", __FUNCTION__);
447
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
454 unsigned i;
455 for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
456 r = read_dentry(mnode, &d_info, i);
457 on_error(r, return r);
458
459 if (!d_info.d_inum) {
460 /*This entry is not used*/
461 continue;
462 }
463
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)) {
468 /*Hit!*/
469 mfs_node_core_get(rfn, mnode->instance,
470 d_info.d_inum);
471 goto found;
472 }
473 }
474 *rfn = NULL;
475found:
476 return EOK;
477}
478
479static aoff64_t mfs_size_get(fs_node_t *node)
480{
481 assert(node);
482
483 const struct mfs_node *mnode = node->data;
484 assert(mnode);
485 assert(mnode->ino_i);
486
487 return mnode->ino_i->i_size;
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
495static int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
496 fs_index_t index)
497{
498 int rc;
499 struct mfs_instance *instance;
500
501 mfsdebug("%s()\n", __FUNCTION__);
502
503 rc = mfs_instance_get(devmap_handle, &instance);
504 on_error(rc, return rc);
505
506 return mfs_node_core_get(rfn, instance, index);
507}
508
509static int mfs_node_put(fs_node_t *fsnode)
510{
511 int rc = EOK;
512 struct mfs_node *mnode = fsnode->data;
513
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 }
533
534 fibril_mutex_unlock(&open_nodes_lock);
535 return rc;
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
559 mfsdebug("%s()\n", __FUNCTION__);
560
561 assert(mnode);
562 assert(mnode->ino_i);
563
564 return mnode->ino_i->i_nlinks;
565}
566
567static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
568 fs_index_t index)
569{
570 fs_node_t *node = NULL;
571 struct mfs_node *mnode = NULL;
572 int rc;
573
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
594 node = malloc(sizeof(fs_node_t));
595 if (!node) {
596 rc = ENOMEM;
597 goto out_err;
598 }
599
600 fs_node_initialize(node);
601
602 mnode = malloc(sizeof(*mnode));
603 if (!mnode) {
604 rc = ENOMEM;
605 goto out_err;
606 }
607
608 struct mfs_ino_info *ino_i;
609
610 rc = get_inode(inst, &ino_i, index);
611 on_error(rc, goto out_err);
612
613 ino_i->index = index;
614 mnode->ino_i = ino_i;
615 mnode->refcnt = 1;
616 link_initialize(&mnode->link);
617
618 mnode->instance = inst;
619 node->data = mnode;
620 mnode->fsnode = node;
621 *rfn = node;
622
623 hash_table_insert(&open_nodes, key, &mnode->link);
624 inst->open_nodes_cnt++;
625
626 fibril_mutex_unlock(&open_nodes_lock);
627
628 return EOK;
629
630out_err:
631 if (node)
632 free(node);
633 if (mnode)
634 free(mnode);
635 fibril_mutex_unlock(&open_nodes_lock);
636 return rc;
637}
638
639static bool mfs_is_directory(fs_node_t *fsnode)
640{
641 const struct mfs_node *node = fsnode->data;
642 return S_ISDIR(node->ino_i->i_mode);
643}
644
645static bool mfs_is_file(fs_node_t *fsnode)
646{
647 struct mfs_node *node = fsnode->data;
648 return S_ISREG(node->ino_i->i_mode);
649}
650
651static int mfs_root_get(fs_node_t **rfn, devmap_handle_t handle)
652{
653 int rc = mfs_node_get(rfn, handle, MFS_ROOT_INO);
654 return rc;
655}
656
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
662static char mfs_plb_get_char(unsigned pos)
663{
664 return mfs_reg.plb_ro[pos % PLB_SIZE];
665}
666
667static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
668{
669 struct mfs_node *parent = pfn->data;
670 struct mfs_node *child = cfn->data;
671 struct mfs_sb_info *sbi = parent->instance->sbi;
672
673 mfsdebug("%s()\n", __FUNCTION__);
674
675 if (str_size(name) > sbi->max_name_len)
676 return ENAMETOOLONG;
677
678 int r = insert_dentry(parent, name, child->ino_i->index);
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);
684 child->ino_i->i_nlinks++;
685 child->ino_i->dirty = true;
686 r = insert_dentry(child, "..", parent->ino_i->index);
687 on_error(r, goto exit_error);
688 parent->ino_i->i_nlinks++;
689 parent->ino_i->dirty = true;
690 }
691
692exit_error:
693 return r;
694}
695
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
704 mfsdebug("%s()\n", __FUNCTION__);
705
706 if (!parent)
707 return EBUSY;
708
709 r = mfs_has_children(&has_children, cfn);
710 on_error(r, return r);
711
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
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
728 chino->dirty = true;
729
730 return r;
731}
732
733static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
734{
735 struct mfs_node *mnode = fsnode->data;
736 struct mfs_sb_info *sbi = mnode->instance->sbi;
737 int r;
738
739 *has_children = false;
740
741 if (!S_ISDIR(mnode->ino_i->i_mode))
742 goto out;
743
744 struct mfs_dentry_info d_info;
745
746 /* The first two dentries are always . and .. */
747 unsigned i;
748 for (i = 2; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
749 r = read_dentry(mnode, &d_info, i);
750 on_error(r, return r);
751
752 if (d_info.d_inum) {
753 /*A valid entry has been found*/
754 *has_children = true;
755 break;
756 }
757 }
758out:
759
760 return EOK;
761}
762
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),
770 IPC_GET_ARG4(*request));
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)) {
792 rc = EINVAL;
793 goto out_error;
794 }
795
796 if (S_ISDIR(ino_i->i_mode)) {
797 aoff64_t spos = pos;
798 struct mfs_dentry_info d_info;
799 struct mfs_sb_info *sbi = mnode->instance->sbi;
800
801 if (pos < 2) {
802 /*Skip the first two dentries ('.' and '..')*/
803 pos = 2;
804 }
805
806 for (; pos < mnode->ino_i->i_size / sbi->dirsize; ++pos) {
807 rc = read_dentry(mnode, &d_info, pos);
808 on_error(rc, goto out_error);
809
810 if (d_info.d_inum) {
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:
821 async_data_read_finalize(callid, d_info.d_name,
822 str_size(d_info.d_name) + 1);
823 bytes = ((pos - spos) + 1);
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;
839
840 rc = read_map(&zone, mnode, pos);
841 on_error(rc, goto out_error);
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 }
850 memset(buf, 0, sizeof(sbi->block_size));
851 async_data_read_finalize(callid,
852 buf + pos % sbi->block_size, bytes);
853 free(buf);
854 goto out_success;
855 }
856
857 rc = block_get(&b, handle, zone, BLOCK_FLAGS_NONE);
858 on_error(rc, goto out_error);
859
860 async_data_read_finalize(callid, b->data +
861 pos % sbi->block_size, bytes);
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:
871 rc = mfs_node_put(fn);
872 async_answer_1(rid, rc, (sysarg_t)bytes);
873 return;
874out_error:
875 ;
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);
879}
880
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),
887 IPC_GET_ARG4(*request));
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*/
929 r = mfs_alloc_zone(mnode->instance, &block);
930 on_error(r, goto out_err);
931 flags = BLOCK_FLAGS_NOREAD;
932 }
933 } else {
934 uint32_t dummy;
935
936 r = mfs_alloc_zone(mnode->instance, &block);
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
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
999 mfsdebug("mfs_destroy_node %d\n", mnode->ino_i->index);
1000
1001 r = mfs_has_children(&has_children, fn);
1002 on_error(r, return r);
1003
1004 assert(!has_children);
1005
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
1012 /*Free the entire inode content*/
1013 r = inode_shrink(mnode, mnode->ino_i->i_size);
1014 on_error(r, return r);
1015 r = mfs_free_inode(mnode->instance, mnode->ino_i->index);
1016 on_error(r, return r);
1017
1018out:
1019 free(mnode->ino_i);
1020 free(mnode);
1021 free(fn);
1022 return r;
1023}
1024
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
1058int mfs_instance_get(devmap_handle_t handle, struct mfs_instance **instance)
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) {
1066 instance_ptr = list_get_instance(link, struct mfs_instance,
1067 link);
1068
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
1082static bool check_magic_number(uint16_t magic, bool *native,
1083 mfs_version_t *version, bool *longfilenames)
1084{
1085 bool rc = true;
1086 *longfilenames = false;
1087
1088 if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
1089 *native = magic == MFS_MAGIC_V1;
1090 *version = MFS_VERSION_V1;
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;
1095 } else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
1096 *native = magic == MFS_MAGIC_V2;
1097 *version = MFS_VERSION_V2;
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;
1102 } else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
1103 *native = magic == MFS_MAGIC_V3;
1104 *version = MFS_VERSION_V3;
1105 } else
1106 rc = false;
1107
1108 return rc;
1109}
1110
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
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
1147/**
1148 * @}
1149 */
1150
Note: See TracBrowser for help on using the repository browser.