Index: kernel/generic/include/ipc/ipc.h
===================================================================
--- kernel/generic/include/ipc/ipc.h	(revision 40e5d6680c4d2ab6b676c86b5db8e47a303170c3)
+++ kernel/generic/include/ipc/ipc.h	(revision 7c0e1f596a64720b6f6a6ec66b3499a9d26511cb)
@@ -106,4 +106,6 @@
 	/** Phone which made or last masqueraded this call. */
 	phone_t *phone;
+	/** User-defined label */
+	sysarg_t label;
 } ipc_data_t;
 
Index: kernel/generic/include/ipc/sysipc.h
===================================================================
--- kernel/generic/include/ipc/sysipc.h	(revision 40e5d6680c4d2ab6b676c86b5db8e47a303170c3)
+++ kernel/generic/include/ipc/sysipc.h	(revision 7c0e1f596a64720b6f6a6ec66b3499a9d26511cb)
@@ -44,5 +44,5 @@
 extern sysarg_t sys_ipc_call_async_fast(sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t, sysarg_t);
-extern sysarg_t sys_ipc_call_async_slow(sysarg_t, ipc_data_t *);
+extern sysarg_t sys_ipc_call_async_slow(sysarg_t, ipc_data_t *, sysarg_t);
 extern sysarg_t sys_ipc_answer_fast(sysarg_t, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t);
Index: kernel/generic/src/ipc/sysipc.c
===================================================================
--- kernel/generic/src/ipc/sysipc.c	(revision 40e5d6680c4d2ab6b676c86b5db8e47a303170c3)
+++ kernel/generic/src/ipc/sysipc.c	(revision 7c0e1f596a64720b6f6a6ec66b3499a9d26511cb)
@@ -347,5 +347,5 @@
 /** Make a fast asynchronous call over IPC.
  *
- * This function can only handle four arguments of payload, but is faster than
+ * This function can only handle three arguments of payload, but is faster than
  * the generic function sys_ipc_call_async_slow().
  *
@@ -355,5 +355,5 @@
  * @param arg2     Service-defined payload argument.
  * @param arg3     Service-defined payload argument.
- * @param arg4     Service-defined payload argument.
+ * @param label    User-defined label.
  *
  * @return Call hash on success.
@@ -362,5 +362,5 @@
  */
 sysarg_t sys_ipc_call_async_fast(sysarg_t handle, sysarg_t imethod,
-    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t arg4)
+    sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, sysarg_t label)
 {
 	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
@@ -378,5 +378,4 @@
 	IPC_SET_ARG2(call->data, arg2);
 	IPC_SET_ARG3(call->data, arg3);
-	IPC_SET_ARG4(call->data, arg4);
 	
 	/*
@@ -385,4 +384,7 @@
 	 */
 	IPC_SET_ARG5(call->data, 0);
+
+	/* Set the user-defined label */
+	call->data.label = label;
 	
 	int res = request_preprocess(call, kobj->phone);
@@ -401,9 +403,11 @@
  * @param handle  Phone capability for the call.
  * @param data    Userspace address of call data with the request.
+ * @param label   User-defined label.
  *
  * @return See sys_ipc_call_async_fast().
  *
  */
-sysarg_t sys_ipc_call_async_slow(sysarg_t handle, ipc_data_t *data)
+sysarg_t sys_ipc_call_async_slow(sysarg_t handle, ipc_data_t *data,
+    sysarg_t label)
 {
 	kobject_t *kobj = kobject_get(TASK, handle, KOBJECT_TYPE_PHONE);
@@ -424,4 +428,7 @@
 		return (sysarg_t) rc;
 	}
+
+	/* Set the user-defined label */
+	call->data.label = label;
 	
 	int res = request_preprocess(call, kobj->phone);
Index: uspace/app/trace/syscalls.c
===================================================================
--- uspace/app/trace/syscalls.c	(revision 40e5d6680c4d2ab6b676c86b5db8e47a303170c3)
+++ uspace/app/trace/syscalls.c	(revision 7c0e1f596a64720b6f6a6ec66b3499a9d26511cb)
@@ -54,5 +54,5 @@
 
     [SYS_IPC_CALL_ASYNC_FAST] = { "ipc_call_async_fast", 6,	V_HASH },
-    [SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 2,	V_HASH },
+    [SYS_IPC_CALL_ASYNC_SLOW] = { "ipc_call_async_slow", 3,	V_HASH },
 
     [SYS_IPC_ANSWER_FAST] = { "ipc_answer_fast",	6,	V_ERRNO },
Index: uspace/lib/c/generic/ipc.c
===================================================================
--- uspace/lib/c/generic/ipc.c	(revision 40e5d6680c4d2ab6b676c86b5db8e47a303170c3)
+++ uspace/lib/c/generic/ipc.c	(revision 7c0e1f596a64720b6f6a6ec66b3499a9d26511cb)
@@ -1,4 +1,5 @@
 /*
  * Copyright (c) 2006 Ondrej Palkovsky
+ * Copyright (c) 2017 Jakub Jermar
  * All rights reserved.
  *
@@ -52,35 +53,13 @@
  * Structures of this type are used for keeping track of sent asynchronous calls.
  */
-typedef struct {
-	link_t list;
-	
+typedef struct async_call {
 	ipc_async_callback_t callback;
 	void *private;
 	
-	union {
-		ipc_callid_t callid;
-		struct {
-			ipc_call_t data;
-			int phoneid;
-		} msg;
-	} u;
+	struct {
+		ipc_call_t data;
+		int phoneid;
+	} msg;
 } async_call_t;
-
-LIST_INITIALIZE(dispatched_calls);
-
-static futex_t ipc_futex = FUTEX_INITIALIZER;
-
-/** Send asynchronous message via syscall.
- *
- * @param phoneid Phone handle for the call.
- * @param data    Call data with the request.
- *
- * @return Hash of the call or an error code.
- *
- */
-static ipc_callid_t ipc_call_async_internal(int phoneid, ipc_call_t *data)
-{
-	return __SYSCALL2(SYS_IPC_CALL_ASYNC_SLOW, phoneid, (sysarg_t) data);
-}
 
 /** Prologue for ipc_call_async_*() functions.
@@ -121,11 +100,8 @@
 	if (!call) {
 		/* Nothing to do regardless if failed or not */
-		futex_unlock(&ipc_futex);
 		return;
 	}
 	
 	if (callid == (ipc_callid_t) IPC_CALLRET_FATAL) {
-		futex_unlock(&ipc_futex);
-		
 		/* Call asynchronous handler with error code */
 		if (call->callback)
@@ -135,15 +111,9 @@
 		return;
 	}
-	
-	call->u.callid = callid;
-	
-	/* Add call to the list of dispatched calls */
-	list_append(&call->list, &dispatched_calls);
-	futex_unlock(&ipc_futex);
 }
 
 /** Fast asynchronous call.
  *
- * This function can only handle four arguments of payload. It is, however,
+ * This function can only handle three arguments of payload. It is, however,
  * faster than the more generic ipc_call_async_slow().
  *
@@ -159,11 +129,9 @@
  * @param arg2        Service-defined payload argument.
  * @param arg3        Service-defined payload argument.
- * @param arg4        Service-defined payload argument.
  * @param private     Argument to be passed to the answer/error callback.
  * @param callback    Answer or error callback.
  */
 void ipc_call_async_fast(int phoneid, sysarg_t imethod, sysarg_t arg1,
-    sysarg_t arg2, sysarg_t arg3, sysarg_t arg4, void *private,
-    ipc_async_callback_t callback)
+    sysarg_t arg2, sysarg_t arg3, void *private, ipc_async_callback_t callback)
 {
 	async_call_t *call = NULL;
@@ -175,12 +143,6 @@
 	}
 	
-	/*
-	 * We need to make sure that we get callid
-	 * before another thread accesses the queue again.
-	 */
-	
-	futex_lock(&ipc_futex);
 	ipc_callid_t callid = __SYSCALL6(SYS_IPC_CALL_ASYNC_FAST, phoneid,
-	    imethod, arg1, arg2, arg3, arg4);
+	    imethod, arg1, arg2, arg3, (sysarg_t) call);
 	
 	ipc_finish_async(callid, phoneid, call);
@@ -213,19 +175,13 @@
 		return;
 	
-	IPC_SET_IMETHOD(call->u.msg.data, imethod);
-	IPC_SET_ARG1(call->u.msg.data, arg1);
-	IPC_SET_ARG2(call->u.msg.data, arg2);
-	IPC_SET_ARG3(call->u.msg.data, arg3);
-	IPC_SET_ARG4(call->u.msg.data, arg4);
-	IPC_SET_ARG5(call->u.msg.data, arg5);
-	
-	/*
-	 * We need to make sure that we get callid
-	 * before another threadaccesses the queue again.
-	 */
-	
-	futex_lock(&ipc_futex);
-	ipc_callid_t callid =
-	    ipc_call_async_internal(phoneid, &call->u.msg.data);
+	IPC_SET_IMETHOD(call->msg.data, imethod);
+	IPC_SET_ARG1(call->msg.data, arg1);
+	IPC_SET_ARG2(call->msg.data, arg2);
+	IPC_SET_ARG3(call->msg.data, arg3);
+	IPC_SET_ARG4(call->msg.data, arg4);
+	IPC_SET_ARG5(call->msg.data, arg5);
+	
+	ipc_callid_t callid = __SYSCALL3(SYS_IPC_CALL_ASYNC_SLOW, phoneid,
+	    (sysarg_t) &call->msg.data, (sysarg_t) call);
 	
 	ipc_finish_async(callid, phoneid, call);
@@ -286,42 +242,17 @@
 /** Handle received answer.
  *
- * Find the hash of the answer and call the answer callback.
- *
- * The answer has the same hash as the request OR'ed with
- * the IPC_CALLID_ANSWERED bit.
- *
- * @todo Use hash table.
- *
  * @param callid Hash of the received answer.
  * @param data   Call data of the answer.
- *
  */
 static void handle_answer(ipc_callid_t callid, ipc_call_t *data)
 {
-	callid &= ~IPC_CALLID_ANSWERED;
-	
-	futex_lock(&ipc_futex);
-	
-	link_t *item;
-	for (item = dispatched_calls.head.next; item != &dispatched_calls.head;
-	    item = item->next) {
-		async_call_t *call =
-		    list_get_instance(item, async_call_t, list);
-		
-		if (call->u.callid == callid) {
-			list_remove(&call->list);
-			
-			futex_unlock(&ipc_futex);
-			
-			if (call->callback)
-				call->callback(call->private,
-				    IPC_GET_RETVAL(*data), data);
-			
-			free(call);
-			return;
-		}
-	}
-	
-	futex_unlock(&ipc_futex);
+	async_call_t *call = data->label;
+
+	if (!call)
+		return;
+
+	if (call->callback)
+		call->callback(call->private, IPC_GET_RETVAL(*data), data);
+	free(call);
 }
 
Index: uspace/lib/c/include/ipc/common.h
===================================================================
--- uspace/lib/c/include/ipc/common.h	(revision 40e5d6680c4d2ab6b676c86b5db8e47a303170c3)
+++ uspace/lib/c/include/ipc/common.h	(revision 7c0e1f596a64720b6f6a6ec66b3499a9d26511cb)
@@ -43,8 +43,11 @@
 #define IPC_FLAG_BLOCKING  0x01
 
+struct async_call;
+
 typedef struct {
 	sysarg_t args[IPC_CALL_LEN];
 	task_id_t in_task_id;
 	sysarg_t in_phone_hash;
+	struct async_call *label;
 } ipc_call_t;
 
Index: uspace/lib/c/include/ipc/ipc.h
===================================================================
--- uspace/lib/c/include/ipc/ipc.h	(revision 40e5d6680c4d2ab6b676c86b5db8e47a303170c3)
+++ uspace/lib/c/include/ipc/ipc.h	(revision 7c0e1f596a64720b6f6a6ec66b3499a9d26511cb)
@@ -89,19 +89,18 @@
 
 #define ipc_call_async_0(phoneid, method, private, callback) \
-	ipc_call_async_fast((phoneid), (method), 0, 0, 0, 0, (private), \
-	    (callback))
+	ipc_call_async_fast((phoneid), (method), 0, 0, 0, (private), (callback))
 #define ipc_call_async_1(phoneid, method, arg1, private, callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), 0, 0, 0, (private), \
+	ipc_call_async_fast((phoneid), (method), (arg1), 0, 0, (private), \
 	    (callback))
 #define ipc_call_async_2(phoneid, method, arg1, arg2, private, callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), 0, 0, \
+	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), 0, \
 	    (private), (callback))
 #define ipc_call_async_3(phoneid, method, arg1, arg2, arg3, private, callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), (arg3), 0, \
+	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), (arg3), \
 	    (private), (callback))
 #define ipc_call_async_4(phoneid, method, arg1, arg2, arg3, arg4, private, \
     callback) \
-	ipc_call_async_fast((phoneid), (method), (arg1), (arg2), (arg3), \
-	    (arg4), (private), (callback))
+	ipc_call_async_slow((phoneid), (method), (arg1), (arg2), (arg3), \
+	    (arg4), 0, (private), (callback))
 #define ipc_call_async_5(phoneid, method, arg1, arg2, arg3, arg4, arg5, \
     private, callback) \
@@ -110,5 +109,5 @@
 
 extern void ipc_call_async_fast(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
-    sysarg_t, void *, ipc_async_callback_t);
+    void *, ipc_async_callback_t);
 extern void ipc_call_async_slow(int, sysarg_t, sysarg_t, sysarg_t, sysarg_t,
     sysarg_t, sysarg_t, void *, ipc_async_callback_t);
