Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision deac215ea66a4a2ddb5875cf4489fe576060ec0d)
+++ boot/Makefile.common	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -102,4 +102,5 @@
 	$(USPACE_PATH)/srv/fs/tmpfs/tmpfs \
 	$(USPACE_PATH)/srv/fs/fat/fat \
+	$(USPACE_PATH)/srv/fs/minixfs/mfs \
 	$(USPACE_PATH)/srv/fs/exfat/exfat \
 	$(USPACE_PATH)/srv/fs/ext2fs/ext2fs \
@@ -154,4 +155,5 @@
 	$(USPACE_PATH)/app/locinfo/locinfo \
 	$(USPACE_PATH)/app/mkfat/mkfat \
+	$(USPACE_PATH)/app/mkminix/mkminix \
 	$(USPACE_PATH)/app/lsusb/lsusb \
 	$(USPACE_PATH)/app/sbi/sbi \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision deac215ea66a4a2ddb5875cf4489fe576060ec0d)
+++ uspace/Makefile	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -48,4 +48,5 @@
 	app/lsusb \
 	app/mkfat \
+	app/mkminix \
 	app/redir \
 	app/sbi \
@@ -82,4 +83,5 @@
 	srv/fs/fat \
 	srv/fs/tmpfs \
+	srv/fs/minixfs \
 	srv/fs/locfs \
 	srv/fs/ext2fs \
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision deac215ea66a4a2ddb5875cf4489fe576060ec0d)
+++ uspace/Makefile.common	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -121,5 +121,5 @@
 LIBPACKET_PREFIX = $(LIB_PREFIX)/packet
 LIBNET_PREFIX = $(LIB_PREFIX)/net
-
+LIBMINIX_PREFIX = $(LIB_PREFIX)/minix
 LIBSCSI_PREFIX = $(LIB_PREFIX)/scsi
 
Index: uspace/app/mkminix/Makefile
===================================================================
--- uspace/app/mkminix/Makefile	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/app/mkminix/Makefile	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -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 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/app/mkminix/mkminix.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,730 @@
+/*
+ * 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' },
+		{ 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(EXCHANGE_SERIALIZE, 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;
+}
+
+/**Inserts the '.' and '..' directory entries in the root directory.
+ *
+ * @param sb		Pointer to the superblock structure.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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;
+}
+
+/**Initialize the inode table.
+ *
+ * @param sb		Pointer to the superblock structure.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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;
+}
+
+/**Initialize a V1 root inode.
+ *
+ * @param sb		Ponter to the superblock structure.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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 - 1].i_mode = S_IFDIR;
+	ino_buf[MFS_ROOT_INO - 1].i_uid = 0;
+	ino_buf[MFS_ROOT_INO - 1].i_gid = 0;
+	ino_buf[MFS_ROOT_INO - 1].i_size = (sb->longnames ? MFSL_DIRSIZE :
+	MFS_DIRSIZE) * 2;
+	ino_buf[MFS_ROOT_INO - 1].i_mtime = sec;
+	ino_buf[MFS_ROOT_INO - 1].i_nlinks = 2;
+	ino_buf[MFS_ROOT_INO - 1].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.
+ *
+ * @param sb		Pointer to the superblock structure.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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 - 1].i_mode = S_IFDIR;
+	ino_buf[MFS_ROOT_INO - 1].i_uid = 0;
+	ino_buf[MFS_ROOT_INO - 1].i_gid = 0;
+	ino_buf[MFS_ROOT_INO - 1].i_size = MFS3_DIRSIZE * 2;
+	ino_buf[MFS_ROOT_INO - 1].i_mtime = sec;
+	ino_buf[MFS_ROOT_INO - 1].i_atime = sec;
+	ino_buf[MFS_ROOT_INO - 1].i_ctime = sec;
+	ino_buf[MFS_ROOT_INO - 1].i_nlinks = 2;
+	ino_buf[MFS_ROOT_INO - 1].i_dzone[0] = sb->first_data_zone;
+
+	rc = write_block(itable_off, 1, ino_buf);
+
+	free(ino_buf);
+	return rc;
+}
+
+/**Initialize the superblock structure on disk.
+ *
+ * @param sb		Pointer to the superblock structure.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+static int init_superblock(struct mfs_sb_info *sb)
+{
+	aoff64_t inodes;
+	unsigned long ind;
+	unsigned long ind2;
+	unsigned long zones;
+	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;
+		ind = MFS_BLOCKSIZE / sizeof(uint16_t);
+		ind2 = ind * ind;
+		sb->max_file_size = (V1_NR_DIRECT_ZONES + ind + ind2) * MFS_BLOCKSIZE;
+	} else {
+		/*Valid for MFS V2/V3*/
+		size_t ptrsize;
+		if (sb->fs_version == 2)
+			ptrsize = sizeof(uint16_t);
+		else
+			ptrsize = sizeof(uint32_t);
+		ind = sb->block_size / ptrsize;
+		ind2 = ind * ind;
+		zones = V2_NR_DIRECT_ZONES + ind + ind2;
+		sb->max_file_size = zones * sb->block_size;
+		sb->n_zones = sb->dev_nblocks > UINT32_MAX ?
+				UINT32_MAX : sb->dev_nblocks;
+
+		if (sb->fs_version == 3) {
+			if(INT32_MAX / sb->block_size < zones)
+				sb->max_file_size = INT32_MAX;
+			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 block size\n", sb->block_size);
+	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 ": max file size = %u\n", sb->max_file_size);
+	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;
+}
+
+/**Write the V1/V2 superblock on disk.
+ *
+ * @param sbi		Pointer to the superblock structure to write on disk.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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 = sbi->max_file_size;
+	sb->s_magic = sbi->magic;
+	sb->s_state = MFS_VALID_FS;
+
+	rc = write_block(MFS_SUPERBLOCK, 1, sb);
+	free(sb);
+
+	return rc;
+}
+
+/**Write the V3s superblock on disk.
+ *
+ * @param sbi		Pointer to the superblock structure to write on disk.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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 = sbi->max_file_size;
+	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;
+}
+
+/**Initialize the inode and block bitmaps on disk.
+ *
+ * @param sb		Pointer to the superblock structure.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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 + 1; ++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;
+}
+
+/**Mark a bitmap entry as used or free.
+ *
+ * @param bmap		32-bit pointer to the bitmap in memory.
+ * @param idx		The index in the bitmap of the bit to set at 1 or 0.
+ * @param v		FREE to clear the bit, USED to set the bit.
+ */
+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);
+}
+
+/**Write a block on disk.
+ *
+ * @param off		64-bit block offset on disk.
+ * @param size		size of the block.
+ * @param data		Pointer to the block content.
+ *
+ * @return		EOK on success or a negative error number.
+ */
+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"
+				"-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/drv/bus/usb/usbhid/kbd.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/drv/bus/usb/usbhid/kbd.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,5 @@
+/*
+ * Dummy file because of shared layout sources.
+ *
+ * Do not delete.
+ */
Index: uspace/drv/bus/usb/usbhid/kbd/layout.h
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/layout.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/drv/bus/usb/usbhid/kbd/layout.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,1 @@
+../layout.h
Index: uspace/drv/bus/usb/usbhid/kbd/main.c
===================================================================
--- uspace/drv/bus/usb/usbhid/kbd/main.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/drv/bus/usb/usbhid/kbd/main.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2010 Vojtech Horky
+ * Copyright (c) 2011 Lubos Slovak
+ * 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 drvusbhid
+ * @{
+ */
+/**
+ * @file
+ * Main routines of USB KBD driver.
+ */
+
+#include <ddf/driver.h>
+#include <usb/debug.h>
+#include <errno.h>
+#include <str_error.h>
+
+#include <usb/dev/driver.h>
+
+#include "kbddev.h"
+#include "kbdrepeat.h"
+
+/*----------------------------------------------------------------------------*/
+
+#define NAME "usbkbd"
+
+/**
+ * Function for adding a new device of type USB/HID/keyboard.
+ *
+ * This functions initializes required structures from the device's descriptors
+ * and starts new fibril for polling the keyboard for events and another one for
+ * handling auto-repeat of keys.
+ *
+ * During initialization, the keyboard is switched into boot protocol, the idle
+ * rate is set to 0 (infinity), resulting in the keyboard only reporting event
+ * when a key is pressed or released. Finally, the LED lights are turned on 
+ * according to the default setup of lock keys.
+ *
+ * @note By default, the keyboards is initialized with Num Lock turned on and 
+ *       other locks turned off.
+ * @note Currently supports only boot-protocol keyboards.
+ *
+ * @param dev Device to add.
+ *
+ * @retval EOK if successful.
+ * @retval ENOMEM if there
+ * @return Other error code inherited from one of functions usb_kbd_init(),
+ *         ddf_fun_bind() and ddf_fun_add_to_class().
+ *
+ * @sa usb_kbd_fibril(), usb_kbd_repeat_fibril()
+ */
+static int usb_kbd_try_add_device(usb_device_t *dev)
+{
+	/* Create the function exposed under /dev/devices. */
+	ddf_fun_t *kbd_fun = ddf_fun_create(dev->ddf_dev, fun_exposed, 
+	    "keyboard");
+	if (kbd_fun == NULL) {
+		usb_log_error("Could not create DDF function node.\n");
+		return ENOMEM;
+	}
+	
+	/* 
+	 * Initialize device (get and process descriptors, get address, etc.)
+	 */
+	usb_log_debug("Initializing USB/HID KBD device...\n");
+	
+	usb_kbd_t *kbd_dev = usb_kbd_new();
+	if (kbd_dev == NULL) {
+		usb_log_error("Error while creating USB/HID KBD device "
+		    "structure.\n");
+		ddf_fun_destroy(kbd_fun);
+		return ENOMEM;  // TODO: some other code??
+	}
+	
+	int rc = usb_kbd_init(kbd_dev, dev);
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to initialize USB/HID KBD device.\n");
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}	
+	
+	usb_log_debug("USB/HID KBD device structure initialized.\n");
+	
+	/*
+	 * Store the initialized keyboard device and keyboard ops
+	 * to the DDF function.
+	 */
+	kbd_fun->driver_data = kbd_dev;
+	kbd_fun->ops = &keyboard_ops;
+
+	rc = ddf_fun_bind(kbd_fun);
+	if (rc != EOK) {
+		usb_log_error("Could not bind DDF function: %s.\n",
+		    str_error(rc));
+		// TODO: Can / should I destroy the DDF function?
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	rc = ddf_fun_add_to_class(kbd_fun, "keyboard");
+	if (rc != EOK) {
+		usb_log_error(
+		    "Could not add DDF function to class 'keyboard': %s.\n",
+		    str_error(rc));
+		ddf_fun_destroy(kbd_fun);
+		usb_kbd_free(&kbd_dev);
+		return rc;
+	}
+	
+	/* Start automated polling function.
+	 * This will create a separate fibril that will query the device
+	 * for the data continuously 
+	 */
+       rc = usb_device_auto_poll(dev,
+	   /* Index of the polling pipe. */
+	   USB_KBD_POLL_EP_NO,
+	   /* Callback when data arrives. */
+	   usb_kbd_polling_callback,
+	   /* How much data to request. */
+	   dev->pipes[USB_KBD_POLL_EP_NO].pipe->max_packet_size,
+	   /* Callback when the polling ends. */
+	   usb_kbd_polling_ended_callback,
+	   /* Custom argument. */
+	   kbd_dev);
+	
+	
+	if (rc != EOK) {
+		usb_log_error("Failed to start polling fibril for `%s'.\n",
+		    dev->ddf_dev->name);
+		return rc;
+	}
+	
+	/*
+	 * Create new fibril for auto-repeat
+	 */
+	fid_t fid = fibril_create(usb_kbd_repeat_fibril, kbd_dev);
+	if (fid == 0) {
+		usb_log_error("Failed to start fibril for KBD auto-repeat");
+		return ENOMEM;
+	}
+	fibril_add_ready(fid);
+
+	(void)keyboard_ops;
+
+	/*
+	 * Hurrah, device is initialized.
+	 */
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+/**
+ * Callback for passing a new device to the driver.
+ *
+ * @note Currently, only boot-protocol keyboards are supported by this driver.
+ *
+ * @param dev Structure representing the new device.
+ *
+ * @retval EOK if successful. 
+ * @retval EREFUSED if the device is not supported.
+ */
+static int usb_kbd_add_device(usb_device_t *dev)
+{
+	usb_log_debug("usb_kbd_add_device()\n");
+	
+	if (dev->interface_no < 0) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add USB KBD device: endpoint not "
+		    "found.\n");
+		return ENOTSUP;
+	}
+	
+	int rc = usb_kbd_try_add_device(dev);
+	
+	if (rc != EOK) {
+		usb_log_warning("Device is not a supported keyboard.\n");
+		usb_log_error("Failed to add KBD device: %s.\n",
+		    str_error(rc));
+		return rc;
+	}
+	
+	usb_log_info("Keyboard `%s' ready to use.\n", dev->ddf_dev->name);
+
+	return EOK;
+}
+
+/*----------------------------------------------------------------------------*/
+
+/* Currently, the framework supports only device adding. Once the framework
+ * supports unplug, more callbacks will be added. */
+static usb_driver_ops_t usb_kbd_driver_ops = {
+        .add_device = usb_kbd_add_device,
+};
+
+
+/* The driver itself. */
+static usb_driver_t usb_kbd_driver = {
+        .name = NAME,
+        .ops = &usb_kbd_driver_ops,
+        .endpoints = usb_kbd_endpoints
+};
+
+/*----------------------------------------------------------------------------*/
+
+int main(int argc, char *argv[])
+{
+	printf(NAME ": HelenOS USB KBD driver.\n");
+
+	usb_log_enable(USB_LOG_LEVEL_DEBUG, NAME);
+
+	return usb_driver_main(&usb_kbd_driver);
+}
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbhid/layout.h
===================================================================
--- uspace/drv/bus/usb/usbhid/layout.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/drv/bus/usb/usbhid/layout.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * Copyright (c) 2011 Lubos Slovak 
+ * (copied from /uspace/srv/hid/kbd/include/layout.h)
+ * 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 drvusbhid
+ * @{
+ */
+/** @file
+ * Keyboard layout.
+ */
+
+#ifndef USB_HID_LAYOUT_H_
+#define USB_HID_LAYOUT_H_
+
+#include <sys/types.h>
+#include <io/console.h>
+
+typedef struct {
+	void (*reset)(void);
+	wchar_t (*parse_ev)(kbd_event_t *);
+} layout_op_t;
+
+extern layout_op_t us_qwerty_op;
+extern layout_op_t us_dvorak_op;
+extern layout_op_t cz_op;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/drv/bus/usb/usbmast/scsi.h
===================================================================
--- uspace/drv/bus/usb/usbmast/scsi.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/drv/bus/usb/usbmast/scsi.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011 Vojtech Horky
+ * 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 drvusbmast
+ * @{
+ */
+/** @file
+ * SCSI related structures.
+ */
+
+#ifndef USB_USBMAST_SCSI_H_
+#define USB_USBMAST_SCSI_H_
+
+#include <sys/types.h>
+#include <usb/usb.h>
+
+typedef struct {
+	uint8_t op_code;
+	uint8_t lun_evpd;
+	uint8_t page_code;
+	uint16_t alloc_length;
+	uint8_t ctrl;
+} __attribute__((packed)) scsi_cmd_inquiry_t;
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/lib/minix/minix.h
===================================================================
--- uspace/lib/minix/minix.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/lib/minix/minix.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -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 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/Makefile	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -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 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,183 @@
+/*
+ * 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 <ns.h>
+#include <async.h>
+#include <errno.h>
+#include <unistd.h>
+#include <task.h>
+#include <stdio.h>
+#include <libfs.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);
+	}
+
+	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 VFS_OUT_MOUNTED:
+			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:
+			mfs_lookup(callid, &call);
+			break;
+		case VFS_OUT_READ:
+			mfs_read(callid, &call);
+			break;
+		case VFS_OUT_OPEN_NODE:
+			mfs_open_node(callid, &call);
+			break;
+		case VFS_OUT_CLOSE:
+			mfs_close(callid, &call);
+			break;
+		case VFS_OUT_WRITE:
+			mfs_write(callid, &call);
+			break;
+		case VFS_OUT_TRUNCATE:
+			mfs_truncate(callid, &call);
+			break;
+		case VFS_OUT_DESTROY:
+			mfs_destroy(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNTED:
+			mfs_unmounted(callid, &call);
+			break;
+		case VFS_OUT_UNMOUNT:
+			mfs_unmount(callid, &call);
+			break;
+		case VFS_OUT_SYNC:
+			mfs_sync(callid, &call);
+			break;
+		default:
+			async_answer_0(callid, ENOTSUP);
+			break;
+		}
+	}
+}
+
+
+int main(int argc, char **argv)
+{
+	int rc;
+
+	printf(NAME ": HelenOS Minix file system server\n");
+
+	async_sess_t *vfs_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
+				SERVICE_VFS, 0, 0);
+
+	if (!vfs_sess) {
+		printf(NAME ": failed to connect to VFS\n");
+		return -1;
+	}
+
+	rc = mfs_global_init();
+	if (rc != EOK) {
+		printf(NAME ": Failed global initialization\n");
+		goto err;
+	}
+
+	rc = fs_register(vfs_sess, &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 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,259 @@
+/*
+ * 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 <macros.h>
+#include <libblock.h>
+#include <libfs.h>
+#include <adt/list.h>
+#include <malloc.h>
+#include <mem.h>
+#include <stdio.h>
+#include <errno.h>
+#include <assert.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
+
+#define on_error(r, inst) do {	\
+				if (r != EOK) inst;	\
+			}while(0)
+
+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;
+	size_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;
+	unsigned open_nodes_cnt;
+};
+
+/*MinixFS node in core*/
+struct mfs_node {
+	struct mfs_ino_info *ino_i;
+	struct mfs_instance *instance;
+	unsigned refcnt;
+	fs_node_t *fsnode;
+	link_t link;
+};
+
+/*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);
+extern void mfs_close(ipc_callid_t rid, ipc_call_t *request);
+extern void mfs_open_node(ipc_callid_t rid, ipc_call_t *request);
+
+extern void
+mfs_read(ipc_callid_t rid, ipc_call_t *request);
+
+extern void
+mfs_write(ipc_callid_t rid, ipc_call_t *request);
+
+extern void
+mfs_truncate(ipc_callid_t rid, ipc_call_t *request);
+
+extern void
+mfs_destroy(ipc_callid_t rid, ipc_call_t *request);
+
+extern void
+mfs_unmounted(ipc_callid_t rid, ipc_call_t *request);
+
+extern void
+mfs_unmount(ipc_callid_t rid, ipc_call_t *request);
+
+extern void
+mfs_sync(ipc_callid_t rid, ipc_call_t *request);
+
+extern int
+mfs_global_init(void);
+
+/*mfs_inode.c*/
+extern 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);
+
+extern int
+inode_shrink(struct mfs_node *mnode, size_t size_shrink);
+
+/*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
+prune_ind_zones(struct mfs_node *mnode, size_t new_size);
+
+/*mfs_dentry.c*/
+extern int
+read_dentry(struct mfs_node *mnode,
+		     struct mfs_dentry_info *d_info, unsigned index);
+
+extern int
+write_dentry(struct mfs_dentry_info *d_info);
+
+extern int
+remove_dentry(struct mfs_node *mnode, const char *d_name);
+
+extern int
+insert_dentry(struct mfs_node *mnode, const char *d_name, fs_index_t d_inum);
+
+/*mfs_balloc.c*/
+extern int
+mfs_alloc_inode(struct mfs_instance *inst, uint32_t *inum);
+
+extern int
+mfs_free_inode(struct mfs_instance *inst, uint32_t inum);
+
+extern int
+mfs_alloc_zone(struct mfs_instance *inst, uint32_t *zone);
+
+extern int
+mfs_free_zone(struct mfs_instance *inst, uint32_t zone);
+
+/*mfs_utils.c*/
+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
+
+/**
+ * @}
+ */
+
Index: uspace/srv/fs/minixfs/mfs_balloc.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_balloc.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs_balloc.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,296 @@
+/*
+ * 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 "mfs.h"
+
+static int
+find_free_bit_and_set(bitchunk_t *b, const int bsize,
+		      const bool native, unsigned start_bit);
+
+static int
+mfs_free_bit(struct mfs_instance *inst, uint32_t idx, bmap_id_t bid);
+
+static int
+mfs_alloc_bit(struct mfs_instance *inst, uint32_t *idx, bmap_id_t bid);
+
+/**Allocate a new inode.
+ *
+ * @param inst		Pointer to the filesystem instance.
+ * @param inum		Pointer to a 32 bit number where the index of
+ * 			the new inode will be saved.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
+mfs_alloc_inode(struct mfs_instance *inst, uint32_t *inum)
+{
+	int r = mfs_alloc_bit(inst, inum, BMAP_INODE);
+
+	*inum += 1;
+	return r;
+}
+
+/**Free an inode.
+ *
+ * @param inst		Pointer to the filesystem instance.
+ * @param inum		Number of the inode to free.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
+mfs_free_inode(struct mfs_instance *inst, uint32_t inum)
+{
+	return mfs_free_bit(inst, inum - 1, BMAP_INODE);
+}
+
+/**Allocate a new zone.
+ *
+ * @param inst		Pointer to the filesystem instance.
+ * @param zone		Pointer to a 32 bit number where the index
+ * 			of the zone will be saved.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
+mfs_alloc_zone(struct mfs_instance *inst, uint32_t *zone)
+{
+	int r = mfs_alloc_bit(inst, zone, BMAP_ZONE);
+
+	*zone += inst->sbi->firstdatazone - 1;
+	return r;
+}
+
+/**Free a zone.
+ *
+ * @param inst		Pointer to the filesystem instance.
+ * @param zone		Index of the zone to free.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
+mfs_free_zone(struct mfs_instance *inst, uint32_t zone)
+{
+	zone -= inst->sbi->firstdatazone - 1;
+
+	return mfs_free_bit(inst, zone, BMAP_ZONE);
+}
+
+/**Clear a bit in a bitmap.
+ *
+ * @param inst		Pointer to the filesystem instance.
+ * @param idx		Index of the bit to clear.
+ * @param bid		BMAP_ZONE if operating on the zone's bitmap,
+ * 			BMAP_INODE if operating on the inode's bitmap.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+static 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;
+	unsigned *search;
+	block_t *b;
+
+	assert(inst != NULL);
+	sbi = inst->sbi;
+	assert(sbi != NULL);
+
+	if (bid == BMAP_ZONE) {
+		search = &sbi->zsearch;
+		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*/
+		search = &sbi->isearch;
+		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);
+	on_error(r, 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 = block_put(b);
+
+	if (*search > idx)
+		*search = idx;
+
+out_err:
+	return r;
+}
+
+/**Search a free bit in a bitmap and mark it as used.
+ *
+ * @param inst		Pointer to the filesystem instance.
+ * @param idx		Pointer of a 32 bit number where the index
+ * 			of the found bit will be stored.
+ * @param bid		BMAP_ZONE if operating on the zone's bitmap,
+ * 			BMAP_INODE if operating on the inode's bitmap.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+static 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);
+
+		on_error(r, goto out);
+
+		unsigned tmp = *search % bits_per_block;
+
+		freebit = find_free_bit_and_set(b->data, sbi->block_size,
+						sbi->native, tmp);
+		if (freebit == -1) {
+			/*No free bit in this block*/
+			r = block_put(b);
+			on_error(r, goto out);
+			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*/
+			r = block_put(b);
+			on_error(r, goto out);
+			break;
+		}
+
+		*search = *idx;
+		b->dirty = true;
+		r = block_put(b);
+		goto out;
+	}
+
+	if (*search > 0) {
+		/*Repeat the search from the first bitmap block*/
+		*search = 0;
+		goto retry;
+	}
+
+	/*Free bit not found, return error*/
+	return ENOSPC;
+
+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 / chunk_bits;
+	     i < bsize / sizeof(bitchunk_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 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs_dentry.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,253 @@
+/*
+ * 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 "mfs.h"
+
+/**Read a directory entry from disk.
+ *
+ * @param mnode		Pointer to the directory node.
+ * @param d_info	Pointer to a directory entry structure where the dentry info
+ *			will be stored.
+ * @param index		index of the dentry in the list.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
+read_dentry(struct mfs_node *mnode,
+		     struct mfs_dentry_info *d_info, 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;
+
+	int r = read_map(&block, mnode, index * sbi->dirsize);
+	on_error(r, goto out_err);
+
+	if (block == 0) {
+		/*End of the dentries list*/
+		r = EOK;
+		goto out_err;
+	}
+
+	r = block_get(&b, inst->handle, block, BLOCK_FLAGS_NONE);
+	on_error(r, goto out_err);
+
+	unsigned dentries_per_zone = sbi->block_size / sbi->dirsize;
+	unsigned dentry_off = index % dentries_per_zone;
+
+	if (sbi->fs_version == MFS_VERSION_V3) {
+		struct mfs3_dentry *d3;
+
+		d3 = b->data + (dentry_off * MFS3_DIRSIZE);
+
+		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 + dentry_off * (longnames ? MFSL_DIRSIZE :
+					    MFS_DIRSIZE);
+		d_info->d_inum = conv16(sbi->native, d->d_inum);
+		memcpy(d_info->d_name, d->d_name, namelen);
+	}
+
+	r = block_put(b);
+
+	d_info->index = index;
+	d_info->node = mnode;
+
+out_err:
+	return r;
+}
+
+/**Write a directory entry on disk.
+ *
+ * @param d_info	Pointer to the directory entry structure to write on disk.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+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);
+	on_error(r, goto out);
+
+	r = block_get(&b, mnode->instance->handle, block, BLOCK_FLAGS_NONE);
+	on_error(r, 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;
+	r = block_put(b);
+
+out:
+	return r;
+}
+
+/**Remove a directory entry from a directory.
+ *
+ * @param mnode		Pointer to the directory node.
+ * @param d_name	Name of the directory entry to delete.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
+remove_dentry(struct mfs_node *mnode, const char *d_name)
+{
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	struct mfs_dentry_info d_info;
+	int r;
+
+	const size_t name_len = str_size(d_name);
+
+	if (name_len > sbi->max_name_len)
+		return ENAMETOOLONG;
+
+	/*Search the directory entry to be removed*/
+	unsigned i;
+	for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize ; ++i) {
+		r = read_dentry(mnode, &d_info, i);
+		on_error(r, return r);
+
+		const size_t d_name_len = str_size(d_info.d_name);
+
+		if (name_len == d_name_len &&
+				!bcmp(d_info.d_name, d_name, name_len)) {
+			d_info.d_inum = 0;
+			r = write_dentry(&d_info);
+			return r;
+		}
+	}
+
+	return ENOENT;
+}
+
+/**Insert a new directory entry in a existing directory.
+ *
+ * @param mnode		Pointer to the directory node.
+ * @param d_name	Name of the new directory entry.
+ * @param d_inum	index of the inode that will be pointed by the new dentry.
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
+insert_dentry(struct mfs_node *mnode, const char *d_name, fs_index_t d_inum)
+{
+	int 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);
+
+	if (name_len > sbi->max_name_len)
+		return ENAMETOOLONG;
+
+	/*Search for an empty dentry*/
+	unsigned i;
+	for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
+		r = read_dentry(mnode, &d_info, i);
+		on_error(r, return r);
+
+		if (d_info.d_inum == 0) {
+			/*This entry is not used*/
+			empty_dentry_found = true;
+			break;
+		}
+	}
+
+	if (!empty_dentry_found) {
+		uint32_t b, pos;
+		pos = mnode->ino_i->i_size;
+		r = read_map(&b, mnode, pos);
+		on_error(r, goto out);
+
+		if (b == 0) {
+			/*Increase the inode size*/
+
+			uint32_t dummy;
+			r = mfs_alloc_zone(mnode->instance, &b);
+			on_error(r, goto out);
+			r = write_map(mnode, pos, b, &dummy);
+			on_error(r, goto out);
+		}
+
+		mnode->ino_i->i_size += sbi->dirsize;
+		mnode->ino_i->dirty = true;
+
+		d_info.index = i;
+		d_info.node = mnode;
+	}
+
+	d_info.d_inum = d_inum;
+	memcpy(d_info.d_name, d_name, name_len);
+	d_info.d_name[name_len] = 0;
+
+	r = write_dentry(&d_info);
+out:
+	return r;
+}
+
+
+/**
+ * @}
+ */
+
Index: uspace/srv/fs/minixfs/mfs_inode.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_inode.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs_inode.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,354 @@
+/*
+ * 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 "mfs.h"
+
+static int
+mfs_write_inode_raw(struct mfs_node *mnode);
+
+static int
+mfs2_write_inode_raw(struct mfs_node *mnode);
+
+static int
+mfs_read_inode_raw(const struct mfs_instance *instance,
+		struct mfs_ino_info **ino_ptr, uint16_t inum);
+
+static int
+mfs2_read_inode_raw(const struct mfs_instance *instance,
+		struct mfs_ino_info **ino_ptr, 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;
+	int r;
+
+	if (sbi->fs_version == MFS_VERSION_V1) {
+		/*Read a MFS V1 inode*/
+		r = mfs_read_inode_raw(inst, ino_i, index);
+	} else {
+		/*Read a MFS V2/V3 inode*/
+		r = mfs2_read_inode_raw(inst, ino_i, index);
+	}
+
+	return r;
+}
+
+static int
+mfs_read_inode_raw(const struct mfs_instance *instance,
+		struct mfs_ino_info **ino_ptr, uint16_t inum) {
+	struct mfs_inode *ino;
+	struct mfs_ino_info *ino_i = NULL;
+	struct mfs_sb_info *sbi;
+	block_t *b;
+	int i, r;
+
+	sbi = instance->sbi;
+	assert(sbi);
+
+	/*inode 0 does not exist*/
+	inum -= 1;
+
+	const int ino_off = inum % sbi->ino_per_block;
+
+	ino_i = malloc(sizeof(*ino_i));
+
+	if (!ino_i) {
+		r = ENOMEM;
+		goto out_err;
+	}
+
+	const int itable_off = sbi->itable_off;
+
+	r = block_get(&b, instance->handle,
+		      itable_off + inum / sbi->ino_per_block,
+		      BLOCK_FLAGS_NONE);
+	on_error(r, goto out_err);
+
+	ino = b->data + ino_off * sizeof(struct mfs_inode);
+
+	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]);
+
+	r = block_put(b);
+	ino_i->dirty = false;
+	*ino_ptr = ino_i;
+
+	return r;
+
+out_err:
+	if (ino_i)
+		free(ino_i);
+	return EOK;
+}
+
+static int
+mfs2_read_inode_raw(const struct mfs_instance *instance,
+		struct mfs_ino_info **ino_ptr, uint32_t inum) {
+	struct mfs2_inode *ino;
+	struct mfs_ino_info *ino_i = NULL;
+	struct mfs_sb_info *sbi;
+	block_t *b;
+	int i, r;
+
+	ino_i = malloc(sizeof(*ino_i));
+
+	if (!ino_i) {
+		r = ENOMEM;
+		goto out_err;
+	}
+
+	sbi = instance->sbi;
+	assert(sbi);
+
+	/*inode 0 does not exist*/
+	inum -= 1;
+
+	const int itable_off = sbi->itable_off;
+	const int ino_off = inum % sbi->ino_per_block;
+
+	r = block_get(&b, instance->handle,
+		      itable_off + inum / sbi->ino_per_block,
+		      BLOCK_FLAGS_NONE);
+	on_error(r, goto out_err);
+
+	ino = b->data + ino_off * sizeof(struct mfs2_inode);
+
+	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]);
+
+	r = block_put(b);
+	ino_i->dirty = false;
+	*ino_ptr = ino_i;
+
+	return r;
+
+out_err:
+	if (ino_i)
+		free(ino_i);
+	return EOK;
+}
+
+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 uint32_t inum = ino_i->index - 1;
+	const int itable_off = sbi->itable_off;
+	const int ino_off = inum % sbi->ino_per_block;
+	const bool native = sbi->native;
+
+	r = block_get(&b, mnode->instance->handle,
+		      itable_off + inum / sbi->ino_per_block,
+		      BLOCK_FLAGS_NONE);
+
+	on_error(r, 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;
+	r = 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 uint32_t inum = ino_i->index - 1;
+	const int itable_off = sbi->itable_off;
+	const int ino_off = inum % sbi->ino_per_block;
+	const bool native = sbi->native;
+
+	r = block_get(&b, mnode->instance->handle,
+		      itable_off + inum / sbi->ino_per_block,
+		      BLOCK_FLAGS_NONE);
+
+	on_error(r, 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_nlinks);
+	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;
+	r = block_put(b);
+	ino_i->dirty = false;
+
+out:
+	return r;
+}
+
+int
+inode_shrink(struct mfs_node *mnode, size_t size_shrink)
+{
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+	const size_t bs = sbi->block_size;
+	int r;
+
+	if (size_shrink == 0) {
+		/*File is empty*/
+		return EOK;
+	}
+
+	const size_t old_size = ino_i->i_size;
+	const size_t new_size = ino_i->i_size - size_shrink;
+
+	assert(size_shrink <= old_size);
+
+	ino_i->dirty = true;
+
+	/*Compute the number of zones to free*/
+	unsigned zones_to_free;
+
+	size_t diff = old_size - new_size;
+	zones_to_free = diff / bs;
+
+	if (diff % bs != 0)
+		zones_to_free++;
+
+	uint32_t pos = old_size - 1;
+	unsigned i;
+	for (i = 0; i < zones_to_free; ++i, pos -= bs) {
+		uint32_t old_zone;
+
+		r = write_map(mnode, pos, 0, &old_zone);
+		on_error(r, goto exit_error);
+
+		ino_i->i_size -= bs;
+
+		if (old_zone == 0)
+			continue; /*Sparse block*/
+
+		r = mfs_free_zone(mnode->instance, old_zone);
+		on_error(r, goto exit_error);
+	}
+
+	ino_i->i_size = new_size;
+
+	return prune_ind_zones(mnode, new_size);
+
+exit_error:
+	return r;
+}
+
+/**
+ * @}
+ */
+
Index: uspace/srv/fs/minixfs/mfs_ops.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_ops.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs_ops.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,1158 @@
+/*
+ * 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 <fibril_synch.h>
+#include <align.h>
+#include <adt/hash_table.h>
+#include "mfs.h"
+
+#define OPEN_NODES_KEYS 2
+#define OPEN_NODES_DEV_HANDLE_KEY 0
+#define OPEN_NODES_INODE_KEY 1
+#define OPEN_NODES_BUCKETS 256
+
+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_unlink(fs_node_t *, fs_node_t *, const char *name);
+static int mfs_destroy_node(fs_node_t *fn);
+static hash_index_t open_nodes_hash(unsigned long key[]);
+static int open_nodes_compare(unsigned long key[], hash_count_t keys,
+		link_t *item);
+static void open_nodes_remove_cb(link_t *link);
+
+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);
+static hash_table_t open_nodes;
+static FIBRIL_MUTEX_INITIALIZE(open_nodes_lock);
+
+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,
+	.unlink = mfs_unlink,
+	.destroy = mfs_destroy_node,
+	.plb_get_char = mfs_plb_get_char,
+	.has_children = mfs_has_children,
+	.lnkcnt_get = mfs_lnkcnt_get
+};
+
+/* Hash table interface for open nodes hash table */
+static hash_index_t open_nodes_hash(unsigned long key[])
+{
+	/* TODO: This is very simple and probably can be improved */
+	return key[OPEN_NODES_INODE_KEY] % OPEN_NODES_BUCKETS;
+}
+
+static int open_nodes_compare(unsigned long key[], hash_count_t keys,
+		link_t *item)
+{
+	struct mfs_node *mnode = hash_table_get_instance(item, struct mfs_node, link);
+	assert(keys > 0);
+	if (mnode->instance->handle !=
+	    ((devmap_handle_t) key[OPEN_NODES_DEV_HANDLE_KEY])) {
+		return false;
+	}
+	if (keys == 1) {
+		return true;
+	}
+	assert(keys == 2);
+	return (mnode->ino_i->index == key[OPEN_NODES_INODE_KEY]);
+}
+
+static void open_nodes_remove_cb(link_t *link)
+{
+	/* We don't use remove callback for this hash table */
+}
+
+static hash_table_operations_t open_nodes_ops = {
+	.hash = open_nodes_hash,
+	.compare = open_nodes_compare,
+	.remove_callback = open_nodes_remove_cb,
+};
+
+int mfs_global_init(void)
+{
+	if (!hash_table_create(&open_nodes, OPEN_NODES_BUCKETS,
+			OPEN_NODES_KEYS, &open_nodes_ops)) {
+		return ENOMEM;
+	}
+	return EOK;
+}
+
+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(EXCHANGE_SERIALIZE, 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;
+	}
+
+	instance->open_nodes_cnt = 0;
+
+	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->block_size = MFS_BLOCKSIZE;
+		if (version == MFS_VERSION_V2) {
+			sbi->nzones = conv32(native, sb->s_nzones2);
+			sbi->ino_per_block = V2_INODES_PER_BLOCK;
+		} else {
+			sbi->nzones = conv16(native, sb->s_nzones);
+			sbi->ino_per_block = V1_INODES_PER_BLOCK;
+		}
+		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");
+
+	fs_node_t *fn;
+	mfs_node_get(&fn, devmap_handle, MFS_ROOT_INO);
+
+	struct mfs_node *nroot = fn->data;
+
+	async_answer_3(rid, EOK,
+			MFS_ROOT_INO,
+			0,
+			nroot->ino_i->i_nlinks);
+
+	mfs_node_put(fn);
+}
+
+void mfs_mount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_mount(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
+}
+
+void mfs_unmount(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_unmount(&mfs_libfs_ops, rid, request);
+}
+
+void mfs_unmounted(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap = (devmap_handle_t) IPC_GET_ARG1(*request);
+	struct mfs_instance *inst;
+
+	int r = mfs_instance_get(devmap, &inst);
+	if (r != EOK) {
+		async_answer_0(rid, r);
+		return;
+	}
+
+	if (inst->open_nodes_cnt != 0) {
+		async_answer_0(rid, EBUSY);
+		return;
+	}
+
+	(void) block_cache_fini(devmap);
+	block_fini(devmap);
+
+	/* Remove the instance from the list */
+	fibril_mutex_lock(&inst_list_mutex);
+	list_remove(&inst->link);
+	fibril_mutex_unlock(&inst_list_mutex);
+
+	free(inst->sbi);
+	free(inst);
+
+	async_answer_0(rid, EOK);
+}
+
+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("%s()\n", __FUNCTION__);
+
+	r = mfs_instance_get(handle, &inst);
+	on_error(r, return r);
+
+	/*Alloc a new inode*/
+	r = mfs_alloc_inode(inst, &inum);
+	on_error(r, 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;
+	}
+
+	if (flags & L_DIRECTORY)
+		ino_i->i_mode = S_IFDIR;
+	else
+		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);
+
+	mfsdebug("new node idx = %d\n", (int) inum);
+
+	ino_i->index = inum;
+	ino_i->dirty = true;
+	mnode->ino_i = ino_i;
+	mnode->instance = inst;
+	mnode->refcnt = 1;
+
+	link_initialize(&mnode->link);
+
+	unsigned long key[] = {
+		[OPEN_NODES_DEV_HANDLE_KEY] = inst->handle,
+		[OPEN_NODES_INODE_KEY] = inum,
+	};
+
+	fibril_mutex_lock(&open_nodes_lock);
+	hash_table_insert(&open_nodes, key, &mnode->link);
+	fibril_mutex_unlock(&open_nodes_lock);
+	inst->open_nodes_cnt++;
+
+	mnode->ino_i->dirty = true;
+
+	fs_node_initialize(fsnode);
+	fsnode->data = mnode;
+	mnode->fsnode = fsnode;
+	*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;
+	int r;
+
+	mfsdebug("%s()\n", __FUNCTION__);
+
+	if (!S_ISDIR(ino_i->i_mode))
+		return ENOTDIR;
+
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	const size_t comp_size = str_size(component);
+
+	unsigned i;
+	for (i = 0; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
+		r = read_dentry(mnode, &d_info, i);
+		on_error(r, return r);
+
+		if (!d_info.d_inum) {
+			/*This entry is not used*/
+			continue;
+		}
+
+		const size_t dentry_name_size = str_size(d_info.d_name);
+
+		if (comp_size == dentry_name_size &&
+			!bcmp(component, d_info.d_name, dentry_name_size)) {
+			/*Hit!*/
+			mfs_node_core_get(rfn, mnode->instance,
+					  d_info.d_inum);
+			goto found;
+		}
+	}
+	*rfn = NULL;
+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);
+
+	return mnode->ino_i->i_size;
+}
+
+void mfs_stat(ipc_callid_t rid, ipc_call_t *request)
+{
+	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("%s()\n", __FUNCTION__);
+
+	rc = mfs_instance_get(devmap_handle, &instance);
+	on_error(rc, return rc);
+
+	return mfs_node_core_get(rfn, instance, index);
+}
+
+static int mfs_node_put(fs_node_t *fsnode)
+{
+	int rc = EOK;
+	struct mfs_node *mnode = fsnode->data;
+
+	mfsdebug("%s()\n", __FUNCTION__);
+
+	fibril_mutex_lock(&open_nodes_lock);
+
+	assert(mnode->refcnt > 0);
+	mnode->refcnt--;
+	if (mnode->refcnt == 0) {
+		unsigned long key[] = {
+			[OPEN_NODES_DEV_HANDLE_KEY] = mnode->instance->handle,
+			[OPEN_NODES_INODE_KEY] = mnode->ino_i->index
+		};
+		hash_table_remove(&open_nodes, key, OPEN_NODES_KEYS);
+		assert(mnode->instance->open_nodes_cnt > 0);
+		mnode->instance->open_nodes_cnt--;
+		rc = put_inode(mnode);
+		free(mnode->ino_i);
+		free(mnode);
+		free(fsnode);
+	}
+
+	fibril_mutex_unlock(&open_nodes_lock);
+	return rc;
+}
+
+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;
+
+	assert(mnode->ino_i);
+	return mnode->ino_i->index;
+}
+
+static unsigned mfs_lnkcnt_get(fs_node_t *fsnode)
+{
+	struct mfs_node *mnode = fsnode->data;
+
+	mfsdebug("%s()\n", __FUNCTION__);
+
+	assert(mnode);
+	assert(mnode->ino_i);
+
+	return mnode->ino_i->i_nlinks;
+}
+
+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;
+
+	mfsdebug("%s()\n", __FUNCTION__);
+
+	fibril_mutex_lock(&open_nodes_lock);
+
+	/* Check if the node is not already open */
+	unsigned long key[] = {
+		[OPEN_NODES_DEV_HANDLE_KEY] = inst->handle,
+		[OPEN_NODES_INODE_KEY] = index,
+	};
+	link_t *already_open = hash_table_find(&open_nodes, key);
+
+	if (already_open) {
+		mnode = hash_table_get_instance(already_open, struct mfs_node, link);
+		*rfn = mnode->fsnode;
+		mnode->refcnt++;
+
+		fibril_mutex_unlock(&open_nodes_lock);
+		return EOK;
+	}
+
+	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);
+	on_error(rc, goto out_err);
+
+	ino_i->index = index;
+	mnode->ino_i = ino_i;
+	mnode->refcnt = 1;
+	link_initialize(&mnode->link);
+
+	mnode->instance = inst;
+	node->data = mnode;
+	mnode->fsnode = node;
+	*rfn = node;
+
+	hash_table_insert(&open_nodes, key, &mnode->link);
+	inst->open_nodes_cnt++;
+
+	fibril_mutex_unlock(&open_nodes_lock);
+
+	return EOK;
+
+out_err:
+	if (node)
+		free(node);
+	if (mnode)
+		free(mnode);
+	fibril_mutex_unlock(&open_nodes_lock);
+	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);
+	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)
+{
+	struct mfs_node *parent = pfn->data;
+	struct mfs_node *child = cfn->data;
+	struct mfs_sb_info *sbi = parent->instance->sbi;
+
+	mfsdebug("%s()\n", __FUNCTION__);
+
+	if (str_size(name) > sbi->max_name_len)
+		return ENAMETOOLONG;
+
+	int r = insert_dentry(parent, name, child->ino_i->index);
+	on_error(r, goto exit_error);
+
+	if (S_ISDIR(child->ino_i->i_mode)) {
+		r = insert_dentry(child, ".", child->ino_i->index);
+		on_error(r, goto exit_error);
+		//child->ino_i->i_nlinks++;
+		//child->ino_i->dirty = true;
+		r = insert_dentry(child, "..", parent->ino_i->index);
+		on_error(r, goto exit_error);
+		//parent->ino_i->i_nlinks++;
+		//parent->ino_i->dirty = true;
+	}
+
+exit_error:
+	return r;
+}
+
+static int
+mfs_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	struct mfs_node *parent = pfn->data;
+	struct mfs_node *child = cfn->data;
+	bool has_children;
+	int r;
+
+	mfsdebug("%s()\n", __FUNCTION__);
+
+	if (!parent)
+		return EBUSY;
+
+	r = mfs_has_children(&has_children, cfn);
+	on_error(r, return r);
+
+	if (has_children)
+		return ENOTEMPTY;
+
+	r = remove_dentry(parent, name);
+	on_error(r, return r);
+
+	struct mfs_ino_info *chino = child->ino_i;
+
+	assert(chino->i_nlinks >= 1);
+	--chino->i_nlinks;
+/*
+	if (chino->i_nlinks == 0 && S_ISDIR(chino->i_mode)) {
+		parent->ino_i->i_nlinks--;
+		parent->ino_i->dirty = true;
+	}
+*/
+
+	chino->dirty = true;
+
+	return r;
+}
+
+static int mfs_has_children(bool *has_children, fs_node_t *fsnode)
+{
+	struct mfs_node *mnode = fsnode->data;
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	int r;
+
+	*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 .. */
+	unsigned i;
+	for (i = 2; i < mnode->ino_i->i_size / sbi->dirsize; ++i) {
+		r = read_dentry(mnode, &d_info, i);
+		on_error(r, return r);
+
+		if (d_info.d_inum) {
+			/*A valid entry has been found*/
+			*has_children = true;
+			break;
+		}
+	}
+out:
+
+	return EOK;
+}
+
+void
+mfs_read(ipc_callid_t rid, ipc_call_t *request)
+{
+	int rc;
+	devmap_handle_t handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request),
+					       IPC_GET_ARG4(*request));
+	fs_node_t *fn;
+
+	rc = mfs_node_get(&fn, handle, index);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	if (!fn) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+
+	struct mfs_node *mnode;
+	struct mfs_ino_info *ino_i;
+	size_t len, bytes = 0;
+	ipc_callid_t callid;
+
+	mnode = fn->data;
+	ino_i = mnode->ino_i;
+
+	if (!async_data_read_receive(&callid, &len)) {
+		rc = EINVAL;
+		goto out_error;
+	}
+
+	if (S_ISDIR(ino_i->i_mode)) {
+		aoff64_t spos = pos;
+		struct mfs_dentry_info d_info;
+		struct mfs_sb_info *sbi = mnode->instance->sbi;
+
+		if (pos < 2) {
+			/*Skip the first two dentries ('.' and '..')*/
+			pos = 2;
+		}
+
+		for (; pos < mnode->ino_i->i_size / sbi->dirsize; ++pos) {
+			rc = read_dentry(mnode, &d_info, pos);
+			on_error(rc, goto out_error);
+
+			if (d_info.d_inum) {
+				/*Dentry found!*/
+				goto found;
+			}
+		}
+
+		rc = mfs_node_put(fn);
+		async_answer_0(callid, rc != EOK ? rc : ENOENT);
+		async_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
+		return;
+found:
+		async_data_read_finalize(callid, d_info.d_name,
+					 str_size(d_info.d_name) + 1);
+		bytes = ((pos - spos) + 1);
+	} else {
+		struct mfs_sb_info *sbi = mnode->instance->sbi;
+
+		if (pos >= (size_t) ino_i->i_size) {
+			/*Trying to read beyond the end of file*/
+			bytes = 0;
+			(void) async_data_read_finalize(callid, NULL, 0);
+			goto out_success;
+		}
+
+		bytes = min(len, sbi->block_size - pos % sbi->block_size);
+		bytes = min(bytes, ino_i->i_size - pos);
+
+		uint32_t zone;
+		block_t *b;
+
+		rc = read_map(&zone, mnode, pos);
+		on_error(rc, goto out_error);
+
+		if (zone == 0) {
+			/*sparse file*/
+			uint8_t *buf = malloc(sbi->block_size);
+			if (!buf) {
+				rc = ENOMEM;
+				goto out_error;
+			}
+			memset(buf, 0, sizeof(sbi->block_size));
+			async_data_read_finalize(callid,
+						 buf + pos % sbi->block_size, bytes);
+			free(buf);
+			goto out_success;
+		}
+
+		rc = block_get(&b, handle, zone, BLOCK_FLAGS_NONE);
+		on_error(rc, goto out_error);
+
+		async_data_read_finalize(callid, b->data +
+					 pos % sbi->block_size, bytes);
+
+		rc = block_put(b);
+		if (rc != EOK) {
+			mfs_node_put(fn);
+			async_answer_0(rid, rc);
+			return;
+		}
+	}
+out_success:
+	rc = mfs_node_put(fn);
+	async_answer_1(rid, rc, (sysarg_t)bytes);
+	return;
+out_error:
+	;
+	int tmp = mfs_node_put(fn);
+	async_answer_0(callid, tmp != EOK ? tmp : rc);
+	async_answer_0(rid, tmp != EOK ? tmp : rc);
+}
+
+void
+mfs_write(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t pos = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request),
+					       IPC_GET_ARG4(*request));
+
+	fs_node_t *fn;
+	int r;
+	int flags = BLOCK_FLAGS_NONE;
+
+	r = mfs_node_get(&fn, handle, index);
+	if (r != EOK) {
+		async_answer_0(rid, r);
+		return;
+	}
+
+	if (!fn) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+
+	ipc_callid_t callid;
+	size_t len;
+
+	if (!async_data_write_receive(&callid, &len)) {
+		r = EINVAL;
+		goto out_err;
+	}
+
+	struct mfs_node *mnode = fn->data;
+	struct mfs_sb_info *sbi = mnode->instance->sbi;
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+	const size_t bs = sbi->block_size;
+	size_t bytes = min(len, bs - pos % bs);
+	size_t boundary = ROUND_UP(ino_i->i_size, bs);
+	uint32_t block;
+
+	if (bytes == bs)
+		flags = BLOCK_FLAGS_NOREAD;
+
+	if (pos < boundary) {
+		r = read_map(&block, mnode, pos);
+		on_error(r, goto out_err);
+
+		if (block == 0) {
+			/*Writing in a sparse block*/
+			r = mfs_alloc_zone(mnode->instance, &block);
+			on_error(r, goto out_err);
+			flags = BLOCK_FLAGS_NOREAD;
+		}
+	} else {
+		uint32_t dummy;
+
+		r = mfs_alloc_zone(mnode->instance, &block);
+		on_error(r, goto out_err);
+
+		r = write_map(mnode, pos, block, &dummy);
+		on_error(r, goto out_err);
+	}
+
+	block_t *b;
+	r = block_get(&b, handle, block, flags);
+	on_error(r, goto out_err);
+
+	async_data_write_finalize(callid, b->data + pos % bs, bytes);
+	b->dirty = true;
+
+	r = block_put(b);
+	if (r != EOK) {
+		mfs_node_put(fn);
+		async_answer_0(rid, r);
+		return;
+	}
+
+	ino_i->i_size = pos + bytes;
+	ino_i->dirty = true;
+	r = mfs_node_put(fn);
+	async_answer_2(rid, r, bytes, pos + bytes);
+	return;
+
+out_err:
+	mfs_node_put(fn);
+	async_answer_0(callid, r);
+	async_answer_0(rid, r);
+}
+
+void
+mfs_destroy(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t handle = (devmap_handle_t)IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	fs_node_t *fn;
+	int r;
+
+	r = mfs_node_get(&fn, handle, index);
+	if (r != EOK) {
+		async_answer_0(rid, r);
+		return;
+	}
+	if (!fn) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+
+	/*Destroy the inode*/
+	r = mfs_destroy_node(fn);
+	async_answer_0(rid, r);
+}
+
+static int
+mfs_destroy_node(fs_node_t *fn)
+{
+	struct mfs_node *mnode = fn->data;
+	bool has_children;
+	int r;
+
+	mfsdebug("mfs_destroy_node %d\n", mnode->ino_i->index);
+
+	r = mfs_has_children(&has_children, fn);
+	on_error(r, goto out);
+
+	assert(!has_children);
+
+	if (mnode->ino_i->i_nlinks > 0) {
+		mfsdebug("nlinks = %d", mnode->ino_i->i_nlinks);
+		r = EOK;
+		goto out;
+	}
+
+	/*Free the entire inode content*/
+	r = inode_shrink(mnode, mnode->ino_i->i_size);
+	on_error(r, goto out);
+	r = mfs_free_inode(mnode->instance, mnode->ino_i->index);
+
+out:
+	mfs_node_put(fn);
+	return r;
+}
+
+void
+mfs_truncate(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t handle = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+	aoff64_t size = (aoff64_t) MERGE_LOUP32(IPC_GET_ARG3(*request),
+						IPC_GET_ARG4(*request));
+	fs_node_t *fn;
+	int r;
+
+	r = mfs_node_get(&fn, handle, index);
+	if (r != EOK) {
+		async_answer_0(rid, r);
+		return;
+	}
+
+	if (!fn) {
+		async_answer_0(rid, r);
+		return;
+	}
+
+	struct mfs_node *mnode = fn->data;
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+
+	if (ino_i->i_size == size)
+		r = EOK;
+	else
+		r = inode_shrink(mnode, ino_i->i_size - size);
+
+	async_answer_0(rid, r);
+	mfs_node_put(fn);
+}
+
+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 = true;
+	*longfilenames = false;
+
+	if (magic == MFS_MAGIC_V1 || magic == MFS_MAGIC_V1R) {
+		*native = magic == MFS_MAGIC_V1;
+		*version = MFS_VERSION_V1;
+	} else if (magic == MFS_MAGIC_V1L || magic == MFS_MAGIC_V1LR) {
+		*native = magic == MFS_MAGIC_V1L;
+		*version = MFS_VERSION_V1;
+		*longfilenames = true;
+	} else if (magic == MFS_MAGIC_V2 || magic == MFS_MAGIC_V2R) {
+		*native = magic == MFS_MAGIC_V2;
+		*version = MFS_VERSION_V2;
+	} else if (magic == MFS_MAGIC_V2L || magic == MFS_MAGIC_V2LR) {
+		*native = magic == MFS_MAGIC_V2L;
+		*version = MFS_VERSION_V2;
+		*longfilenames = true;
+	} else if (magic == MFS_MAGIC_V3 || magic == MFS_MAGIC_V3R) {
+		*native = magic == MFS_MAGIC_V3;
+		*version = MFS_VERSION_V3;
+	} else
+		rc = false;
+
+	return rc;
+}
+
+void
+mfs_close(ipc_callid_t rid, ipc_call_t *request)
+{
+	async_answer_0(rid, EOK);
+}
+
+void
+mfs_open_node(ipc_callid_t rid, ipc_call_t *request)
+{
+	libfs_open_node(&mfs_libfs_ops, mfs_reg.fs_handle, rid, request);
+}
+
+void
+mfs_sync(ipc_callid_t rid, ipc_call_t *request)
+{
+	devmap_handle_t devmap = (devmap_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t index = (fs_index_t) IPC_GET_ARG2(*request);
+
+	fs_node_t *fn;
+	int rc = mfs_node_get(&fn, devmap, index);
+	if (rc != EOK) {
+		async_answer_0(rid, rc);
+		return;
+	}
+	if (!fn) {
+		async_answer_0(rid, ENOENT);
+		return;
+	}
+
+	struct mfs_node *mnode = fn->data;
+	mnode->ino_i->dirty = true;
+
+	rc = mfs_node_put(fn);
+	async_answer_0(rid, rc);
+}
+
+/**
+ * @}
+ */
+
Index: uspace/srv/fs/minixfs/mfs_rw.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_rw.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs_rw.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,386 @@
+/*
+ * 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 "mfs.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 < 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;
+
+	/*Compute the relative block number in file*/
+	int rblock = pos / sbi->block_size;
+
+	return rw_map_ondisk(old_zone, mnode, rblock, true, new_zone);
+}
+
+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;
+
+	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);
+				on_error(r, return r);
+
+				ino_i->i_izone[0] = zone;
+				ino_i->dirty = true;
+			} else {
+				/*Sparse block*/
+				*b = 0;
+				return EOK;
+			}
+		}
+
+		r = read_ind_zone(inst, ino_i->i_izone[0], &ind_zone);
+		on_error(r, 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;
+
+	/*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);
+			on_error(r, return r);
+
+			ino_i->i_izone[1] = zone;
+			ino_i->dirty = true;
+		} else {
+			/*Sparse block*/
+			*b = 0;
+			return EOK;
+		}
+	}
+
+	r = read_ind_zone(inst, ino_i->i_izone[1], &ind_zone);
+	on_error(r, 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);
+			on_error(r, goto out_free_ind1);
+
+			ind_zone[ind2_off] = zone;
+			write_ind_zone(inst, ino_i->i_izone[1], ind_zone);
+		} else {
+			/*Sparse block*/
+			r = EOK;
+			*b = 0;
+			goto out_free_ind1;
+		}
+	}
+
+	r = read_ind_zone(inst, ind_zone[ind2_off], &ind2_zone);
+	on_error(r, 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;
+}
+
+/*Free unused indirect zones*/
+int
+prune_ind_zones(struct mfs_node *mnode, size_t new_size)
+{
+	struct mfs_instance *inst = mnode->instance;
+	struct mfs_sb_info *sbi = inst->sbi;
+	struct mfs_ino_info *ino_i = mnode->ino_i;
+	int nr_direct, ptrs_per_block, rblock, r;
+	int i;
+
+	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);
+	}
+
+	rblock = new_size / sbi->block_size;
+
+	if (rblock < nr_direct) {
+		/*free the single indirect zone*/
+		if (ino_i->i_izone[0]) {
+			r = mfs_free_zone(inst, ino_i->i_izone[0]);
+			on_error(r, return r);
+
+			ino_i->i_izone[0] = 0;
+			ino_i->dirty = true;
+		}
+	}
+
+	rblock -= nr_direct + ptrs_per_block;
+
+	int fzone_to_free = (rblock < 0 ? 0 : rblock) / ptrs_per_block;
+
+	if ((fzone_to_free % ptrs_per_block) != 0)
+		++fzone_to_free;
+
+	/*free the entire double indirect zone*/
+	uint32_t *dbl_zone;
+
+	if (ino_i->i_izone[1] == 0) {
+		/*Nothing to be done*/
+		return EOK;
+	}
+
+	r = read_ind_zone(inst, ino_i->i_izone[1], &dbl_zone);
+	on_error(r, return r);
+
+	for (i = fzone_to_free; i < ptrs_per_block; ++i) {
+		if (dbl_zone[i] == 0)
+			continue;
+
+		r = mfs_free_zone(inst, dbl_zone[i]);
+		on_error(r, goto out);
+	}
+
+	if (fzone_to_free == 0) {
+		r = mfs_free_zone(inst, ino_i->i_izone[1]);
+		ino_i->i_izone[1] = 0;
+		ino_i->dirty = true;
+	}
+out:
+	free(dbl_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);
+	on_error(r, return r);
+
+	memset(b->data, 0, b->size);
+	b->dirty = true;
+
+	return block_put(b);
+}
+
+static int
+alloc_zone_and_clear(struct mfs_instance *inst, uint32_t *zone)
+{
+	int r;
+
+	r = mfs_alloc_zone(inst, zone);
+	on_error(r, return r);
+
+	r = reset_zone_content(inst, *zone);
+	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;
+	const int max_ind_zone_ptrs = (MFS_MAX_BLOCKSIZE / sizeof(uint16_t)) *
+				      sizeof(uint32_t);
+
+	*ind_zone = malloc(max_ind_zone_ptrs);
+	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]);
+	}
+
+	return block_put(b);
+}
+
+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);
+	on_error(r, 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;
+
+	return block_put(b);
+}
+
+
+/**
+ * @}
+ */
+
Index: uspace/srv/fs/minixfs/mfs_utils.c
===================================================================
--- uspace/srv/fs/minixfs/mfs_utils.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/fs/minixfs/mfs_utils.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,63 @@
+/*
+ * 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 "mfs.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/hid/input/include/sun.h
===================================================================
--- uspace/srv/hid/input/include/sun.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/hid/input/include/sun.h	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * 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 kbdgen generic
+ * @brief Sun keyboard virtual port driver.
+ * @ingroup kbd
+ * @{
+ */
+/** @file
+ */
+
+#ifndef KBD_SUN_H_
+#define KBD_SUN_H_
+
+extern int ns16550_port_init(void);
+extern int z8530_port_init(void);
+
+#endif
+
+/**
+ * @}
+ */
Index: uspace/srv/hid/input/port/dummy.c
===================================================================
--- uspace/srv/hid/input/port/dummy.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/hid/input/port/dummy.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2009 Jiri Svoboda
+ * 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 kbd_port
+ * @brief	Dummy keyboard port driver.
+ * @ingroup  kbd
+ * @{
+ */ 
+/** @file
+ */
+
+#include <kbd_port.h>
+#include <kbd.h>
+
+int kbd_port_init(void)
+{
+	return 0;
+}
+
+void kbd_port_yield(void)
+{
+}
+
+void kbd_port_reclaim(void)
+{
+}
+
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
+/** @}
+*/
Index: uspace/srv/hid/input/port/sgcn.c
===================================================================
--- uspace/srv/hid/input/port/sgcn.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/hid/input/port/sgcn.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2008 Pavel Rimsky
+ * 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 kbd_port
+ * @ingroup  kbd
+ * @{
+ */
+/** @file
+ * @brief SGCN (Serengeti Console) keyboard port driver.
+ */
+
+#include <as.h>
+#include <ddi.h>
+#include <async.h>
+#include <kbd.h>
+#include <kbd_port.h>
+#include <sysinfo.h>
+#include <stdio.h>
+#include <thread.h>
+#include <bool.h>
+#include <errno.h>
+
+#define POLL_INTERVAL  10000
+
+/**
+ * SGCN buffer header. It is placed at the very beginning of the SGCN
+ * buffer.
+ */
+typedef struct {
+	/** hard-wired to "CON" */
+	char magic[4];
+	
+	/** we don't need this */
+	char unused[8];
+	
+	/** offset within the SGCN buffer of the input buffer start */
+	uint32_t in_begin;
+	
+	/** offset within the SGCN buffer of the input buffer end */
+	uint32_t in_end;
+	
+	/** offset within the SGCN buffer of the input buffer read pointer */
+	uint32_t in_rdptr;
+	
+	/** offset within the SGCN buffer of the input buffer write pointer */
+	uint32_t in_wrptr;
+} __attribute__ ((packed)) sgcn_buffer_header_t;
+
+/*
+ * Returns a pointer to the object of a given type which is placed at the given
+ * offset from the console buffer beginning.
+ */
+#define SGCN_BUFFER(type, offset) \
+		((type *) (sram_virt_addr + sram_buffer_offset + (offset)))
+
+/** Returns a pointer to the console buffer header. */
+#define SGCN_BUFFER_HEADER	(SGCN_BUFFER(sgcn_buffer_header_t, 0))
+
+/**
+ * Virtual address mapped to SRAM.
+ */
+static uintptr_t sram_virt_addr;
+
+/**
+ * SGCN buffer offset within SGCN.
+ */
+static uintptr_t sram_buffer_offset;
+
+/* polling thread */
+static void sgcn_thread_impl(void *arg);
+
+static volatile bool polling_disabled = false;
+
+/**
+ * Initializes the SGCN driver.
+ * Maps the physical memory (SRAM) and creates the polling thread. 
+ */
+int kbd_port_init(void)
+{
+	sysarg_t sram_paddr;
+	if (sysinfo_get_value("sram.address.physical", &sram_paddr) != EOK)
+		return -1;
+	
+	sysarg_t sram_size;
+	if (sysinfo_get_value("sram.area.size", &sram_size) != EOK)
+		return -1;
+	
+	if (sysinfo_get_value("sram.buffer.offset", &sram_buffer_offset) != EOK)
+		sram_buffer_offset = 0;
+	
+	sram_virt_addr = (uintptr_t) as_get_mappable_page(sram_size);
+	
+	if (physmem_map((void *) sram_paddr, (void *) sram_virt_addr,
+	    sram_size / PAGE_SIZE, AS_AREA_READ | AS_AREA_WRITE) != 0) {
+		printf("SGCN: uspace driver could not map physical memory.");
+		return -1;
+	}
+	
+	thread_id_t tid;
+	int rc = thread_create(sgcn_thread_impl, NULL, "kbd_poll", &tid);
+	if (rc != 0)
+		return rc;
+	
+	return 0;
+}
+
+void kbd_port_yield(void)
+{
+	polling_disabled = true;
+}
+
+void kbd_port_reclaim(void)
+{
+	polling_disabled = false;
+}
+
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
+/**
+ * Handler of the "key pressed" event. Reads codes of all the pressed keys from
+ * the buffer. 
+ */
+static void sgcn_key_pressed(void)
+{
+	char c;
+	
+	uint32_t begin = SGCN_BUFFER_HEADER->in_begin;
+	uint32_t end = SGCN_BUFFER_HEADER->in_end;
+	uint32_t size = end - begin;
+	
+	volatile char *buf_ptr = (volatile char *)
+		SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+	volatile uint32_t *in_wrptr_ptr = &(SGCN_BUFFER_HEADER->in_wrptr);
+	volatile uint32_t *in_rdptr_ptr = &(SGCN_BUFFER_HEADER->in_rdptr);
+	
+	while (*in_rdptr_ptr != *in_wrptr_ptr) {
+		c = *buf_ptr;
+		*in_rdptr_ptr = (((*in_rdptr_ptr) - begin + 1) % size) + begin;
+		buf_ptr = (volatile char *)
+			SGCN_BUFFER(char, SGCN_BUFFER_HEADER->in_rdptr);
+		kbd_push_scancode(c);
+	}
+}
+
+/**
+ * Thread to poll SGCN for keypresses.
+ */
+static void sgcn_thread_impl(void *arg)
+{
+	(void) arg;
+
+	while (1) {
+		if (polling_disabled == false)
+			sgcn_key_pressed();
+		usleep(POLL_INTERVAL);
+	}
+}
+
+/** @}
+ */
Index: uspace/srv/hid/input/port/sun.c
===================================================================
--- uspace/srv/hid/input/port/sun.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/hid/input/port/sun.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009 Martin Decky
+ * 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 kbd_port
+ * @ingroup  kbd
+ * @{
+ */
+/** @file
+ * @brief Sun keyboard virtual port driver.
+ */
+
+#include <kbd.h>
+#include <kbd_port.h>
+#include <sun.h>
+#include <sysinfo.h>
+#include <errno.h>
+#include <bool.h>
+
+/** Sun keyboard virtual port driver.
+ *
+ * This is a virtual port driver which can use
+ * both ns16550_port_init and z8530_port_init
+ * according to the information passed from the
+ * kernel. This is just a temporal hack.
+ *
+ */
+int kbd_port_init(void)
+{
+	sysarg_t z8530;
+	if (sysinfo_get_value("kbd.type.z8530", &z8530) != EOK)
+		z8530 = false;
+	
+	sysarg_t ns16550;
+	if (sysinfo_get_value("kbd.type.ns16550", &ns16550) != EOK)
+		ns16550 = false;
+	
+	if (z8530) {
+		if (z8530_port_init() == 0)
+			return 0;
+	}
+	
+	if (ns16550) {
+		if (ns16550_port_init() == 0)
+			return 0;
+	}
+	
+	return -1;
+}
+
+void kbd_port_yield(void)
+{
+}
+
+void kbd_port_reclaim(void)
+{
+}
+
+void kbd_port_write(uint8_t data)
+{
+	(void) data;
+}
+
+/** @}
+*/
Index: uspace/srv/hid/input/port/z8530.c
===================================================================
--- uspace/srv/hid/input/port/z8530.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
+++ uspace/srv/hid/input/port/z8530.c	(revision 8ff0bd25c8215c84283f8ba039f4cb58b7660280)
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2006 Martin Decky
+ * 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 kbd_port
+ * @ingroup  kbd
+ * @{
+ */
+/** @file
+ * @brief Z8530 keyboard port driver.
+ */
+
+#include <ipc/irc.h>
+#include <async.h>
+#include <async_obsolete.h>
+#include <sysinfo.h>
+#include <kbd.h>
+#include <kbd_port.h>
+#include <sun.h>
+#include <sys/types.h>
+#include <ddi.h>
+#include <errno.h>
+
+#define CHAN_A_STATUS  4
+#define CHAN_A_DATA    6
+
+#define RR0_RCA  1
+
+static irq_cmd_t z8530_cmds[] = {
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = (void *) 0,     /* Will be patched in run-time */
+		.dstarg = 1
+	},
+	{
+		.cmd = CMD_BTEST,
+		.value = RR0_RCA,
+		.srcarg = 1,
+		.dstarg = 3
+	},
+	{
+		.cmd = CMD_PREDICATE,
+		.value = 2,
+		.srcarg = 3
+	},
+	{
+		.cmd = CMD_PIO_READ_8,
+		.addr = (void *) 0,     /* Will be patched in run-time */
+		.dstarg = 2
+	},
+	{
+		.cmd = CMD_ACCEPT
+	}
+};
+	
+irq_code_t z8530_kbd = {
+	sizeof(z8530_cmds) / sizeof(irq_cmd_t),
+	z8530_cmds
+};
+
+static void z8530_irq_handler(ipc_callid_t iid, ipc_call_t *call);
+
+int z8530_port_init(void)
+{
+	sysarg_t kaddr;
+	if (sysinfo_get_value("kbd.address.kernel", &kaddr) != EOK)
+		return -1;
+	
+	sysarg_t inr;
+	if (sysinfo_get_value("kbd.inr", &inr) != EOK)
+		return -1;
+	
+	z8530_cmds[0].addr = (void *) kaddr + CHAN_A_STATUS;
+	z8530_cmds[3].addr = (void *) kaddr + CHAN_A_DATA;
+	
+	async_set_interrupt_received(z8530_irq_handler);
+	register_irq(inr, device_assign_devno(), inr, &z8530_kbd);
+	
+	return 0;
+}
+
+static void z8530_irq_handler(ipc_callid_t iid, ipc_call_t *call)
+{
+	int scan_code = IPC_GET_ARG2(*call);
+	kbd_push_scancode(scan_code);
+	
+	if (irc_service)
+		async_obsolete_msg_1(irc_phone, IRC_CLEAR_INTERRUPT,
+		    IPC_GET_IMETHOD(*call));
+}
+
+/** @}
+ */
