Index: uspace/lib/libc/generic/adt/hash_table.c
===================================================================
--- uspace/lib/libc/generic/adt/hash_table.c	(revision 3698e4420e4bdd79a3251c212fbc1886ecf45436)
+++ uspace/lib/libc/generic/adt/hash_table.c	(revision 231438126d2f4a823b7106c694ea8eecf2d00e54)
@@ -193,4 +193,24 @@
 }
 
+/** Apply fucntion to all items in hash table.
+ *
+ * @param h		Hash table.
+ * @param f		Function to be applied.
+ * @param arg		Argument to be passed to the function.
+ */
+void
+hash_table_apply(hash_table_t *h, void (*f)(link_t *, void *), void *arg)
+{
+	hash_index_t bucket;
+	link_t *cur;
+
+	for (bucket = 0; bucket < h->entries; bucket++) {
+		for (cur = h->entry[bucket].next; cur != &h->entry[bucket];
+		    cur = cur->next) {
+			f(cur, arg);
+		}
+	}
+}
+
 /** @}
  */
Index: uspace/lib/libc/generic/vfs/vfs.c
===================================================================
--- uspace/lib/libc/generic/vfs/vfs.c	(revision 3698e4420e4bdd79a3251c212fbc1886ecf45436)
+++ uspace/lib/libc/generic/vfs/vfs.c	(revision 231438126d2f4a823b7106c694ea8eecf2d00e54)
@@ -197,4 +197,42 @@
 }
 
+int unmount(const char *mp)
+{
+	ipcarg_t rc;
+	ipcarg_t rc_orig;
+	aid_t req;
+	size_t mpa_size;
+	char *mpa;
+	
+	mpa = absolutize(mp, &mpa_size);
+	if (!mpa)
+		return ENOMEM;
+	
+	futex_down(&vfs_phone_futex);
+	async_serialize_start();
+	vfs_connect();
+	
+	req = async_send_0(vfs_phone, VFS_IN_UNMOUNT, NULL);
+	rc = async_data_write_start(vfs_phone, (void *) mpa, mpa_size);
+	if (rc != EOK) {
+		async_wait_for(req, &rc_orig);
+		async_serialize_end();
+		futex_up(&vfs_phone_futex);
+		free(mpa);
+		if (rc_orig == EOK)
+			return (int) rc;
+		else
+			return (int) rc_orig;
+	}
+	
+
+	async_wait_for(req, &rc);
+	async_serialize_end();
+	futex_up(&vfs_phone_futex);
+	free(mpa);
+	
+	return (int) rc;
+}
+
 static int open_internal(const char *abs, size_t abs_size, int lflag, int oflag)
 {
Index: uspace/lib/libc/include/adt/hash_table.h
===================================================================
--- uspace/lib/libc/include/adt/hash_table.h	(revision 3698e4420e4bdd79a3251c212fbc1886ecf45436)
+++ uspace/lib/libc/include/adt/hash_table.h	(revision 231438126d2f4a823b7106c694ea8eecf2d00e54)
@@ -88,4 +88,6 @@
 extern void hash_table_remove(hash_table_t *, unsigned long [], hash_count_t);
 extern void hash_table_destroy(hash_table_t *);
+extern void hash_table_apply(hash_table_t *, void (*)(link_t *, void *),
+    void *);
 
 #endif
Index: uspace/lib/libc/include/ipc/vfs.h
===================================================================
--- uspace/lib/libc/include/ipc/vfs.h	(revision 3698e4420e4bdd79a3251c212fbc1886ecf45436)
+++ uspace/lib/libc/include/ipc/vfs.h	(revision 231438126d2f4a823b7106c694ea8eecf2d00e54)
@@ -86,4 +86,5 @@
 	VFS_OUT_MOUNTED,
 	VFS_OUT_UNMOUNT,
+	VFS_OUT_UNMOUNTED,
 	VFS_OUT_SYNC,
 	VFS_OUT_STAT,
@@ -100,5 +101,5 @@
  * No lookup flags used.
  */
-#define L_NONE  0
+#define L_NONE			0
 
 /**
@@ -107,12 +108,25 @@
  * with L_DIRECTORY.
  */
-#define L_FILE  1
+#define L_FILE			1
 
 /**
- * Lookup wil succeed only if the object is a directory. If L_CREATE is
+ * Lookup will succeed only if the object is a directory. If L_CREATE is
  * specified, an empty directory will be created. This flag is mutually
  * exclusive with L_FILE.
  */
-#define L_DIRECTORY  2
+#define L_DIRECTORY		2
+
+/**
+ * Lookup will succeed only if the object is a root directory. The flag is
+ * mutually exclusive with L_FILE and L_MP.
+ */
+#define L_ROOT			4
+
+/**
+ * Lookup will succeed only if the object is a mount point. The flag is mutually
+ * exclusive with L_FILE and L_ROOT.
+ */
+#define L_MP			8
+
 
 /**
@@ -120,15 +134,15 @@
  * object already exists. L_EXCLUSIVE is implied when L_DIRECTORY is used.
  */
-#define L_EXCLUSIVE  4
+#define L_EXCLUSIVE 		16
 
 /**
  * L_CREATE is used for creating both regular files and directories.
  */
-#define L_CREATE  8
+#define L_CREATE		32
 
 /**
  * L_LINK is used for linking to an already existing nodes.
  */
-#define L_LINK  16
+#define L_LINK			64
 
 /**
@@ -137,13 +151,13 @@
  * VFS_UNLINK.
  */
-#define L_UNLINK  32
+#define L_UNLINK		128
 
 /**
- * L_OPEN is used to indicate that the lookup operation is a part of VFS_OPEN
+ * L_OPEN is used to indicate that the lookup operation is a part of VFS_IN_OPEN
  * call from the client. This means that the server might allocate some
  * resources for the opened file. This flag cannot be passed directly by the
  * client.
  */
-#define L_OPEN  64
+#define L_OPEN			256
 
 #endif
Index: uspace/lib/libc/include/vfs/vfs.h
===================================================================
--- uspace/lib/libc/include/vfs/vfs.h	(revision 3698e4420e4bdd79a3251c212fbc1886ecf45436)
+++ uspace/lib/libc/include/vfs/vfs.h	(revision 231438126d2f4a823b7106c694ea8eecf2d00e54)
@@ -55,4 +55,5 @@
 extern int mount(const char *, const char *, const char *, const char *,
     unsigned int);
+extern int unmount(const char *);
 
 extern void __stdio_init(int filc, fdi_node_t *filv[]);
Index: uspace/lib/libfs/libfs.c
===================================================================
--- uspace/lib/libfs/libfs.c	(revision 3698e4420e4bdd79a3251c212fbc1886ecf45436)
+++ uspace/lib/libfs/libfs.c	(revision 231438126d2f4a823b7106c694ea8eecf2d00e54)
@@ -224,4 +224,49 @@
 	ipc_answer_3(rid, rc, IPC_GET_ARG1(answer), IPC_GET_ARG2(answer),
 	    IPC_GET_ARG3(answer));
+}
+
+void libfs_unmount(libfs_ops_t *ops, ipc_callid_t rid, ipc_call_t *request)
+{
+	dev_handle_t mp_dev_handle = (dev_handle_t) IPC_GET_ARG1(*request);
+	fs_index_t mp_fs_index = (fs_index_t) IPC_GET_ARG2(*request);
+	fs_node_t *fn;
+	int res;
+
+	res = ops->node_get(&fn, mp_dev_handle, mp_fs_index);
+	if ((res != EOK) || (!fn)) {
+		ipc_answer_0(rid, combine_rc(res, ENOENT));
+		return;
+	}
+
+	/*
+	 * We are clearly expecting to find the mount point active.
+	 */
+	if (!fn->mp_data.mp_active) {
+		(void) ops->node_put(fn);
+		ipc_answer_0(rid, EINVAL);
+		return;
+	}
+
+	/*
+	 * Tell the mounted file system to unmount.
+	 */
+	res = async_req_1_0(fn->mp_data.phone, VFS_OUT_UNMOUNTED,
+	    fn->mp_data.dev_handle);
+
+	/*
+	 * If everything went well, perform the clean-up on our side.
+	 */
+	if (res == EOK) {
+		ipc_hangup(fn->mp_data.phone);
+		fn->mp_data.mp_active = false;
+		fn->mp_data.fs_handle = 0;
+		fn->mp_data.dev_handle = 0;
+		fn->mp_data.phone = 0;
+		/* Drop the reference created in libfs_mount(). */
+		(void) ops->node_put(fn);
+	}
+
+	(void) ops->node_put(fn);
+	ipc_answer_0(rid, res);
 }
 
@@ -304,5 +349,16 @@
 		on_error(rc, goto out_with_answer);
 		
-		if ((tmp) && (tmp->mp_data.mp_active)) {
+		/*
+		 * If the matching component is a mount point, there are two
+		 * legitimate semantics of the lookup operation. The first is
+		 * the commonly used one in which the lookup crosses each mount
+		 * point into the mounted file system. The second semantics is
+		 * used mostly during unmount() and differs from the first one
+		 * only in that the last mount point in the looked up path,
+		 * which is also its last component, is not crossed.
+		 */
+
+		if ((tmp) && (tmp->mp_data.mp_active) &&
+		    (!(lflag & L_MP) || (next <= last))) {
 			if (next > last)
 				next = last = first;
@@ -475,4 +531,9 @@
 		goto out;
 	}
+
+	if ((lflag & L_ROOT) && par) {
+		ipc_answer_0(rid, EINVAL);
+		goto out;
+	}
 	
 out_with_answer:
Index: uspace/lib/libfs/libfs.h
===================================================================
--- uspace/lib/libfs/libfs.h	(revision 3698e4420e4bdd79a3251c212fbc1886ecf45436)
+++ uspace/lib/libfs/libfs.h	(revision 231438126d2f4a823b7106c694ea8eecf2d00e54)
@@ -95,4 +95,5 @@
 
 extern void libfs_mount(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
+extern void libfs_unmount(libfs_ops_t *, ipc_callid_t, ipc_call_t *);
 extern void libfs_lookup(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
 extern void libfs_stat(libfs_ops_t *, fs_handle_t, ipc_callid_t, ipc_call_t *);
