Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 17279ead2f144a2631841fc11794d550970a9466)
+++ boot/Makefile.common	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -97,4 +97,5 @@
 	$(USPACE_PATH)/srv/fs/tmpfs/tmpfs \
 	$(USPACE_PATH)/srv/fs/fat/fat \
+	$(USPACE_PATH)/srv/fs/minixfs/mfs \
 	$(USPACE_PATH)/srv/taskmon/taskmon \
 	$(USPACE_PATH)/srv/hw/netif/ne2000/ne2000 \
@@ -128,4 +129,5 @@
 	$(USPACE_PATH)/app/killall/killall \
 	$(USPACE_PATH)/app/mkfat/mkfat \
+	$(USPACE_PATH)/app/mkminix/mkminix \
 	$(USPACE_PATH)/app/sbi/sbi \
 	$(USPACE_PATH)/app/redir/redir \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 17279ead2f144a2631841fc11794d550970a9466)
+++ uspace/Makefile	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -42,4 +42,5 @@
 	app/klog \
 	app/mkfat \
+	app/mkminix \
 	app/redir \
 	app/sbi \
@@ -72,4 +73,5 @@
 	srv/fs/tmpfs \
 	srv/fs/devfs \
+	srv/fs/minixfs \
 	srv/hid/adb_mouse \
 	srv/hid/char_mouse \
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 17279ead2f144a2631841fc11794d550970a9466)
+++ uspace/Makefile.common	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -90,4 +90,6 @@
 LIBNET_PREFIX = $(LIB_PREFIX)/net
 
+LIBMINIX_PREFIX = $(LIB_PREFIX)/minix
+
 BASE_LIBS = $(LIBC_PREFIX)/libc.a $(LIBSOFTINT_PREFIX)/libsoftint.a
 
Index: uspace/app/mkminix/Makefile
===================================================================
--- uspace/app/mkminix/Makefile	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/app/mkminix/Makefile	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,38 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a
+EXTRA_CFLAGS = -I$(LIBBLOCK_PREFIX) -I$(LIBMINIX_PREFIX)
+BINARY = mkminix
+
+SOURCES = \
+	mkminix.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/mkminix/mkminix.c
===================================================================
--- uspace/app/mkminix/mkminix.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/app/mkminix/mkminix.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,651 @@
+/*
+ * Copyright (c) 2010 Jiri Svoboda
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file	mkminix.c
+ * @brief	Tool for creating new Minix file systems.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libblock.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/typefmt.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <mem.h>
+#include <str.h>
+#include <time.h>
+#include <minix.h>
+
+#define NAME	"mkminix"
+
+#define FREE	0
+#define USED	1
+
+#define UPPER(n, size) 			(((n) / (size)) + (((n) % (size)) != 0))
+#define NEXT_DENTRY(p, dirsize)		(p += (dirsize))
+
+typedef enum {
+	HELP_SHORT,
+	HELP_LONG
+} help_level_t;
+
+/*Generic MFS superblock*/
+struct mfs_sb_info {
+	uint64_t n_inodes;
+	uint64_t n_zones;
+	aoff64_t dev_nblocks;
+	unsigned long ibmap_blocks;
+	unsigned long zbmap_blocks;
+	unsigned long first_data_zone;
+	unsigned long itable_size;
+	int log2_zone_size;
+	int ino_per_block;
+	int dirsize;
+	uint32_t max_file_size;
+	uint16_t magic;
+	uint32_t block_size;
+	int fs_version;
+	bool longnames;
+};
+
+static void	help_cmd_mkminix(help_level_t level);
+static int	num_of_set_bits(uint32_t n);
+static int	init_superblock(struct mfs_sb_info *sb);
+static int	write_superblock(const struct mfs_sb_info *sbi);
+static int	write_superblock3(const struct mfs_sb_info *sbi);
+static int	init_bitmaps(const struct mfs_sb_info *sb);
+static int	init_inode_table(const struct mfs_sb_info *sb);
+static int	make_root_ino(const struct mfs_sb_info *sb);
+static int	make_root_ino2(const struct mfs_sb_info *sb);
+static void	mark_bmap(uint32_t *bmap, int idx, int v);
+static int	insert_dentries(const struct mfs_sb_info *sb);
+
+static inline int write_block(aoff64_t off, size_t size, const void *data);
+
+static devmap_handle_t handle;
+static int shift;
+
+static struct option const long_options[] = {
+	{ "help", no_argument, 0, 'h' },
+	{ "long-names", no_argument, 0, 'l' },
+	{ "block-size", required_argument, 0, 'b' },
+	{ "inodes", required_argument, 0, 'i' },
+	{ NULL, no_argument, 0, '1' },
+	{ NULL, no_argument, 0, '2' },
+	{ NULL, no_argument, 0, '3' },
+	{ 0, 0, 0, 0 }
+};
+
+int main (int argc, char **argv)
+{
+	int rc, c, opt_ind;
+	char *device_name;
+	aoff64_t devblock_size;
+
+	struct mfs_sb_info sb;
+
+	/*Default is MinixFS V3*/
+	sb.magic = MFS_MAGIC_V3;
+	sb.fs_version = 3;
+
+	/*Default block size is 4Kb*/
+	sb.block_size = MFS_MAX_BLOCKSIZE;
+	sb.dirsize = MFS3_DIRSIZE;
+	sb.n_inodes = 0;
+	sb.longnames = false;
+	sb.ino_per_block = V3_INODES_PER_BLOCK(MFS_MAX_BLOCKSIZE);
+
+	if (argc == 1) {
+		help_cmd_mkminix(HELP_SHORT);
+		printf("Incorrect number of arguments, try `mkminix --help'\n");
+		exit(0);
+	}
+
+	for (c = 0, optind = 0, opt_ind = 0; c != -1;) {
+		c = getopt_long(argc, argv, "lh12b:i:", long_options, &opt_ind);
+		switch (c) {
+		case 'h':
+			help_cmd_mkminix(HELP_LONG);
+			exit(0);
+		case '1':
+			sb.magic = MFS_MAGIC_V1;
+			sb.block_size = MFS_BLOCKSIZE;
+			sb.fs_version = 1;
+			sb.ino_per_block = V1_INODES_PER_BLOCK;
+			sb.dirsize = MFS_DIRSIZE;
+			break;
+		case '2':
+			sb.magic = MFS_MAGIC_V2;
+			sb.block_size = MFS_BLOCKSIZE;
+			sb.fs_version = 2;
+			sb.ino_per_block = V2_INODES_PER_BLOCK;
+			sb.dirsize = MFS_DIRSIZE;
+			break;
+		case 'b':
+			sb.block_size = (uint32_t) strtol(optarg, NULL, 10);
+			break;
+		case 'i':
+			sb.n_inodes = (uint64_t) strtol(optarg, NULL, 10);
+			break;
+		case 'l':
+			sb.longnames = true;
+			sb.dirsize = MFSL_DIRSIZE;
+			break;
+		}
+	}
+
+	if (sb.block_size < MFS_MIN_BLOCKSIZE || 
+				sb.block_size > MFS_MAX_BLOCKSIZE) {
+		printf(NAME ":Error! Invalid block size.\n");
+		exit(0);
+	} else if (num_of_set_bits(sb.block_size) != 1) {
+		/*Block size must be a power of 2.*/
+		printf(NAME ":Error! Invalid block size.\n");
+		exit(0);
+	} else if (sb.block_size > MFS_BLOCKSIZE && 
+			sb.fs_version != 3) {
+		printf(NAME ":Error! Block size > 1024 is supported by V3 filesystem only.\n");
+		exit(0);
+	} else if (sb.fs_version == 3 && sb.longnames) {
+		printf(NAME ":Error! Long filenames are supported by V1/V2 filesystem only.\n");
+		exit(0);
+	}
+
+	if (sb.block_size == MFS_MIN_BLOCKSIZE)
+		shift = 1;
+	else if (sb.block_size == MFS_MAX_BLOCKSIZE)
+		shift = 3;
+	else
+		shift = 2;
+
+	argv += optind;
+
+	device_name = argv[0];
+
+	if (!device_name) {
+		help_cmd_mkminix(HELP_LONG);
+		exit(0);
+	}
+
+	rc = devmap_device_get_handle(device_name, &handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": Error resolving device `%s'.\n", device_name);
+		return 2;
+	}
+
+	rc = block_init(handle, 2048);
+	if (rc != EOK)  {
+		printf(NAME ": Error initializing libblock.\n");
+		return 2;
+	}
+
+	rc = block_get_bsize(handle, &devblock_size);
+	if (rc != EOK) {
+		printf(NAME ": Error determining device block size.\n");
+		return 2;
+	}
+
+	rc = block_get_nblocks(handle, &sb.dev_nblocks);
+	if (rc != EOK) {
+		printf(NAME ": Warning, failed to obtain block device size.\n");
+	} else {
+		printf(NAME ": Block device has %" PRIuOFF64 " blocks.\n",
+		    sb.dev_nblocks);
+	}
+
+	if (devblock_size != 512) {
+		printf(NAME ": Error. Device block size is not 512 bytes.\n");
+		return 2;
+	}
+
+	/*Minimum block size is 1 Kb*/
+	sb.dev_nblocks /= 2;
+
+	printf(NAME ": Creating Minix file system on device\n");
+
+	/*Initialize superblock*/
+	if (init_superblock(&sb) != EOK) {
+		printf(NAME ": Error. Superblock initialization failed\n");
+		return 2;
+	}
+
+	/*Initialize bitmaps*/
+	if (init_bitmaps(&sb) != EOK) {
+		printf(NAME ": Error. Bitmaps initialization failed\n");
+		return 2;
+	}
+
+	/*Init inode table*/
+	if (init_inode_table(&sb) != EOK) {
+		printf(NAME ": Error. Inode table initialization failed\n");
+		return 2;
+	}
+
+	/*Make the root inode*/
+	if (sb.fs_version == 1)
+		rc = make_root_ino(&sb);
+	else
+		rc = make_root_ino2(&sb);
+
+	if (rc != EOK) {
+		printf(NAME ": Error. Root inode initialization failed\n");
+		return 2;
+	}
+
+	/*Insert directory entries . and ..*/
+	if (insert_dentries(&sb) != EOK) {
+		printf(NAME ": Error. Root directory initialization failed\n");
+		return 2;
+	}
+
+	return 0;
+}
+
+static int insert_dentries(const struct mfs_sb_info *sb)
+{
+	void *root_block;
+	uint8_t *dentry_ptr;
+	int rc;
+	const long root_dblock = sb->first_data_zone;
+
+	root_block = malloc(sb->block_size);
+	memset(root_block, 0x00, sb->block_size);
+
+	if (!root_block)
+		return ENOMEM;
+
+	dentry_ptr = root_block;
+	
+	if (sb->fs_version != 3) {
+		/*Directory entries for V1/V2 filesystem*/
+		struct mfs_dentry *dentry = root_block;
+
+		dentry->d_inum = MFS_ROOT_INO;
+		memcpy(dentry->d_name, ".\0", 2);
+
+		dentry = (struct mfs_dentry *) NEXT_DENTRY(dentry_ptr,
+							sb->dirsize);
+
+		dentry->d_inum = MFS_ROOT_INO;
+		memcpy(dentry->d_name, "..\0", 3);
+	} else {
+		/*Directory entries for V3 filesystem*/
+		struct mfs3_dentry *dentry = root_block;
+
+		dentry->d_inum = MFS_ROOT_INO;
+		memcpy(dentry->d_name, ".\0", 2);
+
+		dentry = (struct mfs3_dentry *) NEXT_DENTRY(dentry_ptr,
+							sb->dirsize);
+
+		dentry->d_inum = MFS_ROOT_INO;
+		memcpy(dentry->d_name, "..\0", 3);
+	}
+
+	rc = write_block(root_dblock, 1, root_block);
+
+	free(root_block);
+	return rc;
+}
+
+static int init_inode_table(const struct mfs_sb_info *sb)
+{
+	unsigned int i;
+	uint8_t *itable_buf;
+	int rc;
+
+	long itable_off = sb->zbmap_blocks + sb->ibmap_blocks + 2;
+	unsigned long itable_size = sb->itable_size;
+
+	itable_buf = malloc(sb->block_size);
+
+	if (!itable_buf)
+		return ENOMEM;
+
+	memset(itable_buf, 0x00, sb->block_size);
+
+	for (i = 0; i < itable_size; ++i, ++itable_off) {
+		rc = write_block(itable_off, 1, itable_buf);
+
+		if (rc != EOK)
+			break;
+	}
+
+	free(itable_buf);
+	return rc;
+}
+
+static int make_root_ino(const struct mfs_sb_info *sb)
+{
+	struct mfs_inode *ino_buf;
+	int rc;
+
+	const long itable_off = sb->zbmap_blocks + sb->ibmap_blocks + 2;
+
+	const time_t sec = time(NULL);
+
+	ino_buf = malloc(MFS_BLOCKSIZE);
+
+	if (!ino_buf)
+		return ENOMEM;
+
+	memset(ino_buf, 0x00, MFS_BLOCKSIZE);
+
+	ino_buf[MFS_ROOT_INO].i_mode = S_IFDIR;
+	ino_buf[MFS_ROOT_INO].i_uid = 0;
+	ino_buf[MFS_ROOT_INO].i_gid = 0;
+	ino_buf[MFS_ROOT_INO].i_size = (sb->longnames ? MFSL_DIRSIZE : MFS_DIRSIZE) * 2;
+	ino_buf[MFS_ROOT_INO].i_mtime = sec;
+	ino_buf[MFS_ROOT_INO].i_nlinks = 2;
+	ino_buf[MFS_ROOT_INO].i_dzone[0] = sb->first_data_zone;
+
+	rc = write_block(itable_off, 1, ino_buf);
+
+	free(ino_buf);
+	return rc;
+}
+
+/*Initialize a Minix V2 root inode on disk, also valid for V3 filesystem*/
+static int make_root_ino2(const struct mfs_sb_info *sb)
+{
+	struct mfs2_inode *ino_buf;
+	int rc;
+
+	/*Compute offset of the first inode table block*/
+	const long itable_off = sb->zbmap_blocks + sb->ibmap_blocks + 2;
+
+	const time_t sec = time(NULL);
+
+	ino_buf = malloc(sb->block_size);
+
+	if (!ino_buf)
+		return ENOMEM;
+
+	memset(ino_buf, 0x00, sb->block_size);
+
+	ino_buf[MFS_ROOT_INO].i_mode = S_IFDIR;
+	ino_buf[MFS_ROOT_INO].i_uid = 0;
+	ino_buf[MFS_ROOT_INO].i_gid = 0;
+	ino_buf[MFS_ROOT_INO].i_size = MFS3_DIRSIZE * 2;
+	ino_buf[MFS_ROOT_INO].i_mtime = sec;
+	ino_buf[MFS_ROOT_INO].i_atime = sec;
+	ino_buf[MFS_ROOT_INO].i_ctime = sec;
+	ino_buf[MFS_ROOT_INO].i_nlinks = 2;
+	ino_buf[MFS_ROOT_INO].i_dzone[0] = sb->first_data_zone;
+
+	rc = write_block(itable_off, 1, ino_buf);
+
+	free(ino_buf);
+	return rc;
+}
+
+static int init_superblock(struct mfs_sb_info *sb)
+{
+	aoff64_t inodes;
+	int rc;
+
+	if (sb->longnames)
+		sb->magic = sb->fs_version == 1 ? MFS_MAGIC_V1L : MFS_MAGIC_V2L;
+
+	/*Compute the number of zones on disk*/
+
+	if (sb->fs_version == 1) {
+		/*Valid only for MFS V1*/
+		sb->n_zones = sb->dev_nblocks > UINT16_MAX ? 
+			UINT16_MAX : sb->dev_nblocks;
+	} else {
+		/*Valid for MFS V2/V3*/
+		sb->n_zones = sb->dev_nblocks > UINT32_MAX ?
+			UINT32_MAX : sb->dev_nblocks;
+
+		if (sb->fs_version == 3) {
+			sb->ino_per_block = V3_INODES_PER_BLOCK(sb->block_size);
+			sb->n_zones /= (sb->block_size / MFS_MIN_BLOCKSIZE);
+		}
+	}
+
+	/*Round up the number of inodes to fill block size*/
+	if (sb->n_inodes == 0)
+		inodes = sb->dev_nblocks / 3;
+	else
+		inodes = sb->n_inodes;
+
+	if (inodes % sb->ino_per_block)
+		inodes = ((inodes / sb->ino_per_block) + 1) * sb->ino_per_block;
+	
+	if (sb->fs_version < 3)
+		sb->n_inodes = inodes > UINT16_MAX ? UINT16_MAX : inodes;
+	else
+		sb->n_inodes = inodes > UINT32_MAX ? UINT32_MAX : inodes;
+
+	/*Compute inode bitmap size in blocks*/
+	sb->ibmap_blocks = UPPER(sb->n_inodes, sb->block_size * 8);
+
+	/*Compute inode table size*/
+	sb->itable_size = sb->n_inodes / sb->ino_per_block;
+
+	/*Compute zone bitmap size in blocks*/
+	sb->zbmap_blocks = UPPER(sb->n_zones, sb->block_size * 8);
+
+	/*Compute first data zone position*/
+	sb->first_data_zone = 2 + sb->itable_size + 
+				sb->zbmap_blocks + sb->ibmap_blocks;
+
+	/*Set log2 of zone to block ratio to zero*/
+	sb->log2_zone_size = 0;
+
+	/*Check for errors*/
+	if (sb->first_data_zone >= sb->n_zones) {
+		printf(NAME ": Error! Insufficient disk space");
+		return ENOMEM;
+	}
+
+	/*Superblock is now ready to be written on disk*/
+	printf(NAME ": %d inodes\n", (uint32_t) sb->n_inodes);
+	printf(NAME ": %d zones\n", (uint32_t) sb->n_zones);
+	printf(NAME ": inode table blocks = %ld\n", sb->itable_size);
+	printf(NAME ": inode bitmap blocks = %ld\n", sb->ibmap_blocks);
+	printf(NAME ": zone bitmap blocks = %ld\n", sb->zbmap_blocks);
+	printf(NAME ": first data zone = %d\n", (uint32_t) sb->first_data_zone);
+	printf(NAME ": long fnames = %s\n", sb->longnames ? "Yes" : "No");
+
+	if (sb->fs_version == 3)
+		rc = write_superblock3(sb);
+	else
+		rc = write_superblock(sb);
+
+	return rc;
+}
+
+static int write_superblock(const struct mfs_sb_info *sbi)
+{
+	struct mfs_superblock *sb;
+	int rc;
+
+	sb = malloc(MFS_SUPERBLOCK_SIZE);;
+
+	if (!sb)
+		return ENOMEM;
+
+	sb->s_ninodes = (uint16_t) sbi->n_inodes;
+	sb->s_nzones = (uint16_t) sbi->n_zones;
+	sb->s_nzones2 = (uint32_t) sbi->n_zones;
+	sb->s_ibmap_blocks = (uint16_t) sbi->ibmap_blocks;
+	sb->s_zbmap_blocks = (uint16_t) sbi->zbmap_blocks;
+	sb->s_first_data_zone = (uint16_t) sbi->first_data_zone;
+	sb->s_log2_zone_size = sbi->log2_zone_size;
+	sb->s_max_file_size = UINT32_MAX;
+	sb->s_magic = sbi->magic;
+	sb->s_state = MFS_VALID_FS;
+
+	rc = write_block(MFS_SUPERBLOCK, 1, sb);
+	free(sb);
+
+	return rc;
+}
+
+static int write_superblock3(const struct mfs_sb_info *sbi)
+{
+	struct mfs3_superblock *sb;
+	int rc;
+
+	sb = malloc(MFS_SUPERBLOCK_SIZE);
+
+	if (!sb)
+		return ENOMEM;
+
+	sb->s_ninodes = (uint32_t) sbi->n_inodes;
+	sb->s_nzones = (uint32_t) sbi->n_zones;
+	sb->s_ibmap_blocks = (uint16_t) sbi->ibmap_blocks;
+	sb->s_zbmap_blocks = (uint16_t) sbi->zbmap_blocks;
+	sb->s_first_data_zone = (uint16_t) sbi->first_data_zone;
+	sb->s_log2_zone_size = sbi->log2_zone_size;
+	sb->s_max_file_size = UINT32_MAX;
+	sb->s_magic = sbi->magic;
+	sb->s_block_size = sbi->block_size;
+	sb->s_disk_version = 3;
+
+	rc = block_write_direct(handle, MFS_SUPERBLOCK << 1, 1 << 1, sb); 
+	free(sb);
+
+	return rc;
+}
+
+static int init_bitmaps(const struct mfs_sb_info *sb)
+{
+	uint32_t *ibmap_buf, *zbmap_buf;
+	uint8_t *ibmap_buf8, *zbmap_buf8;
+	const unsigned int ibmap_nblocks = sb->ibmap_blocks;
+	const unsigned int zbmap_nblocks = sb->zbmap_blocks;
+	unsigned int i;
+	int rc;
+
+	ibmap_buf = malloc(ibmap_nblocks * sb->block_size);
+	zbmap_buf = malloc(zbmap_nblocks * sb->block_size);
+
+	if (!ibmap_buf || !zbmap_buf)
+		return ENOMEM;
+
+	memset(ibmap_buf, 0xFF, ibmap_nblocks * sb->block_size);
+	memset(zbmap_buf, 0xFF, zbmap_nblocks * sb->block_size);
+
+	for (i = 2; i < sb->n_inodes; ++i)
+		mark_bmap(ibmap_buf, i, FREE);
+
+	for (i = sb->first_data_zone + 1; i < sb->n_zones; ++i)
+		mark_bmap(zbmap_buf, i, FREE);
+
+	ibmap_buf8 = (uint8_t *) ibmap_buf;
+	zbmap_buf8 = (uint8_t *) zbmap_buf;
+
+	int start_block = 2;
+
+	for (i = 0; i < ibmap_nblocks; ++i) {
+		if ((rc = write_block(start_block + i,
+				1, (ibmap_buf8 + i * sb->block_size))) != EOK)
+			return rc;
+	}
+
+	start_block = 2 + ibmap_nblocks;
+
+	for (i = 0; i < zbmap_nblocks; ++i) {
+		if ((rc = write_block(start_block + i,
+				1, (zbmap_buf8 + i * sb->block_size))) != EOK)
+			return rc;
+	}
+
+	free(ibmap_buf);
+	free(zbmap_buf);
+
+	return rc;
+}
+
+static void mark_bmap(uint32_t *bmap, int idx, int v)
+{
+	if (v == FREE)
+		bmap[idx / 32] &= ~(1 << (idx % 32));
+	else
+		bmap[idx / 32] |= 1 << (idx % 32);
+}
+
+static inline int write_block(aoff64_t off, size_t size, const void *data)
+{
+	if (shift == 3) {
+		int rc;
+		aoff64_t tmp_off = off << 1;
+		uint8_t *data_ptr = (uint8_t *) data;
+
+		rc = block_write_direct(handle, tmp_off << 2, size << 2, data_ptr);
+
+		if (rc != EOK)
+			return rc;
+
+		data_ptr += 2048;
+		tmp_off++;
+
+		return block_write_direct(handle, tmp_off << 2, size << 2, data_ptr);
+	}
+	return block_write_direct(handle, off << shift, size << shift, data);	
+}
+
+static void help_cmd_mkminix(help_level_t level)
+{
+	if (level == HELP_SHORT) {
+		printf(NAME": tool to create new Minix file systems\n");
+	} else {
+	printf("Usage: [options] device\n"
+		"-1         Make a Minix version 1 filesystem\n"
+		"-2         Make a Minix version 2 filesystem\n"
+		"-3         Make a Minix version 3 filesystem\n"
+		"-b ##      Specify the block size in bytes (V3 only),\n"
+		"           valid block size values are 1024, 2048 and 4096 bytes per block\n"
+		"-i ##      Specify the number of inodes for the filesystem\n"
+		"-l         Use 30-char long filenames (V1/V2 only)\n");
+	}
+}
+
+static int num_of_set_bits(uint32_t n)
+{
+	n = n - ((n >> 1) & 0x55555555);
+	n = (n & 0x33333333) + ((n >> 2) & 0x33333333);
+	return (((n + (n >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
+}
+
+
+/**
+ * @}
+ */
Index: uspace/lib/minix/minix.h
===================================================================
--- uspace/lib/minix/minix.h	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/lib/minix/minix.h	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#ifndef _MINIX_FS_H_
+#define _MINIX_FS_H_
+
+#include <sys/types.h>
+
+#define MFS_BLOCKSIZE		1024
+#define S_ISDIR(m)		(((m) & S_IFMT) == S_IFDIR)
+#define S_ISREG(m)		(((m) & S_IFMT) == S_IFREG)
+#define S_IFDIR			0040000		/*Directory*/
+#define S_IFREG			0100000		/*Regular file*/
+#define S_IFMT			00170000
+
+/*The following block sizes are valid only on V3 filesystem*/
+#define MFS_MIN_BLOCKSIZE	1024
+#define MFS_MAX_BLOCKSIZE	4096
+
+#define MFS_ROOT_INO		1
+#define MFS_SUPERBLOCK		1
+#define MFS_SUPERBLOCK_SIZE	1024
+#define MFS_BOOTBLOCK_SIZE	1024
+
+#define V2_NR_DIRECT_ZONES	7
+#define V2_NR_INDIRECT_ZONES	3
+
+#define V1_NR_DIRECT_ZONES	7
+#define V1_NR_INDIRECT_ZONES	2
+
+#define V1_INODES_PER_BLOCK	(MFS_BLOCKSIZE / sizeof(struct mfs_inode))
+#define V2_INODES_PER_BLOCK	(MFS_BLOCKSIZE / sizeof(struct mfs2_inode))
+#define V3_INODES_PER_BLOCK(bs)	((bs) / sizeof(struct mfs2_inode))
+
+#define MFS_DIRSIZE		16
+#define MFSL_DIRSIZE		32
+#define MFS3_DIRSIZE		64
+
+#define MFS_MAX_NAME_LEN	14
+#define MFS_L_MAX_NAME_LEN	30
+#define MFS3_MAX_NAME_LEN	60
+
+#define MFS_MAGIC_V1		0x137F
+#define MFS_MAGIC_V1R		0x7F13
+
+#define MFS_MAGIC_V1L		0x138F
+#define MFS_MAGIC_V1LR		0x8F13
+
+#define MFS_MAGIC_V2		0x2468
+#define MFS_MAGIC_V2R		0x6824
+
+#define MFS_MAGIC_V2L		0x2478
+#define MFS_MAGIC_V2LR		0x7824
+
+#define MFS_MAGIC_V3		0x4D5A
+#define MFS_MAGIC_V3R		0x5A4D
+
+#define MFS_VALID_FS		0x0001
+#define MFS_ERROR_FS		0x0002
+
+/*MFS V1/V2 superblock data on disk*/
+struct mfs_superblock {
+	/*Total number of inodes on the device*/
+	uint16_t	s_ninodes;
+	/*Total number of zones on the device*/
+	uint16_t	s_nzones;
+	/*Number of inode bitmap blocks*/
+	uint16_t	s_ibmap_blocks;
+	/*Number of zone bitmap blocks*/
+	uint16_t	s_zbmap_blocks;
+	/*First data zone on device*/
+	uint16_t	s_first_data_zone;
+	/*Base 2 logarithm of the zone to block ratio*/
+	uint16_t	s_log2_zone_size;
+	/*Maximum file size expressed in bytes*/
+	uint32_t	s_max_file_size;
+	/*
+	 *Magic number used to recognize MinixFS
+	 *and to detect on-disk endianness
+	 */
+	uint16_t	s_magic;
+	/*Flag used to detect FS errors*/
+	uint16_t	s_state;
+	/*Total number of zones on the device (V2 only)*/
+	uint32_t	s_nzones2;
+} __attribute__ ((packed));
+
+
+/*MFS V3 superblock data on disk*/
+struct mfs3_superblock {
+	/*Total number of inodes on the device*/
+	uint32_t	s_ninodes;
+	uint16_t	s_pad0;
+	/*Number of inode bitmap blocks*/
+	int16_t		s_ibmap_blocks;
+	/*Number of zone bitmap blocks*/
+	int16_t		s_zbmap_blocks;
+	/*First data zone on device*/
+	uint16_t	s_first_data_zone;
+	/*Base 2 logarithm of the zone to block ratio*/
+	int16_t		s_log2_zone_size;
+	int16_t		s_pad1;
+	/*Maximum file size expressed in bytes*/
+	uint32_t	s_max_file_size;
+	/*Total number of zones on the device*/
+	uint32_t	s_nzones;
+	/*
+	 *Magic number used to recognize MinixFS
+	 *and to detect on-disk endianness
+	 */
+	int16_t		s_magic;
+	int16_t		s_pad2;
+	/*Filesystem block size expressed in bytes*/
+	uint16_t	s_block_size;
+	/*Filesystem disk format version*/
+	int8_t		s_disk_version;
+} __attribute__ ((packed));
+
+/*MinixFS V1 inode structure as it is on disk*/
+struct mfs_inode {
+	uint16_t	i_mode;
+	int16_t		i_uid;
+	int32_t		i_size;
+	int32_t		i_mtime;
+	uint8_t		i_gid;
+	uint8_t		i_nlinks;
+	/*Block numbers for direct zones*/
+	uint16_t	i_dzone[V1_NR_DIRECT_ZONES];
+	/*Block numbers for indirect zones*/
+	uint16_t	i_izone[V1_NR_INDIRECT_ZONES];
+} __attribute__ ((packed));
+
+/*MinixFS V2 inode structure as it is on disk (also valid for V3).*/
+struct mfs2_inode {
+	uint16_t 	i_mode;
+	uint16_t 	i_nlinks;
+	int16_t 	i_uid;
+	uint16_t 	i_gid;
+	int32_t 	i_size;
+	int32_t		i_atime;
+	int32_t		i_mtime;
+	int32_t		i_ctime;
+	/*Block numbers for direct zones*/
+	uint32_t	i_dzone[V2_NR_DIRECT_ZONES];
+	/*Block numbers for indirect zones*/
+	uint32_t	i_izone[V2_NR_INDIRECT_ZONES];
+} __attribute__ ((packed));
+
+/*MinixFS V1/V2 directory entry on-disk structure*/
+struct mfs_dentry {
+	uint16_t d_inum;
+	char d_name[0];
+};
+
+/*MinixFS V3 directory entry on-disk structure*/
+struct mfs3_dentry {
+	uint32_t d_inum;
+	char d_name[0];
+};
+
+
+#endif
+
+/**
+ * @}
+ */
+
Index: uspace/srv/fs/minixfs/Makefile
===================================================================
--- uspace/srv/fs/minixfs/Makefile	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/Makefile	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../../..
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBFS_PREFIX)/libfs.a
+EXTRA_CFLAGS += -I$(LIBBLOCK_PREFIX) -I$(LIBFS_PREFIX) -I$(LIBMINIX_PREFIX)
+BINARY = mfs
+
+SOURCES = \
+	mfs.c \
+	mfs_ops.c \
+	mfs_inode.c \
+	mfs_rw.c \
+	mfs_dentry.c \
+	mfs_balloc.c \
+	mfs_utils.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/srv/fs/minixfs/mfs.c
===================================================================
--- uspace/srv/fs/minixfs/mfs.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * Copyright (c) 2008 Jakub Jermar
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+/**
+ * @file	mfs.c
+ * @brief	Minix file system driver for HelenOS.
+ */
+
+#define _MAIN
+
+#include <ipc/services.h>
+#include <ipc/ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <stdio.h>
+#include "mfs.h"
+
+vfs_info_t mfs_vfs_info = {
+	.name = NAME,
+	.concurrent_read_write = false,
+	.write_retains_size = false,	
+};
+
+
+/**
+ * This connection fibril processes VFS requests from VFS.
+ *
+ * In order to support simultaneous VFS requests, our design is as follows.
+ * The connection fibril accepts VFS requests from VFS. If there is only one
+ * instance of the fibril, VFS will need to serialize all VFS requests it sends
+ * to MinixFS. To overcome this bottleneck, VFS can send MinixFS the IPC_M_CONNECT_ME_TO
+ * call. In that case, a new connection fibril will be created, which in turn
+ * will accept the call. Thus, a new phone will be opened for VFS.
+ *
+ * There are few issues with this arrangement. First, VFS can run out of
+ * available phones. In that case, VFS can close some other phones or use one
+ * phone for more serialized requests. Similarily, MinixFS can refuse to duplicate
+ * the connection. VFS should then just make use of already existing phones and
+ * route its requests through them. To avoid paying the fibril creation price 
+ * upon each request, MinixFS might want to keep the connections open after the
+ * request has been completed.
+ */
+
+static void mfs_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	if (iid) {
+		/*
+		 * This only happens for connections opened by
+		 * IPC_M_CONNECT_ME_TO calls as opposed to callback connections
+		 * created by IPC_M_CONNECT_TO_ME.
+		 */
+		async_answer_0(iid, EOK);
+	}
+	
+	printf(NAME ": connection opened\n");
+	while (1) {
+		ipc_callid_t callid;
+		ipc_call_t call;
+	
+		callid = async_get_call(&call);
+		int method = IPC_GET_IMETHOD(call);
+
+		mfsdebug(NAME "method = %d\n", method);
+		switch  (method) {
+		case IPC_M_PHONE_HUNGUP:
+			return;
+		case VFS_OUT_MOUNTED:
+			mfsdebug("Mount request received\n");
+			mfs_mounted(callid, &call);
+			break;
+		case VFS_OUT_MOUNT:
+			mfs_mount(callid, &call);
+			break;
+		case VFS_OUT_STAT:
+			mfs_stat(callid, &call);
+			break;
+		case VFS_OUT_LOOKUP:
+			mfsdebug("lookup called\n");
+			mfs_lookup(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+
+int main(int argc, char **argv)
+{
+	int vfs_phone;
+	int rc;
+
+	printf(NAME ": HelenOS Minix file system server\n");
+
+	vfs_phone = service_connect_blocking(SERVICE_VFS, 0, 0);
+
+	if (vfs_phone < EOK) {
+		printf(NAME ": failed to connect to VFS\n");
+		return -1;
+	}
+
+	rc = fs_register(vfs_phone, &mfs_reg, &mfs_vfs_info, mfs_connection);
+	if (rc != EOK)
+		goto err;
+	
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+	/* not reached */
+	return 0;
+
+err:
+	printf(NAME ": Failed to register file system (%d)\n", rc);
+	return rc;
+}
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs.h
===================================================================
--- uspace/srv/fs/minixfs/mfs.h	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs.h	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */ 
+
+#ifndef _MFS_H_
+#define _MFS_H_
+
+#include <minix.h>
+#include <libblock.h>
+#include <libfs.h>
+#include <adt/list.h>
+#include "../../vfs/vfs.h"
+
+#define NAME		"mfs"
+
+#define DEBUG_MODE
+
+#define min(a, b)	((a) < (b) ? (a) : (b))
+
+#ifdef DEBUG_MODE
+#define mfsdebug(...)	printf(__VA_ARGS__)
+#else
+#define mfsdebug(...)
+#endif
+
+#ifdef _MAIN
+#define GLOBAL
+#else
+#define GLOBAL extern
+#endif
+
+GLOBAL fs_reg_t mfs_reg;
+
+typedef uint32_t bitchunk_t;
+
+typedef enum {
+	BMAP_ZONE,
+	BMAP_INODE
+} bmap_id_t;
+
+typedef enum {
+	MFS_VERSION_V1 = 1,
+	MFS_VERSION_V2,
+	MFS_VERSION_V3
+} mfs_version_t;
+
+/*Generic MinixFS superblock*/
+struct mfs_sb_info {
+	uint32_t ninodes;
+	uint32_t nzones;
+	unsigned long ibmap_blocks;
+	unsigned long zbmap_blocks;
+	unsigned long firstdatazone;
+	int log2_zone_size;
+	int block_size;
+	uint32_t max_file_size;
+	uint16_t magic;
+	uint16_t state;
+
+	/*The following fields do not exist on disk but only in memory*/
+	unsigned long itable_size;
+	mfs_version_t fs_version;
+	int ino_per_block;
+	size_t dirsize;
+	int itable_off;
+	unsigned max_name_len;
+	bool long_names;
+	bool native;
+	unsigned isearch;
+	unsigned zsearch;
+};
+
+/*Generic MinixFS inode*/
+struct mfs_ino_info {
+        uint16_t        i_mode;
+        uint16_t        i_nlinks;
+        int16_t         i_uid;
+        uint16_t        i_gid;
+        int32_t         i_size;
+        int32_t         i_atime;
+        int32_t         i_mtime;
+        int32_t         i_ctime;
+        /*Block numbers for direct zones*/
+        uint32_t        i_dzone[V2_NR_DIRECT_ZONES];
+        /*Block numbers for indirect zones*/
+        uint32_t        i_izone[V2_NR_INDIRECT_ZONES];
+
+	/*The following fields do not exist on disk but only in memory*/
+	bool dirty;
+	fs_index_t index;
+};
+
+/*Generic MFS directory entry*/
+struct mfs_dentry_info {
+	uint32_t d_inum;
+	char d_name[MFS3_MAX_NAME_LEN + 1];
+
+	/*The following fields do not exist on disk but only in memory*/
+
+	/*Index of the dentry in the list*/
+	unsigned index;
+	/*Pointer to the node at witch the dentry belongs*/
+	struct mfs_node *node;
+};
+
+struct mfs_instance {
+	link_t link;
+	devmap_handle_t handle;
+	struct mfs_sb_info *sbi;
+};
+
+/*MinixFS node in core*/
+struct mfs_node {
+	struct mfs_ino_info *ino_i;
+	struct mfs_instance *instance;
+};
+
+/*mfs_ops.c*/
+extern void mfs_mounted(ipc_callid_t rid, ipc_call_t *request);
+extern void mfs_mount(ipc_callid_t rid, ipc_call_t *request);
+extern void mfs_lookup(ipc_callid_t rid, ipc_call_t *request);
+extern int mfs_instance_get(devmap_handle_t handle,
+				struct mfs_instance **instance);
+
+extern void mfs_stat(ipc_callid_t rid, ipc_call_t *request);
+
+/*mfs_inode.c*/
+int
+get_inode(struct mfs_instance *inst, struct mfs_ino_info **ino_i,
+				fs_index_t index);
+
+extern int
+put_inode(struct mfs_node *mnode);
+
+int
+inode_grow(struct mfs_node *mnode, size_t size_grow);
+
+/*mfs_rw.c*/
+extern int
+read_map(uint32_t *b, const struct mfs_node *mnode, const uint32_t pos);
+
+extern int
+write_map(struct mfs_node *mnode, uint32_t pos, uint32_t new_zone,
+				uint32_t *old_zone);
+
+extern int
+free_zone(struct mfs_node *mnode, const uint32_t zone);
+
+/*mfs_dentry.c*/
+extern struct mfs_dentry_info *
+read_directory_entry(struct mfs_node *mnode, unsigned index);
+
+extern int
+write_dentry(struct mfs_dentry_info *d_info);
+
+int
+insert_dentry(struct mfs_node *mnode, char *d_name, fs_index_t d_inum);
+
+/*mfs_balloc.c*/
+extern int
+mfs_alloc_bit(struct mfs_instance *inst, uint32_t *idx, bmap_id_t bid);
+
+extern int
+mfs_free_bit(struct mfs_instance *inst, uint32_t idx, bmap_id_t bid);
+
+#endif
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs_balloc.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_balloc.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs_balloc.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include "mfs.h"
+#include "mfs_utils.h"
+
+static int
+find_free_bit_and_set(bitchunk_t *b, const int bsize,
+				const bool native, unsigned start_bit);
+
+int
+mfs_free_bit(struct mfs_instance *inst, uint32_t idx, bmap_id_t bid)
+{
+	struct mfs_sb_info *sbi;
+	int r;
+	unsigned start_block;
+	block_t *b;
+
+	assert(inst != NULL);
+	sbi = inst->sbi;
+	assert(sbi != NULL);
+
+	if (bid == BMAP_ZONE) {
+		start_block = 2 + sbi->ibmap_blocks;
+		if (idx > sbi->nzones) {
+			printf(NAME ": Error! Trying to free beyond the" \
+					"bitmap max size\n");
+			return -1;
+		}
+	} else {
+		/*bid == BMAP_INODE*/
+		start_block = 2;
+		if (idx > sbi->ninodes) {
+			printf(NAME ": Error! Trying to free beyond the" \
+					"bitmap max size\n");
+			return -1;
+		}
+	}
+
+	/*Compute the bitmap block*/
+	uint32_t block = idx / (sbi->block_size * 8) + start_block;
+
+	r = block_get(&b, inst->handle, block, BLOCK_FLAGS_NONE);
+	if (r != EOK)
+		goto out_err;
+
+	/*Compute the bit index in the block*/
+	idx %= (sbi->block_size * 8);
+	bitchunk_t *ptr = b->data;
+	bitchunk_t chunk;
+	const size_t chunk_bits = sizeof(bitchunk_t) * 8;
+
+	chunk = conv32(sbi->native, ptr[idx / chunk_bits]);
+	chunk &= ~(1 << (idx % chunk_bits));
+	ptr[idx / chunk_bits] = conv32(sbi->native, chunk);
+	b->dirty = true;
+	r = EOK;
+	block_put(b);
+
+out_err:
+	return r;
+}
+
+int
+mfs_alloc_bit(struct mfs_instance *inst, uint32_t *idx, bmap_id_t bid)
+{
+	struct mfs_sb_info *sbi;
+	uint32_t limit;
+	unsigned long nblocks;
+	unsigned *search, i, start_block;
+	unsigned bits_per_block;
+	int r, freebit;
+
+	assert(inst != NULL);
+	sbi = inst->sbi;
+	assert(sbi != NULL);
+
+	if (bid == BMAP_ZONE) {
+		search = &sbi->zsearch;
+		start_block = 2 + sbi->ibmap_blocks;
+		nblocks = sbi->zbmap_blocks;
+		limit = sbi->nzones;
+	} else {
+		/*bid == BMAP_INODE*/
+		search = &sbi->isearch;
+		start_block = 2;
+		nblocks = sbi->ibmap_blocks;
+		limit = sbi->ninodes;
+	}
+	bits_per_block = sbi->block_size * 8;
+
+	block_t *b;
+
+retry:
+
+	for (i = *search / bits_per_block; i < nblocks; ++i) {
+		r = block_get(&b, inst->handle, i + start_block,
+				BLOCK_FLAGS_NONE);
+
+		if (r != EOK)
+			goto out;
+
+		freebit = find_free_bit_and_set(b->data, sbi->block_size,
+						sbi->native, *search);
+		if (freebit == -1) {
+			/*No free bit in this block*/
+			block_put(b);
+			continue;
+		}
+
+		/*Free bit found in this block, compute the real index*/
+		*idx = (freebit + bits_per_block * i);
+		if (*idx > limit) {
+			/*Index is beyond the limit, it is invalid*/
+			block_put(b);
+			break;
+		}
+
+		*search = *idx;
+		b->dirty = true;
+		block_put(b);
+		goto found;
+	}
+
+	if (*search > 0) {
+		/*Repeat the search from the first bitmap block*/
+		*search = 0;
+		goto retry;
+	}
+
+	/*Free bit not found, return error*/
+	return ENOSPC;
+
+found:
+	r = EOK;
+
+out:
+	return r;
+}
+
+static int
+find_free_bit_and_set(bitchunk_t *b, const int bsize,
+				const bool native, unsigned start_bit)
+{
+	int r = -1;
+	unsigned i, j;
+	bitchunk_t chunk;
+	const size_t chunk_bits = sizeof(bitchunk_t) * 8;
+
+	for (i = start_bit; i < bsize / sizeof(uint32_t); ++i) {
+		if (~b[i]) {
+			/*No free bit in this chunk*/
+			continue;
+		}
+
+		chunk = conv32(native, b[i]);
+
+		for (j = 0; j < chunk_bits; ++j) {
+			if (chunk & (1 << j)) {
+				r = i * chunk_bits + j;
+				chunk |= 1 << j;
+				b[i] = conv32(native, chunk);
+				goto found;
+			}
+		}
+	}
+found:
+	return r;
+}
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs_dentry.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_dentry.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs_dentry.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include "mfs.h"
+#include "mfs_utils.h"
+
+struct mfs_dentry_info *
+read_directory_entry(struct mfs_node *mnode, unsigned index)
+{
+	const struct mfs_instance *inst = mnode->instance;
+	const struct mfs_sb_info *sbi = inst->sbi;
+	const bool longnames = sbi->long_names;
+	uint32_t block;
+	block_t *b;
+
+	struct mfs_dentry_info *d_info = malloc(sizeof(*d_info));
+
+	if (!d_info)
+		return NULL;
+
+	int r = read_map(&block, mnode, index * sbi->dirsize);
+	if (r != EOK || block == 0)
+		goto out_err;
+
+	r = block_get(&b, inst->handle, block, BLOCK_FLAGS_NONE);
+	if (r != EOK)
+		goto out_err;
+
+	unsigned dentries_per_zone = sbi->block_size / sbi->dirsize;
+	unsigned dentry_off = index % (dentries_per_zone - 1);
+
+	if (sbi->fs_version == MFS_VERSION_V3) {
+		struct mfs3_dentry *d3;
+
+		d3 = b->data;
+		d3 += dentry_off;
+		d_info->d_inum = conv32(sbi->native, d3->d_inum);
+		memcpy(d_info->d_name, d3->d_name, MFS3_MAX_NAME_LEN);
+	} else {
+		const int namelen = longnames ? MFS_L_MAX_NAME_LEN :
+					MFS_MAX_NAME_LEN;
+
+		struct mfs_dentry *d;
+
+		d = b->data;
+		d += dentry_off;
+		d_info->d_inum = conv16(sbi->native, d->d_inum);
+		memcpy(d_info->d_name, d->d_name, namelen);
+	}
+
+	block_put(b);
+
+	d_info->index = index;
+	d_info->node = mnode;
+	return d_info;
+
+out_err:
+	free(d_info);
+	return NULL;
+}
+
+int
+write_dentry(struct mfs_dentry_info *d_info)
+{
+	struct mfs_node *mnode = d_info->node;
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	const unsigned d_off_bytes = d_info->index * sbi->dirsize;
+	const unsigned dirs_per_block = sbi->block_size / sbi->dirsize;
+	block_t *b;
+	uint32_t block;
+	int r;
+
+	r = read_map(&block, mnode, d_off_bytes);
+	if (r != EOK)
+		goto out;
+
+	r = block_get(&b, mnode->instance->handle, block, BLOCK_FLAGS_NONE);
+	if (r != EOK)
+		goto out;
+
+	const size_t name_len = sbi->max_name_len;
+	uint8_t *ptr = b->data;
+	ptr += (d_info->index % dirs_per_block) * sbi->dirsize;
+
+	if (sbi->fs_version == MFS_VERSION_V3) {
+		struct mfs3_dentry *dentry;
+		dentry = (struct mfs3_dentry *) ptr;
+
+		dentry->d_inum = conv32(sbi->native, d_info->d_inum);
+		memcpy(dentry->d_name, d_info->d_name, name_len);
+	} else {
+		struct mfs_dentry *dentry;
+		dentry = (struct mfs_dentry *) ptr;
+
+		dentry->d_inum = conv16(sbi->native, d_info->d_inum);
+		memcpy(dentry->d_name, d_info->d_name, name_len);
+	}
+
+	b->dirty = true;
+	block_put(b);
+
+out:
+	return r;
+}
+
+int
+insert_dentry(struct mfs_node *mnode, char *d_name, fs_index_t d_inum)
+{
+	int i, r;
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	struct mfs_dentry_info *d_info;
+	bool empty_dentry_found = false;
+
+	const size_t name_len = str_size(d_name);
+
+	assert(name_len <= sbi->max_name_len);
+
+	/*Search for an empty dentry*/
+
+	for (i = 2; ; ++i) {
+		d_info = read_directory_entry(mnode, i);
+
+		if (!d_info) {
+			/*Reached the end of the dentries list*/
+			break;
+		}
+
+		if (d_info->d_inum == 0) {
+			/*This entry is not used*/
+			empty_dentry_found = true;
+			break;
+		}
+		free(d_info);
+	}
+
+	if (!empty_dentry_found) {
+		r = inode_grow(mnode, sbi->dirsize);
+		if (r != EOK)
+			return r;
+
+		d_info = read_directory_entry(mnode, i);
+		if (!d_info)
+			return EIO;
+	}
+
+	d_info->d_inum = d_inum;
+	memcpy(d_info->d_name, d_name, name_len);
+	d_info->d_name[name_len] = 0;
+
+	return  write_dentry(d_info);
+}
+
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs_inode.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_inode.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs_inode.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <mem.h>
+#include "mfs.h"
+#include "mfs_utils.h"
+
+static int
+mfs_write_inode_raw(struct mfs_node *mnode);
+
+static int
+mfs2_write_inode_raw(struct mfs_node *mnode);
+
+static struct mfs_ino_info *
+mfs_read_inode_raw(const struct mfs_instance *instance, uint16_t inum);
+
+static struct mfs_ino_info *
+mfs2_read_inode_raw(const struct mfs_instance *instance, uint32_t inum);
+
+
+int
+get_inode(struct mfs_instance *inst, struct mfs_ino_info **ino_i,
+				fs_index_t index)
+{
+	struct mfs_sb_info *sbi = inst->sbi;
+
+	if (sbi->fs_version == MFS_VERSION_V1) {
+		/*Read a MFS V1 inode*/
+		*ino_i = mfs_read_inode_raw(inst, index);
+	} else {
+		/*Read a MFS V2/V3 inode*/
+		*ino_i = mfs2_read_inode_raw(inst, index);
+	}
+
+	if (*ino_i == NULL)
+		return -1;
+
+	return EOK;
+}
+
+static struct mfs_ino_info *
+mfs_read_inode_raw(const struct mfs_instance *instance, uint16_t inum)
+{
+	struct mfs_inode *ino = NULL;
+	struct mfs_ino_info *ino_i = NULL;
+	struct mfs_sb_info *sbi;
+	block_t *b;
+	int i;
+
+	sbi = instance->sbi;
+	assert(sbi);
+	
+	const int ino_off = inum % sbi->ino_per_block;
+	const size_t ino_size = sizeof(struct mfs_inode);
+
+	ino_i = malloc(sizeof(*ino_i));
+	ino = malloc(ino_size);
+
+	if (!ino || !ino_i)
+		goto out_err;
+
+	const int itable_off = sbi->itable_off;
+
+	if (block_get(&b, instance->handle,
+			itable_off + inum / sbi->ino_per_block,
+			BLOCK_FLAGS_NONE) != EOK)
+		goto out_err;
+
+	memcpy(ino, ((uint8_t *) b->data) + ino_off * ino_size, ino_size);
+
+	ino_i->i_mode = conv16(sbi->native, ino->i_mode);
+	ino_i->i_uid = conv16(sbi->native, ino->i_uid);
+	ino_i->i_size = conv32(sbi->native, ino->i_size);
+	ino_i->i_mtime = conv32(sbi->native, ino->i_mtime);
+	ino_i->i_nlinks = ino->i_nlinks;
+
+	for (i = 0; i < V1_NR_DIRECT_ZONES; ++i)
+		ino_i->i_dzone[i] = conv16(sbi->native, ino->i_dzone[i]);
+
+	for (i = 0; i < V1_NR_INDIRECT_ZONES; ++i)
+		ino_i->i_izone[i] = conv16(sbi->native, ino->i_izone[i]);
+
+	block_put(b);
+	free(ino);
+	ino_i->dirty = false;
+
+	return ino_i;
+
+out_err:
+	if (ino)
+		free(ino);
+	if (ino_i)
+		free(ino_i);
+	return NULL;
+}
+
+static struct mfs_ino_info *
+mfs2_read_inode_raw(const struct mfs_instance *instance, uint32_t inum)
+{
+	struct mfs2_inode *ino = NULL;
+	struct mfs_ino_info *ino_i = NULL;
+	struct mfs_sb_info *sbi;
+	block_t *b;
+	int i;
+
+	const size_t ino_size = sizeof(struct mfs2_inode);
+
+	ino = malloc(ino_size);
+	ino_i = malloc(sizeof(*ino_i));
+
+	if (!ino || !ino_i)
+		goto out_err;
+
+	sbi = instance->sbi;
+	assert(sbi);
+
+	const int itable_off = sbi->itable_off;
+	const int ino_off = inum % sbi->ino_per_block;
+
+	if (block_get(&b, instance->handle, 
+		itable_off + inum / sbi->ino_per_block,
+			BLOCK_FLAGS_NONE) != EOK)
+		goto out_err;
+
+	memcpy(ino, ((uint8_t *)b->data) + ino_off * ino_size, ino_size);
+
+	ino_i->i_mode = conv16(sbi->native, ino->i_mode);
+	ino_i->i_nlinks = conv16(sbi->native, ino->i_nlinks);
+	ino_i->i_uid = conv16(sbi->native, ino->i_uid);
+	ino_i->i_gid = conv16(sbi->native, ino->i_gid);
+	ino_i->i_size = conv32(sbi->native, ino->i_size);
+	ino_i->i_atime = conv32(sbi->native, ino->i_atime);
+	ino_i->i_mtime = conv32(sbi->native, ino->i_mtime);
+	ino_i->i_ctime = conv32(sbi->native, ino->i_ctime);
+
+	for (i = 0; i < V2_NR_DIRECT_ZONES; ++i)
+		ino_i->i_dzone[i] = conv32(sbi->native, ino->i_dzone[i]);
+
+	for (i = 0; i < V2_NR_INDIRECT_ZONES; ++i)
+		ino_i->i_izone[i] = conv32(sbi->native, ino->i_izone[i]);
+
+	block_put(b);
+	free(ino);
+	ino_i->dirty = false;
+
+	return ino_i;
+
+out_err:
+	if (ino)
+		free(ino);
+	if (ino_i)
+		free(ino_i);
+	return NULL;
+}
+
+int
+put_inode(struct mfs_node *mnode)
+{
+	int rc = EOK;
+
+	assert(mnode);
+	assert(mnode->ino_i);
+
+	if (!mnode->ino_i->dirty)
+		goto out;
+
+	struct mfs_instance *inst = mnode->instance;
+	assert(inst);
+	struct mfs_sb_info *sbi = inst->sbi;
+	assert(sbi);
+
+	if (sbi->fs_version == MFS_VERSION_V1)
+		rc = mfs_write_inode_raw(mnode);
+	else
+		rc = mfs2_write_inode_raw(mnode);
+
+out:
+	return rc;
+}
+
+static int
+mfs_write_inode_raw(struct mfs_node *mnode)
+{
+	int i, r;
+	block_t *b;
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+
+	const int itable_off = sbi->itable_off;
+	const int ino_off = ino_i->index % sbi->ino_per_block;
+	const bool native = sbi->native;
+
+	r = block_get(&b, mnode->instance->handle,
+				itable_off + ino_i->index / sbi->ino_per_block,
+				BLOCK_FLAGS_NONE);
+
+	if (r != EOK)
+		goto out;
+
+	struct mfs_inode *ino = b->data;
+	ino += ino_off;
+
+	ino->i_mode = conv16(native, ino_i->i_mode);
+	ino->i_uid = conv16(native, ino_i->i_uid);
+	ino->i_gid = ino_i->i_gid;
+	ino->i_nlinks = ino_i->i_nlinks;
+	ino->i_size = conv32(native, ino_i->i_size);
+	ino->i_mtime = conv32(native, ino_i->i_mtime);
+
+	for (i = 0; i < V1_NR_DIRECT_ZONES; ++i)
+		ino->i_dzone[i] = conv16(native, ino_i->i_dzone[i]);
+	for (i = 0; i < V1_NR_INDIRECT_ZONES; ++i)
+		ino->i_izone[i] = conv16(native, ino_i->i_izone[i]);
+
+	b->dirty = true;
+	block_put(b);
+
+	ino_i->dirty = false;
+out:
+	return r;
+}
+
+static int
+mfs2_write_inode_raw(struct mfs_node *mnode)
+{
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	block_t *b;
+	int i, r;
+
+	const int itable_off = sbi->itable_off;
+	const int ino_off = ino_i->index % sbi->ino_per_block;
+	const bool native = sbi->native;
+	
+	r = block_get(&b, mnode->instance->handle,
+				itable_off + ino_i->index / sbi->ino_per_block,
+				BLOCK_FLAGS_NONE);
+
+	if (r != EOK)
+		goto out;
+
+	struct mfs2_inode *ino2 = b->data;
+	ino2 += ino_off;
+
+	ino2->i_mode = conv16(native, ino_i->i_mode);
+	ino2->i_nlinks = conv16(native, ino_i->i_mode);
+	ino2->i_uid = conv16(native, ino_i->i_uid);
+	ino2->i_gid = conv16(native, ino_i->i_gid);
+	ino2->i_size = conv32(native, ino_i->i_size);	
+	ino2->i_atime = conv32(native, ino_i->i_atime);
+	ino2->i_mtime = conv32(native, ino_i->i_mtime);
+	ino2->i_ctime = conv32(native, ino_i->i_ctime);
+
+	for (i = 0; i < V2_NR_DIRECT_ZONES; ++i)
+		ino2->i_dzone[i] = conv32(native, ino_i->i_dzone[i]);
+
+	for (i = 0; i < V2_NR_INDIRECT_ZONES; ++i)
+		ino2->i_izone[i] = conv32(native, ino_i->i_izone[i]);
+
+	b->dirty = true;
+	block_put(b);
+	ino_i->dirty = false;
+
+out:
+	return r;
+}
+
+int
+inode_grow(struct mfs_node *mnode, size_t size_grow)
+{
+	unsigned i;
+
+	if (size_grow == 0)
+		return EOK;
+
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+	const int bs = sbi->block_size;
+
+	const uint32_t old_size = ino_i->i_size;
+	const uint32_t new_size = old_size + size_grow;
+
+	/*Compute the number of zones to add to the inode*/
+	unsigned zones_to_add = 0;
+	if ((old_size % (bs - 1)) == 0)
+		zones_to_add++;
+
+	zones_to_add += (new_size - old_size) / bs;
+
+	/*Compute the start zone*/
+	unsigned start_zone = old_size / bs;
+	start_zone += (old_size % bs) != 0;
+
+	int r;
+	for (i = 0; i < zones_to_add; ++i) {
+		uint32_t new_zone;
+		uint32_t dummy;
+
+		r = mfs_alloc_bit(mnode->instance, &new_zone, BMAP_ZONE);
+		if (r != EOK)
+			return r;
+
+		r = write_map(mnode, (start_zone + i) * sbi->block_size,
+				new_zone, &dummy);
+		if (r != EOK)
+			return r;
+
+		ino_i->i_size += bs;
+		ino_i->dirty = true;
+	}
+	return EOK;
+}
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_ops.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs_ops.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <fibril_synch.h>
+#include <errno.h>
+#include "mfs.h"
+#include "mfs_utils.h"
+
+static bool check_magic_number(uint16_t magic, bool *native,
+				mfs_version_t *version, bool *longfilenames);
+static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
+			fs_index_t index);
+
+static int mfs_node_put(fs_node_t *fsnode);
+static int mfs_node_open(fs_node_t *fsnode);
+static fs_index_t mfs_index_get(fs_node_t *fsnode);
+static unsigned mfs_lnkcnt_get(fs_node_t *fsnode);
+static char mfs_plb_get_char(unsigned pos);
+static bool mfs_is_directory(fs_node_t *fsnode);
+static bool mfs_is_file(fs_node_t *fsnode);
+static int mfs_has_children(bool *has_children, fs_node_t *fsnode);
+static int mfs_root_get(fs_node_t **rfn, devmap_handle_t handle);
+static devmap_handle_t mfs_device_get(fs_node_t *fsnode);
+static aoff64_t mfs_size_get(fs_node_t *node);
+static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component);
+static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags);
+static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name);
+
+static
+int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
+			fs_index_t index);
+
+
+static LIST_INITIALIZE(inst_list);
+static FIBRIL_MUTEX_INITIALIZE(inst_list_mutex);
+
+libfs_ops_t mfs_libfs_ops = {
+	.size_get = mfs_size_get,
+	.root_get = mfs_root_get,
+	.device_get = mfs_device_get,
+	.is_directory = mfs_is_directory,
+	.is_file = mfs_is_file,
+	.node_get = mfs_node_get,
+	.node_put = mfs_node_put,
+	.node_open = mfs_node_open,
+	.index_get = mfs_index_get,
+	.match = mfs_match,
+	.create = mfs_create_node,
+	.link = mfs_link,
+	.plb_get_char = mfs_plb_get_char,
+	.has_children = mfs_has_children,
+	.lnkcnt_get = mfs_lnkcnt_get
+};
+
+void mfs_mounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap_handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	enum cache_mode cmode;	
+	struct mfs_superblock *sb;
+	struct mfs3_superblock *sb3;
+	struct mfs_sb_info *sbi;
+	struct mfs_instance *instance;
+	bool native, longnames;
+	mfs_version_t version;
+	uint16_t magic;
+
+	/* Accept the mount options */
+	char *opts;
+	int rc = async_data_write_accept((void **) &opts, true, 0, 0, 0, NULL);
+	
+	if (rc != EOK) {
+		mfsdebug("Can't accept async data write\n");
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	/* Check for option enabling write through. */
+	if (str_cmp(opts, "wtcache") == 0)
+		cmode = CACHE_MODE_WT;
+	else
+		cmode = CACHE_MODE_WB;
+
+	free(opts);
+
+	/* initialize libblock */
+	rc = block_init(devmap_handle, 1024);
+	if (rc != EOK) {
+		mfsdebug("libblock initialization failed\n");
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	/*Allocate space for generic MFS superblock*/
+	sbi = malloc(sizeof(*sbi));
+
+	if (!sbi) {
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+
+	/*Allocate space for filesystem instance*/
+	instance = malloc(sizeof(*instance));
+
+	if (!instance) {
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+
+	sb = malloc(MFS_SUPERBLOCK_SIZE);
+
+	if (!sb) {
+		async_answer_0(rid, ENOMEM);
+		return;
+	}
+
+	/* Read the superblock */
+	rc = block_read_direct(devmap_handle, MFS_SUPERBLOCK << 1, 1, sb);
+	if (rc != EOK) {
+		block_fini(devmap_handle);
+		async_answer_0(rid, rc);
+		return;
+	}
+
+	sb3 = (struct mfs3_superblock *) sb;
+
+	if (check_magic_number(sb->s_magic, &native, &version, &longnames)) {
+		/*This is a V1 or V2 Minix filesystem*/
+		magic = sb->s_magic;
+		goto recognized;
+	}
+
+	if (!check_magic_number(sb3->s_magic, &native, &version, &longnames)) {
+		mfsdebug("magic number not recognized\n");
+		block_fini(devmap_handle);
+		async_answer_0(rid, ENOTSUP);
+		return;
+	}
+
+	/*This is a V3 Minix filesystem*/
+
+	magic = sb3->s_magic;
+
+recognized:
+
+	mfsdebug("magic number recognized = %04x\n", magic);
+
+	/*Fill superblock info structure*/
+
+	sbi->fs_version = version;
+	sbi->long_names = longnames;
+	sbi->native = native;
+	sbi->magic = magic;
+	sbi->isearch = 0;
+	sbi->zsearch = 0;
+
+	if (version == MFS_VERSION_V3) {
+		sbi->ninodes = conv32(native, sb3->s_ninodes);
+		sbi->ibmap_blocks = conv16(native, sb3->s_ibmap_blocks);
+		sbi->zbmap_blocks = conv16(native, sb3->s_zbmap_blocks);
+		sbi->firstdatazone = conv16(native, sb3->s_first_data_zone);
+		sbi->log2_zone_size = conv16(native, sb3->s_log2_zone_size);
+		sbi->max_file_size = conv32(native, sb3->s_max_file_size);
+		sbi->nzones = conv32(native, sb3->s_nzones);
+		sbi->block_size = conv16(native, sb3->s_block_size);
+		sbi->ino_per_block = V3_INODES_PER_BLOCK(sbi->block_size);
+		sbi->dirsize = MFS3_DIRSIZE;
+		sbi->max_name_len = MFS3_MAX_NAME_LEN;
+	} else {
+		sbi->ninodes = conv16(native, sb->s_ninodes);
+		sbi->ibmap_blocks = conv16(native, sb->s_ibmap_blocks);
+		sbi->zbmap_blocks = conv16(native, sb->s_zbmap_blocks);
+		sbi->firstdatazone = conv16(native, sb->s_first_data_zone);
+		sbi->log2_zone_size = conv16(native, sb->s_log2_zone_size);
+		sbi->max_file_size = conv32(native, sb->s_max_file_size);
+		sbi->nzones = conv16(native, sb->s_nzones);
+		sbi->block_size = MFS_BLOCKSIZE;
+		sbi->ino_per_block = V1_INODES_PER_BLOCK;
+		if (version == MFS_VERSION_V2)
+			sbi->nzones = conv32(native, sb->s_nzones2);
+		sbi->dirsize = longnames ? MFSL_DIRSIZE : MFS_DIRSIZE;
+		sbi->max_name_len = longnames ? MFS_L_MAX_NAME_LEN :
+				MFS_MAX_NAME_LEN;
+	}
+	sbi->itable_off = 2 + sbi->ibmap_blocks + sbi->zbmap_blocks;
+ 
+	free(sb);
+
+	rc = block_cache_init(devmap_handle, sbi->block_size, 0, cmode);
+
+	if (rc != EOK) {
+		block_fini(devmap_handle);
+		async_answer_0(rid, EINVAL);
+		mfsdebug("block cache initialization failed\n");
+		return;
+	}
+
+	/*Initialize the instance structure and add it to the list*/
+	link_initialize(&instance->link);
+	instance->handle = devmap_handle;
+	instance->sbi = sbi;
+
+	fibril_mutex_lock(&inst_list_mutex);
+	list_append(&instance->link, &inst_list);
+	fibril_mutex_unlock(&inst_list_mutex);
+
+	mfsdebug("mount successful\n");
+
+	async_answer_0(rid, EOK);
+}
+
+void mfs_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_mount(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
+}
+
+devmap_handle_t mfs_device_get(fs_node_t *fsnode)
+{
+	struct mfs_node *node = fsnode->data;
+	return node->instance->handle;
+}
+
+static int mfs_create_node(fs_node_t **rfn, devmap_handle_t handle, int flags)
+{
+	int r;
+	struct mfs_instance *inst;
+	struct mfs_node *mnode;
+	fs_node_t *fsnode;
+	uint32_t inum;
+	
+	mfsdebug("create_node()\n");
+
+	r = mfs_instance_get(handle, &inst);
+	if (r != EOK)
+		return r;
+
+	if (flags & L_DIRECTORY) {
+		/*Not yet supported*/
+		return ENOTSUP;
+	}
+
+	/*Alloc a new inode*/
+	r = mfs_alloc_bit(inst, &inum, BMAP_INODE);
+	if (r != EOK)
+		return r;
+
+	struct mfs_ino_info *ino_i;
+
+	ino_i = malloc(sizeof(*ino_i));
+	if (!ino_i) {
+		r = ENOMEM;
+		goto out_err;
+	}
+
+	mnode = malloc(sizeof(*mnode));
+	if (!mnode) {
+		r = ENOMEM;
+		goto out_err_1;
+	}
+	
+	fsnode = malloc(sizeof(fs_node_t));
+	if (!fsnode) {
+		r = ENOMEM;
+		goto out_err_2;
+	}
+
+	ino_i->i_mode = S_IFREG;
+	ino_i->i_nlinks = 1;
+	ino_i->i_uid = 0;
+	ino_i->i_gid = 0;
+	ino_i->i_size = 0;
+	ino_i->i_atime = 0;
+	ino_i->i_mtime = 0;
+	ino_i->i_ctime = 0;
+
+	memset(ino_i->i_dzone, 0, sizeof(uint32_t) * V2_NR_DIRECT_ZONES);
+	memset(ino_i->i_izone, 0, sizeof(uint32_t) * V2_NR_INDIRECT_ZONES);
+
+	ino_i->index = inum;
+	ino_i->dirty = true;
+	mnode->ino_i = ino_i;
+	mnode->instance = inst;
+
+	put_inode(mnode);
+
+	fs_node_initialize(fsnode);
+	fsnode->data = mnode;
+	*rfn = fsnode;
+
+	return EOK;
+
+out_err_2:
+	free(mnode);
+out_err_1:
+	free(ino_i);
+out_err:
+	return r;
+}
+
+static int mfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
+{
+	struct mfs_node *mnode = pfn->data;
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+	struct mfs_dentry_info *d_info;
+
+	if (!S_ISDIR(ino_i->i_mode))
+		return ENOTDIR;
+
+	mfsdebug("mfs_match()\n");
+
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	const size_t comp_size = str_size(component);
+
+	int i = 2;
+	while (1) {
+		d_info = read_directory_entry(mnode, i++);
+		if (!d_info) {
+			/*Reached the end of the directory entry list*/
+			break;
+		}
+
+		if (!d_info->d_inum) {
+			/*This entry is not used*/
+			free(d_info);
+			continue;
+		}
+
+		if (!bcmp(component, d_info->d_name, min(sbi->max_name_len,
+				comp_size))) {
+			/*Hit!*/
+			mfs_node_core_get(rfn, mnode->instance,
+				d_info->d_inum);
+			free(d_info);
+			goto found;
+		}
+		free(d_info);
+	}
+	*rfn = NULL;
+	return ENOENT;
+found:
+	return EOK;
+}
+
+static aoff64_t mfs_size_get(fs_node_t *node)
+{
+	assert(node);
+
+	const struct mfs_node *mnode = node->data;
+	assert(mnode);
+	assert(mnode->ino_i);
+
+	mfsdebug("inode size is %d\n", (int) mnode->ino_i->i_size);
+
+	return mnode->ino_i->i_size;
+}
+
+void mfs_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	mfsdebug("mfs_stat()\n");
+	libfs_stat(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
+}
+
+static int mfs_node_get(fs_node_t **rfn, devmap_handle_t devmap_handle,
+			fs_index_t index)
+{
+	int rc;
+	struct mfs_instance *instance;
+
+	mfsdebug("mfs_node_get()\n");
+
+	rc = mfs_instance_get(devmap_handle, &instance);
+
+	if (rc != EOK)
+		return rc;
+
+	return mfs_node_core_get(rfn, instance, index);
+}
+
+static int mfs_node_put(fs_node_t *fsnode)
+{
+	struct mfs_node *mnode = fsnode->data;
+
+	mfsdebug("mfs_node_put()\n");
+
+	put_inode(mnode);
+	free(mnode->ino_i);
+	free(mnode);
+
+	return EOK;
+}
+
+static int mfs_node_open(fs_node_t *fsnode)
+{
+	/*
+	 * Opening a file is stateless, nothing
+	 * to be done here.
+	 */
+	return EOK;
+}
+
+static fs_index_t mfs_index_get(fs_node_t *fsnode)
+{
+	struct mfs_node *mnode = fsnode->data;
+
+	mfsdebug("mfs_index_get()\n");
+
+	assert(mnode->ino_i);
+	return mnode->ino_i->index;
+}
+
+static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
+{
+	unsigned rc;
+	struct mfs_node *mnode = fsnode->data;
+
+	assert(mnode);
+	assert(mnode->ino_i);
+
+	rc = mnode->ino_i->i_nlinks;
+	mfsdebug("mfs_lnkcnt_get(): %u\n", rc);
+	return rc;
+}
+
+static int mfs_node_core_get(fs_node_t **rfn, struct mfs_instance *inst,
+			fs_index_t index)
+{
+	fs_node_t *node = NULL;
+	struct mfs_node *mnode = NULL;
+	int rc;
+
+	node = malloc(sizeof(fs_node_t));
+	if (!node) {
+		rc = ENOMEM;
+		goto out_err;
+	}
+
+	fs_node_initialize(node);
+
+	mnode = malloc(sizeof(*mnode));
+	if (!mnode) {
+		rc = ENOMEM;
+		goto out_err;
+	}
+
+	struct mfs_ino_info *ino_i;
+
+	rc = get_inode(inst, &ino_i, index);
+	if (rc != EOK)
+		goto out_err;
+
+	ino_i->index = index;
+	mnode->ino_i = ino_i;
+
+	mnode->instance = inst;
+	node->data = mnode;
+	*rfn = node;
+
+	mfsdebug("node_get_core(%d) OK\n", (int) index);
+
+	return EOK;
+
+out_err:
+	if (node)
+		free(node);
+	if (mnode)
+		free(mnode);
+	return rc;
+}
+
+static bool mfs_is_directory(fs_node_t *fsnode)
+{
+	const struct mfs_node *node = fsnode->data;
+	return S_ISDIR(node->ino_i->i_mode);
+}
+
+static bool mfs_is_file(fs_node_t *fsnode)
+{
+	struct mfs_node *node = fsnode->data;
+	return S_ISREG(node->ino_i->i_mode);
+}
+
+static int mfs_root_get(fs_node_t **rfn, devmap_handle_t handle)
+{
+	int rc = mfs_node_get(rfn, handle, MFS_ROOT_INO);
+
+	mfsdebug("mfs_root_get %s\n", rc == EOK ? "OK" : "FAIL");
+	return rc;
+}
+
+void mfs_lookup(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_lookup(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
+}
+
+static char mfs_plb_get_char(unsigned pos)
+{
+	return mfs_reg.plb_ro[pos % PLB_SIZE];
+}
+
+static int mfs_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	mfsdebug("mfs_link()\n");
+	return ENOTSUP;
+}
+
+static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
+{
+	struct mfs_node *mnode = fsnode->data;
+
+	*has_children = false;
+
+	if (!S_ISDIR(mnode->ino_i->i_mode))
+		goto out;
+
+	struct mfs_dentry_info *d_info;
+	
+	/* The first two dentries are always . and .. */
+	int i = 2;
+	while (1) {
+		d_info = read_directory_entry(mnode, i++);
+
+		if (!d_info) {
+			/*Reached the end of the dentries list*/
+			break;
+		}
+
+		if (d_info->d_inum) {
+			/*A valid entry has been found*/
+			*has_children = true;
+			free(d_info);
+			break;
+		}
+
+		free(d_info);
+	}
+
+out:
+
+	if (*has_children)
+		mfsdebug("Has children\n");
+	else
+		mfsdebug("Has not children\n");
+
+	return EOK;
+}
+
+/*
+ * Find a filesystem instance given the devmap handle
+ */
+int mfs_instance_get(devmap_handle_t handle, struct mfs_instance **instance)
+{
+	link_t *link;
+	struct mfs_instance *instance_ptr;
+
+	fibril_mutex_lock(&inst_list_mutex);
+
+	for (link = inst_list.next; link != &inst_list; link = link->next) {
+		instance_ptr = list_get_instance(link, struct mfs_instance,
+				link);
+		
+		if (instance_ptr->handle == handle) {
+			*instance = instance_ptr;
+			fibril_mutex_unlock(&inst_list_mutex);
+			return EOK;
+		}
+	}
+
+	mfsdebug("Instance not found\n");
+
+	fibril_mutex_unlock(&inst_list_mutex);
+	return EINVAL;
+}
+
+static bool check_magic_number(uint16_t magic, bool *native,
+				mfs_version_t *version, bool *longfilenames)
+{
+	bool rc = false;
+	*longfilenames = false;
+
+	if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
+		*native = magic == MFS_MAGIC_V1;
+		*version = MFS_VERSION_V1;
+		rc = true;
+	} else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
+		*native = magic == MFS_MAGIC_V1L;
+		*version = MFS_VERSION_V1;
+		*longfilenames = true;
+		rc = true;
+	} else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
+		*native = magic == MFS_MAGIC_V2;
+		*version = MFS_VERSION_V2;
+		rc = true;
+	} else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
+		*native = magic == MFS_MAGIC_V2L;
+		*version = MFS_VERSION_V2;
+		*longfilenames = true;
+		rc = true;
+	} else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
+		*native = magic == MFS_MAGIC_V3;
+		*version = MFS_VERSION_V3;
+		rc = true;
+	}
+
+	return rc;
+}
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs_rw.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_rw.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs_rw.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,340 @@
+/*
+g
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include "mfs.h"
+#include "mfs_utils.h"
+
+static int
+rw_map_ondisk(uint32_t *b, const struct mfs_node *mnode, int rblock,
+				bool write_mode, uint32_t w_block);
+
+static int
+reset_zone_content(struct mfs_instance *inst, uint32_t zone);
+
+static int
+alloc_zone_and_clear(struct mfs_instance *inst, uint32_t *zone);
+
+static int
+read_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t **ind_zone);
+
+static int
+write_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t *ind_zone);
+
+
+/**Given the position in the file expressed in
+ *bytes, this function returns the on-disk block
+ *relative to that position.
+ *Returns zero if the block does not exist.
+ */
+int
+read_map(uint32_t *b, const struct mfs_node *mnode, uint32_t pos)
+{
+	int r;
+	const struct mfs_sb_info *sbi = mnode->instance->sbi;
+	const int block_size = sbi->block_size;
+
+	/*Compute relative block number in file*/
+	int rblock = pos / block_size;
+
+	if (mnode->ino_i->i_size < (int32_t) pos) {
+		/*Trying to read beyond the end of file*/
+		r = EOK;
+		*b = 0;
+		goto out;
+	}
+
+	r = rw_map_ondisk(b, mnode, rblock, false, 0);
+out:
+	return r;
+}
+
+int
+write_map(struct mfs_node *mnode, const uint32_t pos, uint32_t new_zone, 
+				uint32_t *old_zone)
+{
+	const struct mfs_sb_info *sbi = mnode->instance->sbi;
+	const int block_size = sbi->block_size;
+
+	/*Compute the relative block number in file*/
+	int rblock = pos / block_size;
+
+	return rw_map_ondisk(old_zone, mnode, rblock, true, new_zone);
+}
+
+int
+free_zone(struct mfs_node *mnode, const uint32_t zone)
+{
+	int r;
+	uint32_t old_zone;
+
+	r = rw_map_ondisk(&old_zone, mnode, zone, true, 0);
+	if (r != EOK)
+		return r;
+
+	if (old_zone > 0)
+		r = mfs_free_bit(mnode->instance, old_zone, BMAP_ZONE);
+
+	return r;
+}
+
+static int
+rw_map_ondisk(uint32_t *b, const struct mfs_node *mnode, int rblock,
+				bool write_mode, uint32_t w_block)
+{
+	int r, nr_direct;
+	int ptrs_per_block;
+	uint32_t *ind_zone, *ind2_zone;
+
+	assert(mnode);
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+
+	assert(ino_i);
+	assert(mnode->instance);
+
+	struct mfs_instance *inst = mnode->instance;
+	struct mfs_sb_info *sbi = inst->sbi;
+	assert(sbi);
+
+	const mfs_version_t fs_version = sbi->fs_version;
+
+	if (fs_version == MFS_VERSION_V1) {
+		nr_direct = V1_NR_DIRECT_ZONES;
+		ptrs_per_block = MFS_BLOCKSIZE / sizeof(uint16_t);
+	} else {
+		nr_direct = V2_NR_DIRECT_ZONES;
+		ptrs_per_block = sbi->block_size / sizeof(uint32_t);
+	}
+
+	/*Check if the wanted block is in the direct zones*/
+	if (rblock < nr_direct) {
+		*b = ino_i->i_dzone[rblock];
+		if (write_mode) {
+			ino_i->i_dzone[rblock] = w_block;
+			ino_i->dirty = true;
+		}
+		return EOK;
+	}
+	rblock -= nr_direct - 1;
+
+	if (rblock < ptrs_per_block) {
+		/*The wanted block is in the single indirect zone chain*/
+		if (ino_i->i_izone[0] == 0) {
+			if (write_mode) {
+				uint32_t zone;
+				r = alloc_zone_and_clear(inst, &zone);
+				if (r != EOK)
+					return r;
+
+				ino_i->i_izone[0] = zone;
+				ino_i->dirty = true;
+			} else
+				return -1;
+		}
+
+		r = read_ind_zone(inst, ino_i->i_izone[0], &ind_zone);
+		if (r != EOK)
+			return r;
+
+		*b = ind_zone[rblock];
+		if (write_mode) {
+			ind_zone[rblock] = w_block;
+			write_ind_zone(inst, ino_i->i_izone[0], ind_zone);
+		}
+
+		goto out_free_ind1;
+	}
+
+	rblock -= ptrs_per_block - 1;
+
+	/*The wanted block is in the double indirect zone chain*/
+
+	/*read the first indirect zone of the chain*/
+	if (ino_i->i_izone[1] == 0) {
+		if (write_mode) {
+			uint32_t zone;
+			r = alloc_zone_and_clear(inst, &zone);
+			if (r != EOK)
+				return r;
+
+			ino_i->i_izone[1] = zone;
+			ino_i->dirty = true;
+		} else
+			return -1;
+	}
+
+	r = read_ind_zone(inst, ino_i->i_izone[1], &ind_zone);
+	if (r != EOK)
+		return r;
+
+	/*
+	 *Compute the position of the second indirect
+	 *zone pointer in the chain.
+	 */
+	uint32_t ind2_off = rblock / ptrs_per_block;
+
+	/*read the second indirect zone of the chain*/
+	if (ind_zone[ind2_off] == 0) {
+		if (write_mode) {
+			uint32_t zone;
+			r = alloc_zone_and_clear(inst, &zone);
+			if(r != EOK)
+				goto out_free_ind1;
+			ind_zone[ind2_off] = zone;
+			write_ind_zone(inst, ino_i->i_izone[1], ind_zone);
+		} else {
+			r = -1;
+			goto out_free_ind1;
+		}
+	}
+
+	r = read_ind_zone(inst, ind_zone[ind2_off], &ind2_zone);
+	if (r != EOK)
+		goto out_free_ind1;
+
+	*b = ind2_zone[ind2_off % ptrs_per_block];
+	if (write_mode) {
+		ind2_zone[ind2_off % ptrs_per_block] = w_block;
+		write_ind_zone(inst, ind_zone[ind2_off], ind2_zone);
+	}
+
+	r = EOK;
+
+	free(ind2_zone);
+out_free_ind1:
+	free(ind_zone);
+	return r;
+}
+
+
+static int
+reset_zone_content(struct mfs_instance *inst, uint32_t zone)
+{
+	block_t *b;
+	int r;
+
+	r = block_get(&b, inst->handle, zone, BLOCK_FLAGS_NOREAD);
+	if (r != EOK)
+		return r;
+
+	memset(b->data, 0, b->size);
+	b->dirty = true;
+	block_put(b);
+
+	return EOK;
+}
+
+static int
+alloc_zone_and_clear(struct mfs_instance *inst, uint32_t *zone)
+{
+	int r;
+
+	r = mfs_alloc_bit(inst, zone, BMAP_ZONE);
+	if (r != EOK)
+		goto out;
+
+	r = reset_zone_content(inst, *zone);
+out:
+	return r;
+}
+
+static int
+read_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t **ind_zone)
+{
+	struct mfs_sb_info *sbi = inst->sbi;
+	int r;
+	unsigned i;
+	block_t *b;
+
+	*ind_zone = malloc(sbi->block_size);
+	if (*ind_zone == NULL)
+		return ENOMEM;
+
+	r = block_get(&b, inst->handle, zone, BLOCK_FLAGS_NONE);
+	if (r != EOK) {
+		free(*ind_zone);
+		return r;
+	}
+
+	if (sbi->fs_version == MFS_VERSION_V1) {
+		uint16_t *src_ptr = b->data;
+
+		for (i = 0; i < sbi->block_size / sizeof(uint16_t); ++i)
+			(*ind_zone)[i] = conv16(sbi->native, src_ptr[i]);
+	} else {
+		uint32_t *src_ptr = b->data;
+
+		for (i = 0; i < sbi->block_size / sizeof(uint32_t); ++i)
+			(*ind_zone)[i] = conv32(sbi->native, src_ptr[i]);
+	}
+
+	block_put(b);
+	
+	return EOK;
+}
+
+static int
+write_ind_zone(struct mfs_instance *inst, uint32_t zone, uint32_t *ind_zone)
+{
+	struct mfs_sb_info *sbi = inst->sbi;
+	int r;
+	unsigned i;
+	block_t *b;
+
+	r = block_get(&b, inst->handle, zone, BLOCK_FLAGS_NONE);
+	if (r != EOK)
+		return r;
+
+	if (sbi->fs_version == MFS_VERSION_V1) {
+		uint16_t *dest_ptr = b->data;
+
+		for (i = 0; i < sbi->block_size / sizeof(uint16_t); ++i)
+			dest_ptr[i] = conv16(sbi->native, ind_zone[i]);
+	} else {
+		uint32_t *dest_ptr = b->data;
+
+		for (i = 0; i < sbi->block_size / sizeof(uint32_t); ++i)
+			dest_ptr[i] = conv32(sbi->native, ind_zone[i]);
+
+	}
+	b->dirty = true;
+	block_put(b);
+	return EOK;
+}
+
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs_utils.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_utils.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs_utils.c	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#include <byteorder.h>
+#include <assert.h>
+#include <errno.h>
+#include "mfs.h"
+#include "mfs_utils.h"
+
+uint16_t conv16(bool native, uint16_t n)
+{
+	if (native)
+		return n;
+
+	return uint16_t_byteorder_swap(n);
+}
+
+uint32_t conv32(bool native, uint32_t n)
+{
+	if (native)
+		return n;
+
+	return uint32_t_byteorder_swap(n);
+}
+
+uint64_t conv64(bool native, uint64_t n)
+{
+	if (native)
+		return n;
+
+	return uint64_t_byteorder_swap(n);
+}
+
+/**
+ * @}
+ */ 
+
Index: uspace/srv/fs/minixfs/mfs_utils.h
===================================================================
--- uspace/srv/fs/minixfs/mfs_utils.h	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
+++ uspace/srv/fs/minixfs/mfs_utils.h	(revision 969d88e9150467ef7c5e378c3ad4045fc2a63851)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Maurizio Lombardi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup fs
+ * @{
+ */
+
+#ifndef _MFS_UTILS_H_
+#define _MFS_UTILS_H_
+
+#include <sys/types.h>
+#include <bool.h>
+#include "mfs.h"
+
+extern uint16_t
+conv16(bool native, uint16_t n);
+
+extern uint32_t
+conv32(bool native, uint32_t n);
+
+extern uint64_t
+conv64(bool native, uint64_t n);
+
+#endif
+
+/**
+ * @}
+ */ 
+
