Index: uspace/srv/vfs/vfs_ops.c
===================================================================
--- uspace/srv/vfs/vfs_ops.c	(revision c4aca2ce29b16f034724660fe30761fde0732fd2)
+++ uspace/srv/vfs/vfs_ops.c	(revision e095644fa3dee2172f750ac4b6c58a572cec9c46)
@@ -431,5 +431,141 @@
 void vfs_unmount(ipc_callid_t rid, ipc_call_t *request)
 {
-	ipc_answer_0(rid, ENOTSUP);
+	int rc;
+	char *mp;
+	vfs_lookup_res_t mp_res;
+	vfs_lookup_res_t mr_res;
+	vfs_node_t *mp_node;
+	vfs_node_t *mr_node;
+	int phone;
+
+	/*
+	 * Receive the mount point path.
+	 */
+	rc = async_data_string_receive(&mp, MAX_PATH_LEN);
+	if (rc != EOK)
+		ipc_answer_0(rid, rc);
+
+	/*
+	 * Taking the namespace lock will do two things for us. First, it will
+	 * prevent races with other lookup operations. Second, it will stop new
+	 * references to already existing VFS nodes and creation of new VFS
+	 * nodes. This is because new references are added as a result of some
+	 * lookup operation or at least of some operation which is protected by
+	 * the namespace lock.
+	 */
+	fibril_rwlock_write_lock(&namespace_rwlock);
+	
+	/*
+	 * Lookup the mounted root and instantiate it.
+	 */
+	rc = vfs_lookup_internal(mp, L_NONE, &mr_res, NULL);
+	if (rc != EOK) {
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		free(mp);
+		ipc_answer_0(rid, rc);
+		return;
+	}
+	mr_node = vfs_node_get(&mr_res);
+	if (!mr_node) {
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		free(mp);
+		ipc_answer_0(rid, ENOMEM);
+		return;
+	}
+
+	/*
+	 * Count the total number of references for the mounted file system. We
+	 * are expecting at least two. One which we got above and one which we
+	 * got when the file system was mounted. If we find more, it means that
+	 * the file system cannot be gracefully unmounted at the moment because
+	 * someone is working with it.
+	 */
+	if (vfs_nodes_refcount_sum_get(mr_node->fs_handle,
+	    mr_node->dev_handle) != 2) {
+		fibril_rwlock_write_unlock(&namespace_rwlock);
+		vfs_node_put(mr_node);
+		free(mp);
+		ipc_answer_0(rid, EBUSY);
+		return;
+	}
+
+	if (str_cmp(mp, "/") == 0) {
+
+		/*
+		 * Unmounting the root file system.
+		 *
+		 * In this case, there is no mount point node and we send
+		 * VFS_OUT_UNMOUNTED directly to the mounted file system.
+		 */
+
+		free(mp);
+		phone = vfs_grab_phone(mr_node->fs_handle);
+		rc = async_req_1_0(phone, VFS_OUT_UNMOUNTED,
+		    mr_node->dev_handle);
+		vfs_release_phone(phone);
+		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&namespace_rwlock);
+			vfs_node_put(mr_node);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+		rootfs.fs_handle = 0;
+		rootfs.dev_handle = 0;
+	} else {
+
+		/*
+		 * Unmounting a non-root file system.
+		 *
+		 * We have a regular mount point node representing the parent
+		 * file system, so we delegate the operation to it.
+		 */
+
+		/*
+		 * The L_NOCROSS_LAST_MP flag is essential if we really want to
+		 * lookup the mount point and not the mounted root.
+		 */
+		rc = vfs_lookup_internal(mp, L_NOCROSS_LAST_MP, &mp_res, NULL);
+		free(mp);
+		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&namespace_rwlock);
+			vfs_node_put(mr_node);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+		vfs_node_t *mp_node = vfs_node_get(&mp_res);
+		if (!mp_node) {
+			fibril_rwlock_write_unlock(&namespace_rwlock);
+			vfs_node_put(mr_node);
+			ipc_answer_0(rid, ENOMEM);
+			return;
+		}
+
+		phone = vfs_grab_phone(mp_node->fs_handle);
+		rc = async_req_2_0(phone, VFS_OUT_UNMOUNT, mp_node->fs_handle,
+		    mp_node->dev_handle);
+		vfs_release_phone(phone);
+		if (rc != EOK) {
+			fibril_rwlock_write_unlock(&namespace_rwlock);
+			vfs_node_put(mp_node);
+			vfs_node_put(mr_node);
+			ipc_answer_0(rid, rc);
+			return;
+		}
+
+		/* Drop the reference we got above. */
+		vfs_node_put(mp_node);
+		/* Drop the reference from when the file system was mounted. */
+		vfs_node_put(mp_node);
+	}
+
+
+	/*
+	 * All went well, the mounted file system was successfully unmounted.
+	 * The only thing left is to forget the unmounted root VFS node.
+	 */
+	vfs_node_forget(mr_node);
+
+	fibril_rwlock_write_unlock(&namespace_rwlock);
+	ipc_answer_0(rid, EOK);
 }
 
