Index: uspace/srv/bd/ata_bd/Makefile
===================================================================
--- uspace/srv/bd/ata_bd/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/ata_bd/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,50 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
+.PHONY: all clean
 
-LIBC_PREFIX = ../../../lib/libc
-SOFTINT_PREFIX = ../../../lib/softint
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = ata_bd
-SOURCES = \
-	ata_bd.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/bd/ata_bd/Makefile.build
===================================================================
--- uspace/srv/bd/ata_bd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/ata_bd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	ata_bd.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/bd/ata_bd/Makefile.common
===================================================================
--- uspace/srv/bd/ata_bd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/ata_bd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = ata_bd
Index: uspace/srv/bd/ata_bd/ata_bd.c
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/ata_bd/ata_bd.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -35,6 +35,12 @@
  * @brief ATA disk driver
  *
- * This driver currently works only with CHS addressing and uses PIO.
- * Currently based on the (now obsolete) ATA-1, ATA-2 standards.
+ * This driver supports CHS, 28-bit and 48-bit LBA addressing. It only uses
+ * PIO transfers. There is no support DMA, the PACKET feature set or any other
+ * fancy features such as S.M.A.R.T, removable devices, etc.
+ *
+ * This driver is based on the ATA-1, ATA-2, ATA-3 and ATA/ATAPI-4 through 7
+ * standards, as published by the ANSI, NCITS and INCITS standards bodies,
+ * which are freely available. This driver contains no vendor-specific
+ * code at this moment.
  *
  * The driver services a single controller which can have up to two disks
@@ -50,4 +56,5 @@
 #include <as.h>
 #include <fibril_sync.h>
+#include <string.h>
 #include <devmap.h>
 #include <sys/types.h>
@@ -55,4 +62,5 @@
 #include <bool.h>
 #include <task.h>
+#include <macros.h>
 
 #include "ata_bd.h"
@@ -79,11 +87,17 @@
 static int ata_bd_init(void);
 static void ata_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
-static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
+static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
     void *buf);
-static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
+static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
+    const void *buf);
+static int ata_bd_read_block(int disk_id, uint64_t ba, size_t cnt,
     void *buf);
-static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
+static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
     const void *buf);
-static int drive_identify(int drive_id, disk_t *d);
+static int disk_init(disk_t *d, int disk_id);
+static int drive_identify(int drive_id, void *buf);
+static void disk_print_summary(disk_t *d);
+static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc);
+static void coord_sc_program(const block_coord_t *bc, uint16_t scnt);
 static int wait_status(unsigned set, unsigned n_reset, uint8_t *pstatus,
     unsigned timeout);
@@ -97,5 +111,5 @@
 	printf(NAME ": ATA disk driver\n");
 
-	printf("I/O address 0x%x\n", cmd_physical);
+	printf("I/O address 0x%p/0x%p\n", ctl_physical, cmd_physical);
 
 	if (ata_bd_init() != EOK)
@@ -106,9 +120,8 @@
 		fflush(stdout);
 
-		rc = drive_identify(i, &disk[i]);
+		rc = disk_init(&disk[i], i);
 
 		if (rc == EOK) {
-			printf("%u cylinders, %u heads, %u sectors\n",
-			    disk[i].cylinders, disk[i].heads, disk[i].sectors);
+			disk_print_summary(&disk[i]);
 		} else {
 			printf("Not found.\n");
@@ -147,4 +160,32 @@
 }
 
+/** Print one-line device summary. */
+static void disk_print_summary(disk_t *d)
+{
+	uint64_t mbytes;
+
+	printf("%s: ", d->model);
+
+	switch (d->amode) {
+	case am_chs:
+		printf("CHS %u cylinders, %u heads, %u sectors",
+		    disk->geom.cylinders, disk->geom.heads, disk->geom.sectors);
+		break;
+	case am_lba28:
+		printf("LBA-28");
+		break;
+	case am_lba48:
+		printf("LBA-48");
+		break;
+	}
+
+	printf(" %llu blocks", d->blocks, d->blocks / (2 * 1024));
+
+	mbytes = d->blocks / (2 * 1024);
+	if (mbytes > 0)
+		printf(" %llu MB.", mbytes);
+
+	printf("\n");
+}
 
 /** Register driver and enable device I/O. */
@@ -190,6 +231,6 @@
 	int flags;
 	int retval;
-	off_t idx;
-	size_t size;
+	uint64_t ba;
+	size_t cnt;
 	int disk_id, i;
 
@@ -211,5 +252,5 @@
 	ipc_answer_0(iid, EOK);
 
-	if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
+	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
 		ipc_answer_0(callid, EHANGUP);
 		return;
@@ -222,5 +263,5 @@
 	}
 
-	(void) ipc_share_out_finalize(callid, fs_va);
+	(void) async_share_out_finalize(callid, fs_va);
 
 	while (1) {
@@ -232,15 +273,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-		case BD_WRITE_BLOCK:
-			idx = IPC_GET_ARG1(call);
-			size = IPC_GET_ARG2(call);
-			if (size > comm_size) {
-				retval = EINVAL;
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
 				break;
 			}
-			retval = ata_bd_rdwr(disk_id, method, idx,
-			    size, fs_va);
+			retval = ata_bd_read_blocks(disk_id, ba, cnt, fs_va);
 			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = ata_bd_write_blocks(disk_id, ba, cnt, fs_va);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			retval = EINVAL;
@@ -251,40 +304,121 @@
 }
 
-/** Transfer a logical block from/to the device.
- *
- * @param disk_id	Device index (0 or 1)
- * @param method	@c BD_READ_BLOCK or @c BD_WRITE_BLOCK
- * @param blk_idx	Index of the first block.
- * @param size		Size of the logical block.
- * @param buf		Data buffer.
- *
- * @return EOK on success, EIO on error.
- */
-static int ata_bd_rdwr(int disk_id, ipcarg_t method, off_t blk_idx, size_t size,
-    void *buf)
-{
+/** Initialize a disk.
+ *
+ * Probes for a disk, determines its parameters and initializes
+ * the disk structure.
+ */
+static int disk_init(disk_t *d, int disk_id)
+{
+	identify_data_t idata;
+	uint8_t model[40];
+	uint16_t w;
+	uint8_t c;
+	size_t pos, len;
 	int rc;
-	size_t now;
-
-	while (size > 0) {
-		now = size < block_size ? size : block_size;
-		if (now != block_size)
-			return EINVAL;
-
-		if (method == BD_READ_BLOCK)
-			rc = ata_bd_read_block(disk_id, blk_idx, 1, buf);
-		else
-			rc = ata_bd_write_block(disk_id, blk_idx, 1, buf);
-
+	unsigned i;
+
+	rc = drive_identify(disk_id, &idata);
+	if (rc != EOK) {
+		d->present = false;
+		return rc;
+	}
+
+	if ((idata.caps & cap_lba) == 0) {
+		/* Device only supports CHS addressing. */
+		d->amode = am_chs;
+
+		d->geom.cylinders = idata.cylinders;
+		d->geom.heads = idata.heads;
+		d->geom.sectors = idata.sectors;
+
+		d->blocks = d->geom.cylinders * d->geom.heads * d->geom.sectors;
+	} else if ((idata.cmd_set1 & cs1_addr48) == 0) {
+		/* Device only supports LBA-28 addressing. */
+		d->amode = am_lba28;
+
+		d->geom.cylinders = 0;
+		d->geom.heads = 0;
+		d->geom.sectors = 0;
+
+		d->blocks =
+		     (uint32_t) idata.total_lba28_0 | 
+		    ((uint32_t) idata.total_lba28_1 << 16);
+	} else {
+		/* Device supports LBA-48 addressing. */
+		d->amode = am_lba48;
+
+		d->geom.cylinders = 0;
+		d->geom.heads = 0;
+		d->geom.sectors = 0;
+
+		d->blocks =
+		     (uint64_t) idata.total_lba48_0 |
+		    ((uint64_t) idata.total_lba48_1 << 16) |
+		    ((uint64_t) idata.total_lba48_2 << 32) | 
+		    ((uint64_t) idata.total_lba48_3 << 48);
+	}
+
+	/*
+	 * Convert model name to string representation.
+	 */
+	for (i = 0; i < 20; i++) {
+		w = idata.model_name[i];
+		model[2 * i] = w >> 8;
+		model[2 * i + 1] = w & 0x00ff;
+	}
+
+	len = 40;
+	while (len > 0 && model[len - 1] == 0x20)
+		--len;
+
+	pos = 0;
+	for (i = 0; i < len; ++i) {
+		c = model[i];
+		if (c >= 0x80) c = '?';
+
+		chr_encode(c, d->model, &pos, 40);
+	}
+	d->model[pos] = '\0';
+
+	d->present = true;
+	fibril_mutex_initialize(&d->lock);
+
+	return EOK;
+}
+
+/** Read multiple blocks from the device. */
+static int ata_bd_read_blocks(int disk_id, uint64_t ba, size_t cnt,
+    void *buf) {
+
+	int rc;
+
+	while (cnt > 0) {
+		rc = ata_bd_read_block(disk_id, ba, 1, buf);
 		if (rc != EOK)
 			return rc;
 
+		++ba;
+		--cnt;
 		buf += block_size;
-		blk_idx++;
-
-		if (size > block_size)
-			size -= block_size;
-		else
-			size = 0;
+	}
+
+	return EOK;
+}
+
+/** Write multiple blocks to the device. */
+static int ata_bd_write_blocks(int disk_id, uint64_t ba, size_t cnt,
+    const void *buf) {
+
+	int rc;
+
+	while (cnt > 0) {
+		rc = ata_bd_write_block(disk_id, ba, 1, buf);
+		if (rc != EOK)
+			return rc;
+
+		++ba;
+		--cnt;
+		buf += block_size;
 	}
 
@@ -294,11 +428,11 @@
 /** Issue IDENTIFY command.
  *
- * This is used to detect whether an ATA device is present and if so,
- * to determine its parameters. The parameters are written to @a d.
+ * Reads @c identify data into the provided buffer. This is used to detect
+ * whether an ATA device is present and if so, to determine its parameters.
  *
  * @param disk_id	Device ID, 0 or 1.
- * @param d		Device structure to store parameters in.
- */
-static int drive_identify(int disk_id, disk_t *d)
+ * @param buf		Pointer to a 512-byte buffer.
+ */
+static int drive_identify(int disk_id, void *buf)
 {
 	uint16_t data;
@@ -308,5 +442,4 @@
 
 	drv_head = ((disk_id != 0) ? DHR_DRV : 0);
-	d->present = false;
 
 	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_PROBE) != EOK)
@@ -330,100 +463,4 @@
 
 	if ((status & SR_DRQ) != 0) {
-//		for (i = 0; i < block_size / 2; i++) {
-//			data = pio_read_16(&cmd->data_port);
-//			((uint16_t *) buf)[i] = data;
-//		}
-
-		for (i = 0; i < block_size / 2; i++) {
-			data = pio_read_16(&cmd->data_port);
-
-			switch (i) {
-			case 1: d->cylinders = data; break;
-			case 3: d->heads = data; break;
-			case 6: d->sectors = data; break;
-			}
-		}
-	}
-
-	if ((status & SR_ERR) != 0)
-		return EIO;
-
-	d->blocks = d->cylinders * d->heads * d->sectors;
-
-	d->present = true;
-	fibril_mutex_initialize(&d->lock);
-
-	return EOK;
-}
-
-/** Read a physical from the device.
- *
- * @param disk_id	Device index (0 or 1)
- * @param blk_idx	Index of the first block.
- * @param blk_cnt	Number of blocks to transfer.
- * @param buf		Buffer for holding the data.
- *
- * @return EOK on success, EIO on error.
- */
-static int ata_bd_read_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
-    void *buf)
-{
-	size_t i;
-	uint16_t data;
-	uint8_t status;
-	uint64_t c, h, s;
-	uint64_t idx;
-	uint8_t drv_head;
-	disk_t *d;
-
-	d = &disk[disk_id];
-
-	/* Check device bounds. */
-	if (blk_idx >= d->blocks)
-		return EINVAL;
-
-	/* Compute CHS. */
-	c = blk_idx / (d->heads * d->sectors);
-	idx = blk_idx % (d->heads * d->sectors);
-
-	h = idx / d->sectors;
-	s = 1 + (idx % d->sectors);
-
-	/* New value for Drive/Head register */
-	drv_head =
-	    ((disk_id != 0) ? DHR_DRV : 0) |
-	    (h & 0x0f);
-
-	fibril_mutex_lock(&d->lock);
-
-	/* Program a Read Sectors operation. */
-
-	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
-		fibril_mutex_unlock(&d->lock);
-		return EIO;
-	}
-
-	pio_write_8(&cmd->drive_head, drv_head);
-
-	if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
-		fibril_mutex_unlock(&d->lock);
-		return EIO;
-	}
-
-	pio_write_8(&cmd->sector_count, 1);
-	pio_write_8(&cmd->sector_number, s);
-	pio_write_8(&cmd->cylinder_low, c & 0xff);
-	pio_write_8(&cmd->cylinder_high, c >> 16);
-
-	pio_write_8(&cmd->command, CMD_READ_SECTORS);
-
-	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
-		fibril_mutex_unlock(&d->lock);
-		return EIO;
-	}
-
-	if ((status & SR_DRQ) != 0) {
-		/* Read data from the device buffer. */
-
 		for (i = 0; i < block_size / 2; i++) {
 			data = pio_read_16(&cmd->data_port);
@@ -435,48 +472,42 @@
 		return EIO;
 
-	fibril_mutex_unlock(&d->lock);
-	return EOK;
-}
-
-/** Write a physical block to the device.
+	return EOK;
+}
+
+/** Read a physical from the device.
  *
  * @param disk_id	Device index (0 or 1)
- * @param blk_idx	Index of the first block.
- * @param blk_cnt	Number of blocks to transfer.
- * @param buf		Buffer holding the data to write.
+ * @param ba		Address the first block.
+ * @param cnt		Number of blocks to transfer.
+ * @param buf		Buffer for holding the data.
  *
  * @return EOK on success, EIO on error.
  */
-static int ata_bd_write_block(int disk_id, uint64_t blk_idx, size_t blk_cnt,
-    const void *buf)
+static int ata_bd_read_block(int disk_id, uint64_t ba, size_t blk_cnt,
+    void *buf)
 {
 	size_t i;
+	uint16_t data;
 	uint8_t status;
-	uint64_t c, h, s;
-	uint64_t idx;
 	uint8_t drv_head;
 	disk_t *d;
+	block_coord_t bc;
 
 	d = &disk[disk_id];
-
-	/* Check device bounds. */
-	if (blk_idx >= d->blocks)
+	bc.h = 0;	/* Silence warning. */
+
+	/* Compute block coordinates. */
+	if (coord_calc(d, ba, &bc) != EOK)
 		return EINVAL;
-
-	/* Compute CHS. */
-	c = blk_idx / (d->heads * d->sectors);
-	idx = blk_idx % (d->heads * d->sectors);
-
-	h = idx / d->sectors;
-	s = 1 + (idx % d->sectors);
 
 	/* New value for Drive/Head register */
 	drv_head =
 	    ((disk_id != 0) ? DHR_DRV : 0) |
-	    (h & 0x0f);
+	    ((d->amode != am_chs) ? DHR_LBA : 0) |
+	    (bc.h & 0x0f);
 
 	fibril_mutex_lock(&d->lock);
 
-	/* Program a Write Sectors operation. */
+	/* Program a Read Sectors operation. */
 
 	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
@@ -492,10 +523,83 @@
 	}
 
-	pio_write_8(&cmd->sector_count, 1);
-	pio_write_8(&cmd->sector_number, s);
-	pio_write_8(&cmd->cylinder_low, c & 0xff);
-	pio_write_8(&cmd->cylinder_high, c >> 16);
-
-	pio_write_8(&cmd->command, CMD_WRITE_SECTORS);
+	/* Program block coordinates into the device. */
+	coord_sc_program(&bc, 1);
+
+	pio_write_8(&cmd->command, d->amode == am_lba48 ?
+	    CMD_READ_SECTORS_EXT : CMD_READ_SECTORS);
+
+	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	if ((status & SR_DRQ) != 0) {
+		/* Read data from the device buffer. */
+
+		for (i = 0; i < block_size / 2; i++) {
+			data = pio_read_16(&cmd->data_port);
+			((uint16_t *) buf)[i] = data;
+		}
+	}
+
+	if ((status & SR_ERR) != 0)
+		return EIO;
+
+	fibril_mutex_unlock(&d->lock);
+	return EOK;
+}
+
+/** Write a physical block to the device.
+ *
+ * @param disk_id	Device index (0 or 1)
+ * @param ba		Address of the first block.
+ * @param cnt		Number of blocks to transfer.
+ * @param buf		Buffer holding the data to write.
+ *
+ * @return EOK on success, EIO on error.
+ */
+static int ata_bd_write_block(int disk_id, uint64_t ba, size_t cnt,
+    const void *buf)
+{
+	size_t i;
+	uint8_t status;
+	uint8_t drv_head;
+	disk_t *d;
+	block_coord_t bc;
+
+	d = &disk[disk_id];
+	bc.h = 0;	/* Silence warning. */
+
+	/* Compute block coordinates. */
+	if (coord_calc(d, ba, &bc) != EOK)
+		return EINVAL;
+
+	/* New value for Drive/Head register */
+	drv_head =
+	    ((disk_id != 0) ? DHR_DRV : 0) |
+	    ((d->amode != am_chs) ? DHR_LBA : 0) |
+	    (bc.h & 0x0f);
+
+	fibril_mutex_lock(&d->lock);
+
+	/* Program a Write Sectors operation. */
+
+	if (wait_status(0, ~SR_BSY, NULL, TIMEOUT_BSY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	pio_write_8(&cmd->drive_head, drv_head);
+
+	if (wait_status(SR_DRDY, ~SR_BSY, NULL, TIMEOUT_DRDY) != EOK) {
+		fibril_mutex_unlock(&d->lock);
+		return EIO;
+	}
+
+	/* Program block coordinates into the device. */
+	coord_sc_program(&bc, 1);
+
+	pio_write_8(&cmd->command, d->amode == am_lba48 ?
+	    CMD_WRITE_SECTORS_EXT : CMD_WRITE_SECTORS);
 
 	if (wait_status(0, ~SR_BSY, &status, TIMEOUT_BSY) != EOK) {
@@ -518,4 +622,79 @@
 
 	return EOK;
+}
+
+/** Calculate block coordinates.
+ *
+ * Calculates block coordinates in the best coordinate system supported
+ * by the device. These can be later programmed into the device using
+ * @c coord_sc_program().
+ *
+ * @return EOK on success or EINVAL if block index is past end of device.
+ */
+static int coord_calc(disk_t *d, uint64_t ba, block_coord_t *bc)
+{
+	uint64_t c;
+	uint64_t idx;
+
+	/* Check device bounds. */
+	if (ba >= d->blocks)
+		return EINVAL;
+
+	bc->amode = d->amode;
+
+	switch (d->amode) {
+	case am_chs:
+		/* Compute CHS coordinates. */
+		c = ba / (d->geom.heads * d->geom.sectors);
+		idx = ba % (d->geom.heads * d->geom.sectors);
+
+		bc->cyl_lo = c & 0xff;
+		bc->cyl_hi = (c >> 8) & 0xff;
+		bc->h      = (idx / d->geom.sectors) & 0x0f;
+		bc->sector = (1 + (idx % d->geom.sectors)) & 0xff;
+		break;
+
+	case am_lba28:
+		/* Compute LBA-28 coordinates. */
+		bc->c0 = ba & 0xff;		/* bits 0-7 */
+		bc->c1 = (ba >> 8) & 0xff;	/* bits 8-15 */
+		bc->c2 = (ba >> 16) & 0xff;	/* bits 16-23 */
+		bc->h  = (ba >> 24) & 0x0f;	/* bits 24-27 */
+		break;
+
+	case am_lba48:
+		/* Compute LBA-48 coordinates. */
+		bc->c0 = ba & 0xff;		/* bits 0-7 */
+		bc->c1 = (ba >> 8) & 0xff;	/* bits 8-15 */
+		bc->c2 = (ba >> 16) & 0xff;	/* bits 16-23 */
+		bc->c3 = (ba >> 24) & 0xff;	/* bits 24-31 */
+		bc->c4 = (ba >> 32) & 0xff;	/* bits 32-39 */
+		bc->c5 = (ba >> 40) & 0xff;	/* bits 40-47 */
+		bc->h  = 0;
+		break;
+	}
+
+	return EOK;
+}
+
+/** Program block coordinates and sector count into ATA registers.
+ *
+ * Note that bc->h must be programmed separately into the device/head register.
+ */
+static void coord_sc_program(const block_coord_t *bc, uint16_t scnt)
+{
+	if (bc->amode == am_lba48) {
+		/* Write high-order bits. */
+		pio_write_8(&cmd->sector_count, scnt >> 8);
+		pio_write_8(&cmd->sector_number, bc->c3);
+		pio_write_8(&cmd->cylinder_low, bc->c4);
+		pio_write_8(&cmd->cylinder_high, bc->c5);
+	}
+
+	/* Write low-order bits. */
+	pio_write_8(&cmd->sector_count, scnt & 0x00ff);
+	pio_write_8(&cmd->sector_number, bc->c0);
+	pio_write_8(&cmd->cylinder_low, bc->c1);
+	pio_write_8(&cmd->cylinder_high, bc->c2);
 }
 
Index: uspace/srv/bd/ata_bd/ata_bd.h
===================================================================
--- uspace/srv/bd/ata_bd/ata_bd.h	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/ata_bd/ata_bd.h	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -38,4 +38,5 @@
 #include <sys/types.h>
 #include <fibril_sync.h>
+#include <string.h>
 
 enum {
@@ -115,5 +116,6 @@
 
 enum drive_head_bits {
-	DHR_DRV		= 0x10
+	DHR_LBA		= 0x40,	/**< Use LBA addressing mode */
+	DHR_DRV		= 0x10	/**< Select device 1 */
 };
 
@@ -130,7 +132,9 @@
 
 enum ata_command {
-	CMD_IDENTIFY_DRIVE	= 0xEC,
 	CMD_READ_SECTORS	= 0x20,
-	CMD_WRITE_SECTORS	= 0x30
+	CMD_READ_SECTORS_EXT	= 0x24,
+	CMD_WRITE_SECTORS	= 0x30,
+	CMD_WRITE_SECTORS_EXT	= 0x34,
+	CMD_IDENTIFY_DRIVE	= 0xEC
 };
 
@@ -142,10 +146,143 @@
 };
 
+/** Data returned from @c identify command. */
+typedef struct {
+	uint16_t gen_conf;
+	uint16_t cylinders;
+	uint16_t _res2;
+	uint16_t heads;
+	uint16_t _vs4;
+	uint16_t _vs5;
+	uint16_t sectors;
+	uint16_t _vs7;
+	uint16_t _vs8;
+	uint16_t _vs9;
+
+	uint16_t serial_number[10];
+	uint16_t _vs20;
+	uint16_t _vs21;
+	uint16_t vs_bytes;
+	uint16_t firmware_rev[4];
+	uint16_t model_name[20];
+
+	uint16_t max_rw_multiple;
+	uint16_t _res48;
+	uint16_t caps;
+	uint16_t _res50;
+	uint16_t pio_timing;
+	uint16_t dma_timing;
+
+	uint16_t validity;
+	uint16_t cur_cyl;
+	uint16_t cur_heads;
+	uint16_t cur_sectors;
+	uint16_t cur_capacity0;
+	uint16_t cur_capacity1;
+	uint16_t mss;
+	uint16_t total_lba28_0;
+	uint16_t total_lba28_1;
+	uint16_t sw_dma;
+	uint16_t mw_dma;
+	uint16_t pio_modes;
+	uint16_t min_mw_dma_cycle;
+	uint16_t rec_mw_dma_cycle;
+	uint16_t min_raw_pio_cycle;
+	uint16_t min_iordy_pio_cycle;
+
+	uint16_t _res69;
+	uint16_t _res70;
+	uint16_t _res71;
+	uint16_t _res72;
+	uint16_t _res73;
+	uint16_t _res74;
+
+	uint16_t queue_depth;
+	uint16_t _res76[1 + 79 - 76];
+	uint16_t version_maj;
+	uint16_t version_min;
+	uint16_t cmd_set0;
+	uint16_t cmd_set1;
+	uint16_t csf_sup_ext;
+	uint16_t csf_enabled0;
+	uint16_t csf_enabled1;
+	uint16_t csf_default;
+	uint16_t udma;
+
+	uint16_t _res89[1 + 99 - 89];
+
+	/* Total number of blocks in LBA-48 addressing */
+	uint16_t total_lba48_0;
+	uint16_t total_lba48_1;
+	uint16_t total_lba48_2;
+	uint16_t total_lba48_3;
+
+	/* Note: more fields are defined in ATA/ATAPI-7 */
+	uint16_t _res104[1 + 127 - 104];
+	uint16_t _vs128[1 + 159 - 128];
+	uint16_t _res160[1 + 255 - 160];
+} identify_data_t;
+
+enum ata_caps {
+	cap_iordy	= 0x0800,
+	cap_iordy_cbd	= 0x0400,
+	cap_lba		= 0x0200,
+	cap_dma		= 0x0100
+};
+
+/** Bits of @c identify_data_t.cmd_set1 */
+enum ata_cs1 {
+	cs1_addr48	= 0x0400	/**< 48-bit address feature set */
+};
+
+/** Block addressing mode. */
+enum addr_mode {
+	am_chs,		/**< CHS block addressing */
+	am_lba28,	/**< LBA-28 block addressing */
+	am_lba48	/**< LBA-48 block addressing */
+};
+
+/** Block coordinates */
+typedef struct {
+	/** Addressing mode used */
+	enum addr_mode amode;
+
+	union {
+		/** CHS coordinates */
+		struct {
+			uint8_t sector;
+			uint8_t cyl_lo;
+			uint8_t cyl_hi;
+		};
+		/** LBA coordinates */
+		struct {
+			uint8_t c0;
+			uint8_t c1;
+			uint8_t c2;
+			uint8_t c3;
+			uint8_t c4;
+			uint8_t c5;
+		};
+	};
+
+	/** Lower 4 bits for device/head register */
+	uint8_t h;
+} block_coord_t;
+
 typedef struct {
 	bool present;
-	unsigned heads;
-	unsigned cylinders;
-	unsigned sectors;
+	enum addr_mode amode;
+
+	/*
+	 * Geometry. Only valid if operating in CHS mode.
+	 */
+	struct {
+		unsigned heads;
+		unsigned cylinders;
+		unsigned sectors;
+	} geom;
+
 	uint64_t blocks;
+
+	char model[STR_BOUNDS(40) + 1];
 
 	fibril_mutex_t lock;
Index: uspace/srv/bd/file_bd/Makefile
===================================================================
--- uspace/srv/bd/file_bd/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/file_bd/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,50 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
+.PHONY: all clean
 
-LIBC_PREFIX = ../../../lib/libc
-SOFTINT_PREFIX = ../../../lib/softint
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = file_bd
-SOURCES = \
-	file_bd.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/bd/file_bd/Makefile.build
===================================================================
--- uspace/srv/bd/file_bd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/file_bd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	file_bd.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/bd/file_bd/Makefile.common
===================================================================
--- uspace/srv/bd/file_bd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/file_bd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = file_bd
Index: uspace/srv/bd/file_bd/file_bd.c
===================================================================
--- uspace/srv/bd/file_bd/file_bd.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/file_bd/file_bd.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -51,8 +51,9 @@
 #include <bool.h>
 #include <task.h>
+#include <macros.h>
 
 #define NAME "file_bd"
 
-static size_t comm_size;
+static const size_t block_size = 512;
 static FILE *img;
 
@@ -62,6 +63,6 @@
 static int file_bd_init(const char *fname);
 static void file_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
-static int file_bd_read(off_t blk_idx, size_t size, void *buf);
-static int file_bd_write(off_t blk_idx, size_t size, void *buf);
+static int file_bd_read_blocks(uint64_t ba, size_t cnt, void *buf);
+static int file_bd_write_blocks(uint64_t ba, size_t cnt, const void *buf);
 
 int main(int argc, char **argv)
@@ -120,13 +121,14 @@
 	ipc_call_t call;
 	ipcarg_t method;
+	size_t comm_size;
 	int flags;
 	int retval;
-	off_t idx;
-	size_t size;
+	uint64_t ba;
+	size_t cnt;
 
 	/* Answer the IPC_M_CONNECT_ME_TO call. */
 	ipc_answer_0(iid, EOK);
 
-	if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
+	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
 		ipc_answer_0(callid, EHANGUP);
 		return;
@@ -139,5 +141,5 @@
 	}
 
-	(void) ipc_share_out_finalize(callid, fs_va);
+	(void) async_share_out_finalize(callid, fs_va);
 
 	while (1) {
@@ -149,17 +151,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-		case BD_WRITE_BLOCK:
-			idx = IPC_GET_ARG1(call);
-			size = IPC_GET_ARG2(call);
-			if (size > comm_size) {
-				retval = EINVAL;
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
 				break;
 			}
-			if (method == BD_READ_BLOCK)
-				retval = file_bd_read(idx, size, fs_va);
-			else
-				retval = file_bd_write(idx, size, fs_va);
+			retval = file_bd_read_blocks(ba, cnt, fs_va);
 			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = file_bd_write_blocks(ba, cnt, fs_va);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			retval = EINVAL;
@@ -170,5 +182,6 @@
 }
 
-static int file_bd_read(off_t blk_idx, size_t size, void *buf)
+/** Read blocks from the device. */
+static int file_bd_read_blocks(uint64_t ba, size_t cnt, void *buf)
 {
 	size_t n_rd;
@@ -176,6 +189,6 @@
 	fibril_mutex_lock(&dev_lock);
 
-	fseek(img, blk_idx * size, SEEK_SET);
-	n_rd = fread(buf, 1, size, img);
+	fseek(img, ba * block_size, SEEK_SET);
+	n_rd = fread(buf, block_size, cnt, img);
 
 	if (ferror(img)) {
@@ -186,11 +199,12 @@
 	fibril_mutex_unlock(&dev_lock);
 
-	if (n_rd < size) 
-		return EINVAL;	/* Read beyond end of disk */
+	if (n_rd < cnt)
+		return EINVAL;	/* Read beyond end of device */
 
 	return EOK;
 }
 
-static int file_bd_write(off_t blk_idx, size_t size, void *buf)
+/** Write blocks to the device. */
+static int file_bd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
 {
 	size_t n_wr;
@@ -198,8 +212,8 @@
 	fibril_mutex_lock(&dev_lock);
 
-	fseek(img, blk_idx * size, SEEK_SET);
-	n_wr = fread(buf, 1, size, img);
-
-	if (ferror(img) || n_wr < size) {
+	fseek(img, ba * block_size, SEEK_SET);
+	n_wr = fread(buf, block_size, cnt, img);
+
+	if (ferror(img) || n_wr < cnt) {
 		fibril_mutex_unlock(&dev_lock);
 		return EIO;	/* Write error */
Index: uspace/srv/bd/gxe_bd/Makefile
===================================================================
--- uspace/srv/bd/gxe_bd/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/gxe_bd/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,50 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
+.PHONY: all clean
 
-LIBC_PREFIX = ../../../lib/libc
-SOFTINT_PREFIX = ../../../lib/softint
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = gxe_bd
-SOURCES = \
-	gxe_bd.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/bd/gxe_bd/Makefile.build
===================================================================
--- uspace/srv/bd/gxe_bd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/gxe_bd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	gxe_bd.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/bd/gxe_bd/Makefile.common
===================================================================
--- uspace/srv/bd/gxe_bd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/gxe_bd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = gxe_bd
Index: uspace/srv/bd/gxe_bd/gxe_bd.c
===================================================================
--- uspace/srv/bd/gxe_bd/gxe_bd.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/gxe_bd/gxe_bd.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -47,4 +47,5 @@
 #include <sys/types.h>
 #include <errno.h>
+#include <macros.h>
 #include <task.h>
 
@@ -97,10 +98,10 @@
 static int gxe_bd_init(void);
 static void gxe_bd_connection(ipc_callid_t iid, ipc_call_t *icall);
-static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
+static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
     void *buf);
-static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size,
-    void *buf);
-static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size,
+static int gxe_bd_write_blocks(int disk_id, uint64_t ba, unsigned cnt,
     const void *buf);
+static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf);
+static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf);
 
 int main(int argc, char **argv)
@@ -163,6 +164,6 @@
 	int flags;
 	int retval;
-	off_t idx;
-	size_t size;
+	uint64_t ba;
+	unsigned cnt;
 	int disk_id, i;
 
@@ -184,5 +185,10 @@
 	ipc_answer_0(iid, EOK);
 
-	if (!ipc_share_out_receive(&callid, &comm_size, &flags)) {
+	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
+		ipc_answer_0(callid, EHANGUP);
+		return;
+	}
+
+	if (comm_size < block_size) {
 		ipc_answer_0(callid, EHANGUP);
 		return;
@@ -195,5 +201,5 @@
 	}
 
-	(void) ipc_share_out_finalize(callid, fs_va);
+	(void) async_share_out_finalize(callid, fs_va);
 
 	while (1) {
@@ -205,15 +211,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-		case BD_WRITE_BLOCK:
-			idx = IPC_GET_ARG1(call);
-			size = IPC_GET_ARG2(call);
-			if (size > comm_size) {
-				retval = EINVAL;
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
 				break;
 			}
-			retval = gx_bd_rdwr(disk_id, method, idx * size,
-			    size, fs_va);
+			retval = gxe_bd_read_blocks(disk_id, ba, cnt, fs_va);
 			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = gxe_bd_write_blocks(disk_id, ba, cnt, fs_va);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			retval = EINVAL;
@@ -224,43 +242,55 @@
 }
 
-static int gx_bd_rdwr(int disk_id, ipcarg_t method, off_t offset, size_t size,
-    void *buf)
-{
+/** Read multiple blocks from the device. */
+static int gxe_bd_read_blocks(int disk_id, uint64_t ba, unsigned cnt,
+    void *buf) {
+
 	int rc;
-	size_t now;
-
-	while (size > 0) {
-		now = size < block_size ? size : block_size;
-
-		if (method == BD_READ_BLOCK)
-			rc = gxe_bd_read_block(disk_id, offset, now, buf);
-		else
-			rc = gxe_bd_write_block(disk_id, offset, now, buf);
-
+
+	while (cnt > 0) {
+		rc = gxe_bd_read_block(disk_id, ba, buf);
 		if (rc != EOK)
 			return rc;
 
+		++ba;
+		--cnt;
 		buf += block_size;
-		offset += block_size;
-
-		if (size > block_size)
-			size -= block_size;
-		else
-			size = 0;
-	}
-
-	return EOK;
-}
-
-static int gxe_bd_read_block(int disk_id, uint64_t offset, size_t size,
-    void *buf)
+	}
+
+	return EOK;
+}
+
+/** Write multiple blocks to the device. */
+static int gxe_bd_write_blocks(int disk_id, uint64_t ba, unsigned cnt,
+    const void *buf) {
+
+	int rc;
+
+	while (cnt > 0) {
+		rc = gxe_bd_write_block(disk_id, ba, buf);
+		if (rc != EOK)
+			return rc;
+
+		++ba;
+		--cnt;
+		buf += block_size;
+	}
+
+	return EOK;
+}
+
+/** Read a block from the device. */
+static int gxe_bd_read_block(int disk_id, uint64_t ba, void *buf)
 {
 	uint32_t status;
+	uint64_t byte_addr;
 	size_t i;
 	uint32_t w;
 
+	byte_addr = ba * block_size;
+
 	fibril_mutex_lock(&dev_lock[disk_id]);
-	pio_write_32(&dev->offset_lo, (uint32_t) offset);
-	pio_write_32(&dev->offset_hi, offset >> 32);
+	pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
+	pio_write_32(&dev->offset_hi, byte_addr >> 32);
 	pio_write_32(&dev->disk_id, disk_id);
 	pio_write_32(&dev->control, CTL_READ_START);
@@ -272,5 +302,5 @@
 	}
 
-	for (i = 0; i < size; i++) {
+	for (i = 0; i < block_size; i++) {
 		((uint8_t *) buf)[i] = w = pio_read_8(&dev->buffer[i]);
 	}
@@ -280,17 +310,21 @@
 }
 
-static int gxe_bd_write_block(int disk_id, uint64_t offset, size_t size,
-    const void *buf)
+/** Write a block to the device. */
+static int gxe_bd_write_block(int disk_id, uint64_t ba, const void *buf)
 {
 	uint32_t status;
+	uint64_t byte_addr;
 	size_t i;
 
-	for (i = 0; i < size; i++) {
+	byte_addr = ba * block_size;
+
+	fibril_mutex_lock(&dev_lock[disk_id]);
+
+	for (i = 0; i < block_size; i++) {
 		pio_write_8(&dev->buffer[i], ((const uint8_t *) buf)[i]);
 	}
 
-	fibril_mutex_lock(&dev_lock[disk_id]);
-	pio_write_32(&dev->offset_lo, (uint32_t) offset);
-	pio_write_32(&dev->offset_hi, offset >> 32);
+	pio_write_32(&dev->offset_lo, (uint32_t) byte_addr);
+	pio_write_32(&dev->offset_hi, byte_addr >> 32);
 	pio_write_32(&dev->disk_id, disk_id);
 	pio_write_32(&dev->control, CTL_WRITE_START);
Index: uspace/srv/bd/rd/Makefile
===================================================================
--- uspace/srv/bd/rd/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/rd/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,50 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
+.PHONY: all clean
 
-LIBC_PREFIX = ../../../lib/libc
-SOFTINT_PREFIX = ../../../lib/softint
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = rd
-SOURCES = \
-	rd.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/bd/rd/Makefile.build
===================================================================
--- uspace/srv/bd/rd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/rd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	rd.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/bd/rd/Makefile.common
===================================================================
--- uspace/srv/bd/rd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/bd/rd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = rd
Index: uspace/srv/bd/rd/rd.c
===================================================================
--- uspace/srv/bd/rd/rd.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/bd/rd/rd.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -55,11 +55,18 @@
 #include <devmap.h>
 #include <ipc/bd.h>
+#include <macros.h>
 
 #define NAME "rd"
 
-/** Pointer to the ramdisk's image. */
+/** Pointer to the ramdisk's image */
 static void *rd_addr;
-/** Size of the ramdisk. */
+/** Size of the ramdisk */
 static size_t rd_size;
+
+/** Block size */
+static const size_t block_size = 512;
+
+static int rd_read_blocks(uint64_t ba, size_t cnt, void *buf);
+static int rd_write_blocks(uint64_t ba, size_t cnt, const void *buf);
 
 /**
@@ -82,7 +89,7 @@
 	int retval;
 	void *fs_va = NULL;
-	off_t offset;
-	size_t block_size;
-	size_t maxblock_size;
+	uint64_t ba;
+	size_t cnt;
+	size_t comm_size;
 
 	/*
@@ -95,8 +102,8 @@
 	 */
 	int flags;
-	if (ipc_share_out_receive(&callid, &maxblock_size, &flags)) {
-		fs_va = as_get_mappable_page(maxblock_size);
+	if (async_share_out_receive(&callid, &comm_size, &flags)) {
+		fs_va = as_get_mappable_page(comm_size);
 		if (fs_va) {
-			(void) ipc_share_out_finalize(callid, fs_va);
+			(void) async_share_out_finalize(callid, fs_va);
 		} else {
 			ipc_answer_0(callid, EHANGUP);
@@ -123,48 +130,27 @@
 			ipc_answer_0(callid, EOK);
 			return;
-		case BD_READ_BLOCK:
-			offset = IPC_GET_ARG1(call);
-			block_size = IPC_GET_ARG2(call);
-			if (block_size > maxblock_size) {
-				/*
-				 * Maximum block size exceeded.
-				 */
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
 				retval = ELIMIT;
 				break;
 			}
-			if (offset * block_size > rd_size - block_size) {
-				/*
-				 * Reading past the end of the device.
-				 */
+			retval = rd_read_blocks(ba, cnt, fs_va);
+			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
 				retval = ELIMIT;
 				break;
 			}
-			fibril_rwlock_read_lock(&rd_lock);
-			memcpy(fs_va, rd_addr + offset * block_size, block_size);
-			fibril_rwlock_read_unlock(&rd_lock);
-			retval = EOK;
+			retval = rd_write_blocks(ba, cnt, fs_va);
 			break;
-		case BD_WRITE_BLOCK:
-			offset = IPC_GET_ARG1(call);
-			block_size = IPC_GET_ARG2(call);
-			if (block_size > maxblock_size) {
-				/*
-				 * Maximum block size exceeded.
-				 */
-				retval = ELIMIT;
-				break;
-			}
-			if (offset * block_size > rd_size - block_size) {
-				/*
-				 * Writing past the end of the device.
-				 */
-				retval = ELIMIT;
-				break;
-			}
-			fibril_rwlock_write_lock(&rd_lock);
-			memcpy(rd_addr + offset * block_size, fs_va, block_size);
-			fibril_rwlock_write_unlock(&rd_lock);
-			retval = EOK;
-			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
 		default:
 			/*
@@ -181,4 +167,34 @@
 }
 
+/** Read blocks from the device. */
+static int rd_read_blocks(uint64_t ba, size_t cnt, void *buf)
+{
+	if ((ba + cnt) * block_size > rd_size) {
+		/* Reading past the end of the device. */
+		return ELIMIT;
+	}
+
+	fibril_rwlock_read_lock(&rd_lock);
+	memcpy(buf, rd_addr + ba * block_size, block_size * cnt);
+	fibril_rwlock_read_unlock(&rd_lock);
+
+	return EOK;
+}
+
+/** Write blocks to the device. */
+static int rd_write_blocks(uint64_t ba, size_t cnt, const void *buf)
+{
+	if ((ba + cnt) * block_size > rd_size) {
+		/* Writing past the end of the device. */
+		return ELIMIT;
+	}
+
+	fibril_rwlock_write_lock(&rd_lock);
+	memcpy(rd_addr + ba * block_size, buf, block_size * cnt);
+	fibril_rwlock_write_unlock(&rd_lock);
+
+	return EOK;
+}
+
 /** Prepare the ramdisk image for operation. */
 static bool rd_init(void)
Index: uspace/srv/cir/fhc/Makefile
===================================================================
--- uspace/srv/cir/fhc/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/cir/fhc/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,50 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
+.PHONY: all clean
 
-LIBC_PREFIX = ../../../lib/libc
-SOFTINT_PREFIX = ../../../lib/softint
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = fhc
-SOURCES = \
-	fhc.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/cir/fhc/Makefile.build
===================================================================
--- uspace/srv/cir/fhc/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/cir/fhc/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	fhc.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/cir/fhc/Makefile.common
===================================================================
--- uspace/srv/cir/fhc/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/cir/fhc/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = fhc
Index: uspace/srv/cir/obio/Makefile
===================================================================
--- uspace/srv/cir/obio/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/cir/obio/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,50 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
+.PHONY: all clean
 
-LIBC_PREFIX = ../../../lib/libc
-SOFTINT_PREFIX = ../../../lib/softint
-
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = obio
-SOURCES = \
-	obio.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/cir/obio/Makefile.build
===================================================================
--- uspace/srv/cir/obio/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/cir/obio/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	obio.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/cir/obio/Makefile.common
===================================================================
--- uspace/srv/cir/obio/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/cir/obio/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = obio
Index: uspace/srv/console/Makefile
===================================================================
--- uspace/srv/console/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/console/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,73 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../lib/libc
-SOFTINT_PREFIX = ../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-CFLAGS += -I.
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = console
-
-GENERIC_SOURCES = \
-	console.c \
-	screenbuffer.c \
-	keybuffer.c \
-	gcons.c
-
-IMAGES = \
-	gfx/helenos.ppm \
-	gfx/nameic.ppm \
-	gfx/cons_selected.ppm \
-	gfx/cons_idle.ppm \
-	gfx/cons_has_data.ppm \
-	gfx/cons_kernel.ppm \
-	gfx/anim_1.ppm \
-	gfx/anim_2.ppm \
-	gfx/anim_3.ppm \
-	gfx/anim_4.ppm
-
-GENERIC_OBJECTS := $(addsuffix .o,$(basename $(GENERIC_SOURCES))) \
-	$(addsuffix .o,$(basename $(IMAGES)))
-
-OBJECTS := $(GENERIC_OBJECTS)
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
-
-%.o: %.ppm
-	$(OBJCOPY) -I binary -O $(BFD_NAME) -B $(BFD_ARCH) $< $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/console/Makefile.build
===================================================================
--- uspace/srv/console/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/console/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,79 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	console.c \
+	screenbuffer.c \
+	keybuffer.c \
+	gcons.c
+
+IMAGES = \
+	gfx/helenos.ppm \
+	gfx/nameic.ppm \
+	gfx/cons_selected.ppm \
+	gfx/cons_idle.ppm \
+	gfx/cons_has_data.ppm \
+	gfx/cons_kernel.ppm \
+	gfx/anim_1.ppm \
+	gfx/anim_2.ppm \
+	gfx/anim_3.ppm \
+	gfx/anim_4.ppm
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES))) $(addsuffix .o,$(basename $(IMAGES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+%.o: %.ppm
+	$(OBJCOPY) -I binary -O $(BFD_NAME) -B $(BFD_ARCH) $< $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/console/Makefile.common
===================================================================
--- uspace/srv/console/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/console/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = console
Index: uspace/srv/console/console.c
===================================================================
--- uspace/srv/console/console.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/console/console.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -40,5 +40,4 @@
 #include <ipc/services.h>
 #include <errno.h>
-#include <keybuffer.h>
 #include <ipc/console.h>
 #include <unistd.h>
@@ -55,4 +54,5 @@
 #include "console.h"
 #include "gcons.h"
+#include "keybuffer.h"
 #include "screenbuffer.h"
 
@@ -429,5 +429,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -442,5 +442,5 @@
 	}
 	
-	(void) ipc_data_write_finalize(callid, buf, size);
+	(void) async_data_write_finalize(callid, buf, size);
 	
 	async_serialize_start();
@@ -464,5 +464,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_read_receive(&callid, &size)) {
+	if (!async_data_read_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -489,5 +489,5 @@
 	
 	if (pos == size) {
-		(void) ipc_data_read_finalize(callid, buf, size);
+		(void) async_data_read_finalize(callid, buf, size);
 		ipc_answer_1(rid, EOK, size);
 		free(buf);
@@ -713,5 +713,5 @@
 	
 	if (interbuffer) {
-		if (ipc_share_out_start(fb_info.phone, interbuffer,
+		if (async_share_out_start(fb_info.phone, interbuffer,
 		    AS_AREA_READ) != EOK) {
 			as_area_destroy(interbuffer);
Index: uspace/srv/console/gcons.c
===================================================================
--- uspace/srv/console/gcons.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/console/gcons.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -339,5 +339,5 @@
 		goto exit;
 	
-	rc = ipc_share_out_start(fbphone, shm, PROTO_READ);
+	rc = async_share_out_start(fbphone, shm, PROTO_READ);
 	if (rc)
 		goto drop;
@@ -409,5 +409,5 @@
 		goto exit;
 	
-	rc = ipc_share_out_start(fbphone, shm, PROTO_READ);
+	rc = async_share_out_start(fbphone, shm, PROTO_READ);
 	if (rc)
 		goto drop;
Index: uspace/srv/console/keybuffer.c
===================================================================
--- uspace/srv/console/keybuffer.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/console/keybuffer.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -35,6 +35,6 @@
  */
 
-#include <keybuffer.h>
 #include <futex.h>
+#include "keybuffer.h"
 
 atomic_t keybuffer_futex = FUTEX_INITIALIZER;
Index: uspace/srv/console/screenbuffer.c
===================================================================
--- uspace/srv/console/screenbuffer.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/console/screenbuffer.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -33,8 +33,8 @@
  */
 
-#include <screenbuffer.h>
 #include <io/style.h>
 #include <malloc.h>
 #include <unistd.h>
+#include "screenbuffer.h"
 
 /** Store one character to screenbuffer.
Index: uspace/srv/devmap/Makefile
===================================================================
--- uspace/srv/devmap/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/devmap/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,51 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../lib/libc
-SOFTINT_PREFIX = ../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = devmap
-SOURCES = \
-	devmap.c 
-
-CFLAGS += -D$(UARCH)
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/devmap/Makefile.build
===================================================================
--- uspace/srv/devmap/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/devmap/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	devmap.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/devmap/Makefile.common
===================================================================
--- uspace/srv/devmap/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/devmap/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = devmap
Index: uspace/srv/devmap/devmap.c
===================================================================
--- uspace/srv/devmap/devmap.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/devmap/devmap.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -213,5 +213,5 @@
 	ipc_callid_t callid;
 	size_t name_size;
-	if (!ipc_data_write_receive(&callid, &name_size)) {
+	if (!async_data_write_receive(&callid, &name_size)) {
 		free(driver);
 		ipc_answer_0(callid, EREFUSED);
@@ -241,5 +241,5 @@
 	 * Send confirmation to sender and get data into buffer.
 	 */
-	if (ipc_data_write_finalize(callid, driver->name, name_size) != EOK) {
+	if (async_data_write_finalize(callid, driver->name, name_size) != EOK) {
 		free(driver->name);
 		free(driver);
@@ -358,5 +358,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		free(device);
 		ipc_answer_0(iid, EREFUSED);
@@ -381,5 +381,5 @@
 	}
 	
-	ipc_data_write_finalize(callid, device->name, size);
+	async_data_write_finalize(callid, device->name, size);
 	device->name[size] = 0;
 	
@@ -466,5 +466,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EREFUSED);
 		ipc_answer_0(iid, EREFUSED);
@@ -491,5 +491,5 @@
 	 * Send confirmation to sender and get data into buffer.
 	 */
-	ipcarg_t retval = ipc_data_write_finalize(callid, name, size);
+	ipcarg_t retval = async_data_write_finalize(callid, name, size);
 	if (retval != EOK) {
 		ipc_answer_0(iid, EREFUSED);
@@ -553,5 +553,5 @@
 	 * size_t name_size = str_size(device->name);
 	 *
-	 * int rc = ipc_data_write_send(phone, device->name, name_size);
+	 * int rc = async_data_write_send(phone, device->name, name_size);
 	 * if (rc != EOK) {
 	 *     async_wait_for(req, NULL);
@@ -576,5 +576,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_read_receive(&callid, &size)) {
+	if (!async_data_read_receive(&callid, &size)) {
 		ipc_answer_0(callid, EREFUSED);
 		ipc_answer_0(iid, EREFUSED);
@@ -608,5 +608,5 @@
 	}
 	
-	ipcarg_t retval = ipc_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
+	ipcarg_t retval = async_data_read_finalize(callid, desc, pos * sizeof(dev_desc_t));
 	if (retval != EOK) {
 		ipc_answer_0(iid, EREFUSED);
Index: uspace/srv/fb/Makefile
===================================================================
--- uspace/srv/fb/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fb/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,89 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../lib/libc
-SOFTINT_PREFIX = ../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = fb
-SOURCES = \
-	main.c \
-	ppm.c
-
-ifneq ($(UARCH),ia64)
-	SOURCES += fb.c \
-		font-8x16.c
-	CFLAGS += -DFB_ENABLED
-endif
-
-ifeq ($(UARCH),ia32)
-	SOURCES += ega.c
-	CFLAGS += -DEGA_ENABLED
-endif
-
-ifeq ($(UARCH),ia64)
-	SOURCES += ega.c \
-		ski.c \
-		serial_console.c
-	CFLAGS += -DSKI_ENABLED
-	CFLAGS += -DEGA_ENABLED
-endif
-
-ifeq ($(UARCH),amd64)
-	SOURCES += ega.c
-	CFLAGS += -DEGA_ENABLED
-endif
-
-ifeq ($(UARCH),mips32)
-	SOURCES += msim.c \
-		serial_console.c
-	CFLAGS += -DMSIM_ENABLED
-endif
-
-ifeq ($(UARCH),sparc64)
-	SOURCES += sgcn.c \
-		serial_console.c
-	CFLAGS += -DSGCN_ENABLED
-endif
-
-CFLAGS += -D$(UARCH)
-
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/fb/Makefile.build
===================================================================
--- uspace/srv/fb/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fb/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,100 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	main.c \
+	ppm.c
+
+ifneq ($(UARCH),ia64)
+	SOURCES += fb.c \
+		font-8x16.c
+	CFLAGS += -DFB_ENABLED
+endif
+
+ifeq ($(UARCH),ia32)
+	SOURCES += ega.c
+	CFLAGS += -DEGA_ENABLED
+endif
+
+ifeq ($(UARCH),ia64)
+	SOURCES += ega.c \
+		ski.c \
+		serial_console.c
+	CFLAGS += -DSKI_ENABLED
+	CFLAGS += -DEGA_ENABLED
+endif
+
+ifeq ($(UARCH),amd64)
+	SOURCES += ega.c
+	CFLAGS += -DEGA_ENABLED
+endif
+
+ifeq ($(UARCH),mips32)
+	SOURCES += msim.c \
+		serial_console.c
+	CFLAGS += -DMSIM_ENABLED
+endif
+
+ifeq ($(UARCH),sparc64)
+	SOURCES += sgcn.c \
+		serial_console.c
+	CFLAGS += -DSGCN_ENABLED
+endif
+
+CFLAGS += -D$(UARCH)
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/fb/Makefile.common
===================================================================
--- uspace/srv/fb/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fb/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = fb
Index: uspace/srv/fs/devfs/Makefile
===================================================================
--- uspace/srv/fs/devfs/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/devfs/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,56 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../../lib/libc
-LIBFS_PREFIX = ../../../lib/libfs
-SOFTINT_PREFIX = ../../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-CFLAGS += -I $(LIBFS_PREFIX) 
-
-LIBS = \
-	$(LIBFS_PREFIX)/libfs.a \
-	$(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = devfs
-SOURCES = \
-	devfs.c \
-	devfs_ops.c
-
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/fs/devfs/Makefile.build
===================================================================
--- uspace/srv/fs/devfs/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fs/devfs/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,64 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I$(LIBFS_PREFIX)
+
+## Sources
+#
+
+SOURCES = \
+	devfs.c \
+	devfs_ops.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/fs/devfs/Makefile.common
===================================================================
--- uspace/srv/fs/devfs/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fs/devfs/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+LIBFS_PREFIX = ../../../lib/libfs
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBFS_PREFIX)/libfs.a $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = devfs
Index: uspace/srv/fs/devfs/devfs.c
===================================================================
--- uspace/srv/fs/devfs/devfs.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/devfs/devfs.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -44,4 +44,5 @@
 #include <async.h>
 #include <errno.h>
+#include <task.h>
 #include <libfs.h>
 #include "devfs.h"
@@ -51,5 +52,5 @@
 
 static vfs_info_t devfs_vfs_info = {
-	.name = "devfs",
+	.name = NAME,
 };
 
@@ -131,4 +132,5 @@
 	
 	printf(NAME ": Accepting connections\n");
+	task_retval(0);
 	async_manager();
 	
Index: uspace/srv/fs/devfs/devfs_ops.c
===================================================================
--- uspace/srv/fs/devfs/devfs_ops.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/devfs/devfs_ops.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -108,5 +108,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -121,5 +121,5 @@
 	}
 	
-	ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
+	ipcarg_t retval = async_data_write_finalize(callid, opts, size);
 	if (retval != EOK) {
 		ipc_answer_0(rid, retval);
@@ -286,5 +286,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_read_receive(&callid, &size) ||
+	if (!async_data_read_receive(&callid, &size) ||
 	    size != sizeof(struct stat)) {
 		ipc_answer_0(callid, EINVAL);
@@ -315,5 +315,5 @@
 	}
 
-	ipc_data_read_finalize(callid, &stat, sizeof(struct stat));
+	async_data_read_finalize(callid, &stat, sizeof(struct stat));
 	ipc_answer_0(rid, EOK);
 }
@@ -340,5 +340,5 @@
 		
 		ipc_callid_t callid;
-		if (!ipc_data_read_receive(&callid, NULL)) {
+		if (!async_data_read_receive(&callid, NULL)) {
 			fibril_mutex_unlock(&devices_mutex);
 			ipc_answer_0(callid, EINVAL);
@@ -367,5 +367,5 @@
 		ipc_callid_t callid;
 		size_t size;
-		if (!ipc_data_read_receive(&callid, &size)) {
+		if (!async_data_read_receive(&callid, &size)) {
 			ipc_answer_0(callid, EINVAL);
 			ipc_answer_0(rid, EINVAL);
@@ -384,5 +384,5 @@
 		
 		if (pos < max) {
-			ipc_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
+			async_data_read_finalize(callid, desc[pos].name, str_size(desc[pos].name) + 1);
 		} else {
 			ipc_answer_0(callid, ENOENT);
@@ -418,5 +418,5 @@
 		
 		ipc_callid_t callid;
-		if (!ipc_data_write_receive(&callid, NULL)) {
+		if (!async_data_write_receive(&callid, NULL)) {
 			fibril_mutex_unlock(&devices_mutex);
 			ipc_answer_0(callid, EINVAL);
Index: uspace/srv/fs/fat/Makefile
===================================================================
--- uspace/srv/fs/fat/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/fat/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,60 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../../lib/libc
-LIBFS_PREFIX = ../../../lib/libfs
-LIBBLOCK_PREFIX = ../../../lib/libblock
-SOFTINT_PREFIX = ../../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-CFLAGS += -I $(LIBFS_PREFIX) -I $(LIBBLOCK_PREFIX)
-
-LIBS = \
-	$(LIBFS_PREFIX)/libfs.a \
-	$(LIBBLOCK_PREFIX)/libblock.a \
-	$(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = fat
-SOURCES = \
-	fat.c \
-	fat_ops.c \
-	fat_idx.c \
-	fat_dentry.c \
-	fat_fat.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/fs/fat/Makefile.build
===================================================================
--- uspace/srv/fs/fat/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fs/fat/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,67 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I$(LIBFS_PREFIX) -I$(LIBBLOCK_PREFIX)
+
+## Sources
+#
+
+SOURCES = \
+	fat.c \
+	fat_ops.c \
+	fat_idx.c \
+	fat_dentry.c \
+	fat_fat.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/fs/fat/Makefile.common
===================================================================
--- uspace/srv/fs/fat/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fs/fat/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+LIBFS_PREFIX = ../../../lib/libfs
+LIBBLOCK_PREFIX = ../../../lib/libblock
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBFS_PREFIX)/libfs.a $(LIBBLOCK_PREFIX)/libblock.a $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = fat
Index: uspace/srv/fs/fat/fat.c
===================================================================
--- uspace/srv/fs/fat/fat.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/fat/fat.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -43,11 +43,13 @@
 #include <errno.h>
 #include <unistd.h>
+#include <task.h>
 #include <stdio.h>
 #include <libfs.h>
 #include "../../vfs/vfs.h"
 
+#define NAME	"fat"
 
 vfs_info_t fat_vfs_info = {
-	.name = "fat",
+	.name = NAME,
 };
 
@@ -83,5 +85,5 @@
 	}
 	
-	dprintf("VFS-FAT connection established.\n");
+	dprintf(NAME ": connection opened\n");
 	while (1) {
 		ipc_callid_t callid;
@@ -137,5 +139,5 @@
 	int rc;
 
-	printf("fat: HelenOS FAT file system server.\n");
+	printf(NAME ": HelenOS FAT file system server\n");
 
 	rc = fat_idx_init();
@@ -145,5 +147,5 @@
 	vfs_phone = ipc_connect_me_to_blocking(PHONE_NS, SERVICE_VFS, 0, 0);
 	if (vfs_phone < EOK) {
-		printf("fat: failed to connect to VFS\n");
+		printf(NAME ": failed to connect to VFS\n");
 		return -1;
 	}
@@ -155,7 +157,6 @@
 	}
 	
-	dprintf("FAT filesystem registered, fs_handle=%d.\n",
-	    fat_reg.fs_handle);
-
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
 	async_manager();
 	/* not reached */
@@ -163,5 +164,5 @@
 
 err:
-	printf("Failed to register the FAT file system (%d)\n", rc);
+	printf(NAME ": Failed to register file system (%d)\n", rc);
 	return rc;
 }
Index: uspace/srv/fs/fat/fat.h
===================================================================
--- uspace/srv/fs/fat/fat.h	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/fat/fat.h	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -89,5 +89,5 @@
 			uint16_t	signature;
 		} __attribute__ ((packed));
-		struct {
+		struct fat32 {
 			/* FAT32 only */
 			/** Sectors per FAT. */
@@ -215,5 +215,5 @@
 extern void fat_sync(ipc_callid_t, ipc_call_t *);
 
-extern fat_idx_t *fat_idx_get_new(dev_handle_t);
+extern int fat_idx_get_new(fat_idx_t **, dev_handle_t);
 extern fat_idx_t *fat_idx_get_by_pos(dev_handle_t, fat_cluster_t, unsigned);
 extern fat_idx_t *fat_idx_get_by_index(dev_handle_t, fs_index_t);
Index: uspace/srv/fs/fat/fat_fat.c
===================================================================
--- uspace/srv/fs/fat/fat_fat.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/fat/fat_fat.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -61,12 +61,15 @@
  * @param dev_handle	Device handle of the device with the file.
  * @param firstc	First cluster to start the walk with.
- * @param lastc		If non-NULL, output argument hodling the last cluster number visited.
+ * @param lastc		If non-NULL, output argument hodling the last cluster
+ *			number visited.
+ * @param numc		If non-NULL, output argument holding the number of
+ *			clusters seen during the walk.
  * @param max_clusters	Maximum number of clusters to visit.	
  *
- * @return		Number of clusters seen during the walk.
- */
-uint16_t 
+ * @return		EOK on success or a negative error code.
+ */
+int 
 fat_cluster_walk(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
-    fat_cluster_t *lastc, uint16_t max_clusters)
+    fat_cluster_t *lastc, uint16_t *numc, uint16_t max_clusters)
 {
 	block_t *b;
@@ -75,4 +78,5 @@
 	uint16_t clusters = 0;
 	fat_cluster_t clst = firstc;
+	int rc;
 
 	bps = uint16_t_le2host(bs->bps);
@@ -83,5 +87,7 @@
 		if (lastc)
 			*lastc = firstc;
-		return 0;
+		if (numc)
+			*numc = 0;
+		return EOK;
 	}
 
@@ -96,8 +102,12 @@
 		fidx = clst % (bps / sizeof(fat_cluster_t));
 		/* read FAT1 */
-		b = block_get(dev_handle, rscnt + fsec, BLOCK_FLAGS_NONE);
+		rc = block_get(&b, dev_handle, rscnt + fsec, BLOCK_FLAGS_NONE);
+		if (rc != EOK)
+			return rc;
 		clst = uint16_t_le2host(((fat_cluster_t *)b->data)[fidx]);
 		assert(clst != FAT_CLST_BAD);
-		block_put(b);
+		rc = block_put(b);
+		if (rc != EOK)
+			return rc;
 		clusters++;
 	}
@@ -105,10 +115,13 @@
 	if (lastc && clst < FAT_CLST_LAST1)
 		*lastc = clst;
-
-	return clusters;
+	if (numc)
+		*numc = clusters;
+
+	return EOK;
 }
 
 /** Read block from file located on a FAT file system.
  *
+ * @param block		Pointer to a block pointer for storing result.
  * @param bs		Buffer holding the boot sector of the file system.
  * @param dev_handle	Device handle of the file system.
@@ -118,11 +131,10 @@
  * @param flags		Flags passed to libblock.
  *
- * @return		Block structure holding the requested block.
- */
-block_t *
-_fat_block_get(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc,
-    bn_t bn, int flags)
-{
-	block_t *b;
+ * @return		EOK on success or a negative error code.
+ */
+int
+_fat_block_get(block_t **block, fat_bs_t *bs, dev_handle_t dev_handle,
+    fat_cluster_t firstc, bn_t bn, int flags)
+{
 	unsigned bps;
 	unsigned rscnt;		/* block address of the first FAT */
@@ -131,6 +143,8 @@
 	unsigned sf;
 	unsigned ssa;		/* size of the system area */
-	unsigned clusters, max_clusters;
+	uint16_t clusters;
+	unsigned max_clusters;
 	fat_cluster_t lastc;
+	int rc;
 
 	bps = uint16_t_le2host(bs->bps);
@@ -146,17 +160,20 @@
 		/* root directory special case */
 		assert(bn < rds);
-		b = block_get(dev_handle, rscnt + bs->fatcnt * sf + bn, flags);
-		return b;
+		rc = block_get(block, dev_handle, rscnt + bs->fatcnt * sf + bn,
+		    flags);
+		return rc;
 	}
 
 	max_clusters = bn / bs->spc;
-	clusters = fat_cluster_walk(bs, dev_handle, firstc, &lastc,
+	rc = fat_cluster_walk(bs, dev_handle, firstc, &lastc, &clusters,
 	    max_clusters);
+	if (rc != EOK)
+		return rc;
 	assert(clusters == max_clusters);
 
-	b = block_get(dev_handle, ssa + (lastc - FAT_CLST_FIRST) * bs->spc +
-	    bn % bs->spc, flags);
-
-	return b;
+	rc = block_get(block, dev_handle,
+	    ssa + (lastc - FAT_CLST_FIRST) * bs->spc + bn % bs->spc, flags);
+
+	return rc;
 }
 
@@ -170,6 +187,8 @@
  *			this argument is ignored.
  * @param pos		Position in the last node block.
- */
-void fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, off_t pos)
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int fat_fill_gap(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl, off_t pos)
 {
 	uint16_t bps;
@@ -177,4 +196,5 @@
 	block_t *b;
 	off_t o, boundary;
+	int rc;
 
 	bps = uint16_t_le2host(bs->bps);
@@ -188,21 +208,31 @@
 	    	int flags = (o % bps == 0) ?
 		    BLOCK_FLAGS_NOREAD : BLOCK_FLAGS_NONE;
-		b = fat_block_get(bs, nodep, o / bps, flags);
+		rc = fat_block_get(&b, bs, nodep, o / bps, flags);
+		if (rc != EOK)
+			return rc;
 		memset(b->data + o % bps, 0, bps - o % bps);
 		b->dirty = true;		/* need to sync node */
-		block_put(b);
+		rc = block_put(b);
+		if (rc != EOK)
+			return rc;
 	}
 	
 	if (o >= pos)
-		return;
+		return EOK;
 	
 	/* zero out the initial part of the new cluster chain */
 	for (o = boundary; o < pos; o += bps) {
-		b = _fat_block_get(bs, nodep->idx->dev_handle, mcl,
+		rc = _fat_block_get(&b, bs, nodep->idx->dev_handle, mcl,
 		    (o - boundary) / bps, BLOCK_FLAGS_NOREAD);
+		if (rc != EOK)
+			return rc;
 		memset(b->data, 0, min(bps, pos - o));
 		b->dirty = true;		/* need to sync node */
-		block_put(b);
-	}
+		rc = block_put(b);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
 }
 
@@ -212,25 +242,30 @@
  * @param dev_handle	Device handle for the file system.
  * @param clst		Cluster which to get.
- *
- * @return		Value found in the cluster.
- */
-fat_cluster_t
-fat_get_cluster(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t clst)
+ * @param value		Output argument holding the value of the cluster.
+ *
+ * @return		EOK or a negative error code.
+ */
+int
+fat_get_cluster(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t clst,
+    fat_cluster_t *value)
 {
 	block_t *b;
 	uint16_t bps;
 	uint16_t rscnt;
-	fat_cluster_t *cp, value;
+	fat_cluster_t *cp;
+	int rc;
 
 	bps = uint16_t_le2host(bs->bps);
 	rscnt = uint16_t_le2host(bs->rscnt);
 
-	b = block_get(dev_handle, rscnt + (clst * sizeof(fat_cluster_t)) / bps,
-	    BLOCK_FLAGS_NONE);
+	rc = block_get(&b, dev_handle, rscnt +
+	    (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
 	cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
-	value = uint16_t_le2host(*cp);
-	block_put(b);
-	
-	return value;
+	*value = uint16_t_le2host(*cp);
+	rc = block_put(b);
+	
+	return rc;
 }
 
@@ -242,6 +277,8 @@
  * @param clst		Cluster which is to be set.
  * @param value		Value to set the cluster with.
- */
-void
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int
 fat_set_cluster(fat_bs_t *bs, dev_handle_t dev_handle, unsigned fatno,
     fat_cluster_t clst, fat_cluster_t value)
@@ -252,4 +289,5 @@
 	uint16_t sf;
 	fat_cluster_t *cp;
+	int rc;
 
 	bps = uint16_t_le2host(bs->bps);
@@ -258,10 +296,13 @@
 
 	assert(fatno < bs->fatcnt);
-	b = block_get(dev_handle, rscnt + sf * fatno +
+	rc = block_get(&b, dev_handle, rscnt + sf * fatno +
 	    (clst * sizeof(fat_cluster_t)) / bps, BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
 	cp = (fat_cluster_t *)b->data + clst % (bps / sizeof(fat_cluster_t));
 	*cp = host2uint16_t_le(value);
 	b->dirty = true;		/* need to sync block */
-	block_put(b);
+	rc = block_put(b);
+	return rc;
 }
 
@@ -272,17 +313,24 @@
  * @param lifo		Chain of allocated clusters.
  * @param nclsts	Number of clusters in the lifo chain.
- */
-void fat_alloc_shadow_clusters(fat_bs_t *bs, dev_handle_t dev_handle,
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int fat_alloc_shadow_clusters(fat_bs_t *bs, dev_handle_t dev_handle,
     fat_cluster_t *lifo, unsigned nclsts)
 {
 	uint8_t fatno;
 	unsigned c;
+	int rc;
 
 	for (fatno = FAT1 + 1; fatno < bs->fatcnt; fatno++) {
 		for (c = 0; c < nclsts; c++) {
-			fat_set_cluster(bs, dev_handle, fatno, lifo[c],
+			rc = fat_set_cluster(bs, dev_handle, fatno, lifo[c],
 			    c == 0 ? FAT_CLST_LAST1 : lifo[c - 1]);
+			if (rc != EOK)
+				return rc;
 		}
 	}
+
+	return EOK;
 }
 
@@ -311,8 +359,13 @@
 	uint16_t rscnt;
 	uint16_t sf;
+	uint16_t ts;
+	unsigned rde;
+	unsigned rds;
+	unsigned ssa;
 	block_t *blk;
 	fat_cluster_t *lifo;	/* stack for storing free cluster numbers */ 
 	unsigned found = 0;	/* top of the free cluster number stack */
 	unsigned b, c, cl; 
+	int rc;
 
 	lifo = (fat_cluster_t *) malloc(nclsts * sizeof(fat_cluster_t));
@@ -323,4 +376,10 @@
 	rscnt = uint16_t_le2host(bs->rscnt);
 	sf = uint16_t_le2host(bs->sec_per_fat);
+	rde = uint16_t_le2host(bs->root_ent_max);
+	ts = uint16_t_le2host(bs->totsec16);
+
+	rds = (sizeof(fat_dentry_t) * rde) / bps;
+	rds += ((sizeof(fat_dentry_t) * rde) % bps != 0);
+	ssa = rscnt + bs->fatcnt * sf + rds;
 	
 	/*
@@ -329,6 +388,21 @@
 	fibril_mutex_lock(&fat_alloc_lock);
 	for (b = 0, cl = 0; b < sf; b++) {
-		blk = block_get(dev_handle, rscnt + b, BLOCK_FLAGS_NONE);
+		rc = block_get(&blk, dev_handle, rscnt + b, BLOCK_FLAGS_NONE);
+		if (rc != EOK)
+			goto error;
 		for (c = 0; c < bps / sizeof(fat_cluster_t); c++, cl++) {
+			/*
+			 * Check if the cluster is physically there. This check
+			 * becomes necessary when the file system is created
+			 * with fewer total sectors than how many is inferred
+			 * from the size of the file allocation table.
+			 */
+			if ((cl - 2) * bs->spc + ssa >= ts) {
+				rc = block_put(blk);
+				if (rc != EOK)
+					goto error;
+				goto out;
+			}
+
 			fat_cluster_t *clst = (fat_cluster_t *)blk->data + c;
 			if (uint16_t_le2host(*clst) == FAT_CLST_RES0) {
@@ -344,8 +418,12 @@
 				if (++found == nclsts) {
 					/* we are almost done */
-					block_put(blk);
+					rc = block_put(blk);
+					if (rc != EOK)
+						goto error;
 					/* update the shadow copies of FAT */
-					fat_alloc_shadow_clusters(bs,
+					rc = fat_alloc_shadow_clusters(bs,
 					    dev_handle, lifo, nclsts);
+					if (rc != EOK)
+						goto error;
 					*mcl = lifo[found - 1];
 					*lcl = lifo[0];
@@ -356,6 +434,13 @@
 			}
 		}
-		block_put(blk);
-	}
+		rc = block_put(blk);
+		if (rc != EOK) {
+error:
+			fibril_mutex_unlock(&fat_alloc_lock);
+			free(lifo);
+			return rc;
+		}
+	}
+out:
 	fibril_mutex_unlock(&fat_alloc_lock);
 
@@ -365,6 +450,10 @@
 	 */
 	while (found--) {
-		fat_set_cluster(bs, dev_handle, FAT1, lifo[found],
+		rc = fat_set_cluster(bs, dev_handle, FAT1, lifo[found],
 		    FAT_CLST_RES0);
+		if (rc != EOK) {
+			free(lifo);
+			return rc;
+		}
 	}
 	
@@ -378,20 +467,31 @@
  * @param dev_handle	Device handle of the file system.
  * @param firstc	First cluster in the chain which is to be freed.
- */
-void
+ *
+ * @return		EOK on success or a negative return code.
+ */
+int
 fat_free_clusters(fat_bs_t *bs, dev_handle_t dev_handle, fat_cluster_t firstc)
 {
 	unsigned fatno;
 	fat_cluster_t nextc;
+	int rc;
 
 	/* Mark all clusters in the chain as free in all copies of FAT. */
 	while (firstc < FAT_CLST_LAST1) {
 		assert(firstc >= FAT_CLST_FIRST && firstc < FAT_CLST_BAD);
-		nextc = fat_get_cluster(bs, dev_handle, firstc);
-		for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
-			fat_set_cluster(bs, dev_handle, fatno, firstc,
+		rc = fat_get_cluster(bs, dev_handle, firstc, &nextc);
+		if (rc != EOK)
+			return rc;
+		for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
+			rc = fat_set_cluster(bs, dev_handle, fatno, firstc,
 			    FAT_CLST_RES0);
+			if (rc != EOK)
+				return rc;
+		}
+
 		firstc = nextc;
 	}
+
+	return EOK;
 }
 
@@ -401,21 +501,35 @@
  * @param nodep		Node representing the file.
  * @param mcl		First cluster of the cluster chain to append.
- */
-void fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl)
+ *
+ * @return		EOK on success or a negative error code.
+ */
+int fat_append_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t mcl)
 {
 	dev_handle_t dev_handle = nodep->idx->dev_handle;
 	fat_cluster_t lcl;
+	uint16_t numc;
 	uint8_t fatno;
-
-	if (fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl,
-	    (uint16_t) -1) == 0) {
+	int rc;
+
+	rc = fat_cluster_walk(bs, dev_handle, nodep->firstc, &lcl, &numc,
+	    (uint16_t) -1);
+	if (rc != EOK)
+		return rc;
+
+	if (numc == 0) {
 		/* No clusters allocated to the node yet. */
 		nodep->firstc = mcl;
 		nodep->dirty = true;		/* need to sync node */
-		return;
-	}
-
-	for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
-		fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lcl, mcl);
+		return EOK;
+	}
+
+	for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
+		rc = fat_set_cluster(bs, nodep->idx->dev_handle, fatno, lcl,
+		    mcl);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
 }
 
@@ -427,11 +541,17 @@
  *			argument is FAT_CLST_RES0, then all clusters will
  *			be chopped off.
- */
-void fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lastc)
-{
+ *
+ * @return		EOK on success or a negative return code.
+ */
+int fat_chop_clusters(fat_bs_t *bs, fat_node_t *nodep, fat_cluster_t lastc)
+{
+	int rc;
+
 	dev_handle_t dev_handle = nodep->idx->dev_handle;
 	if (lastc == FAT_CLST_RES0) {
 		/* The node will have zero size and no clusters allocated. */
-		fat_free_clusters(bs, dev_handle, nodep->firstc);
+		rc = fat_free_clusters(bs, dev_handle, nodep->firstc);
+		if (rc != EOK)
+			return rc;
 		nodep->firstc = FAT_CLST_RES0;
 		nodep->dirty = true;		/* need to sync node */
@@ -440,16 +560,26 @@
 		unsigned fatno;
 
-		nextc = fat_get_cluster(bs, dev_handle, lastc);
+		rc = fat_get_cluster(bs, dev_handle, lastc, &nextc);
+		if (rc != EOK)
+			return rc;
 
 		/* Terminate the cluster chain in all copies of FAT. */
-		for (fatno = FAT1; fatno < bs->fatcnt; fatno++)
-			fat_set_cluster(bs, dev_handle, fatno, lastc, FAT_CLST_LAST1);
+		for (fatno = FAT1; fatno < bs->fatcnt; fatno++) {
+			rc = fat_set_cluster(bs, dev_handle, fatno, lastc,
+			    FAT_CLST_LAST1);
+			if (rc != EOK)
+				return rc;
+		}
 
 		/* Free all following clusters. */
-		fat_free_clusters(bs, dev_handle, nextc);
-	}
-}
-
-void
+		rc = fat_free_clusters(bs, dev_handle, nextc);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
+}
+
+int
 fat_zero_cluster(struct fat_bs *bs, dev_handle_t dev_handle, fat_cluster_t c)
 {
@@ -457,13 +587,21 @@
 	block_t *b;
 	unsigned bps;
+	int rc;
 
 	bps = uint16_t_le2host(bs->bps);
 	
 	for (i = 0; i < bs->spc; i++) {
-		b = _fat_block_get(bs, dev_handle, c, i, BLOCK_FLAGS_NOREAD);
+		rc = _fat_block_get(&b, bs, dev_handle, c, i,
+		    BLOCK_FLAGS_NOREAD);
+		if (rc != EOK)
+			return rc;
 		memset(b->data, 0, bps);
 		b->dirty = true;
-		block_put(b);
-	}
+		rc = block_put(b);
+		if (rc != EOK)
+			return rc;
+	}
+
+	return EOK;
 }
 
Index: uspace/srv/fs/fat/fat_fat.h
===================================================================
--- uspace/srv/fs/fat/fat_fat.h	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/fat/fat_fat.h	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -59,30 +59,32 @@
 typedef uint16_t fat_cluster_t;
 
-#define fat_clusters_get(bs, dh, fc) \
-    fat_cluster_walk((bs), (dh), (fc), NULL, (uint16_t) -1)
-extern uint16_t fat_cluster_walk(struct fat_bs *, dev_handle_t, fat_cluster_t,
-    fat_cluster_t *, uint16_t);
+#define fat_clusters_get(numc, bs, dh, fc) \
+    fat_cluster_walk((bs), (dh), (fc), NULL, (numc), (uint16_t) -1)
+extern int fat_cluster_walk(struct fat_bs *, dev_handle_t, fat_cluster_t,
+    fat_cluster_t *, uint16_t *, uint16_t);
 
-#define fat_block_get(bs, np, bn, flags) \
-    _fat_block_get((bs), (np)->idx->dev_handle, (np)->firstc, (bn), (flags))
+#define fat_block_get(b, bs, np, bn, flags) \
+    _fat_block_get((b), (bs), (np)->idx->dev_handle, (np)->firstc, (bn), \
+    (flags))
 
-extern struct block *_fat_block_get(struct fat_bs *, dev_handle_t,
+extern int _fat_block_get(block_t **, struct fat_bs *, dev_handle_t,
     fat_cluster_t, bn_t, int);
   
-extern void fat_append_clusters(struct fat_bs *, struct fat_node *,
+extern int fat_append_clusters(struct fat_bs *, struct fat_node *,
     fat_cluster_t);
-extern void fat_chop_clusters(struct fat_bs *, struct fat_node *,
+extern int fat_chop_clusters(struct fat_bs *, struct fat_node *,
     fat_cluster_t);
 extern int fat_alloc_clusters(struct fat_bs *, dev_handle_t, unsigned,
     fat_cluster_t *, fat_cluster_t *);
-extern void fat_free_clusters(struct fat_bs *, dev_handle_t, fat_cluster_t);
-extern void fat_alloc_shadow_clusters(struct fat_bs *, dev_handle_t,
+extern int fat_free_clusters(struct fat_bs *, dev_handle_t, fat_cluster_t);
+extern int fat_alloc_shadow_clusters(struct fat_bs *, dev_handle_t,
     fat_cluster_t *, unsigned);
-extern fat_cluster_t fat_get_cluster(struct fat_bs *, dev_handle_t, fat_cluster_t);
-extern void fat_set_cluster(struct fat_bs *, dev_handle_t, unsigned,
+extern int fat_get_cluster(struct fat_bs *, dev_handle_t, fat_cluster_t,
+    fat_cluster_t *);
+extern int fat_set_cluster(struct fat_bs *, dev_handle_t, unsigned,
     fat_cluster_t, fat_cluster_t);
-extern void fat_fill_gap(struct fat_bs *, struct fat_node *, fat_cluster_t,
+extern int fat_fill_gap(struct fat_bs *, struct fat_node *, fat_cluster_t,
     off_t);
-extern void fat_zero_cluster(struct fat_bs *, dev_handle_t, fat_cluster_t);
+extern int fat_zero_cluster(struct fat_bs *, dev_handle_t, fat_cluster_t);
 
 #endif
Index: uspace/srv/fs/fat/fat_idx.c
===================================================================
--- uspace/srv/fs/fat/fat_idx.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/fat/fat_idx.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -339,5 +339,5 @@
 }
 
-static fat_idx_t *fat_idx_create(dev_handle_t dev_handle)
+static int fat_idx_create(fat_idx_t **fidxp, dev_handle_t dev_handle)
 {
 	fat_idx_t *fidx;
@@ -345,8 +345,8 @@
 	fidx = (fat_idx_t *) malloc(sizeof(fat_idx_t));
 	if (!fidx) 
-		return NULL;
+		return ENOMEM;
 	if (!fat_index_alloc(dev_handle, &fidx->index)) {
 		free(fidx);
-		return NULL;
+		return ENOSPC;
 	}
 		
@@ -359,16 +359,18 @@
 	fidx->nodep = NULL;
 
-	return fidx;
-}
-
-fat_idx_t *fat_idx_get_new(dev_handle_t dev_handle)
+	*fidxp = fidx;
+	return EOK;
+}
+
+int fat_idx_get_new(fat_idx_t **fidxp, dev_handle_t dev_handle)
 {
 	fat_idx_t *fidx;
+	int rc;
 
 	fibril_mutex_lock(&used_lock);
-	fidx = fat_idx_create(dev_handle);
-	if (!fidx) {
+	rc = fat_idx_create(&fidx, dev_handle);
+	if (rc != EOK) {
 		fibril_mutex_unlock(&used_lock);
-		return NULL;
+		return rc;
 	}
 		
@@ -382,5 +384,6 @@
 	fibril_mutex_unlock(&used_lock);
 
-	return fidx;
+	*fidxp = fidx;
+	return EOK;
 }
 
@@ -401,6 +404,8 @@
 		fidx = hash_table_get_instance(l, fat_idx_t, uph_link);
 	} else {
-		fidx = fat_idx_create(dev_handle);
-		if (!fidx) {
+		int rc;
+
+		rc = fat_idx_create(&fidx, dev_handle);
+		if (rc != EOK) {
 			fibril_mutex_unlock(&used_lock);
 			return NULL;
Index: uspace/srv/fs/fat/fat_ops.c
===================================================================
--- uspace/srv/fs/fat/fat_ops.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/fat/fat_ops.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -65,4 +65,26 @@
 static LIST_INITIALIZE(ffn_head);
 
+/*
+ * Forward declarations of FAT libfs operations.
+ */
+static int fat_root_get(fs_node_t **, dev_handle_t);
+static int fat_match(fs_node_t **, fs_node_t *, const char *);
+static int fat_node_get(fs_node_t **, dev_handle_t, fs_index_t);
+static int fat_node_put(fs_node_t *);
+static int fat_create_node(fs_node_t **, dev_handle_t, int);
+static int fat_destroy_node(fs_node_t *);
+static int fat_link(fs_node_t *, fs_node_t *, const char *);
+static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
+static int fat_has_children(bool *, fs_node_t *);
+static fs_index_t fat_index_get(fs_node_t *);
+static size_t fat_size_get(fs_node_t *);
+static unsigned fat_lnkcnt_get(fs_node_t *);
+static char fat_plb_get_char(unsigned);
+static bool fat_is_directory(fs_node_t *);
+static bool fat_is_file(fs_node_t *node);
+
+/*
+ * Helper functions.
+ */
 static void fat_node_initialize(fat_node_t *node)
 {
@@ -78,5 +100,5 @@
 }
 
-static void fat_node_sync(fat_node_t *node)
+static int fat_node_sync(fat_node_t *node)
 {
 	block_t *b;
@@ -85,4 +107,5 @@
 	uint16_t bps;
 	unsigned dps;
+	int rc;
 	
 	assert(node->dirty);
@@ -93,6 +116,8 @@
 	
 	/* Read the block that contains the dentry of interest. */
-	b = _fat_block_get(bs, node->idx->dev_handle, node->idx->pfc,
+	rc = _fat_block_get(&b, bs, node->idx->dev_handle, node->idx->pfc,
 	    (node->idx->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
+	if (rc != EOK)
+		return rc;
 
 	d = ((fat_dentry_t *)b->data) + (node->idx->pdi % dps);
@@ -108,11 +133,13 @@
 	
 	b->dirty = true;		/* need to sync block */
-	block_put(b);
-}
-
-static fat_node_t *fat_node_get_new(void)
+	rc = block_put(b);
+	return rc;
+}
+
+static int fat_node_get_new(fat_node_t **nodepp)
 {
 	fs_node_t *fn;
 	fat_node_t *nodep;
+	int rc;
 
 	fibril_mutex_lock(&ffn_mutex);
@@ -130,6 +157,15 @@
 		list_remove(&nodep->ffn_link);
 		fibril_mutex_unlock(&ffn_mutex);
-		if (nodep->dirty)
-			fat_node_sync(nodep);
+		if (nodep->dirty) {
+			rc = fat_node_sync(nodep);
+			if (rc != EOK) {
+				idxp_tmp->nodep = NULL;
+				fibril_mutex_unlock(&nodep->lock);
+				fibril_mutex_unlock(&idxp_tmp->lock);
+				free(nodep->bp);
+				free(nodep);
+				return rc;
+			}
+		}
 		idxp_tmp->nodep = NULL;
 		fibril_mutex_unlock(&nodep->lock);
@@ -142,9 +178,9 @@
 		fn = (fs_node_t *)malloc(sizeof(fs_node_t));
 		if (!fn)
-			return NULL;
+			return ENOMEM;
 		nodep = (fat_node_t *)malloc(sizeof(fat_node_t));
 		if (!nodep) {
 			free(fn);
-			return NULL;
+			return ENOMEM;
 		}
 	}
@@ -154,5 +190,6 @@
 	nodep->bp = fn;
 	
-	return nodep;
+	*nodepp = nodep;
+	return EOK;
 }
 
@@ -161,5 +198,5 @@
  * @param idxp		Locked index structure.
  */
-static fat_node_t *fat_node_get_core(fat_idx_t *idxp)
+static int fat_node_get_core(fat_node_t **nodepp, fat_idx_t *idxp)
 {
 	block_t *b;
@@ -170,4 +207,5 @@
 	unsigned spc;
 	unsigned dps;
+	int rc;
 
 	if (idxp->nodep) {
@@ -177,8 +215,12 @@
 		 */
 		fibril_mutex_lock(&idxp->nodep->lock);
-		if (!idxp->nodep->refcnt++)
+		if (!idxp->nodep->refcnt++) {
+			fibril_mutex_lock(&ffn_mutex);
 			list_remove(&idxp->nodep->ffn_link);
+			fibril_mutex_unlock(&ffn_mutex);
+		}
 		fibril_mutex_unlock(&idxp->nodep->lock);
-		return idxp->nodep;
+		*nodepp = idxp->nodep;
+		return EOK;
 	}
 
@@ -189,7 +231,7 @@
 	assert(idxp->pfc);
 
-	nodep = fat_node_get_new();
-	if (!nodep)
-		return NULL;
+	rc = fat_node_get_new(&nodep);
+	if (rc != EOK)
+		return rc;
 
 	bs = block_bb_get(idxp->dev_handle);
@@ -199,7 +241,10 @@
 
 	/* Read the block that contains the dentry of interest. */
-	b = _fat_block_get(bs, idxp->dev_handle, idxp->pfc,
+	rc = _fat_block_get(&b, bs, idxp->dev_handle, idxp->pfc,
 	    (idxp->pdi * sizeof(fat_dentry_t)) / bps, BLOCK_FLAGS_NONE);
-	assert(b);
+	if (rc != EOK) {
+		(void) fat_node_put(FS_NODE(nodep));
+		return rc;
+	}
 
 	d = ((fat_dentry_t *)b->data) + (idxp->pdi % dps);
@@ -216,6 +261,12 @@
 		 * size of the directory by walking the FAT.
 		 */
-		nodep->size = bps * spc * fat_clusters_get(bs, idxp->dev_handle,
+		uint16_t clusters;
+		rc = fat_clusters_get(&clusters, bs, idxp->dev_handle,
 		    uint16_t_le2host(d->firstc));
+		if (rc != EOK) {
+			(void) fat_node_put(FS_NODE(nodep));
+			return rc;
+		}
+		nodep->size = bps * spc * clusters;
 	} else {
 		nodep->type = FAT_FILE;
@@ -226,5 +277,9 @@
 	nodep->refcnt = 1;
 
-	block_put(b);
+	rc = block_put(b);
+	if (rc != EOK) {
+		(void) fat_node_put(FS_NODE(nodep));
+		return rc;
+	}
 
 	/* Link the idx structure with the node structure. */
@@ -232,25 +287,7 @@
 	idxp->nodep = nodep;
 
-	return nodep;
-}
-
-/*
- * Forward declarations of FAT libfs operations.
- */
-static fs_node_t *fat_node_get(dev_handle_t, fs_index_t);
-static void fat_node_put(fs_node_t *);
-static fs_node_t *fat_create_node(dev_handle_t, int);
-static int fat_destroy_node(fs_node_t *);
-static int fat_link(fs_node_t *, fs_node_t *, const char *);
-static int fat_unlink(fs_node_t *, fs_node_t *, const char *);
-static fs_node_t *fat_match(fs_node_t *, const char *);
-static fs_index_t fat_index_get(fs_node_t *);
-static size_t fat_size_get(fs_node_t *);
-static unsigned fat_lnkcnt_get(fs_node_t *);
-static bool fat_has_children(fs_node_t *);
-static fs_node_t *fat_root_get(dev_handle_t);
-static char fat_plb_get_char(unsigned);
-static bool fat_is_directory(fs_node_t *);
-static bool fat_is_file(fs_node_t *node);
+	*nodepp = nodep;
+	return EOK;
+}
 
 /*
@@ -258,324 +295,10 @@
  */
 
-/** Instantiate a FAT in-core node. */
-fs_node_t *fat_node_get(dev_handle_t dev_handle, fs_index_t index)
-{
-	fat_node_t *nodep;
-	fat_idx_t *idxp;
-
-	idxp = fat_idx_get_by_index(dev_handle, index);
-	if (!idxp)
-		return NULL;
-	/* idxp->lock held */
-	nodep = fat_node_get_core(idxp);
-	fibril_mutex_unlock(&idxp->lock);
-	return FS_NODE(nodep);
-}
-
-void fat_node_put(fs_node_t *fn)
-{
-	fat_node_t *nodep = FAT_NODE(fn);
-	bool destroy = false;
-
-	fibril_mutex_lock(&nodep->lock);
-	if (!--nodep->refcnt) {
-		if (nodep->idx) {
-			fibril_mutex_lock(&ffn_mutex);
-			list_append(&nodep->ffn_link, &ffn_head);
-			fibril_mutex_unlock(&ffn_mutex);
-		} else {
-			/*
-			 * The node does not have any index structure associated
-			 * with itself. This can only mean that we are releasing
-			 * the node after a failed attempt to allocate the index
-			 * structure for it.
-			 */
-			destroy = true;
-		}
-	}
-	fibril_mutex_unlock(&nodep->lock);
-	if (destroy) {
-		free(nodep->bp);
-		free(nodep);
-	}
-}
-
-fs_node_t *fat_create_node(dev_handle_t dev_handle, int flags)
-{
-	fat_idx_t *idxp;
-	fat_node_t *nodep;
-	fat_bs_t *bs;
-	fat_cluster_t mcl, lcl;
-	uint16_t bps;
-	int rc;
-
-	bs = block_bb_get(dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	if (flags & L_DIRECTORY) {
-		/* allocate a cluster */
-		rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
-		if (rc != EOK) 
-			return NULL;
-	}
-
-	nodep = fat_node_get_new();
-	if (!nodep) {
-		fat_free_clusters(bs, dev_handle, mcl);	
-		return NULL;
-	}
-	idxp = fat_idx_get_new(dev_handle);
-	if (!idxp) {
-		fat_free_clusters(bs, dev_handle, mcl);	
-		fat_node_put(FS_NODE(nodep));
-		return NULL;
-	}
-	/* idxp->lock held */
-	if (flags & L_DIRECTORY) {
-		/* Populate the new cluster with unused dentries. */
-		fat_zero_cluster(bs, dev_handle, mcl);
-		nodep->type = FAT_DIRECTORY;
-		nodep->firstc = mcl;
-		nodep->size = bps * bs->spc;
-	} else {
-		nodep->type = FAT_FILE;
-		nodep->firstc = FAT_CLST_RES0;
-		nodep->size = 0;
-	}
-	nodep->lnkcnt = 0;	/* not linked anywhere */
-	nodep->refcnt = 1;
-	nodep->dirty = true;
-
-	nodep->idx = idxp;
-	idxp->nodep = nodep;
-
-	fibril_mutex_unlock(&idxp->lock);
-	return FS_NODE(nodep);
-}
-
-int fat_destroy_node(fs_node_t *fn)
-{
-	fat_node_t *nodep = FAT_NODE(fn);
-	fat_bs_t *bs;
-
-	/*
-	 * The node is not reachable from the file system. This means that the
-	 * link count should be zero and that the index structure cannot be
-	 * found in the position hash. Obviously, we don't need to lock the node
-	 * nor its index structure.
-	 */
-	assert(nodep->lnkcnt == 0);
-
-	/*
-	 * The node may not have any children.
-	 */
-	assert(fat_has_children(fn) == false);
-
-	bs = block_bb_get(nodep->idx->dev_handle);
-	if (nodep->firstc != FAT_CLST_RES0) {
-		assert(nodep->size);
-		/* Free all clusters allocated to the node. */
-		fat_free_clusters(bs, nodep->idx->dev_handle, nodep->firstc);
-	}
-
-	fat_idx_destroy(nodep->idx);
-	free(nodep->bp);
-	free(nodep);
-	return EOK;
-}
-
-int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
-{
-	fat_node_t *parentp = FAT_NODE(pfn);
-	fat_node_t *childp = FAT_NODE(cfn);
-	fat_dentry_t *d;
-	fat_bs_t *bs;
-	block_t *b;
-	unsigned i, j;
-	uint16_t bps;
-	unsigned dps;
-	unsigned blocks;
-	fat_cluster_t mcl, lcl;
-	int rc;
-
-	fibril_mutex_lock(&childp->lock);
-	if (childp->lnkcnt == 1) {
-		/*
-		 * On FAT, we don't support multiple hard links.
-		 */
-		fibril_mutex_unlock(&childp->lock);
-		return EMLINK;
-	}
-	assert(childp->lnkcnt == 0);
-	fibril_mutex_unlock(&childp->lock);
-
-	if (!fat_dentry_name_verify(name)) {
-		/*
-		 * Attempt to create unsupported name.
-		 */
-		return ENOTSUP;
-	}
-
-	/*
-	 * Get us an unused parent node's dentry or grow the parent and allocate
-	 * a new one.
-	 */
-	
-	fibril_mutex_lock(&parentp->idx->lock);
-	bs = block_bb_get(parentp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-	dps = bps / sizeof(fat_dentry_t);
-
-	blocks = parentp->size / bps;
-
-	for (i = 0; i < blocks; i++) {
-		b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
-		for (j = 0; j < dps; j++) {
-			d = ((fat_dentry_t *)b->data) + j;
-			switch (fat_classify_dentry(d)) {
-			case FAT_DENTRY_SKIP:
-			case FAT_DENTRY_VALID:
-				/* skipping used and meta entries */
-				continue;
-			case FAT_DENTRY_FREE:
-			case FAT_DENTRY_LAST:
-				/* found an empty slot */
-				goto hit;
-			}
-		}
-		block_put(b);
-	}
-	j = 0;
-	
-	/*
-	 * We need to grow the parent in order to create a new unused dentry.
-	 */
-	if (parentp->firstc == FAT_CLST_ROOT) {
-		/* Can't grow the root directory. */
-		fibril_mutex_unlock(&parentp->idx->lock);
-		return ENOSPC;
-	}
-	rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
-	if (rc != EOK) {
-		fibril_mutex_unlock(&parentp->idx->lock);
-		return rc;
-	}
-	fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
-	fat_append_clusters(bs, parentp, mcl);
-	parentp->size += bps * bs->spc;
-	parentp->dirty = true;		/* need to sync node */
-	b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
-	d = (fat_dentry_t *)b->data;
-
-hit:
-	/*
-	 * At this point we only establish the link between the parent and the
-	 * child.  The dentry, except of the name and the extension, will remain
-	 * uninitialized until the corresponding node is synced. Thus the valid
-	 * dentry data is kept in the child node structure.
-	 */
-	memset(d, 0, sizeof(fat_dentry_t));
-	fat_dentry_name_set(d, name);
-	b->dirty = true;		/* need to sync block */
-	block_put(b);
-	fibril_mutex_unlock(&parentp->idx->lock);
-
-	fibril_mutex_lock(&childp->idx->lock);
-	
-	/*
-	 * If possible, create the Sub-directory Identifier Entry and the
-	 * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
-	 * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
-	 * not use them anyway, so this is rather a sign of our good will.
-	 */
-	b = fat_block_get(bs, childp, 0, BLOCK_FLAGS_NONE);
-	d = (fat_dentry_t *)b->data;
-	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
-	    str_cmp(d->name, FAT_NAME_DOT) == 0) {
-	   	memset(d, 0, sizeof(fat_dentry_t));
-	   	str_cpy(d->name, 8, FAT_NAME_DOT);
-		str_cpy(d->ext, 3, FAT_EXT_PAD);
-		d->attr = FAT_ATTR_SUBDIR;
-		d->firstc = host2uint16_t_le(childp->firstc);
-		/* TODO: initialize also the date/time members. */
-	}
-	d++;
-	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
-	    str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
-		memset(d, 0, sizeof(fat_dentry_t));
-		str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
-		str_cpy(d->ext, 3, FAT_EXT_PAD);
-		d->attr = FAT_ATTR_SUBDIR;
-		d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
-		    host2uint16_t_le(FAT_CLST_RES0) :
-		    host2uint16_t_le(parentp->firstc);
-		/* TODO: initialize also the date/time members. */
-	}
-	b->dirty = true;		/* need to sync block */
-	block_put(b);
-
-	childp->idx->pfc = parentp->firstc;
-	childp->idx->pdi = i * dps + j;
-	fibril_mutex_unlock(&childp->idx->lock);
-
-	fibril_mutex_lock(&childp->lock);
-	childp->lnkcnt = 1;
-	childp->dirty = true;		/* need to sync node */
-	fibril_mutex_unlock(&childp->lock);
-
-	/*
-	 * Hash in the index structure into the position hash.
-	 */
-	fat_idx_hashin(childp->idx);
-
-	return EOK;
-}
-
-int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
-{
-	fat_node_t *parentp = FAT_NODE(pfn);
-	fat_node_t *childp = FAT_NODE(cfn);
-	fat_bs_t *bs;
-	fat_dentry_t *d;
-	uint16_t bps;
-	block_t *b;
-
-	if (!parentp)
-		return EBUSY;
-	
-	if (fat_has_children(cfn))
-		return ENOTEMPTY;
-
-	fibril_mutex_lock(&parentp->lock);
-	fibril_mutex_lock(&childp->lock);
-	assert(childp->lnkcnt == 1);
-	fibril_mutex_lock(&childp->idx->lock);
-	bs = block_bb_get(childp->idx->dev_handle);
-	bps = uint16_t_le2host(bs->bps);
-
-	b = _fat_block_get(bs, childp->idx->dev_handle, childp->idx->pfc,
-	    (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
-	    BLOCK_FLAGS_NONE);
-	d = (fat_dentry_t *)b->data +
-	    (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
-	/* mark the dentry as not-currently-used */
-	d->name[0] = FAT_DENTRY_ERASED;
-	b->dirty = true;		/* need to sync block */
-	block_put(b);
-
-	/* remove the index structure from the position hash */
-	fat_idx_hashout(childp->idx);
-	/* clear position information */
-	childp->idx->pfc = FAT_CLST_RES0;
-	childp->idx->pdi = 0;
-	fibril_mutex_unlock(&childp->idx->lock);
-	childp->lnkcnt = 0;
-	childp->dirty = true;
-	fibril_mutex_unlock(&childp->lock);
-	fibril_mutex_unlock(&parentp->lock);
-
-	return EOK;
-}
-
-fs_node_t *fat_match(fs_node_t *pfn, const char *component)
+int fat_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
+{
+	return fat_node_get(rfn, dev_handle, 0);
+}
+
+int fat_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
 {
 	fat_bs_t *bs;
@@ -588,4 +311,5 @@
 	fat_dentry_t *d;
 	block_t *b;
+	int rc;
 
 	fibril_mutex_lock(&parentp->idx->lock);
@@ -595,5 +319,9 @@
 	blocks = parentp->size / bps;
 	for (i = 0; i < blocks; i++) {
-		b = fat_block_get(bs, parentp, i, BLOCK_FLAGS_NONE);
+		rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&parentp->idx->lock);
+			return rc;
+		}
 		for (j = 0; j < dps; j++) { 
 			d = ((fat_dentry_t *)b->data) + j;
@@ -603,7 +331,9 @@
 				continue;
 			case FAT_DENTRY_LAST:
-				block_put(b);
+				/* miss */
+				rc = block_put(b);
 				fibril_mutex_unlock(&parentp->idx->lock);
-				return NULL;
+				*rfn = NULL;
+				return rc;
 			default:
 			case FAT_DENTRY_VALID:
@@ -629,36 +359,420 @@
 					 * run out of 32-bit indices.
 					 */
-					block_put(b);
-					return NULL;
+					rc = block_put(b);
+					return (rc == EOK) ? ENOMEM : rc;
 				}
-				nodep = fat_node_get_core(idx);
+				rc = fat_node_get_core(&nodep, idx);
 				fibril_mutex_unlock(&idx->lock);
-				block_put(b);
-				return FS_NODE(nodep);
+				if (rc != EOK) {
+					(void) block_put(b);
+					return rc;
+				}
+				*rfn = FS_NODE(nodep);
+				rc = block_put(b);
+				if (rc != EOK)
+					(void) fat_node_put(*rfn);
+				return rc;
 			}
 		}
-		block_put(b);
+		rc = block_put(b);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&parentp->idx->lock);
+			return rc;
+		}
 	}
 
 	fibril_mutex_unlock(&parentp->idx->lock);
-	return NULL;
-}
-
-fs_index_t fat_index_get(fs_node_t *fn)
-{
-	return FAT_NODE(fn)->idx->index;
-}
-
-size_t fat_size_get(fs_node_t *fn)
-{
-	return FAT_NODE(fn)->size;
-}
-
-unsigned fat_lnkcnt_get(fs_node_t *fn)
-{
-	return FAT_NODE(fn)->lnkcnt;
-}
-
-bool fat_has_children(fs_node_t *fn)
+	*rfn = NULL;
+	return EOK;
+}
+
+/** Instantiate a FAT in-core node. */
+int fat_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
+{
+	fat_node_t *nodep;
+	fat_idx_t *idxp;
+	int rc;
+
+	idxp = fat_idx_get_by_index(dev_handle, index);
+	if (!idxp) {
+		*rfn = NULL;
+		return EOK;
+	}
+	/* idxp->lock held */
+	rc = fat_node_get_core(&nodep, idxp);
+	fibril_mutex_unlock(&idxp->lock);
+	if (rc == EOK)
+		*rfn = FS_NODE(nodep);
+	return rc;
+}
+
+int fat_node_put(fs_node_t *fn)
+{
+	fat_node_t *nodep = FAT_NODE(fn);
+	bool destroy = false;
+
+	fibril_mutex_lock(&nodep->lock);
+	if (!--nodep->refcnt) {
+		if (nodep->idx) {
+			fibril_mutex_lock(&ffn_mutex);
+			list_append(&nodep->ffn_link, &ffn_head);
+			fibril_mutex_unlock(&ffn_mutex);
+		} else {
+			/*
+			 * The node does not have any index structure associated
+			 * with itself. This can only mean that we are releasing
+			 * the node after a failed attempt to allocate the index
+			 * structure for it.
+			 */
+			destroy = true;
+		}
+	}
+	fibril_mutex_unlock(&nodep->lock);
+	if (destroy) {
+		free(nodep->bp);
+		free(nodep);
+	}
+	return EOK;
+}
+
+int fat_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int flags)
+{
+	fat_idx_t *idxp;
+	fat_node_t *nodep;
+	fat_bs_t *bs;
+	fat_cluster_t mcl, lcl;
+	uint16_t bps;
+	int rc;
+
+	bs = block_bb_get(dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	if (flags & L_DIRECTORY) {
+		/* allocate a cluster */
+		rc = fat_alloc_clusters(bs, dev_handle, 1, &mcl, &lcl);
+		if (rc != EOK)
+			return rc;
+		/* populate the new cluster with unused dentries */
+		rc = fat_zero_cluster(bs, dev_handle, mcl);
+		if (rc != EOK) {
+			(void) fat_free_clusters(bs, dev_handle, mcl);
+			return rc;
+		}
+	}
+
+	rc = fat_node_get_new(&nodep);
+	if (rc != EOK) {
+		(void) fat_free_clusters(bs, dev_handle, mcl);
+		return rc;
+	}
+	rc = fat_idx_get_new(&idxp, dev_handle);
+	if (rc != EOK) {
+		(void) fat_free_clusters(bs, dev_handle, mcl);	
+		(void) fat_node_put(FS_NODE(nodep));
+		return rc;
+	}
+	/* idxp->lock held */
+	if (flags & L_DIRECTORY) {
+		nodep->type = FAT_DIRECTORY;
+		nodep->firstc = mcl;
+		nodep->size = bps * bs->spc;
+	} else {
+		nodep->type = FAT_FILE;
+		nodep->firstc = FAT_CLST_RES0;
+		nodep->size = 0;
+	}
+	nodep->lnkcnt = 0;	/* not linked anywhere */
+	nodep->refcnt = 1;
+	nodep->dirty = true;
+
+	nodep->idx = idxp;
+	idxp->nodep = nodep;
+
+	fibril_mutex_unlock(&idxp->lock);
+	*rfn = FS_NODE(nodep);
+	return EOK;
+}
+
+int fat_destroy_node(fs_node_t *fn)
+{
+	fat_node_t *nodep = FAT_NODE(fn);
+	fat_bs_t *bs;
+	bool has_children;
+	int rc;
+
+	/*
+	 * The node is not reachable from the file system. This means that the
+	 * link count should be zero and that the index structure cannot be
+	 * found in the position hash. Obviously, we don't need to lock the node
+	 * nor its index structure.
+	 */
+	assert(nodep->lnkcnt == 0);
+
+	/*
+	 * The node may not have any children.
+	 */
+	rc = fat_has_children(&has_children, fn);
+	if (rc != EOK)
+		return rc;
+	assert(!has_children);
+
+	bs = block_bb_get(nodep->idx->dev_handle);
+	if (nodep->firstc != FAT_CLST_RES0) {
+		assert(nodep->size);
+		/* Free all clusters allocated to the node. */
+		rc = fat_free_clusters(bs, nodep->idx->dev_handle,
+		    nodep->firstc);
+	}
+
+	fat_idx_destroy(nodep->idx);
+	free(nodep->bp);
+	free(nodep);
+	return rc;
+}
+
+int fat_link(fs_node_t *pfn, fs_node_t *cfn, const char *name)
+{
+	fat_node_t *parentp = FAT_NODE(pfn);
+	fat_node_t *childp = FAT_NODE(cfn);
+	fat_dentry_t *d;
+	fat_bs_t *bs;
+	block_t *b;
+	unsigned i, j;
+	uint16_t bps;
+	unsigned dps;
+	unsigned blocks;
+	fat_cluster_t mcl, lcl;
+	int rc;
+
+	fibril_mutex_lock(&childp->lock);
+	if (childp->lnkcnt == 1) {
+		/*
+		 * On FAT, we don't support multiple hard links.
+		 */
+		fibril_mutex_unlock(&childp->lock);
+		return EMLINK;
+	}
+	assert(childp->lnkcnt == 0);
+	fibril_mutex_unlock(&childp->lock);
+
+	if (!fat_dentry_name_verify(name)) {
+		/*
+		 * Attempt to create unsupported name.
+		 */
+		return ENOTSUP;
+	}
+
+	/*
+	 * Get us an unused parent node's dentry or grow the parent and allocate
+	 * a new one.
+	 */
+	
+	fibril_mutex_lock(&parentp->idx->lock);
+	bs = block_bb_get(parentp->idx->dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+	dps = bps / sizeof(fat_dentry_t);
+
+	blocks = parentp->size / bps;
+
+	for (i = 0; i < blocks; i++) {
+		rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&parentp->idx->lock);
+			return rc;
+		}
+		for (j = 0; j < dps; j++) {
+			d = ((fat_dentry_t *)b->data) + j;
+			switch (fat_classify_dentry(d)) {
+			case FAT_DENTRY_SKIP:
+			case FAT_DENTRY_VALID:
+				/* skipping used and meta entries */
+				continue;
+			case FAT_DENTRY_FREE:
+			case FAT_DENTRY_LAST:
+				/* found an empty slot */
+				goto hit;
+			}
+		}
+		rc = block_put(b);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&parentp->idx->lock);
+			return rc;
+		}
+	}
+	j = 0;
+	
+	/*
+	 * We need to grow the parent in order to create a new unused dentry.
+	 */
+	if (parentp->firstc == FAT_CLST_ROOT) {
+		/* Can't grow the root directory. */
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return ENOSPC;
+	}
+	rc = fat_alloc_clusters(bs, parentp->idx->dev_handle, 1, &mcl, &lcl);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	rc = fat_zero_cluster(bs, parentp->idx->dev_handle, mcl);
+	if (rc != EOK) {
+		(void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	rc = fat_append_clusters(bs, parentp, mcl);
+	if (rc != EOK) {
+		(void) fat_free_clusters(bs, parentp->idx->dev_handle, mcl);
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	parentp->size += bps * bs->spc;
+	parentp->dirty = true;		/* need to sync node */
+	rc = fat_block_get(&b, bs, parentp, i, BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		fibril_mutex_unlock(&parentp->idx->lock);
+		return rc;
+	}
+	d = (fat_dentry_t *)b->data;
+
+hit:
+	/*
+	 * At this point we only establish the link between the parent and the
+	 * child.  The dentry, except of the name and the extension, will remain
+	 * uninitialized until the corresponding node is synced. Thus the valid
+	 * dentry data is kept in the child node structure.
+	 */
+	memset(d, 0, sizeof(fat_dentry_t));
+	fat_dentry_name_set(d, name);
+	b->dirty = true;		/* need to sync block */
+	rc = block_put(b);
+	fibril_mutex_unlock(&parentp->idx->lock);
+	if (rc != EOK) 
+		return rc;
+
+	fibril_mutex_lock(&childp->idx->lock);
+	
+	/*
+	 * If possible, create the Sub-directory Identifier Entry and the
+	 * Sub-directory Parent Pointer Entry (i.e. "." and ".."). These entries
+	 * are not mandatory according to Standard ECMA-107 and HelenOS VFS does
+	 * not use them anyway, so this is rather a sign of our good will.
+	 */
+	rc = fat_block_get(&b, bs, childp, 0, BLOCK_FLAGS_NONE);
+	if (rc != EOK) {
+		/*
+		 * Rather than returning an error, simply skip the creation of
+		 * these two entries.
+		 */
+		goto skip_dots;
+	}
+	d = (fat_dentry_t *)b->data;
+	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
+	    str_cmp(d->name, FAT_NAME_DOT) == 0) {
+	   	memset(d, 0, sizeof(fat_dentry_t));
+	   	str_cpy(d->name, 8, FAT_NAME_DOT);
+		str_cpy(d->ext, 3, FAT_EXT_PAD);
+		d->attr = FAT_ATTR_SUBDIR;
+		d->firstc = host2uint16_t_le(childp->firstc);
+		/* TODO: initialize also the date/time members. */
+	}
+	d++;
+	if (fat_classify_dentry(d) == FAT_DENTRY_LAST ||
+	    str_cmp(d->name, FAT_NAME_DOT_DOT) == 0) {
+		memset(d, 0, sizeof(fat_dentry_t));
+		str_cpy(d->name, 8, FAT_NAME_DOT_DOT);
+		str_cpy(d->ext, 3, FAT_EXT_PAD);
+		d->attr = FAT_ATTR_SUBDIR;
+		d->firstc = (parentp->firstc == FAT_CLST_ROOT) ?
+		    host2uint16_t_le(FAT_CLST_RES0) :
+		    host2uint16_t_le(parentp->firstc);
+		/* TODO: initialize also the date/time members. */
+	}
+	b->dirty = true;		/* need to sync block */
+	/*
+	 * Ignore the return value as we would have fallen through on error
+	 * anyway.
+	 */
+	(void) block_put(b);
+skip_dots:
+
+	childp->idx->pfc = parentp->firstc;
+	childp->idx->pdi = i * dps + j;
+	fibril_mutex_unlock(&childp->idx->lock);
+
+	fibril_mutex_lock(&childp->lock);
+	childp->lnkcnt = 1;
+	childp->dirty = true;		/* need to sync node */
+	fibril_mutex_unlock(&childp->lock);
+
+	/*
+	 * Hash in the index structure into the position hash.
+	 */
+	fat_idx_hashin(childp->idx);
+
+	return EOK;
+}
+
+int fat_unlink(fs_node_t *pfn, fs_node_t *cfn, const char *nm)
+{
+	fat_node_t *parentp = FAT_NODE(pfn);
+	fat_node_t *childp = FAT_NODE(cfn);
+	fat_bs_t *bs;
+	fat_dentry_t *d;
+	uint16_t bps;
+	block_t *b;
+	bool has_children;
+	int rc;
+
+	if (!parentp)
+		return EBUSY;
+	
+	rc = fat_has_children(&has_children, cfn);
+	if (rc != EOK)
+		return rc;
+	if (has_children)
+		return ENOTEMPTY;
+
+	fibril_mutex_lock(&parentp->lock);
+	fibril_mutex_lock(&childp->lock);
+	assert(childp->lnkcnt == 1);
+	fibril_mutex_lock(&childp->idx->lock);
+	bs = block_bb_get(childp->idx->dev_handle);
+	bps = uint16_t_le2host(bs->bps);
+
+	rc = _fat_block_get(&b, bs, childp->idx->dev_handle, childp->idx->pfc,
+	    (childp->idx->pdi * sizeof(fat_dentry_t)) / bps,
+	    BLOCK_FLAGS_NONE);
+	if (rc != EOK) 
+		goto error;
+	d = (fat_dentry_t *)b->data +
+	    (childp->idx->pdi % (bps / sizeof(fat_dentry_t)));
+	/* mark the dentry as not-currently-used */
+	d->name[0] = FAT_DENTRY_ERASED;
+	b->dirty = true;		/* need to sync block */
+	rc = block_put(b);
+	if (rc != EOK)
+		goto error;
+
+	/* remove the index structure from the position hash */
+	fat_idx_hashout(childp->idx);
+	/* clear position information */
+	childp->idx->pfc = FAT_CLST_RES0;
+	childp->idx->pdi = 0;
+	fibril_mutex_unlock(&childp->idx->lock);
+	childp->lnkcnt = 0;
+	childp->dirty = true;
+	fibril_mutex_unlock(&childp->lock);
+	fibril_mutex_unlock(&parentp->lock);
+
+	return EOK;
+
+error:
+	fibril_mutex_unlock(&parentp->idx->lock);
+	fibril_mutex_unlock(&childp->lock);
+	fibril_mutex_unlock(&childp->idx->lock);
+	return rc;
+}
+
+int fat_has_children(bool *has_children, fs_node_t *fn)
 {
 	fat_bs_t *bs;
@@ -669,7 +783,10 @@
 	block_t *b;
 	unsigned i, j;
-
-	if (nodep->type != FAT_DIRECTORY)
-		return false;
+	int rc;
+
+	if (nodep->type != FAT_DIRECTORY) {
+		*has_children = false;
+		return EOK;
+	}
 	
 	fibril_mutex_lock(&nodep->idx->lock);
@@ -683,5 +800,9 @@
 		fat_dentry_t *d;
 	
-		b = fat_block_get(bs, nodep, i, BLOCK_FLAGS_NONE);
+		rc = fat_block_get(&b, bs, nodep, i, BLOCK_FLAGS_NONE);
+		if (rc != EOK) {
+			fibril_mutex_unlock(&nodep->idx->lock);
+			return rc;
+		}
 		for (j = 0; j < dps; j++) {
 			d = ((fat_dentry_t *)b->data) + j;
@@ -691,27 +812,42 @@
 				continue;
 			case FAT_DENTRY_LAST:
-				block_put(b);
+				rc = block_put(b);
 				fibril_mutex_unlock(&nodep->idx->lock);
-				return false;
+				*has_children = false;
+				return rc;
 			default:
 			case FAT_DENTRY_VALID:
-				block_put(b);
+				rc = block_put(b);
 				fibril_mutex_unlock(&nodep->idx->lock);
-				return true;
+				*has_children = true;
+				return rc;
 			}
-			block_put(b);
+		}
+		rc = block_put(b);
+		if (rc != EOK) {
 			fibril_mutex_unlock(&nodep->idx->lock);
-			return true;
-		}
-		block_put(b);
+			return rc;	
+		}
 	}
 
 	fibril_mutex_unlock(&nodep->idx->lock);
-	return false;
-}
-
-fs_node_t *fat_root_get(dev_handle_t dev_handle)
-{
-	return fat_node_get(dev_handle, 0);
+	*has_children = false;
+	return EOK;
+}
+
+
+fs_index_t fat_index_get(fs_node_t *fn)
+{
+	return FAT_NODE(fn)->idx->index;
+}
+
+size_t fat_size_get(fs_node_t *fn)
+{
+	return FAT_NODE(fn)->size;
+}
+
+unsigned fat_lnkcnt_get(fs_node_t *fn)
+{
+	return FAT_NODE(fn)->lnkcnt;
 }
 
@@ -733,4 +869,5 @@
 /** libfs operations */
 libfs_ops_t fat_libfs_ops = {
+	.root_get = fat_root_get,
 	.match = fat_match,
 	.node_get = fat_node_get,
@@ -740,9 +877,8 @@
 	.link = fat_link,
 	.unlink = fat_unlink,
+	.has_children = fat_has_children,
 	.index_get = fat_index_get,
 	.size_get = fat_size_get,
 	.lnkcnt_get = fat_lnkcnt_get,
-	.has_children = fat_has_children,
-	.root_get = fat_root_get,
 	.plb_get_char =	fat_plb_get_char,
 	.is_directory = fat_is_directory,
@@ -766,5 +902,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -777,5 +913,5 @@
 		return;
 	}
-	ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
+	ipcarg_t retval = async_data_write_finalize(callid, opts, size);
 	if (retval != EOK) {
 		ipc_answer_0(rid, retval);
@@ -799,5 +935,5 @@
 
 	/* prepare the boot block */
-	rc = block_bb_read(dev_handle, BS_BLOCK * BS_SIZE, BS_SIZE);
+	rc = block_bb_read(dev_handle, BS_BLOCK);
 	if (rc != EOK) {
 		block_fini(dev_handle);
@@ -895,5 +1031,5 @@
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 	off_t pos = (off_t)IPC_GET_ARG3(*request);
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	fs_node_t *fn;
 	fat_node_t *nodep;
 	fat_bs_t *bs;
@@ -901,5 +1037,11 @@
 	size_t bytes;
 	block_t *b;
-
+	int rc;
+
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
@@ -910,5 +1052,5 @@
 	ipc_callid_t callid;
 	size_t len;
-	if (!ipc_data_read_receive(&callid, &len)) {
+	if (!async_data_read_receive(&callid, &len)) {
 		fat_node_put(fn);
 		ipc_answer_0(callid, EINVAL);
@@ -929,13 +1071,24 @@
 			/* reading beyond the EOF */
 			bytes = 0;
-			(void) ipc_data_read_finalize(callid, NULL, 0);
+			(void) async_data_read_finalize(callid, NULL, 0);
 		} else {
 			bytes = min(len, bps - pos % bps);
 			bytes = min(bytes, nodep->size - pos);
-			b = fat_block_get(bs, nodep, pos / bps,
+			rc = fat_block_get(&b, bs, nodep, pos / bps,
 			    BLOCK_FLAGS_NONE);
-			(void) ipc_data_read_finalize(callid, b->data + pos % bps,
+			if (rc != EOK) {
+				fat_node_put(fn);
+				ipc_answer_0(callid, rc);
+				ipc_answer_0(rid, rc);
+				return;
+			}
+			(void) async_data_read_finalize(callid, b->data + pos % bps,
 			    bytes);
-			block_put(b);
+			rc = block_put(b);
+			if (rc != EOK) {
+				fat_node_put(fn);
+				ipc_answer_0(rid, rc);
+				return;
+			}
 		}
 	} else {
@@ -959,5 +1112,8 @@
 			off_t o;
 
-			b = fat_block_get(bs, nodep, bnum, BLOCK_FLAGS_NONE);
+			rc = fat_block_get(&b, bs, nodep, bnum,
+			    BLOCK_FLAGS_NONE);
+			if (rc != EOK)
+				goto err;
 			for (o = pos % (bps / sizeof(fat_dentry_t));
 			    o < bps / sizeof(fat_dentry_t);
@@ -969,28 +1125,41 @@
 					continue;
 				case FAT_DENTRY_LAST:
-					block_put(b);
+					rc = block_put(b);
+					if (rc != EOK)
+						goto err;
 					goto miss;
 				default:
 				case FAT_DENTRY_VALID:
 					fat_dentry_name_get(d, name);
-					block_put(b);
+					rc = block_put(b);
+					if (rc != EOK)
+						goto err;
 					goto hit;
 				}
 			}
-			block_put(b);
+			rc = block_put(b);
+			if (rc != EOK)
+				goto err;
 			bnum++;
 		}
 miss:
-		fat_node_put(fn);
-		ipc_answer_0(callid, ENOENT);
-		ipc_answer_1(rid, ENOENT, 0);
-		return;
+		rc = fat_node_put(fn);
+		ipc_answer_0(callid, rc != EOK ? rc : ENOENT);
+		ipc_answer_1(rid, rc != EOK ? rc : ENOENT, 0);
+		return;
+
+err:
+		(void) fat_node_put(fn);
+		ipc_answer_0(callid, rc);
+		ipc_answer_0(rid, rc);
+		return;
+
 hit:
-		(void) ipc_data_read_finalize(callid, name, str_size(name) + 1);
+		(void) async_data_read_finalize(callid, name, str_size(name) + 1);
 		bytes = (pos - spos) + 1;
 	}
 
-	fat_node_put(fn);
-	ipc_answer_1(rid, EOK, (ipcarg_t)bytes);
+	rc = fat_node_put(fn);
+	ipc_answer_1(rid, rc, (ipcarg_t)bytes);
 }
 
@@ -1000,8 +1169,8 @@
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 	off_t pos = (off_t)IPC_GET_ARG3(*request);
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	fs_node_t *fn;
 	fat_node_t *nodep;
 	fat_bs_t *bs;
-	size_t bytes;
+	size_t bytes, size;
 	block_t *b;
 	uint16_t bps;
@@ -1010,5 +1179,11 @@
 	off_t boundary;
 	int flags = BLOCK_FLAGS_NONE;
-	
+	int rc;
+	
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
@@ -1019,6 +1194,6 @@
 	ipc_callid_t callid;
 	size_t len;
-	if (!ipc_data_write_receive(&callid, &len)) {
-		fat_node_put(fn);
+	if (!async_data_write_receive(&callid, &len)) {
+		(void) fat_node_put(fn);
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -1050,16 +1225,34 @@
 		 * next block size boundary.
 		 */
-		fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
-		b = fat_block_get(bs, nodep, pos / bps, flags);
-		(void) ipc_data_write_finalize(callid, b->data + pos % bps,
+		rc = fat_fill_gap(bs, nodep, FAT_CLST_RES0, pos);
+		if (rc != EOK) {
+			(void) fat_node_put(fn);
+			ipc_answer_0(callid, rc);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+		rc = fat_block_get(&b, bs, nodep, pos / bps, flags);
+		if (rc != EOK) {
+			(void) fat_node_put(fn);
+			ipc_answer_0(callid, rc);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+		(void) async_data_write_finalize(callid, b->data + pos % bps,
 		    bytes);
 		b->dirty = true;		/* need to sync block */
-		block_put(b);
+		rc = block_put(b);
+		if (rc != EOK) {
+			(void) fat_node_put(fn);
+			ipc_answer_0(rid, rc);
+			return;
+		}
 		if (pos + bytes > nodep->size) {
 			nodep->size = pos + bytes;
 			nodep->dirty = true;	/* need to sync node */
 		}
-		ipc_answer_2(rid, EOK, bytes, nodep->size);	
-		fat_node_put(fn);
+		size = nodep->size;
+		rc = fat_node_put(fn);
+		ipc_answer_2(rid, rc, bytes, nodep->size);
 		return;
 	} else {
@@ -1068,5 +1261,4 @@
 		 * clusters for the node and zero them out.
 		 */
-		int status;
 		unsigned nclsts;
 		fat_cluster_t mcl, lcl; 
@@ -1074,29 +1266,55 @@
 		nclsts = (ROUND_UP(pos + bytes, bpc) - boundary) / bpc;
 		/* create an independent chain of nclsts clusters in all FATs */
-		status = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
-		if (status != EOK) {
+		rc = fat_alloc_clusters(bs, dev_handle, nclsts, &mcl, &lcl);
+		if (rc != EOK) {
 			/* could not allocate a chain of nclsts clusters */
-			fat_node_put(fn);
-			ipc_answer_0(callid, status);
-			ipc_answer_0(rid, status);
+			(void) fat_node_put(fn);
+			ipc_answer_0(callid, rc);
+			ipc_answer_0(rid, rc);
 			return;
 		}
 		/* zero fill any gaps */
-		fat_fill_gap(bs, nodep, mcl, pos);
-		b = _fat_block_get(bs, dev_handle, lcl, (pos / bps) % spc,
+		rc = fat_fill_gap(bs, nodep, mcl, pos);
+		if (rc != EOK) {
+			(void) fat_free_clusters(bs, dev_handle, mcl);
+			(void) fat_node_put(fn);
+			ipc_answer_0(callid, rc);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+		rc = _fat_block_get(&b, bs, dev_handle, lcl, (pos / bps) % spc,
 		    flags);
-		(void) ipc_data_write_finalize(callid, b->data + pos % bps,
+		if (rc != EOK) {
+			(void) fat_free_clusters(bs, dev_handle, mcl);
+			(void) fat_node_put(fn);
+			ipc_answer_0(callid, rc);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+		(void) async_data_write_finalize(callid, b->data + pos % bps,
 		    bytes);
 		b->dirty = true;		/* need to sync block */
-		block_put(b);
+		rc = block_put(b);
+		if (rc != EOK) {
+			(void) fat_free_clusters(bs, dev_handle, mcl);
+			(void) fat_node_put(fn);
+			ipc_answer_0(rid, rc);
+			return;
+		}
 		/*
 		 * Append the cluster chain starting in mcl to the end of the
 		 * node's cluster chain.
 		 */
-		fat_append_clusters(bs, nodep, mcl);
-		nodep->size = pos + bytes;
+		rc = fat_append_clusters(bs, nodep, mcl);
+		if (rc != EOK) {
+			(void) fat_free_clusters(bs, dev_handle, mcl);
+			(void) fat_node_put(fn);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+		nodep->size = size = pos + bytes;
 		nodep->dirty = true;		/* need to sync node */
-		ipc_answer_2(rid, EOK, bytes, nodep->size);
-		fat_node_put(fn);
+		rc = fat_node_put(fn);
+		ipc_answer_2(rid, rc, bytes, size);
 		return;
 	}
@@ -1108,5 +1326,5 @@
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
 	size_t size = (off_t)IPC_GET_ARG3(*request);
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	fs_node_t *fn;
 	fat_node_t *nodep;
 	fat_bs_t *bs;
@@ -1116,4 +1334,9 @@
 	int rc;
 
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
@@ -1147,10 +1370,16 @@
 		 */
 		if (size == 0) {
-			fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
+			rc = fat_chop_clusters(bs, nodep, FAT_CLST_RES0);
+			if (rc != EOK)
+				goto out;
 		} else {
 			fat_cluster_t lastc;
-			(void) fat_cluster_walk(bs, dev_handle, nodep->firstc,
-			    &lastc, (size - 1) / bpc);
-			fat_chop_clusters(bs, nodep, lastc);
+			rc = fat_cluster_walk(bs, dev_handle, nodep->firstc,
+			    &lastc, NULL, (size - 1) / bpc);
+			if (rc != EOK)
+				goto out;
+			rc = fat_chop_clusters(bs, nodep, lastc);
+			if (rc != EOK)
+				goto out;
 		}
 		nodep->size = size;
@@ -1158,4 +1387,5 @@
 		rc = EOK;	
 	}
+out:
 	fat_node_put(fn);
 	ipc_answer_0(rid, rc);
@@ -1172,7 +1402,12 @@
 	dev_handle_t dev_handle = (dev_handle_t)IPC_GET_ARG1(*request);
 	fs_index_t index = (fs_index_t)IPC_GET_ARG2(*request);
+	fs_node_t *fn;
 	int rc;
 
-	fs_node_t *fn = fat_node_get(dev_handle, index);
+	rc = fat_node_get(&fn, dev_handle, index);
+	if (rc != EOK) {
+		ipc_answer_0(rid, rc);
+		return;
+	}
 	if (!fn) {
 		ipc_answer_0(rid, ENOENT);
Index: uspace/srv/fs/tmpfs/Makefile
===================================================================
--- uspace/srv/fs/tmpfs/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/tmpfs/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,58 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../../lib/libc
-LIBFS_PREFIX = ../../../lib/libfs
-LIBBLOCK_PREFIX = ../../../lib/libblock
-SOFTINT_PREFIX = ../../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-CFLAGS += -I $(LIBFS_PREFIX) -I $(LIBBLOCK_PREFIX)
-
-LIBS = \
-	$(LIBFS_PREFIX)/libfs.a \
-	$(LIBBLOCK_PREFIX)/libblock.a \
-	$(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = tmpfs
-SOURCES = \
-	tmpfs.c \
-	tmpfs_ops.c \
-	tmpfs_dump.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/fs/tmpfs/Makefile.build
===================================================================
--- uspace/srv/fs/tmpfs/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fs/tmpfs/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,65 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I$(LIBFS_PREFIX) -I$(LIBBLOCK_PREFIX)
+
+## Sources
+#
+
+SOURCES = \
+	tmpfs.c \
+	tmpfs_ops.c \
+	tmpfs_dump.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/fs/tmpfs/Makefile.common
===================================================================
--- uspace/srv/fs/tmpfs/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/fs/tmpfs/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,41 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+LIBFS_PREFIX = ../../../lib/libfs
+LIBBLOCK_PREFIX = ../../../lib/libblock
+SOFTINT_PREFIX = ../../../lib/softint
+LIBS = $(LIBFS_PREFIX)/libfs.a $(LIBBLOCK_PREFIX)/libblock.a $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = tmpfs
Index: uspace/srv/fs/tmpfs/tmpfs.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/tmpfs/tmpfs.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -48,4 +48,5 @@
 #include <unistd.h>
 #include <stdio.h>
+#include <task.h>
 #include <libfs.h>
 #include "../../vfs/vfs.h"
@@ -55,5 +56,5 @@
 
 vfs_info_t tmpfs_vfs_info = {
-	.name = "tmpfs",
+	.name = NAME,
 };
 
@@ -90,5 +91,5 @@
 	}
 	
-	dprintf("VFS-TMPFS connection established.\n");
+	dprintf(NAME ": connection opened\n");
 	while (1) {
 		ipc_callid_t callid;
@@ -162,4 +163,5 @@
 
 	printf(NAME ": Accepting connections\n");
+	task_retval(0);
 	async_manager();
 	/* not reached */
Index: uspace/srv/fs/tmpfs/tmpfs_dump.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/tmpfs/tmpfs_dump.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -47,5 +47,5 @@
 #include <byteorder.h>
 
-#define TMPFS_BLOCK_SIZE	1024
+#define TMPFS_COMM_SIZE		1024
 
 struct rdentry {
@@ -69,5 +69,5 @@
 		
 		if (block_seqread(dev, bufpos, buflen, pos, &entry,
-		    sizeof(entry), TMPFS_BLOCK_SIZE) != EOK)
+		    sizeof(entry)) != EOK)
 			return false;
 		
@@ -82,6 +82,6 @@
 				return false;
 			
-			fn = ops->create(dev, L_FILE);
-			if (fn == NULL) {
+			rc = ops->create(&fn, dev, L_FILE);
+			if (rc != EOK || fn == NULL) {
 				free(fname);
 				return false;
@@ -89,6 +89,6 @@
 			
 			if (block_seqread(dev, bufpos, buflen, pos, fname,
-			    entry.len, TMPFS_BLOCK_SIZE) != EOK) {
-				ops->destroy(fn);
+			    entry.len) != EOK) {
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -98,5 +98,5 @@
 			rc = ops->link(pfn, fn, fname);
 			if (rc != EOK) {
-				ops->destroy(fn);
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -105,5 +105,5 @@
 			
 			if (block_seqread(dev, bufpos, buflen, pos, &size,
-			    sizeof(size), TMPFS_BLOCK_SIZE) != EOK)
+			    sizeof(size)) != EOK)
 				return false;
 			
@@ -117,5 +117,5 @@
 			nodep->size = size;
 			if (block_seqread(dev, bufpos, buflen, pos, nodep->data,
-			    size, TMPFS_BLOCK_SIZE) != EOK)
+			    size) != EOK)
 				return false;
 			
@@ -126,6 +126,6 @@
 				return false;
 			
-			fn = ops->create(dev, L_DIRECTORY);
-			if (fn == NULL) {
+			rc = ops->create(&fn, dev, L_DIRECTORY);
+			if (rc != EOK || fn == NULL) {
 				free(fname);
 				return false;
@@ -133,6 +133,6 @@
 			
 			if (block_seqread(dev, bufpos, buflen, pos, fname,
-			    entry.len, TMPFS_BLOCK_SIZE) != EOK) {
-				ops->destroy(fn);
+			    entry.len) != EOK) {
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -142,5 +142,5 @@
 			rc = ops->link(pfn, fn, fname);
 			if (rc != EOK) {
-				ops->destroy(fn);
+				(void) ops->destroy(fn);
 				free(fname);
 				return false;
@@ -164,7 +164,8 @@
 {
 	libfs_ops_t *ops = &tmpfs_libfs_ops;
+	fs_node_t *fn;
 	int rc;
 
-	rc = block_init(dev, TMPFS_BLOCK_SIZE);
+	rc = block_init(dev, TMPFS_COMM_SIZE);
 	if (rc != EOK)
 		return false; 
@@ -175,6 +176,5 @@
 	
 	char tag[6];
-	if (block_seqread(dev, &bufpos, &buflen, &pos, tag, 5,
-	    TMPFS_BLOCK_SIZE) != EOK)
+	if (block_seqread(dev, &bufpos, &buflen, &pos, tag, 5) != EOK)
 		goto error;
 	
@@ -183,6 +183,9 @@
 		goto error;
 	
-	if (!tmpfs_restore_recursion(dev, &bufpos, &buflen, &pos,
-	    ops->root_get(dev)))
+	rc = ops->root_get(&fn, dev);
+	if (rc != EOK)
+		goto error;
+
+	if (!tmpfs_restore_recursion(dev, &bufpos, &buflen, &pos, fn))
 		goto error;
 		
Index: uspace/srv/fs/tmpfs/tmpfs_ops.c
===================================================================
--- uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/fs/tmpfs/tmpfs_ops.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -67,13 +67,24 @@
 
 /* Forward declarations of static functions. */
-static fs_node_t *tmpfs_match(fs_node_t *, const char *);
-static fs_node_t *tmpfs_node_get(dev_handle_t, fs_index_t);
-static void tmpfs_node_put(fs_node_t *);
-static fs_node_t *tmpfs_create_node(dev_handle_t, int);
+static int tmpfs_match(fs_node_t **, fs_node_t *, const char *);
+static int tmpfs_node_get(fs_node_t **, dev_handle_t, fs_index_t);
+static int tmpfs_node_put(fs_node_t *);
+static int tmpfs_create_node(fs_node_t **, dev_handle_t, int);
+static int tmpfs_destroy_node(fs_node_t *);
 static int tmpfs_link_node(fs_node_t *, fs_node_t *, const char *);
 static int tmpfs_unlink_node(fs_node_t *, fs_node_t *, const char *);
-static int tmpfs_destroy_node(fs_node_t *);
 
 /* Implementation of helper functions. */
+static int tmpfs_root_get(fs_node_t **rfn, dev_handle_t dev_handle)
+{
+	return tmpfs_node_get(rfn, dev_handle, TMPFS_SOME_ROOT); 
+}
+
+static int tmpfs_has_children(bool *has_children, fs_node_t *fn)
+{
+	*has_children = !list_empty(&TMPFS_NODE(fn)->cs_head);
+	return EOK;
+}
+
 static fs_index_t tmpfs_index_get(fs_node_t *fn)
 {
@@ -89,14 +100,4 @@
 {
 	return TMPFS_NODE(fn)->lnkcnt;
-}
-
-static bool tmpfs_has_children(fs_node_t *fn)
-{
-	return !list_empty(&TMPFS_NODE(fn)->cs_head);
-}
-
-static fs_node_t *tmpfs_root_get(dev_handle_t dev_handle)
-{
-	return tmpfs_node_get(dev_handle, TMPFS_SOME_ROOT); 
 }
 
@@ -118,4 +119,5 @@
 /** libfs operations */
 libfs_ops_t tmpfs_libfs_ops = {
+	.root_get = tmpfs_root_get,
 	.match = tmpfs_match,
 	.node_get = tmpfs_node_get,
@@ -125,9 +127,8 @@
 	.link = tmpfs_link_node,
 	.unlink = tmpfs_unlink_node,
+	.has_children = tmpfs_has_children,
 	.index_get = tmpfs_index_get,
 	.size_get = tmpfs_size_get,
 	.lnkcnt_get = tmpfs_lnkcnt_get,
-	.has_children = tmpfs_has_children,
-	.root_get = tmpfs_root_get,
 	.plb_get_char = tmpfs_plb_get_char,
 	.is_directory = tmpfs_is_directory,
@@ -197,7 +198,8 @@
 {
 	fs_node_t *rfn;
+	int rc;
 	
-	rfn = tmpfs_create_node(dev_handle, L_DIRECTORY);
-	if (!rfn) 
+	rc = tmpfs_create_node(&rfn, dev_handle, L_DIRECTORY);
+	if (rc != EOK || !rfn)
 		return false;
 	TMPFS_NODE(rfn)->lnkcnt = 0;	/* FS root is not linked */
@@ -205,5 +207,5 @@
 }
 
-fs_node_t *tmpfs_match(fs_node_t *pfn, const char *component)
+int tmpfs_match(fs_node_t **rfn, fs_node_t *pfn, const char *component)
 {
 	tmpfs_node_t *parentp = TMPFS_NODE(pfn);
@@ -212,14 +214,17 @@
 	for (lnk = parentp->cs_head.next; lnk != &parentp->cs_head;
 	    lnk = lnk->next) {
-		tmpfs_dentry_t *dentryp = list_get_instance(lnk, tmpfs_dentry_t,
-		    link);
-		if (!str_cmp(dentryp->name, component))
-			return FS_NODE(dentryp->node);
-	}
-
-	return NULL;
-}
-
-fs_node_t *tmpfs_node_get(dev_handle_t dev_handle, fs_index_t index)
+		tmpfs_dentry_t *dentryp;
+		dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
+		if (!str_cmp(dentryp->name, component)) {
+			*rfn = FS_NODE(dentryp->node);
+			return EOK;
+		}
+	}
+
+	*rfn = NULL;
+	return EOK;
+}
+
+int tmpfs_node_get(fs_node_t **rfn, dev_handle_t dev_handle, fs_index_t index)
 {
 	unsigned long key[] = {
@@ -228,30 +233,42 @@
 	};
 	link_t *lnk = hash_table_find(&nodes, key);
-	if (!lnk)
-		return NULL;
-	return FS_NODE(hash_table_get_instance(lnk, tmpfs_node_t, nh_link));
-}
-
-void tmpfs_node_put(fs_node_t *fn)
+	if (lnk) {
+		tmpfs_node_t *nodep;
+		nodep = hash_table_get_instance(lnk, tmpfs_node_t, nh_link);
+		*rfn = FS_NODE(nodep);
+	} else {
+		*rfn = NULL;
+	}
+	return EOK;	
+}
+
+int tmpfs_node_put(fs_node_t *fn)
 {
 	/* nothing to do */
-}
-
-fs_node_t *tmpfs_create_node(dev_handle_t dev_handle, int lflag)
-{
+	return EOK;
+}
+
+int tmpfs_create_node(fs_node_t **rfn, dev_handle_t dev_handle, int lflag)
+{
+	fs_node_t *rootfn;
+	int rc;
+
 	assert((lflag & L_FILE) ^ (lflag & L_DIRECTORY));
 
 	tmpfs_node_t *nodep = malloc(sizeof(tmpfs_node_t));
 	if (!nodep)
-		return NULL;
+		return ENOMEM;
 	tmpfs_node_initialize(nodep);
 	nodep->bp = malloc(sizeof(fs_node_t));
 	if (!nodep->bp) {
 		free(nodep);
-		return NULL;
+		return ENOMEM;
 	}
 	fs_node_initialize(nodep->bp);
 	nodep->bp->data = nodep;	/* link the FS and TMPFS nodes */
-	if (!tmpfs_root_get(dev_handle))
+
+	rc = tmpfs_root_get(&rootfn, dev_handle);
+	assert(rc == EOK);
+	if (!rootfn)
 		nodep->index = TMPFS_SOME_ROOT;
 	else
@@ -269,5 +286,26 @@
 	};
 	hash_table_insert(&nodes, key, &nodep->nh_link);
-	return FS_NODE(nodep);
+	*rfn = FS_NODE(nodep);
+	return EOK;
+}
+
+int tmpfs_destroy_node(fs_node_t *fn)
+{
+	tmpfs_node_t *nodep = TMPFS_NODE(fn);
+	
+	assert(!nodep->lnkcnt);
+	assert(list_empty(&nodep->cs_head));
+
+	unsigned long key[] = {
+		[NODES_KEY_INDEX] = nodep->index,
+		[NODES_KEY_DEV] = nodep->dev_handle
+	};
+	hash_table_remove(&nodes, key, 2);
+
+	if (nodep->type == TMPFS_FILE)
+		free(nodep->data);
+	free(nodep->bp);
+	free(nodep);
+	return EOK;
 }
 
@@ -343,32 +381,13 @@
 }
 
-int tmpfs_destroy_node(fs_node_t *fn)
-{
-	tmpfs_node_t *nodep = TMPFS_NODE(fn);
-	
-	assert(!nodep->lnkcnt);
-	assert(list_empty(&nodep->cs_head));
-
-	unsigned long key[] = {
-		[NODES_KEY_INDEX] = nodep->index,
-		[NODES_KEY_DEV] = nodep->dev_handle
-	};
-	hash_table_remove(&nodes, key, 2);
-
-	if (nodep->type == TMPFS_FILE)
-		free(nodep->data);
-	free(nodep->bp);
-	free(nodep);
-	return EOK;
-}
-
 void tmpfs_mounted(ipc_callid_t rid, ipc_call_t *request)
 {
 	dev_handle_t dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
+	int rc;
 
 	/* accept the mount options */
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -381,5 +400,5 @@
 		return;
 	}
-	ipcarg_t retval = ipc_data_write_finalize(callid, opts, size);
+	ipcarg_t retval = async_data_write_finalize(callid, opts, size);
 	if (retval != EOK) {
 		ipc_answer_0(rid, retval);
@@ -395,5 +414,8 @@
 	}
 
-	tmpfs_node_t *rootp = TMPFS_NODE(tmpfs_root_get(dev_handle));
+	fs_node_t *rootfn;
+	rc = tmpfs_root_get(&rootfn, dev_handle);
+	assert(rc == EOK);
+	tmpfs_node_t *rootp = TMPFS_NODE(rootfn);
 	if (str_cmp(opts, "restore") == 0) {
 		if (tmpfs_restore(dev_handle))
@@ -445,5 +467,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_read_receive(&callid, &size)) {
+	if (!async_data_read_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);	
 		ipc_answer_0(rid, EINVAL);
@@ -454,5 +476,5 @@
 	if (nodep->type == TMPFS_FILE) {
 		bytes = max(0, min(nodep->size - pos, size));
-		(void) ipc_data_read_finalize(callid, nodep->data + pos,
+		(void) async_data_read_finalize(callid, nodep->data + pos,
 		    bytes);
 	} else {
@@ -481,5 +503,5 @@
 		dentryp = list_get_instance(lnk, tmpfs_dentry_t, link);
 
-		(void) ipc_data_read_finalize(callid, dentryp->name,
+		(void) async_data_read_finalize(callid, dentryp->name,
 		    str_size(dentryp->name) + 1);
 		bytes = 1;
@@ -519,5 +541,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);	
 		ipc_answer_0(rid, EINVAL);
@@ -530,5 +552,5 @@
 	if (pos + size <= nodep->size) {
 		/* The file size is not changing. */
-		(void) ipc_data_write_finalize(callid, nodep->data + pos, size);
+		(void) async_data_write_finalize(callid, nodep->data + pos, size);
 		ipc_answer_2(rid, EOK, size, nodep->size);
 		return;
@@ -552,5 +574,5 @@
 	nodep->size += delta;
 	nodep->data = newdata;
-	(void) ipc_data_write_finalize(callid, nodep->data + pos, size);
+	(void) async_data_write_finalize(callid, nodep->data + pos, size);
 	ipc_answer_2(rid, EOK, size, nodep->size);
 }
Index: uspace/srv/kbd/Makefile
===================================================================
--- uspace/srv/kbd/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/kbd/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,159 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../lib/libc
-SOFTINT_PREFIX = ../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-CFLAGS += -Iinclude
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = kbd
-GENERIC_SOURCES = \
-	generic/kbd.c \
-	genarch/gsp.c \
-	genarch/stroke.c
-
-ARCH_SOURCES =
-GENARCH_SOURCES = \
-	layout/cz.c \
-	layout/us_qwerty.c \
-	layout/us_dvorak.c
-
-ifeq ($(UARCH), amd64)
-	GENARCH_SOURCES += \
-		port/i8042.c \
-		ctl/pc.c
-endif
-
-ifeq ($(UARCH), arm32)
-ifeq ($(MACHINE), testarm)
-	GENARCH_SOURCES += \
-		port/gxemul.c
-	
-	ifeq ($(CONFIG_FB), y)
-		GENARCH_SOURCES += \
-			ctl/gxe_fb.c
-	else
-		GENARCH_SOURCES += \
-			ctl/stty.c
-	endif
-endif
-ifeq ($(MACHINE), integratorcp)
-	 GENARCH_SOURCES += \
-		port/pl050.c \
-		ctl/pl050.c
-endif
-endif
-
-ifeq ($(UARCH), ia32)
-	GENARCH_SOURCES += \
-		port/i8042.c \
-		ctl/pc.c
-endif
-
-ifeq ($(MACHINE), i460GX)
-	GENARCH_SOURCES += \
-		port/i8042.c \
-		ctl/pc.c
-endif
-
-ifeq ($(MACHINE), ski)
-	GENARCH_SOURCES += \
-		port/ski.c \
-		ctl/stty.c
-endif
-
-ifeq ($(MACHINE), msim)
-	GENARCH_SOURCES += \
-		port/msim.c \
-		ctl/stty.c
-endif
-
-ifeq ($(MACHINE), lgxemul)
-	GENARCH_SOURCES += \
-		port/gxemul.c
-	
-	ifeq ($(CONFIG_FB), y)
-		GENARCH_SOURCES += \
-			ctl/gxe_fb.c
-	else
-		GENARCH_SOURCES += \
-			ctl/stty.c
-	endif
-endif
-
-ifeq ($(MACHINE), bgxemul)
-	GENARCH_SOURCES += \
-		port/gxemul.c
-	
-	ifeq ($(CONFIG_FB), y)
-		GENARCH_SOURCES += \
-			ctl/gxe_fb.c
-	else
-		GENARCH_SOURCES += \
-			ctl/stty.c
-	endif
-endif
-
-ifeq ($(UARCH), ppc32)
-	GENARCH_SOURCES += \
-		port/dummy.c \
-		ctl/stty.c
-endif
-
-ifeq ($(UARCH), sparc64)
-	ifeq ($(MACHINE),serengeti)
-		GENARCH_SOURCES += \
-			port/sgcn.c \
-			ctl/stty.c
-	else
-		GENARCH_SOURCES += \
-			port/sun.c \
-			port/z8530.c \
-			port/ns16550.c \
-			ctl/sun.c
-	endif
-endif
-
-GENERIC_OBJECTS := $(addsuffix .o,$(basename $(GENERIC_SOURCES)))
-ARCH_OBJECTS := $(addsuffix .o,$(basename $(ARCH_SOURCES)))
-GENARCH_OBJECTS := $(addsuffix .o,$(basename $(GENARCH_SOURCES)))
-
-OBJECTS := $(ARCH_OBJECTS) $(GENERIC_OBJECTS) $(GENARCH_OBJECTS)
-
-.PHONY: all clean depend disasm links
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/kbd/Makefile.build
===================================================================
--- uspace/srv/kbd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/kbd/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,164 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -Iinclude
+
+## Sources
+#
+
+SOURCES = \
+	generic/kbd.c \
+	genarch/gsp.c \
+	genarch/stroke.c \
+	layout/cz.c \
+	layout/us_qwerty.c \
+	layout/us_dvorak.c
+
+ifeq ($(UARCH),amd64)
+	SOURCES += \
+		port/i8042.c \
+		ctl/pc.c
+endif
+
+ifeq ($(UARCH),arm32)
+	ifeq ($(MACHINE),testarm)
+		SOURCES += \
+			port/gxemul.c
+		
+		ifeq ($(CONFIG_FB),y)
+			SOURCES += \
+				ctl/gxe_fb.c
+		else
+			SOURCES += \
+				ctl/stty.c
+		endif
+	endif
+	ifeq ($(MACHINE),integratorcp)
+		SOURCES += \
+			port/pl050.c \
+			ctl/pl050.c
+	endif
+endif
+
+ifeq ($(UARCH),ia32)
+	SOURCES += \
+		port/i8042.c \
+		ctl/pc.c
+endif
+
+ifeq ($(MACHINE),i460GX)
+	SOURCES += \
+		port/i8042.c \
+		ctl/pc.c
+endif
+
+ifeq ($(MACHINE),ski)
+	SOURCES += \
+		port/ski.c \
+		ctl/stty.c
+endif
+
+ifeq ($(MACHINE),msim)
+	SOURCES += \
+		port/msim.c \
+		ctl/stty.c
+endif
+
+ifeq ($(MACHINE),lgxemul)
+	SOURCES += \
+		port/gxemul.c
+	
+	ifeq ($(CONFIG_FB),y)
+		SOURCES += \
+			ctl/gxe_fb.c
+	else
+		SOURCES += \
+			ctl/stty.c
+	endif
+endif
+
+ifeq ($(MACHINE),bgxemul)
+	SOURCES += \
+		port/gxemul.c
+	
+	ifeq ($(CONFIG_FB),y)
+		SOURCES += \
+			ctl/gxe_fb.c
+	else
+		SOURCES += \
+			ctl/stty.c
+	endif
+endif
+
+ifeq ($(UARCH),ppc32)
+	SOURCES += \
+		port/dummy.c \
+		ctl/stty.c
+endif
+
+ifeq ($(UARCH),sparc64)
+	ifeq ($(MACHINE),serengeti)
+		SOURCES += \
+			port/sgcn.c \
+			ctl/stty.c
+	else
+		SOURCES += \
+			port/sun.c \
+			port/z8530.c \
+			port/ns16550.c \
+			ctl/sun.c
+	endif
+endif
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/kbd/Makefile.common
===================================================================
--- uspace/srv/kbd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/kbd/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = kbd
Index: uspace/srv/loader/Makefile
===================================================================
--- uspace/srv/loader/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/loader/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,5 +1,5 @@
 #
 # Copyright (c) 2005 Martin Decky
-# Copyright (c) 2008 Jiri Svoboda
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -28,56 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../lib/libc
-SOFTINT_PREFIX = ../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-include arch/$(UARCH)/Makefile.inc
-
-CFLAGS += -Iinclude
-
-LIBS = $(LIBC_PREFIX)/libc.a $(SOFTINT_PREFIX)/libsoftint.a
-
-## Sources
-#
-
-OUTPUT = loader
-GENERIC_SOURCES = \
-	main.c \
-	elf_load.c \
-	interp.s
-
-SOURCES := $(GENERIC_SOURCES) $(ARCH_SOURCES)
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OBJECTS) $(OUTPUT).map $(OUTPUT).disasm arch/$(UARCH)/_link.ld Makefile.depend
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS) arch/$(UARCH)/_link.ld
-	$(LD) -T arch/$(UARCH)/_link.ld $(LFLAGS) $(OBJECTS) $(LIBS) -o $@ -Map $(OUTPUT).map
-
-disasm:
-	$(OBJDUMP) -d $(OUTPUT) >$(OUTPUT).disasm
-
-arch/$(UARCH)/_link.ld: arch/$(UARCH)/_link.ld.in
-	$(CC) $(DEFS) $(CFLAGS) -DLIBC_PREFIX=$(LIBC_PREFIX) -E -x c $< | grep -v "^\#" > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm arch/*/_link.ld
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/loader/Makefile.build
===================================================================
--- uspace/srv/loader/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/loader/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,74 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+include arch/$(UARCH)/Makefile.inc
+
+CFLAGS += -Iinclude
+LINK = arch/$(UARCH)/_link.ld
+
+## Sources
+#
+
+GENERIC_SOURCES = \
+	main.c \
+	elf_load.c \
+	interp.s
+
+SOURCES := $(GENERIC_SOURCES) $(ARCH_SOURCES)
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS) $(LINK)
+	$(LD) -T $(LINK) $(LFLAGS) $(OBJECTS) $(LIBS) -o $@ -Map $(OUTPUT).map
+
+$(LINK): $(LINK).in
+	$(GCC) $(DEFS) $(CFLAGS) -DLIBC_PREFIX=$(LIBC_PREFIX) -E -x c $< | grep -v "^\#" > $@
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+%.o: %.s $(DEPEND)
+	$(AS) $(AFLAGS) $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/loader/Makefile.common
===================================================================
--- uspace/srv/loader/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/loader/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a $(SOFTINT_PREFIX)/libsoftint.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = loader
Index: uspace/srv/loader/arch/ia32/_link.ld.in
===================================================================
--- uspace/srv/loader/arch/ia32/_link.ld.in	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/loader/arch/ia32/_link.ld.in	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -8,5 +8,5 @@
 PHDRS {
 	interp PT_INTERP;
-        text PT_LOAD FILEHDR PHDRS FLAGS(5);
+	text PT_LOAD FILEHDR PHDRS FLAGS(5);
 	data PT_LOAD FLAGS(6);
 }
@@ -16,13 +16,14 @@
 		*(.interp);
 	} :interp
-
+	
 	. = 0x70001000;
-
+	
 	.init ALIGN(0x1000) : SUBALIGN(0x1000) {
 		*(.init);
 	} :text
+	
 	.text : {
 		*(.text);
-                *(.rodata*);
+		*(.rodata*);
 	} :text
 	
@@ -30,9 +31,12 @@
 		*(.data);
 	} :data
+	
 	.tdata : {
 		_tdata_start = .;
 		*(.tdata);
+		*(.gnu.linkonce.tb.*);
 		_tdata_end = .;
 	} :data
+	
 	.tbss : {
 		_tbss_start = .;
@@ -40,11 +44,14 @@
 		_tbss_end = .;
 	} :data
+	
 	_tls_alignment = MAX(ALIGNOF(.tdata), ALIGNOF(.tbss));
+	
 	.bss : {
-                *(COMMON);
-                *(.bss);
+		*(COMMON);
+		*(.bss);
 	} :data
 	
 	. = ALIGN(0x1000);
+	
 	_heap = .;
 	
@@ -52,4 +59,3 @@
 		*(*);
 	}
-
 }
Index: uspace/srv/loader/arch/ia32/ia32.s
===================================================================
--- uspace/srv/loader/arch/ia32/ia32.s	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/loader/arch/ia32/ia32.s	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -40,7 +40,7 @@
 	movl 0x8(%ebp), %eax
 
-	# %ebx := pcb
-	# pcb is passed to the entry point int %ebx
-	mov 0xc(%ebp), %ebx
+	# %edi := pcb
+	# pcb is passed to the entry point in %edi
+	mov 0xc(%ebp), %edi
 
 	# Save a tiny bit of stack space
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/loader/main.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -72,4 +72,7 @@
 static pcb_t pcb;
 
+/** Current working directory */
+static char *cwd = NULL;
+
 /** Number of arguments */
 static int argc = 0;
@@ -102,5 +105,5 @@
 	task_id = task_get_id();
 	
-	if (!ipc_data_read_receive(&callid, &len)) {
+	if (!async_data_read_receive(&callid, &len)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -111,8 +114,36 @@
 		len = sizeof(task_id);
 	
-	ipc_data_read_finalize(callid, &task_id, len);
+	async_data_read_finalize(callid, &task_id, len);
 	ipc_answer_0(rid, EOK);
 }
 
+/** Receive a call setting the current working directory.
+ *
+ * @param rid
+ * @param request
+ */
+static void ldr_set_cwd(ipc_callid_t rid, ipc_call_t *request)
+{
+	ipc_callid_t callid;
+	size_t len;
+	
+	if (!async_data_write_receive(&callid, &len)) {
+		ipc_answer_0(callid, EINVAL);
+		ipc_answer_0(rid, EINVAL);
+		return;
+	}
+	
+	cwd = malloc(len + 1);
+	if (!cwd) {
+		ipc_answer_0(callid, ENOMEM);
+		ipc_answer_0(rid, ENOMEM);
+		return;
+	}
+	
+	async_data_write_finalize(callid, cwd, len);
+	cwd[len] = '\0';
+	
+	ipc_answer_0(rid, EOK);
+}
 
 /** Receive a call setting pathname of the program to execute.
@@ -127,5 +158,5 @@
 	char *name_buf;
 	
-	if (!ipc_data_write_receive(&callid, &len)) {
+	if (!async_data_write_receive(&callid, &len)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -140,5 +171,5 @@
 	}
 	
-	ipc_data_write_finalize(callid, name_buf, len);
+	async_data_write_finalize(callid, name_buf, len);
 	ipc_answer_0(rid, EOK);
 	
@@ -164,5 +195,5 @@
 	int n;
 	
-	if (!ipc_data_write_receive(&callid, &buf_size)) {
+	if (!async_data_write_receive(&callid, &buf_size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -187,5 +218,5 @@
 	}
 	
-	ipc_data_write_finalize(callid, arg_buf, buf_size);
+	async_data_write_finalize(callid, arg_buf, buf_size);
 	
 	arg_buf[buf_size] = '\0';
@@ -239,5 +270,5 @@
 	ipc_callid_t callid;
 	size_t buf_size;
-	if (!ipc_data_write_receive(&callid, &buf_size)) {
+	if (!async_data_write_receive(&callid, &buf_size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -268,5 +299,5 @@
 	}
 	
-	ipc_data_write_finalize(callid, fil_buf, buf_size);
+	async_data_write_finalize(callid, fil_buf, buf_size);
 	
 	int count = buf_size / sizeof(fdi_node_t);
@@ -312,4 +343,6 @@
 	
 	elf_create_pcb(&prog_info, &pcb);
+	
+	pcb.cwd = cwd;
 	
 	pcb.argc = argc;
@@ -406,4 +439,7 @@
 		case LOADER_GET_TASKID:
 			ldr_get_taskid(callid, &call);
+			continue;
+		case LOADER_SET_CWD:
+			ldr_set_cwd(callid, &call);
 			continue;
 		case LOADER_SET_PATHNAME:
Index: uspace/srv/ns/Makefile
===================================================================
--- uspace/srv/ns/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/ns/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,4 +1,5 @@
 #
 # Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -27,52 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../lib/libc
-SOFTINT_PREFIX = ../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = ns
-SOURCES = \
-	ns.c \
-	service.c \
-	clonable.c \
-	task.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/ns/Makefile.build
===================================================================
--- uspace/srv/ns/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/ns/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,64 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	ns.c \
+	service.c \
+	clonable.c \
+	task.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/ns/Makefile.common
===================================================================
--- uspace/srv/ns/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/ns/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = ns
Index: uspace/srv/ns/service.c
===================================================================
--- uspace/srv/ns/service.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/ns/service.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -156,9 +156,6 @@
 		
 		hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
-		ipcarg_t retval = ipc_forward_fast(pr->callid, hs->phone,
-		    pr->arg2, pr->arg3, 0, IPC_FF_NONE);
-		
-		if (!(pr->callid & IPC_CALLID_NOTIFICATION))
-			ipc_answer_0(pr->callid, retval);
+		(void) ipc_forward_fast(pr->callid, hs->phone, pr->arg2,
+		    pr->arg3, 0, IPC_FF_NONE);
 		
 		list_remove(cur);
@@ -242,6 +239,7 @@
 	
 	hashed_service_t *hs = hash_table_get_instance(link, hashed_service_t, link);
-	retval = ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
+	(void) ipc_forward_fast(callid, hs->phone, IPC_GET_ARG2(*call),
 	    IPC_GET_ARG3(*call), 0, IPC_FF_NONE);
+	return;
 	
 out:
Index: uspace/srv/part/mbr_part/Makefile
===================================================================
--- uspace/srv/part/mbr_part/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/part/mbr_part/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+include Makefile.common
+
+.PHONY: all clean
+
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
+
+clean:
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/part/mbr_part/Makefile.build
===================================================================
--- uspace/srv/part/mbr_part/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/part/mbr_part/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,63 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+CFLAGS += -I$(LIBBLOCK_PREFIX)
+
+## Sources
+#
+
+SOURCES = \
+	mbr_part.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/part/mbr_part/Makefile.common
===================================================================
--- uspace/srv/part/mbr_part/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/part/mbr_part/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+SOFTINT_PREFIX = ../../../lib/softint
+LIBBLOCK_PREFIX = ../../../lib/libblock
+LIBS = $(LIBBLOCK_PREFIX)/libblock.a $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = mbr_part
Index: uspace/srv/part/mbr_part/mbr_part.c
===================================================================
--- uspace/srv/part/mbr_part/mbr_part.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/part/mbr_part/mbr_part.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,508 @@
+/*
+ * 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 bd
+ * @{
+ */
+
+/**
+ * @file
+ * @brief PC MBR partition driver
+ *
+ * Handles the PC MBR partitioning scheme. Uses a block device
+ * and provides one for each partition.
+ *
+ * Limitations:
+ * 
+ * Only works with boot records using LBA. CHS-only records are not
+ * supported.
+ *
+ * Referemces:
+ *	
+ * The source of MBR structures for this driver have been the following
+ * Wikipedia articles:
+ *	- http://en.wikipedia.org/wiki/Master_Boot_Record
+ *	- http://en.wikipedia.org/wiki/Extended_boot_record
+ *
+ * The fact that the extended partition has type 0x05 is pure observation.
+ * (TODO: can it have any other type number?)
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ipc/ipc.h>
+#include <ipc/bd.h>
+#include <async.h>
+#include <as.h>
+#include <fibril_sync.h>
+#include <devmap.h>
+#include <sys/types.h>
+#include <libblock.h>
+#include <devmap.h>
+#include <errno.h>
+#include <bool.h>
+#include <byteorder.h>
+#include <assert.h>
+#include <macros.h>
+#include <task.h>
+
+#define NAME "mbr_part"
+
+enum {
+	/** Number of primary partition records */
+	N_PRIMARY	= 4,
+
+	/** Boot record signature */
+	BR_SIGNATURE	= 0xAA55
+};
+
+enum ptype {
+	/** Unused partition entry */
+	PT_UNUSED	= 0x00,
+	/** Extended partition */
+	PT_EXTENDED	= 0x05,
+};
+
+/** Partition */
+typedef struct part {
+	/** Primary partition entry is in use */
+	bool present;
+	/** Address of first block */
+	bn_t start_addr;
+	/** Number of blocks */
+	bn_t length;
+	/** Device representing the partition (outbound device) */
+	dev_handle_t dev;
+	/** Points to next partition structure. */
+	struct part *next;
+} part_t;
+
+/** Structure of a partition table entry */
+typedef struct {
+	uint8_t status;
+	/** CHS of fist block in partition */
+	uint8_t first_chs[3];
+	/** Partition type */
+	uint8_t ptype;
+	/** CHS of last block in partition */
+	uint8_t last_chs[3];
+	/** LBA of first block in partition */
+	uint32_t first_lba;
+	/** Number of blocks in partition */
+	uint32_t length;
+} __attribute__((packed)) pt_entry_t;
+
+/** Structure of a boot-record block */
+typedef struct {
+	/* Area for boot code */
+	uint8_t code_area[440];
+
+	/* Optional media ID */
+	uint32_t media_id;
+
+	uint16_t pad0;
+
+	/** Partition table entries */
+	pt_entry_t pte[N_PRIMARY];
+
+	/** Boot record block signature (@c BR_SIGNATURE) */
+	uint16_t signature;
+} __attribute__((packed)) br_block_t;
+
+
+static size_t block_size;
+
+/** Partitioned device (inbound device) */
+static dev_handle_t indev_handle;
+
+/** List of partitions. This structure is an empty head. */
+static part_t plist_head;
+
+static int mbr_init(const char *dev_name);
+static int mbr_part_read(void);
+static part_t *mbr_part_new(void);
+static void mbr_pte_to_part(uint32_t base, const pt_entry_t *pte, part_t *part);
+static void mbr_connection(ipc_callid_t iid, ipc_call_t *icall);
+static int mbr_bd_read(part_t *p, uint64_t ba, size_t cnt, void *buf);
+static int mbr_bd_write(part_t *p, uint64_t ba, size_t cnt, const void *buf);
+static int mbr_bsa_translate(part_t *p, uint64_t ba, size_t cnt, uint64_t *gba);
+
+int main(int argc, char **argv)
+{
+	printf(NAME ": PC MBR partition driver\n");
+
+	if (argc != 2) {
+		printf("Expected one argument (device name).\n");
+		return -1;
+	}
+
+	if (mbr_init(argv[1]) != EOK)
+		return -1;
+
+	printf(NAME ": Accepting connections\n");
+	task_retval(0);
+	async_manager();
+
+	/* Not reached */
+	return 0;
+}
+
+static int mbr_init(const char *dev_name)
+{
+	int rc;
+	int i;
+	char *name;
+	dev_handle_t dev;
+	uint64_t size_mb;
+	part_t *part;
+
+	rc = devmap_device_get_handle(dev_name, &indev_handle, 0);
+	if (rc != EOK) {
+		printf(NAME ": could not resolve device `%s'.\n", dev_name);
+		return rc;
+	}
+
+	rc = block_init(indev_handle, 2048);
+	if (rc != EOK)  {
+		printf(NAME ": could not init libblock.\n");
+		return rc;
+	}
+
+	/* Determine and verify block size. */
+
+	rc = block_get_bsize(indev_handle, &block_size);
+	if (rc != EOK) {
+		printf(NAME ": error getting block size.\n");
+		return rc;
+	}
+
+	if (block_size < 512 || (block_size % 512) != 0) {
+		printf(NAME ": invalid block size %d.\n");
+		return ENOTSUP;
+	}
+
+	/* Read in partition records. */
+	rc = mbr_part_read();
+	if (rc != EOK)
+		return rc;
+
+	/* Register the driver with device mapper. */
+	rc = devmap_driver_register(NAME, mbr_connection);
+	if (rc != EOK) {
+		printf(NAME ": Unable to register driver.\n");
+		return rc;
+	}
+
+	/*
+	 * Create partition devices.
+	 */
+	i = 0;
+	part = plist_head.next;
+
+	while (part != NULL) {
+		/* Skip absent partitions. */
+		if (!part->present) {
+			part = part->next;
+			++i;
+			continue;
+		}
+
+		asprintf(&name, "%sp%d", dev_name, i);
+		if (name == NULL)
+			return ENOMEM;
+
+		rc = devmap_device_register(name, &dev);
+		if (rc != EOK) {
+			devmap_hangup_phone(DEVMAP_DRIVER);
+			printf(NAME ": Unable to register device %s.\n", name);
+			return rc;
+		}
+
+		size_mb = (part->length * block_size + 1024 * 1024 - 1)
+		    / (1024 * 1024);
+		printf(NAME ": Registered device %s: %llu blocks %llu MB.\n",
+		    name, part->length, size_mb);
+
+		part->dev = dev;
+		free(name);
+
+		part = part->next;
+		++i;
+	}
+
+	return EOK;
+}
+
+/** Read in partition records. */
+static int mbr_part_read(void)
+{
+	int i, rc;
+	br_block_t *brb;
+	uint16_t sgn;
+	uint32_t ba;
+	part_t *ext_part, cp;
+	uint32_t base;
+	part_t *prev, *p;
+
+	brb = malloc(sizeof(br_block_t));
+	if (brb == NULL) {
+		printf(NAME ": Failed allocating memory.\n");
+		return ENOMEM;	
+	}
+
+	/*
+	 * Read primary partition entries.
+	 */
+
+	rc = block_read_direct(indev_handle, 0, 1, brb);
+	if (rc != EOK) {
+		printf(NAME ": Failed reading MBR block.\n");
+		return rc;
+	}
+
+	sgn = uint16_t_le2host(brb->signature);
+	if (sgn != BR_SIGNATURE) {
+		printf(NAME ": Invalid boot record signature 0x%04X.\n", sgn);
+		return EINVAL;
+	}
+
+	ext_part = NULL;
+	plist_head.next = NULL;
+	prev = &plist_head;
+
+	for (i = 0; i < N_PRIMARY; ++i) {
+		p = mbr_part_new();
+		if (p == NULL)
+			return ENOMEM;
+
+		mbr_pte_to_part(0, &brb->pte[i], p);
+		prev->next = p;
+		prev = p;
+
+		if (brb->pte[i].ptype == PT_EXTENDED) {
+			p->present = false;
+			ext_part = p;
+		}
+	}
+
+	if (ext_part == NULL)
+		return EOK;
+
+	printf("Extended partition found.\n");
+
+	/*
+	 * Read extended partition entries.
+	 */
+
+	cp.start_addr = ext_part->start_addr;
+	cp.length = ext_part->length;
+	base = ext_part->start_addr;
+
+	do {
+		/*
+		 * Addressing in the EBR chain is relative to the beginning
+		 * of the extended partition.
+		 */
+		ba = cp.start_addr;
+		rc = block_read_direct(indev_handle, ba, 1, brb);
+		if (rc != EOK) {
+			printf(NAME ": Failed reading EBR block at %u.\n", ba);
+			return rc;
+		}
+
+		sgn = uint16_t_le2host(brb->signature);
+		if (sgn != BR_SIGNATURE) {
+			printf(NAME ": Invalid boot record signature 0x%04X "
+			    " in EBR at %u.\n", sgn, ba);
+			return EINVAL;
+		}
+
+		p = mbr_part_new();
+		if (p == NULL)
+			return ENOMEM;
+
+		/* First PTE is the logical partition itself. */
+		mbr_pte_to_part(base, &brb->pte[0], p);
+		prev->next = p;
+		prev = p;
+
+		/* Second PTE describes next chain element. */
+		mbr_pte_to_part(base, &brb->pte[1], &cp);
+	} while (cp.present);
+
+	return EOK;
+}
+
+/** Allocate a new @c part_t structure. */
+static part_t *mbr_part_new(void)
+{
+	return malloc(sizeof(part_t));
+}
+
+/** Parse partition table entry. */
+static void mbr_pte_to_part(uint32_t base, const pt_entry_t *pte, part_t *part)
+{
+	uint32_t sa, len;
+
+	sa = uint32_t_le2host(pte->first_lba);
+	len = uint32_t_le2host(pte->length);
+
+	part->start_addr = base + sa;
+	part->length     = len;
+
+	part->present = (pte->ptype != PT_UNUSED) ? true : false;
+
+	part->dev = 0;
+	part->next = NULL;
+}
+
+static void mbr_connection(ipc_callid_t iid, ipc_call_t *icall)
+{
+	size_t comm_size;
+	void *fs_va = NULL;
+	ipc_callid_t callid;
+	ipc_call_t call;
+	ipcarg_t method;
+	dev_handle_t dh;
+	int flags;
+	int retval;
+	uint64_t ba;
+	size_t cnt;
+	part_t *part;
+
+	/* Get the device handle. */
+	dh = IPC_GET_ARG1(*icall);
+
+	/* 
+	 * Determine which partition device is the client connecting to.
+	 * A linear search is not terribly fast, but we only do this
+	 * once for each connection.
+	 */
+	part = plist_head.next;
+	while (part != NULL && part->dev != dh)
+		part = part->next;
+
+	if (part == NULL) {
+		ipc_answer_0(iid, EINVAL);
+		return;
+	}
+
+	assert(part->present == true);
+
+	/* Answer the IPC_M_CONNECT_ME_TO call. */
+	ipc_answer_0(iid, EOK);
+
+	if (!async_share_out_receive(&callid, &comm_size, &flags)) {
+		ipc_answer_0(callid, EHANGUP);
+		return;
+	}
+
+	fs_va = as_get_mappable_page(comm_size);
+	if (fs_va == NULL) {
+		ipc_answer_0(callid, EHANGUP);
+		return;
+	}
+
+	(void) async_share_out_finalize(callid, fs_va);
+
+	while (1) {
+		callid = async_get_call(&call);
+		method = IPC_GET_METHOD(call);
+		switch (method) {
+		case IPC_M_PHONE_HUNGUP:
+			/* The other side has hung up. */
+			ipc_answer_0(callid, EOK);
+			return;
+		case BD_READ_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = mbr_bd_read(part, ba, cnt, fs_va);
+			break;
+		case BD_WRITE_BLOCKS:
+			ba = MERGE_LOUP32(IPC_GET_ARG1(call),
+			    IPC_GET_ARG2(call));
+			cnt = IPC_GET_ARG3(call);
+			if (cnt * block_size > comm_size) {
+				retval = ELIMIT;
+				break;
+			}
+			retval = mbr_bd_write(part, ba, cnt, fs_va);
+			break;
+		case BD_GET_BLOCK_SIZE:
+			ipc_answer_1(callid, EOK, block_size);
+			continue;
+
+		default:
+			retval = EINVAL;
+			break;
+		}
+		ipc_answer_0(callid, retval);
+	}
+}
+
+/** Read blocks from partition. */
+static int mbr_bd_read(part_t *p, uint64_t ba, size_t cnt, void *buf)
+{
+	uint64_t gba;
+
+	if (mbr_bsa_translate(p, ba, cnt, &gba) != EOK)
+		return ELIMIT;
+
+	return block_read_direct(indev_handle, gba, cnt, buf);
+}
+
+/** Write blocks to partition. */
+static int mbr_bd_write(part_t *p, uint64_t ba, size_t cnt, const void *buf)
+{
+	uint64_t gba;
+
+	if (mbr_bsa_translate(p, ba, cnt, &gba) != EOK)
+		return ELIMIT;
+
+	return block_write_direct(indev_handle, gba, cnt, buf);
+}
+
+/** Translate block segment address with range checking. */
+static int mbr_bsa_translate(part_t *p, uint64_t ba, size_t cnt, uint64_t *gba)
+{
+	if (ba + cnt > p->length)
+		return ELIMIT;
+
+	*gba = p->start_addr + ba;
+	return EOK;
+}
+
+/**
+ * @}
+ */
Index: uspace/srv/pci/Makefile
===================================================================
--- uspace/srv/pci/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/pci/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -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.
+#
+
+include Makefile.common
+
+.PHONY: all clean
+
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
+
+$(LIBPCI):
+	$(MAKE) -C libpci
+
+clean:
+	$(MAKE) -C libpci clean
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/pci/Makefile.build
===================================================================
--- uspace/srv/pci/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/pci/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	pci.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/pci/Makefile.common
===================================================================
--- uspace/srv/pci/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/pci/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBPCI = libpci/libpci.a
+LIBS = $(LIBPCI) $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = pci
Index: uspace/srv/pci/libpci/Makefile
===================================================================
--- uspace/srv/pci/libpci/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/pci/libpci/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+include Makefile.common
+
+.PHONY: all clean
+
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBC_PREFIX)/libc.a
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
+
+clean:
+	rm -f $(DEPEND) $(DEPEND_PREV) $(LIBPCI)
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/pci/libpci/Makefile.build
===================================================================
--- uspace/srv/pci/libpci/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/pci/libpci/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,61 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	access.c \
+	generic.c \
+	names.c \
+	i386-ports.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(LIBPCI)
+
+-include $(DEPEND)
+
+$(LIBPCI): $(OBJECTS)
+	$(AR) rc $@ $(OBJECTS)
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/pci/libpci/Makefile.common
===================================================================
--- uspace/srv/pci/libpci/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/pci/libpci/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../../lib/libc
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+LIBPCI = libpci.a
Index: uspace/srv/vfs/Makefile
===================================================================
--- uspace/srv/vfs/Makefile	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/vfs/Makefile	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2006 Martin Decky
-# Copyright (c) 2008 Jakub Jermar
+# Copyright (c) 2005 Martin Decky
+# Copyright (c) 2007 Jakub Jermar
 # All rights reserved.
 #
@@ -28,54 +28,13 @@
 #
 
-## Setup toolchain
-#
+include Makefile.common
 
-LIBC_PREFIX = ../../lib/libc
-SOFTINT_PREFIX = ../../lib/softint
+.PHONY: all clean
 
-include $(LIBC_PREFIX)/Makefile.toolchain
-
-LIBS = $(LIBC_PREFIX)/libc.a
-
-## Sources
-#
-
-OUTPUT = vfs
-SOURCES = \
-	vfs.c \
-	vfs_node.c \
-	vfs_file.c \
-	vfs_ops.c \
-	vfs_lookup.c \
-	vfs_register.c
-
-OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
-
-.PHONY: all clean depend disasm
-
-all: $(OUTPUT) $(OUTPUT).disasm
-
--include Makefile.depend
+all: $(LIBC_PREFIX)/../../../Makefile.config $(LIBC_PREFIX)/../../../config.h $(LIBC_PREFIX)/../../../config.defs $(LIBS)
+	-[ -f $(DEPEND) ] && mv -f $(DEPEND) $(DEPEND_PREV)
+	$(MAKE) -f Makefile.build
 
 clean:
-	-rm -f $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm Makefile.depend $(OBJECTS)
-
-depend:
-	$(CC) $(DEFS) $(CFLAGS) -M $(SOURCES) > Makefile.depend
-
-$(OUTPUT): $(OBJECTS) $(LIBS)
-	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
-
-disasm: $(OUTPUT).disasm
-
-$(OUTPUT).disasm: $(OUTPUT)
-	$(OBJDUMP) -d $< > $@
-
-%.o: %.S
-	$(CC) $(DEFS) $(AFLAGS) $(CFLAGS) -D__ASM__ -c $< -o $@
-
-%.o: %.s
-	$(AS) $(AFLAGS) $< -o $@
-
-%.o: %.c
-	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+	rm -f $(DEPEND) $(DEPEND_PREV) $(OUTPUT) $(OUTPUT).map $(OUTPUT).disasm
+	find . -name '*.o' -follow -exec rm \{\} \;
Index: uspace/srv/vfs/Makefile.build
===================================================================
--- uspace/srv/vfs/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/vfs/Makefile.build	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,66 @@
+#
+# 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.
+#
+
+## Setup toolchain
+#
+
+include Makefile.common
+include $(LIBC_PREFIX)/Makefile.toolchain
+
+## Sources
+#
+
+SOURCES = \
+	vfs.c \
+	vfs_node.c \
+	vfs_file.c \
+	vfs_ops.c \
+	vfs_lookup.c \
+	vfs_register.c
+
+OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
+
+.PHONY: all
+
+all: $(OUTPUT) $(OUTPUT).disasm
+
+-include $(DEPEND)
+
+$(OUTPUT).disasm: $(OUTPUT)
+	$(OBJDUMP) -d $< > $@
+
+$(OUTPUT): $(OBJECTS) $(LIBS)
+	$(LD) -T $(LIBC_PREFIX)/arch/$(UARCH)/_link.ld $(OBJECTS) $(LIBS) $(LFLAGS) -o $@ -Map $(OUTPUT).map
+
+%.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) -c $< -o $@
+
+$(DEPEND):
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
Index: uspace/srv/vfs/Makefile.common
===================================================================
--- uspace/srv/vfs/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
+++ uspace/srv/vfs/Makefile.common	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -0,0 +1,39 @@
+#
+# Copyright (c) 2005 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.
+#
+
+
+## Common names
+#
+
+LIBC_PREFIX = ../../lib/libc
+SOFTINT_PREFIX = ../../lib/softint
+LIBS = $(LIBC_PREFIX)/libc.a
+
+DEPEND = Makefile.depend
+DEPEND_PREV = $(DEPEND).prev
+OUTPUT = vfs
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/vfs/vfs.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -126,4 +126,6 @@
 			vfs_sync(callid, &call);
 			break;
+		case VFS_IN_DUP:
+			vfs_dup(callid, &call);
 		default:
 			ipc_answer_0(callid, ENOTSUP);
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/vfs/vfs.h	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -186,5 +186,6 @@
 extern bool vfs_files_init(void);
 extern vfs_file_t *vfs_file_get(int);
-extern int vfs_fd_alloc(void);
+extern int vfs_fd_assign(vfs_file_t *file, int fd);
+extern int vfs_fd_alloc(bool desc);
 extern int vfs_fd_free(int);
 
@@ -200,4 +201,5 @@
 extern void vfs_open_node(ipc_callid_t, ipc_call_t *);
 extern void vfs_sync(ipc_callid_t, ipc_call_t *);
+extern void vfs_dup(ipc_callid_t, ipc_call_t *);
 extern void vfs_close(ipc_callid_t, ipc_call_t *);
 extern void vfs_read(ipc_callid_t, ipc_call_t *);
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/vfs/vfs_file.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -76,8 +76,11 @@
 /** Allocate a file descriptor.
  *
- * @return		First available file descriptor or a negative error
- *			code.
- */
-int vfs_fd_alloc(void)
+ * @param desc If true, look for an available file descriptor
+ *             in a descending order.
+ *
+ * @return First available file descriptor or a negative error
+ *         code.
+ */
+int vfs_fd_alloc(bool desc)
 {
 	if (!vfs_files_init())
@@ -85,5 +88,10 @@
 	
 	unsigned int i;
-	for (i = 0; i < MAX_OPEN_FILES; i++) {
+	if (desc)
+		i = MAX_OPEN_FILES - 1;
+	else
+		i = 0;
+	
+	while (true) {
 		if (!files[i]) {
 			files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
@@ -96,4 +104,16 @@
 			return (int) i;
 		}
+		
+		if (desc) {
+			if (i == 0)
+				break;
+			
+			i--;
+		} else {
+			if (i == MAX_OPEN_FILES - 1)
+				break;
+			
+			i++;
+		}
 	}
 	
@@ -118,4 +138,27 @@
 	vfs_file_delref(files[fd]);
 	files[fd] = NULL;
+	
+	return EOK;
+}
+
+/** Assign a file to a file descriptor.
+ *
+ * @param file File to assign.
+ * @param fd   File descriptor to assign to.
+ *
+ * @return EOK on success or EINVAL if fd is an invalid or already
+ *         used file descriptor.
+ *
+ */
+int vfs_fd_assign(vfs_file_t *file, int fd)
+{
+	if (!vfs_files_init())
+		return ENOMEM;
+	
+	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (files[fd] != NULL))
+		return EINVAL;
+	
+	files[fd] = file;
+	vfs_file_addref(files[fd]);
 	
 	return EOK;
Index: uspace/srv/vfs/vfs_lookup.c
===================================================================
--- uspace/srv/vfs/vfs_lookup.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/vfs/vfs_lookup.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -209,5 +209,4 @@
 	    (ipcarg_t) result->triplet.index, &answer);
 	
-	
 	ipcarg_t rc;
 	async_wait_for(req, &rc);
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/vfs/vfs_ops.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -125,5 +125,5 @@
 			    (ipcarg_t) dev_handle, &answer);
 			/* send the mount options */
-			rc = ipc_data_write_start(phone, (void *)opts,
+			rc = async_data_write_start(phone, (void *)opts,
 			    str_size(opts));
 			if (rc != EOK) {
@@ -207,5 +207,5 @@
 	
 	/* send the mount options */
-	rc = ipc_data_write_start(phone, (void *)opts, str_size(opts));
+	rc = async_data_write_start(phone, (void *)opts, str_size(opts));
 	if (rc != EOK) {
 		async_wait_for(msg, NULL);
@@ -268,5 +268,5 @@
 	ipc_callid_t callid;
 	size_t size;
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -290,5 +290,5 @@
 	
 	/* Deliver the mount point. */
-	ipcarg_t retval = ipc_data_write_finalize(callid, mp, size);
+	ipcarg_t retval = async_data_write_finalize(callid, mp, size);
 	if (retval != EOK) {
 		ipc_answer_0(rid, retval);
@@ -299,5 +299,5 @@
 	
 	/* Now we expect to receive the mount options. */
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -324,5 +324,5 @@
 
 	/* Deliver the mount options. */
-	retval = ipc_data_write_finalize(callid, opts, size);
+	retval = async_data_write_finalize(callid, opts, size);
 	if (retval != EOK) {
 		ipc_answer_0(rid, retval);
@@ -337,5 +337,5 @@
 	 * system.
 	 */
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -370,5 +370,5 @@
 	
 	/* Deliver the file system name. */
-	retval = ipc_data_write_finalize(callid, fs_name, size);
+	retval = async_data_write_finalize(callid, fs_name, size);
 	if (retval != EOK) {
 		ipc_answer_0(rid, retval);
@@ -469,5 +469,5 @@
 	
 	ipc_callid_t callid;
-	if (!ipc_data_write_receive(&callid, &len)) {
+	if (!async_data_write_receive(&callid, &len)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -483,5 +483,5 @@
 	
 	int rc;
-	if ((rc = ipc_data_write_finalize(callid, path, len))) {
+	if ((rc = async_data_write_finalize(callid, path, len))) {
 		ipc_answer_0(rid, rc);
 		free(path);
@@ -543,5 +543,5 @@
 	 * structure.
 	 */
-	int fd = vfs_fd_alloc();
+	int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
 	if (fd < 0) {
 		vfs_node_put(node);
@@ -620,5 +620,5 @@
 	 * structure.
 	 */
-	int fd = vfs_fd_alloc();
+	int fd = vfs_fd_alloc((oflag & O_DESC) != 0);
 	if (fd < 0) {
 		vfs_node_put(node);
@@ -679,4 +679,39 @@
 }
 
+static int vfs_close_internal(vfs_file_t *file)
+{
+	/*
+	 * Lock the open file structure so that no other thread can manipulate
+	 * the same open file at a time.
+	 */
+	fibril_mutex_lock(&file->lock);
+	
+	if (file->refcnt <= 1) {
+		/* Only close the file on the destination FS server
+		   if there are no more file descriptors (except the
+		   present one) pointing to this file. */
+		
+		int fs_phone = vfs_grab_phone(file->node->fs_handle);
+		
+		/* Make a VFS_OUT_CLOSE request at the destination FS server. */
+		aid_t msg;
+		ipc_call_t answer;
+		msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle,
+		    file->node->index, &answer);
+		
+		/* Wait for reply from the FS server. */
+		ipcarg_t rc;
+		async_wait_for(msg, &rc);
+		
+		vfs_release_phone(fs_phone);
+		fibril_mutex_unlock(&file->lock);
+		
+		return IPC_GET_ARG1(answer);
+	}
+	
+	fibril_mutex_unlock(&file->lock);
+	return EOK;
+}
+
 void vfs_close(ipc_callid_t rid, ipc_call_t *request)
 {
@@ -690,30 +725,10 @@
 	}
 	
-	/*
-	 * Lock the open file structure so that no other thread can manipulate
-	 * the same open file at a time.
-	 */
-	fibril_mutex_lock(&file->lock);
-	int fs_phone = vfs_grab_phone(file->node->fs_handle);
-	
-	/* Make a VFS_OUT_CLOSE request at the destination FS server. */
-	aid_t msg;
-	ipc_call_t answer;
-	msg = async_send_2(fs_phone, VFS_OUT_CLOSE, file->node->dev_handle,
-	    file->node->index, &answer);
-
-	/* Wait for reply from the FS server. */
-	ipcarg_t rc;
-	async_wait_for(msg, &rc);
-
-	vfs_release_phone(fs_phone);
-	fibril_mutex_unlock(&file->lock);
-	
-	int retval = IPC_GET_ARG1(answer);
-	if (retval != EOK)
-		ipc_answer_0(rid, retval);
-	
-	retval = vfs_fd_free(fd);
-	ipc_answer_0(rid, retval);
+	int ret = vfs_close_internal(file);
+	if (ret != EOK)
+		ipc_answer_0(rid, ret);
+	
+	ret = vfs_fd_free(fd);
+	ipc_answer_0(rid, ret);
 }
 
@@ -747,7 +762,7 @@
 	int res;
 	if (read)
-		res = ipc_data_read_receive(&callid, NULL);
+		res = async_data_read_receive(&callid, NULL);
 	else 
-		res = ipc_data_write_receive(&callid, NULL);
+		res = async_data_write_receive(&callid, NULL);
 	if (!res) {
 		ipc_answer_0(callid, EINVAL);
@@ -934,5 +949,4 @@
 {
 	int fd = IPC_GET_ARG1(*request);
-	size_t size = IPC_GET_ARG2(*request);
 	ipcarg_t rc;
 
@@ -944,5 +958,5 @@
 
 	ipc_callid_t callid;
-	if (!ipc_data_read_receive(&callid, NULL)) {
+	if (!async_data_read_receive(&callid, NULL)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -970,5 +984,5 @@
 	ipc_callid_t callid;
 
-	if (!ipc_data_write_receive(&callid, &len)) {
+	if (!async_data_write_receive(&callid, &len)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -982,5 +996,5 @@
 	}
 	int rc;
-	if ((rc = ipc_data_write_finalize(callid, path, len))) {
+	if ((rc = async_data_write_finalize(callid, path, len))) {
 		ipc_answer_0(rid, rc);
 		free(path);
@@ -989,5 +1003,5 @@
 	path[len] = '\0';
 
-	if (!ipc_data_read_receive(&callid, NULL)) {
+	if (!async_data_read_receive(&callid, NULL)) {
 		free(path);
 		ipc_answer_0(callid, EINVAL);
@@ -1038,5 +1052,5 @@
 	ipc_callid_t callid;
 
-	if (!ipc_data_write_receive(&callid, &len)) {
+	if (!async_data_write_receive(&callid, &len)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -1050,5 +1064,5 @@
 	}
 	int rc;
-	if ((rc = ipc_data_write_finalize(callid, path, len))) {
+	if ((rc = async_data_write_finalize(callid, path, len))) {
 		ipc_answer_0(rid, rc);
 		free(path);
@@ -1075,5 +1089,5 @@
 	ipc_callid_t callid;
 
-	if (!ipc_data_write_receive(&callid, &len)) {
+	if (!async_data_write_receive(&callid, &len)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -1087,5 +1101,5 @@
 	}
 	int rc;
-	if ((rc = ipc_data_write_finalize(callid, path, len))) {
+	if ((rc = async_data_write_finalize(callid, path, len))) {
 		ipc_answer_0(rid, rc);
 		free(path);
@@ -1126,5 +1140,5 @@
 
 	/* Retrieve the old path. */
-	if (!ipc_data_write_receive(&callid, &olen)) {
+	if (!async_data_write_receive(&callid, &olen)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -1137,5 +1151,5 @@
 		return;
 	}
-	if ((rc = ipc_data_write_finalize(callid, old, olen))) {
+	if ((rc = async_data_write_finalize(callid, old, olen))) {
 		ipc_answer_0(rid, rc);
 		free(old);
@@ -1145,5 +1159,5 @@
 	
 	/* Retrieve the new path. */
-	if (!ipc_data_write_receive(&callid, &nlen)) {
+	if (!async_data_write_receive(&callid, &nlen)) {
 		ipc_answer_0(callid, EINVAL);
 		ipc_answer_0(rid, EINVAL);
@@ -1158,5 +1172,5 @@
 		return;
 	}
-	if ((rc = ipc_data_write_finalize(callid, new, nlen))) {
+	if ((rc = async_data_write_finalize(callid, new, nlen))) {
 		ipc_answer_0(rid, rc);
 		free(old);
@@ -1311,4 +1325,55 @@
 }
 
+void vfs_dup(ipc_callid_t rid, ipc_call_t *request)
+{
+	int oldfd = IPC_GET_ARG1(*request);
+	int newfd = IPC_GET_ARG2(*request);
+	
+	/* Lookup the file structure corresponding to oldfd. */
+	vfs_file_t *oldfile = vfs_file_get(oldfd);
+	if (!oldfile) {
+		ipc_answer_0(rid, EBADF);
+		return;
+	}
+	
+	/* If the file descriptors are the same, do nothing. */
+	if (oldfd == newfd) {
+		ipc_answer_1(rid, EOK, newfd);
+		return;
+	}
+	
+	/*
+	 * Lock the open file structure so that no other thread can manipulate
+	 * the same open file at a time.
+	 */
+	fibril_mutex_lock(&oldfile->lock);
+	
+	/* Lookup an open file structure possibly corresponding to newfd. */
+	vfs_file_t *newfile = vfs_file_get(newfd);
+	if (newfile) {
+		/* Close the originally opened file. */
+		int ret = vfs_close_internal(newfile);
+		if (ret != EOK) {
+			ipc_answer_0(rid, ret);
+			return;
+		}
+		
+		ret = vfs_fd_free(newfd);
+		if (ret != EOK) {
+			ipc_answer_0(rid, ret);
+			return;
+		}
+	}
+	
+	/* Assign the old file to newfd. */
+	int ret = vfs_fd_assign(oldfile, newfd);
+	fibril_mutex_unlock(&oldfile->lock);
+	
+	if (ret != EOK)
+		ipc_answer_0(rid, ret);
+	else
+		ipc_answer_1(rid, EOK, newfd);
+}
+
 /**
  * @}
Index: uspace/srv/vfs/vfs_register.c
===================================================================
--- uspace/srv/vfs/vfs_register.c	(revision fcbd1be0f221add9330a1d6c130818a501791166)
+++ uspace/srv/vfs/vfs_register.c	(revision 1787e527c803ec9bf678df8b19b0de9e18985f12)
@@ -122,5 +122,5 @@
 	 * VFS info structure from the client FS.
 	 */
-	if (!ipc_data_write_receive(&callid, &size)) {
+	if (!async_data_write_receive(&callid, &size)) {
 		/*
 		 * The client doesn't obey the same protocol as we do.
@@ -163,5 +163,5 @@
 	fibril_mutex_initialize(&fs_info->phone_lock);
 		
-	rc = ipc_data_write_finalize(callid, &fs_info->vfs_info, size);
+	rc = async_data_write_finalize(callid, &fs_info->vfs_info, size);
 	if (rc != EOK) {
 		dprintf("Failed to deliver the VFS info into our AS, rc=%d.\n",
@@ -229,5 +229,5 @@
 	 */
 
-	if (!ipc_share_in_receive(&callid, &size)) {
+	if (!async_share_in_receive(&callid, &size)) {
 		dprintf("Unexpected call, method = %d\n", IPC_GET_METHOD(call));
 		list_remove(&fs_info->fs_link);
@@ -257,5 +257,5 @@
 	 * Commit to read-only sharing the PLB with the client.
 	 */
-	(void) ipc_share_in_finalize(callid, plb,
+	(void) async_share_in_finalize(callid, plb,
 	    AS_AREA_READ | AS_AREA_CACHEABLE);
 
