Index: uspace/lib/c/include/vfs/vfs.h
===================================================================
--- uspace/lib/c/include/vfs/vfs.h	(revision 455f190e4b0862368809250e0ad9bfb7504cfe9a)
+++ uspace/lib/c/include/vfs/vfs.h	(revision 2bc13887b01d3564a8c108afbefac57d08de3845)
@@ -41,4 +41,8 @@
 #include <stdio.h>
 
+enum vfs_change_state_type {
+	VFS_PASS_HANDLE
+};
+
 /** Libc version of the VFS triplet.
  *
Index: uspace/srv/vfs/vfs.c
===================================================================
--- uspace/srv/vfs/vfs.c	(revision 455f190e4b0862368809250e0ad9bfb7504cfe9a)
+++ uspace/srv/vfs/vfs.c	(revision 2bc13887b01d3564a8c108afbefac57d08de3845)
@@ -37,4 +37,6 @@
 
 #include <ipc/services.h>
+#include <abi/ipc/event.h>
+#include <event.h>
 #include <ns.h>
 #include <async.h>
@@ -130,4 +132,21 @@
 }
 
+enum {
+	VFS_TASK_STATE_CHANGE
+};
+
+static void notification_received(ipc_callid_t callid, ipc_call_t *call)
+{
+	switch (IPC_GET_IMETHOD(*call)) {
+	case VFS_TASK_STATE_CHANGE:
+		if (IPC_GET_ARG1(*call) == VFS_PASS_HANDLE)
+			vfs_pass_handle(IPC_GET_ARG4(*call),
+			    IPC_GET_ARG5(*call), (int) IPC_GET_ARG2(*call));
+		break;
+	default:
+		break;
+	}
+}
+
 int main(int argc, char **argv)
 {
@@ -170,4 +189,10 @@
 
 	/*
+	 * Set notification handler and subscribe to notifications.
+	 */
+	async_set_interrupt_received(notification_received);
+	event_task_subscribe(EVENT_TASK_STATE_CHANGE, VFS_TASK_STATE_CHANGE);
+
+	/*
 	 * Register at the naming service.
 	 */
Index: uspace/srv/vfs/vfs.h
===================================================================
--- uspace/srv/vfs/vfs.h	(revision 455f190e4b0862368809250e0ad9bfb7504cfe9a)
+++ uspace/srv/vfs/vfs.h	(revision 2bc13887b01d3564a8c108afbefac57d08de3845)
@@ -188,4 +188,6 @@
 extern void *vfs_client_data_create(void);
 extern void vfs_client_data_destroy(void *);
+
+extern void vfs_pass_handle(sysarg_t, sysarg_t, int);
 
 extern vfs_file_t *vfs_file_get(int);
Index: uspace/srv/vfs/vfs_file.c
===================================================================
--- uspace/srv/vfs/vfs_file.c	(revision 455f190e4b0862368809250e0ad9bfb7504cfe9a)
+++ uspace/srv/vfs/vfs_file.c	(revision 2bc13887b01d3564a8c108afbefac57d08de3845)
@@ -53,35 +53,36 @@
 } vfs_client_data_t;
 
+static int _vfs_fd_free(vfs_client_data_t *, int);
+
 /** Initialize the table of open files. */
-static bool vfs_files_init(void)
-{
-	fibril_mutex_lock(&VFS_DATA->lock);
-	if (!FILES) {
-		FILES = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
-		if (!FILES) {
-			fibril_mutex_unlock(&VFS_DATA->lock);
+static bool vfs_files_init(vfs_client_data_t *vfs_data)
+{
+	fibril_mutex_lock(&vfs_data->lock);
+	if (!vfs_data->files) {
+		vfs_data->files = malloc(MAX_OPEN_FILES * sizeof(vfs_file_t *));
+		if (!vfs_data->files) {
+			fibril_mutex_unlock(&vfs_data->lock);
 			return false;
 		}
-		memset(FILES, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
-	}
-	fibril_mutex_unlock(&VFS_DATA->lock);
+		memset(vfs_data->files, 0, MAX_OPEN_FILES * sizeof(vfs_file_t *));
+	}
+	fibril_mutex_unlock(&vfs_data->lock);
 	return true;
 }
 
 /** Cleanup the table of open files. */
-static void vfs_files_done(void)
+static void vfs_files_done(vfs_client_data_t *vfs_data)
 {
 	int i;
 
-	if (!FILES)
+	if (!vfs_data->files)
 		return;
 
 	for (i = 0; i < MAX_OPEN_FILES; i++) {
-		if (FILES[i]) {
-			(void) vfs_fd_free(i);
-		}
-	}
-	
-	free(FILES);
+		if (vfs_data->files[i])
+			(void) _vfs_fd_free(vfs_data, i);
+	}
+	
+	free(vfs_data->files);
 }
 
@@ -103,5 +104,5 @@
 	vfs_client_data_t *vfs_data = (vfs_client_data_t *) data;
 
-	vfs_files_done();
+	vfs_files_done(vfs_data);
 	free(vfs_data);
 }
@@ -131,7 +132,7 @@
  *			incremented.
  */
-static void vfs_file_addref(vfs_file_t *file)
-{
-	assert(fibril_mutex_is_locked(&VFS_DATA->lock));
+static void vfs_file_addref(vfs_client_data_t *vfs_data, vfs_file_t *file)
+{
+	assert(fibril_mutex_is_locked(&vfs_data->lock));
 
 	file->refcnt++;
@@ -143,9 +144,9 @@
  *			decremented.
  */
-static int vfs_file_delref(vfs_file_t *file)
+static int vfs_file_delref(vfs_client_data_t *vfs_data, vfs_file_t *file)
 {
 	int rc = EOK;
 
-	assert(fibril_mutex_is_locked(&VFS_DATA->lock));
+	assert(fibril_mutex_is_locked(&vfs_data->lock));
 
 	if (file->refcnt-- == 1) {
@@ -162,16 +163,7 @@
 }
 
-
-/** Allocate a file descriptor.
- *
- * @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())
+static int _vfs_fd_alloc(vfs_client_data_t *vfs_data, bool desc)
+{
+	if (!vfs_files_init(vfs_data))
 		return ENOMEM;
 	
@@ -182,17 +174,17 @@
 		i = 0;
 	
-	fibril_mutex_lock(&VFS_DATA->lock);
+	fibril_mutex_lock(&vfs_data->lock);
 	while (true) {
-		if (!FILES[i]) {
-			FILES[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
-			if (!FILES[i]) {
-				fibril_mutex_unlock(&VFS_DATA->lock);
+		if (!vfs_data->files[i]) {
+			vfs_data->files[i] = (vfs_file_t *) malloc(sizeof(vfs_file_t));
+			if (!vfs_data->files[i]) {
+				fibril_mutex_unlock(&vfs_data->lock);
 				return ENOMEM;
 			}
 			
-			memset(FILES[i], 0, sizeof(vfs_file_t));
-			fibril_mutex_initialize(&FILES[i]->lock);
-			vfs_file_addref(FILES[i]);
-			fibril_mutex_unlock(&VFS_DATA->lock);
+			memset(vfs_data->files[i], 0, sizeof(vfs_file_t));
+			fibril_mutex_initialize(&vfs_data->files[i]->lock);
+			vfs_file_addref(vfs_data, vfs_data->files[i]);
+			fibril_mutex_unlock(&vfs_data->lock);
 			return (int) i;
 		}
@@ -210,7 +202,40 @@
 		}
 	}
-	fibril_mutex_unlock(&VFS_DATA->lock);
+	fibril_mutex_unlock(&vfs_data->lock);
 	
 	return EMFILE;
+}
+
+/** Allocate a file descriptor.
+ *
+ * @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)
+{
+	return _vfs_fd_alloc(VFS_DATA, desc);
+}
+
+static int _vfs_fd_free(vfs_client_data_t *vfs_data, int fd)
+{
+	int rc;
+
+	if (!vfs_files_init(vfs_data))
+		return ENOMEM;
+
+	fibril_mutex_lock(&vfs_data->lock);	
+	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || !vfs_data->files[fd]) {
+		fibril_mutex_unlock(&vfs_data->lock);
+		return EBADF;
+	}
+	
+	rc = vfs_file_delref(vfs_data, vfs_data->files[fd]);
+	vfs_data->files[fd] = NULL;
+	fibril_mutex_unlock(&vfs_data->lock);
+	
+	return rc;
 }
 
@@ -224,20 +249,5 @@
 int vfs_fd_free(int fd)
 {
-	int rc;
-
-	if (!vfs_files_init())
-		return ENOMEM;
-
-	fibril_mutex_lock(&VFS_DATA->lock);	
-	if ((fd < 0) || (fd >= MAX_OPEN_FILES) || (FILES[fd] == NULL)) {
-		fibril_mutex_unlock(&VFS_DATA->lock);
-		return EBADF;
-	}
-	
-	rc = vfs_file_delref(FILES[fd]);
-	FILES[fd] = NULL;
-	fibril_mutex_unlock(&VFS_DATA->lock);
-	
-	return rc;
+	return _vfs_fd_free(VFS_DATA, fd);
 }
 
@@ -253,5 +263,5 @@
 int vfs_fd_assign(vfs_file_t *file, int fd)
 {
-	if (!vfs_files_init())
+	if (!vfs_files_init(VFS_DATA))
 		return ENOMEM;
 
@@ -263,5 +273,5 @@
 	
 	FILES[fd] = file;
-	vfs_file_addref(FILES[fd]);
+	vfs_file_addref(VFS_DATA, FILES[fd]);
 	fibril_mutex_unlock(&VFS_DATA->lock);
 	
@@ -269,29 +279,41 @@
 }
 
-/** Find VFS file structure for a given file descriptor.
- *
- * @param fd		File descriptor.
- *
- * @return		VFS file structure corresponding to fd.
- */
-vfs_file_t *vfs_file_get(int fd)
-{
-	if (!vfs_files_init())
+static vfs_file_t *_vfs_file_get(vfs_client_data_t *vfs_data, int fd)
+{
+	if (!vfs_files_init(vfs_data))
 		return NULL;
 	
-	fibril_mutex_lock(&VFS_DATA->lock);
+	fibril_mutex_lock(&vfs_data->lock);
 	if ((fd >= 0) && (fd < MAX_OPEN_FILES)) {
-		vfs_file_t *file = FILES[fd];
+		vfs_file_t *file = vfs_data->files[fd];
 		if (file != NULL) {
-			vfs_file_addref(file);
-			fibril_mutex_unlock(&VFS_DATA->lock);
+			vfs_file_addref(vfs_data, file);
+			fibril_mutex_unlock(&vfs_data->lock);
 			return file;
 		}
 	}
-	fibril_mutex_unlock(&VFS_DATA->lock);
+	fibril_mutex_unlock(&vfs_data->lock);
 	
 	return NULL;
 }
 
+/** Find VFS file structure for a given file descriptor.
+ *
+ * @param fd		File descriptor.
+ *
+ * @return		VFS file structure corresponding to fd.
+ */
+vfs_file_t *vfs_file_get(int fd)
+{
+	return _vfs_file_get(VFS_DATA, fd);
+}
+
+static void _vfs_file_put(vfs_client_data_t *vfs_data, vfs_file_t *file)
+{
+	fibril_mutex_lock(&vfs_data->lock);
+	vfs_file_delref(vfs_data, file);
+	fibril_mutex_unlock(&vfs_data->lock);
+}
+
 /** Stop using a file structure.
  *
@@ -300,7 +322,54 @@
 void vfs_file_put(vfs_file_t *file)
 {
-	fibril_mutex_lock(&VFS_DATA->lock);
-	vfs_file_delref(file);
-	fibril_mutex_unlock(&VFS_DATA->lock);
+	_vfs_file_put(VFS_DATA, file);
+}
+
+void vfs_pass_handle(sysarg_t donor_hash, sysarg_t acceptor_hash, int donor_fd)
+{
+	vfs_client_data_t *donor_data = NULL;
+	vfs_client_data_t *acceptor_data = NULL;
+	vfs_file_t *donor_file = NULL;
+	vfs_file_t *acceptor_file = NULL;
+	int acceptor_fd;
+
+	donor_data = async_get_client_data_by_hash(donor_hash);
+	if (!donor_data)
+		return;
+	acceptor_data = async_get_client_data_by_hash(acceptor_hash);
+	if (!acceptor_data)
+		goto out;
+
+	donor_file = _vfs_file_get(donor_data, donor_fd);
+	if (!donor_file)
+		goto out;
+
+	acceptor_fd = _vfs_fd_alloc(acceptor_data, false);
+	if (acceptor_fd < 0)
+		goto out;
+
+	/*
+	 * Add a new reference to the underlying VFS node.
+	 */
+	vfs_node_addref(donor_file->node);
+
+	acceptor_file = _vfs_file_get(acceptor_data, acceptor_fd);
+	assert(acceptor_file);
+
+	/*
+	 * Inherit attributes from the donor.
+	 */
+	acceptor_file->node = donor_file->node;
+	acceptor_file->append = donor_file->append;
+	acceptor_file->pos = donor_file->pos;
+
+out:
+	if (donor_data)
+		async_put_client_data_by_hash(donor_hash);
+	if (acceptor_data)
+		async_put_client_data_by_hash(acceptor_hash);
+	if (donor_file)
+		_vfs_file_put(donor_data, donor_file);
+	if (acceptor_file)
+		_vfs_file_put(acceptor_data, acceptor_file);
 }
 
