Index: uspace/lib/c/generic/loader.c
===================================================================
--- uspace/lib/c/generic/loader.c	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/lib/c/generic/loader.c	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -271,6 +271,5 @@
 	
 	for (i = 0; files[i]; i++) {
-		rc = async_state_change_start(exch, VFS_PASS_HANDLE, *files[i],
-		    0, vfs_exch); 
+		rc = vfs_pass_handle(vfs_exch, *files[i], exch);
 		if (rc != EOK)
 			break;
Index: uspace/lib/c/generic/vfs/vfs.c
===================================================================
--- uspace/lib/c/generic/vfs/vfs.c	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/lib/c/generic/vfs/vfs.c	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -419,18 +419,12 @@
 	req = async_send_1(exch, VFS_IN_READ, fildes, &answer);
 	rc = async_data_read_start(exch, (void *) buf, nbyte);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		
-		sysarg_t rc_orig;
-		async_wait_for(req, &rc_orig);
-		
-		if (rc_orig == EOK)
-			return rc;
-		else
-			return rc_orig;
-	}
-	
-	vfs_exchange_end(exch);
-	async_wait_for(req, &rc);
+
+	vfs_exchange_end(exch);
+	
+	if (rc == EOK) {
+		async_wait_for(req, &rc);
+	} else {
+		async_forget(req);
+	}
 	
 	if (rc != EOK)
@@ -467,19 +461,13 @@
 	req = async_send_1(exch, VFS_IN_WRITE, fildes, &answer);
 	rc = async_data_write_start(exch, (void *) buf, nbyte);
-	if (rc != EOK) {
-		vfs_exchange_end(exch);
-		
-		sysarg_t rc_orig;
-		async_wait_for(req, &rc_orig);
-		
-		if (rc_orig == EOK)
-			return rc;
-		else
-			return rc_orig;
-	}
-	
-	vfs_exchange_end(exch);
-	async_wait_for(req, &rc);
-	
+	
+	vfs_exchange_end(exch);
+	
+	if (rc == EOK) {
+		async_wait_for(req, &rc);
+	} else {
+		async_forget(req);
+	}
+
 	if (rc != EOK)
 		return rc;
@@ -1055,19 +1043,4 @@
 }
 
-int vfs_fd_wait(void)
-{
-	async_exch_t *exch = vfs_exchange_begin();
-	
-	sysarg_t ret;
-	sysarg_t rc = async_req_0_1(exch, VFS_IN_WAIT_HANDLE, &ret);
-	
-	vfs_exchange_end(exch);
-	
-	if (rc == EOK)
-		return (int) ret;
-	
-	return (int) rc;
-}
-
 int vfs_get_mtab_list(list_t *mtab_list)
 {
@@ -1172,4 +1145,40 @@
 }
 
+int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch)
+{
+	return async_state_change_start(exch, VFS_PASS_HANDLE, (sysarg_t)file, 0, vfs_exch);
+}
+
+int vfs_receive_handle()
+{
+	ipc_callid_t callid;
+	if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
+		async_answer_0(callid, EINVAL);
+		return EINVAL;
+	}
+
+	async_exch_t *vfs_exch = vfs_exchange_begin();
+
+	async_state_change_finalize(callid, vfs_exch);
+
+	sysarg_t ret;
+	sysarg_t rc = async_req_0_1(vfs_exch, VFS_IN_WAIT_HANDLE, &ret);
+
+	async_exchange_end(vfs_exch);
+
+	if (rc != EOK) {
+		return rc;
+	}
+	return ret;
+}
+
+int vfs_clone(int file, bool high_descriptor)
+{
+	async_exch_t *vfs_exch = vfs_exchange_begin();
+	int rc = async_req_2_0(vfs_exch, VFS_IN_CLONE, (sysarg_t) file, (sysarg_t) high_descriptor);
+	vfs_exchange_end(vfs_exch);
+	return rc;
+}
+
 /** @}
  */
Index: uspace/lib/c/include/ipc/vfs.h
===================================================================
--- uspace/lib/c/include/ipc/vfs.h	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/lib/c/include/ipc/vfs.h	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -83,4 +83,5 @@
 	VFS_IN_OPEN2,
 	VFS_IN_UNLINK2,
+	VFS_IN_CLONE,
 } vfs_in_request_t;
 
Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -58,5 +58,4 @@
 extern int vfs_fhandle(FILE *, int *);
 
-extern int vfs_fd_wait(void);
 extern int vfs_get_mtab_list(list_t *mtab_list);
 
@@ -67,4 +66,10 @@
 extern int _vfs_open(int file, int mode);
 
+extern int vfs_pass_handle(async_exch_t *vfs_exch, int file, async_exch_t *exch);
+extern int vfs_receive_handle(void);
+
+extern int vfs_clone(int file, bool high_descriptor);
+
+
 #endif
 
Index: uspace/srv/loader/main.c
===================================================================
--- uspace/srv/loader/main.c	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/srv/loader/main.c	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -227,13 +227,8 @@
 
 	for (filc = 0; filc < count; filc++) {
-		ipc_callid_t callid;
-		int fd;
-
-		if (!async_state_change_receive(&callid, NULL, NULL, NULL)) {
-			async_answer_0(callid, EINVAL);
+		int fd = vfs_receive_handle();
+		if (fd < 0) {
 			break;
 		}
-		async_state_change_finalize(callid, vfs_exch);
-		fd = vfs_fd_wait();
 		assert(fd == (int) filc);
 	}
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/srv/vfs/vfs.c	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -149,4 +149,7 @@
 			vfs_statfs(callid, &call);
 			break;
+		case VFS_IN_CLONE:
+			vfs_op_clone(callid, &call);
+			break;
 		default:
 			async_answer_0(callid, ENOTSUP);
@@ -164,5 +167,5 @@
 {
 	if (IPC_GET_ARG1(*call) == VFS_PASS_HANDLE)
-		vfs_pass_handle(
+		vfs_op_pass_handle(
 		    (task_id_t) MERGE_LOUP32(IPC_GET_ARG4(*call),
 		    IPC_GET_ARG5(*call)), call->in_task_id,
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/srv/vfs/vfs.h	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -196,5 +196,5 @@
 extern void vfs_client_data_destroy(void *);
 
-extern void vfs_pass_handle(task_id_t, task_id_t, int);
+extern void vfs_op_pass_handle(task_id_t, task_id_t, int);
 extern int vfs_wait_handle_internal(void);
 
@@ -237,4 +237,5 @@
 extern void vfs_open2(ipc_callid_t, ipc_call_t *);
 extern void vfs_unlink2(ipc_callid_t, ipc_call_t *);
+extern void vfs_op_clone(ipc_callid_t, ipc_call_t *);
 
 #endif
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/srv/vfs/vfs_file.c	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -360,5 +360,5 @@
 }
 
-void vfs_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
+void vfs_op_pass_handle(task_id_t donor_id, task_id_t acceptor_id, int donor_fd)
 {
 	vfs_client_data_t *donor_data = NULL;
@@ -397,5 +397,4 @@
 	 */
 	vfs_node_addref(donor_file->node);
-	(void) vfs_open_node_remote(donor_file->node);
 
 	assert(acceptor_file);
@@ -412,4 +411,8 @@
 	acceptor_file->open_read = donor_file->open_read;
 	acceptor_file->open_write = donor_file->open_write;
+
+	if (acceptor_file->open_read || acceptor_file->open_write) {
+		(void) vfs_open_node_remote(acceptor_file->node);
+	}
 
 out:
Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision c577a9a0f9567ece9535f388111534237421f139)
+++ uspace/srv/vfs/vfs_ops.c	(revision 354b642cd1acfdf8efcc67d153164d8bcae75215)
@@ -696,5 +696,5 @@
 	vfs_file_t *file = vfs_file_get(fd);
 	if (!file)
-		return ENOENT;
+		return EBADF;
 	
 	if ((read && !file->open_read) || (!read && !file->open_write)) {
@@ -705,4 +705,6 @@
 	vfs_info_t *fs_info = fs_handle_to_info(file->node->fs_handle);
 	assert(fs_info);
+	
+	bool rlock = read || ((fs_info->concurrent_read_write) && (fs_info->write_retains_size));
 	
 	/*
@@ -711,9 +713,9 @@
 	 * write implementation does not modify the file size.
 	 */
-	if ((read) ||
-	    ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
+	if (rlock) {
 		fibril_rwlock_read_lock(&file->node->contents_rwlock);
-	else
+	} else {
 		fibril_rwlock_write_lock(&file->node->contents_rwlock);
+	}
 	
 	if (file->node->type == VFS_NODE_DIRECTORY) {
@@ -722,5 +724,15 @@
 		 * while we are in readdir().
 		 */
-		assert(read);
+		
+		if (!read) {
+			if (rlock) {
+				fibril_rwlock_read_unlock(&file->node->contents_rwlock);
+			} else {
+				fibril_rwlock_write_unlock(&file->node->contents_rwlock);
+			}
+			vfs_file_put(file);
+			return EINVAL;
+		}
+		
 		fibril_rwlock_read_lock(&namespace_rwlock);
 	}
@@ -746,18 +758,19 @@
 	
 	/* Unlock the VFS node. */
-	if ((read) ||
-	    ((fs_info->concurrent_read_write) && (fs_info->write_retains_size)))
+	if (rlock) {
 		fibril_rwlock_read_unlock(&file->node->contents_rwlock);
-	else {
+	} else {
 		/* Update the cached version of node's size. */
-		if (rc == EOK)
+		if (rc == EOK) {
 			file->node->size = MERGE_LOUP32(IPC_GET_ARG2(answer),
 			    IPC_GET_ARG3(answer));
+		}
 		fibril_rwlock_write_unlock(&file->node->contents_rwlock);
 	}
 	
 	/* Update the position pointer and unlock the open file. */
-	if (rc == EOK)
+	if (rc == EOK) {
 		file->pos += bytes;
+	}
 	vfs_file_put(file);	
 
@@ -1354,4 +1367,35 @@
 }
 
+void vfs_op_clone(ipc_callid_t rid, ipc_call_t *request)
+{
+	int oldfd = IPC_GET_ARG1(*request);
+	bool desc = IPC_GET_ARG2(*request);
+	
+	/* Lookup the file structure corresponding to fd. */
+	vfs_file_t *oldfile = vfs_file_get(oldfd);
+	if (!oldfile) {
+		async_answer_0(rid, EBADF);
+		return;
+	}
+	
+	vfs_file_t *newfile;
+	int newfd = vfs_fd_alloc(&newfile, desc);
+	if (newfd < 0) {
+		async_answer_0(rid, newfd);
+		vfs_file_put(oldfile);
+		return;
+	}
+	
+	assert(oldfile->node != NULL);
+	
+	newfile->node = oldfile->node;
+	newfile->permissions = oldfile->permissions;
+
+	vfs_file_put(oldfile);
+	vfs_file_put(newfile);
+	
+	async_answer_0(rid, newfd);
+}
+
 /**
  * @}
