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

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

Fix cache initialization, cmode was not used at all

  • Property mode set to 100644
File size: 13.9 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 <stdio.h>
34#include <stdlib.h>
35#include <assert.h>
36#include <fibril_synch.h>
37#include <errno.h>
38#include "mfs.h"
39#include "mfs_utils.h"
40
41static bool check_magic_number(uint16_t magic, bool *native,
42 mfs_version_t *version, bool *longfilenames);
43static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
44 fs_index_t index);
45
46static int mfs_node_put(fs_node_t *fsnode);
47static int mfs_node_open(fs_node_t *fsnode);
48static fs_index_t mfs_index_get(fs_node_t *fsnode);
49static unsigned mfs_lnkcnt_get(fs_node_t *fsnode);
50static char mfs_plb_get_char(unsigned pos);
51static bool mfs_is_directory(fs_node_t *fsnode);
52static bool mfs_is_file(fs_node_t *fsnode);
53static int mfs_has_children(bool *has_children, fs_node_t *fsnode);
54static int mfs_root_get(fs_node_t **rfn, devmap_handle_t handle);
55static devmap_handle_t mfs_device_get(fs_node_t *fsnode);
56static aoff64_t mfs_size_get(fs_node_t *node);
57static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
58static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags);
59
60static
61int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
62 fs_index_t index);
63
64
65static LIST_INITIALIZE(inst_list);
66static FIBRIL_MUTEX_INITIALIZE(inst_list_mutex);
67
68libfs_ops_t mfs_libfs_ops = {
69 .size_get = mfs_size_get,
70 .root_get = mfs_root_get,
71 .device_get = mfs_device_get,
72 .is_directory = mfs_is_directory,
73 .is_file = mfs_is_file,
74 .node_get = mfs_node_get,
75 .node_put = mfs_node_put,
76 .node_open = mfs_node_open,
77 .index_get = mfs_index_get,
78 .match = mfs_match,
79 .create = mfs_create_node,
80 .plb_get_char = mfs_plb_get_char,
81 .has_children = mfs_has_children,
82 .lnkcnt_get = mfs_lnkcnt_get
83};
84
85void mfs_mounted(ipc_callid_t rid, ipc_call_t *request)
86{
87 devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
88 enum cache_mode cmode;
89 struct mfs_superblock *sb;
90 struct mfs3_superblock *sb3;
91 struct mfs_sb_info *sbi;
92 struct mfs_instance *instance;
93 bool native, longnames;
94 mfs_version_t version;
95 uint16_t magic;
96
97 /* Accept the mount options */
98 char *opts;
99 int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
100
101 if (rc != EOK) {
102 mfsdebug("Can't accept async data write\n");
103 async_answer_0(rid, rc);
104 return;
105 }
106
107 /* Check for option enabling write through. */
108 if (str_cmp(opts, "wtcache") == 0)
109 cmode = CACHE_MODE_WT;
110 else
111 cmode = CACHE_MODE_WB;
112
113 free(opts);
114
115 /* initialize libblock */
116 rc = block_init(devmap_handle, 1024);
117 if (rc != EOK) {
118 mfsdebug("libblock initialization failed\n");
119 async_answer_0(rid, rc);
120 return;
121 }
122
123 /*Allocate space for generic MFS superblock*/
124 sbi = malloc(sizeof(*sbi));
125
126 if (!sbi) {
127 async_answer_0(rid, ENOMEM);
128 return;
129 }
130
131 /*Allocate space for filesystem instance*/
132 instance = malloc(sizeof(*instance));
133
134 if (!instance) {
135 async_answer_0(rid, ENOMEM);
136 return;
137 }
138
139 sb = malloc(MFS_SUPERBLOCK_SIZE);
140
141 if (!sb) {
142 async_answer_0(rid, ENOMEM);
143 return;
144 }
145
146 /* Read the superblock */
147 rc = block_read_direct(devmap_handle, MFS_SUPERBLOCK << 1, 1, sb);
148 if (rc != EOK) {
149 block_fini(devmap_handle);
150 async_answer_0(rid, rc);
151 return;
152 }
153
154 sb3 = (struct mfs3_superblock *) sb;
155
156 if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
157 /*This is a V1 or V2 Minix filesystem*/
158 magic = sb->s_magic;
159 goto recognized;
160 }
161
162 if (!check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
163 mfsdebug("magic number not recognized\n");
164 block_fini(devmap_handle);
165 async_answer_0(rid, ENOTSUP);
166 return;
167 }
168
169 /*This is a V3 Minix filesystem*/
170
171 magic = sb3->s_magic;
172
173recognized:
174
175 mfsdebug("magic number recognized = %04x\n", magic);
176
177 /*Fill superblock info structure*/
178
179 sbi->fs_version = version;
180 sbi->long_names = longnames;
181 sbi->native = native;
182 sbi->magic = magic;
183 sbi->isearch = 0;
184 sbi->zsearch = 0;
185
186 if (version == MFS_VERSION_V3) {
187 sbi->ninodes = conv32(native, sb3->s_ninodes);
188 sbi->ibmap_blocks = conv16(native, sb3->s_ibmap_blocks);
189 sbi->zbmap_blocks = conv16(native, sb3->s_zbmap_blocks);
190 sbi->firstdatazone = conv16(native, sb3->s_first_data_zone);
191 sbi->log2_zone_size = conv16(native, sb3->s_log2_zone_size);
192 sbi->max_file_size = conv32(native, sb3->s_max_file_size);
193 sbi->nzones = conv32(native, sb3->s_nzones);
194 sbi->block_size = conv16(native, sb3->s_block_size);
195 sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
196 sbi->dirsize = MFS3_DIRSIZE;
197 sbi->max_name_len = MFS3_MAX_NAME_LEN;
198 } else {
199 sbi->ninodes = conv16(native, sb->s_ninodes);
200 sbi->ibmap_blocks = conv16(native, sb->s_ibmap_blocks);
201 sbi->zbmap_blocks = conv16(native, sb->s_zbmap_blocks);
202 sbi->firstdatazone = conv16(native, sb->s_first_data_zone);
203 sbi->log2_zone_size = conv16(native, sb->s_log2_zone_size);
204 sbi->max_file_size = conv32(native, sb->s_max_file_size);
205 sbi->nzones = conv16(native, sb->s_nzones);
206 sbi->block_size = MFS_BLOCKSIZE;
207 sbi->ino_per_block = V1_INODES_PER_BLOCK;
208 if (version == MFS_VERSION_V2)
209 sbi->nzones = conv32(native, sb->s_nzones2);
210 sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
211 sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
212 MFS_MAX_NAME_LEN;
213 }
214 sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
215
216 free(sb);
217
218 rc = block_cache_init(devmap_handle, sbi->block_size, 0, cmode);
219
220 if (rc != EOK) {
221 block_fini(devmap_handle);
222 async_answer_0(rid, EINVAL);
223 mfsdebug("block cache initialization failed\n");
224 return;
225 }
226
227 /*Initialize the instance structure and add it to the list*/
228 link_initialize(&instance->link);
229 instance->handle = devmap_handle;
230 instance->sbi = sbi;
231
232 fibril_mutex_lock(&inst_list_mutex);
233 list_append(&instance->link, &inst_list);
234 fibril_mutex_unlock(&inst_list_mutex);
235
236 mfsdebug("mount successful\n");
237
238 async_answer_0(rid, EOK);
239}
240
241void mfs_mount(ipc_callid_t rid, ipc_call_t *request)
242{
243 libfs_mount(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
244}
245
246devmap_handle_t mfs_device_get(fs_node_t *fsnode)
247{
248 struct mfs_node *node = fsnode->data;
249 return node->instance->handle;
250}
251
252static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags)
253{
254 mfsdebug("create_node()\n");
255 return ENOTSUP;
256}
257
258static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
259{
260 struct mfs_node *mnode = pfn->data;
261 struct mfs_ino_info *ino_i = mnode->ino_i;
262 struct mfs_dentry_info *d_info;
263
264 if (!S_ISDIR(ino_i->i_mode))
265 return ENOTDIR;
266
267 mfsdebug("mfs_match()\n");
268
269 struct mfs_sb_info *sbi = mnode->instance->sbi;
270 const size_t comp_size = str_size(component);
271
272 int i = 2;
273 while (1) {
274 d_info = read_directory_entry(mnode, i++);
275 if (!d_info) {
276 /*Reached the end of the directory entry list*/
277 break;
278 }
279
280 if (!d_info->d_inum) {
281 /*This entry is not used*/
282 free(d_info);
283 continue;
284 }
285
286 if (!bcmp(component, d_info->d_name, min(sbi->max_name_len,
287 comp_size))) {
288 /*Hit!*/
289 mfs_node_core_get(rfn, mnode->instance,
290 d_info->d_inum);
291 free(d_info);
292 goto found;
293 }
294 free(d_info);
295 }
296 *rfn = NULL;
297 return ENOENT;
298found:
299 return EOK;
300}
301
302static aoff64_t mfs_size_get(fs_node_t *node)
303{
304 assert(node);
305
306 const struct mfs_node *mnode = node->data;
307 assert(mnode);
308 assert(mnode->ino_i);
309
310 mfsdebug("inode size is %d\n", (int) mnode->ino_i->i_size);
311
312 return mnode->ino_i->i_size;
313}
314
315void mfs_stat(ipc_callid_t rid, ipc_call_t *request)
316{
317 mfsdebug("mfs_stat()\n");
318 libfs_stat(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
319}
320
321static int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
322 fs_index_t index)
323{
324 int rc;
325 struct mfs_instance *instance;
326
327 mfsdebug("mfs_node_get()\n");
328
329 rc = mfs_instance_get(devmap_handle, &instance);
330
331 if (rc != EOK)
332 return rc;
333
334 return mfs_node_core_get(rfn, instance, index);
335}
336
337static int mfs_node_put(fs_node_t *fsnode)
338{
339 struct mfs_node *mnode = fsnode->data;
340
341 mfsdebug("mfs_node_put()\n");
342
343 assert(mnode->ino_i);
344
345 if (mnode->ino_i->dirty) {
346 /*TODO: Write inode on disk*/
347 }
348
349 free(mnode->ino_i);
350 free(mnode);
351
352 return EOK;
353}
354
355static int mfs_node_open(fs_node_t *fsnode)
356{
357 /*
358 * Opening a file is stateless, nothing
359 * to be done here.
360 */
361 return EOK;
362}
363
364static fs_index_t mfs_index_get(fs_node_t *fsnode)
365{
366 struct mfs_node *mnode = fsnode->data;
367
368 mfsdebug("mfs_index_get()\n");
369
370 assert(mnode->ino_i);
371 return mnode->ino_i->index;
372}
373
374static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
375{
376 unsigned rc;
377 struct mfs_node *mnode = fsnode->data;
378
379 assert(mnode);
380 assert(mnode->ino_i);
381
382 rc = mnode->ino_i->i_nlinks;
383 mfsdebug("mfs_lnkcnt_get(): %u\n", rc);
384 return rc;
385}
386
387static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
388 fs_index_t index)
389{
390 fs_node_t *node = NULL;
391 struct mfs_node *mnode = NULL;
392 int rc;
393
394 const struct mfs_sb_info *sbi = inst->sbi;
395
396 node = malloc(sizeof(fs_node_t));
397 if (!node) {
398 rc = ENOMEM;
399 goto out_err;
400 }
401
402 fs_node_initialize(node);
403
404 mnode = malloc(sizeof(*mnode));
405 if (!mnode) {
406 rc = ENOMEM;
407 goto out_err;
408 }
409
410 struct mfs_ino_info *ino_i;
411
412 if (sbi->fs_version == MFS_VERSION_V1) {
413 /*Read MFS V1 inode*/
414 ino_i = mfs_read_inode_raw(inst, index);
415 } else {
416 /*Read MFS V2/V3 inode*/
417 ino_i = mfs2_read_inode_raw(inst, index);
418 }
419
420 if (!ino_i)
421 goto out_err;
422
423 ino_i->index = index;
424 mnode->ino_i = ino_i;
425
426 mnode->instance = inst;
427 node->data = mnode;
428 *rfn = node;
429
430 mfsdebug("node_get_core(%d) OK\n", (int) index);
431
432 return EOK;
433
434out_err:
435 if (node)
436 free(node);
437 if (mnode)
438 free(mnode);
439 return rc;
440}
441
442static bool mfs_is_directory(fs_node_t *fsnode)
443{
444 const struct mfs_node *node = fsnode->data;
445 return S_ISDIR(node->ino_i->i_mode);
446}
447
448static bool mfs_is_file(fs_node_t *fsnode)
449{
450 struct mfs_node *node = fsnode->data;
451 return S_ISREG(node->ino_i->i_mode);
452}
453
454static int mfs_root_get(fs_node_t **rfn, devmap_handle_t handle)
455{
456 int rc = mfs_node_get(rfn, handle, MFS_ROOT_INO);
457
458 mfsdebug("mfs_root_get %s\n", rc == EOK ? "OK" : "FAIL");
459 return rc;
460}
461
462void mfs_lookup(ipc_callid_t rid, ipc_call_t *request)
463{
464 libfs_lookup(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
465}
466
467static char mfs_plb_get_char(unsigned pos)
468{
469 return mfs_reg.plb_ro[pos % PLB_SIZE];
470}
471
472static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
473{
474 struct mfs_node *mnode = fsnode->data;
475 const struct mfs_ino_info *ino_i = mnode->ino_i;
476 const struct mfs_instance *inst = mnode->instance;
477 const struct mfs_sb_info *sbi = inst->sbi;
478 uint32_t n_dentries = 0;
479
480 *has_children = false;
481
482 if (!S_ISDIR(mnode->ino_i->i_mode))
483 goto out;
484
485 struct mfs_dentry_info *d_info;
486 n_dentries = ino_i->i_size / sbi->dirsize;
487
488 /* The first two dentries are always . and .. */
489 assert(n_dentries >= 2);
490
491 if (n_dentries == 2)
492 goto out;
493
494 int i = 2;
495 while (1) {
496 d_info = read_directory_entry(mnode, i++);
497
498 if (!d_info) {
499 /*Reached the end of the dentries list*/
500 break;
501 }
502
503 if (d_info->d_inum) {
504 /*A valid entry has been found*/
505 *has_children = true;
506 free(d_info);
507 break;
508 }
509
510 free(d_info);
511 }
512
513out:
514
515 if (n_dentries > 2 && !*has_children)
516 printf(NAME ": Filesystem corruption detected\n");
517
518 if (*has_children)
519 mfsdebug("Has children\n");
520 else
521 mfsdebug("Has not children\n");
522
523 return EOK;
524}
525
526/*
527 * Find a filesystem instance given the devmap handle
528 */
529int mfs_instance_get(devmap_handle_t handle, struct mfs_instance **instance)
530{
531 link_t *link;
532 struct mfs_instance *instance_ptr;
533
534 fibril_mutex_lock(&inst_list_mutex);
535
536 for (link = inst_list.next; link != &inst_list; link = link->next) {
537 instance_ptr = list_get_instance(link, struct mfs_instance,
538 link);
539
540 if (instance_ptr->handle == handle) {
541 *instance = instance_ptr;
542 fibril_mutex_unlock(&inst_list_mutex);
543 return EOK;
544 }
545 }
546
547 mfsdebug("Instance not found\n");
548
549 fibril_mutex_unlock(&inst_list_mutex);
550 return EINVAL;
551}
552
553static bool check_magic_number(uint16_t magic, bool *native,
554 mfs_version_t *version, bool *longfilenames)
555{
556 bool rc = false;
557 *longfilenames = false;
558
559 if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
560 *native = magic == MFS_MAGIC_V1;
561 *version = MFS_VERSION_V1;
562 rc = true;
563 } else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
564 *native = magic == MFS_MAGIC_V1L;
565 *version = MFS_VERSION_V1;
566 *longfilenames = true;
567 rc = true;
568 } else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
569 *native = magic == MFS_MAGIC_V2;
570 *version = MFS_VERSION_V2;
571 rc = true;
572 } else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
573 *native = magic == MFS_MAGIC_V2L;
574 *version = MFS_VERSION_V2;
575 *longfilenames = true;
576 rc = true;
577 } else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
578 *native = magic == MFS_MAGIC_V3;
579 *version = MFS_VERSION_V3;
580 rc = true;
581 }
582
583 return rc;
584}
585
586/**
587 * @}
588 */
589
Note: See TracBrowser for help on using the repository browser.