|
@@ -746,8 +746,16 @@ static void ipc_leader_exit (struct shim_ipc_port * port, IDTYPE vmid,
|
|
put_ipc_info(info);
|
|
put_ipc_info(info);
|
|
}
|
|
}
|
|
|
|
|
|
-static void __discover_ns (bool block, bool need_connect, bool need_locate)
|
|
+/*
|
|
|
|
+ * __discover_ns(): Discover the leader of this namespace.
|
|
|
|
+ * @block: Whether to block for discovery.
|
|
|
|
+ * @need_locate: Need the location information of the leader.
|
|
|
|
+ */
|
|
|
|
+static void __discover_ns (bool block, bool need_locate)
|
|
{
|
|
{
|
|
|
|
+ bool ipc_pending = false;
|
|
|
|
+ lock(cur_process.lock);
|
|
|
|
+
|
|
if (NS_LEADER) {
|
|
if (NS_LEADER) {
|
|
if (NS_LEADER->vmid == cur_process.vmid) {
|
|
if (NS_LEADER->vmid == cur_process.vmid) {
|
|
if (need_locate && qstrempty(&NS_LEADER->uri)) {
|
|
if (need_locate && qstrempty(&NS_LEADER->uri)) {
|
|
@@ -760,44 +768,67 @@ static void __discover_ns (bool block, bool need_connect, bool need_locate)
|
|
&ipc_leader_exit);
|
|
&ipc_leader_exit);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return;
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- if ((need_connect || need_locate) && !qstrempty(&NS_LEADER->uri))
|
|
+ if (!qstrempty(&NS_LEADER->uri))
|
|
- return;
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Now we need to discover the leader through IPC. Because IPC calls can be blocking,
|
|
|
|
+ * we need to temporarily release cur_process.lock to prevent deadlocks. If the discovery
|
|
|
|
+ * succeeds, NS_LEADER will contain the IPC information of the namespace leader.
|
|
|
|
+ */
|
|
|
|
+
|
|
unlock(cur_process.lock);
|
|
unlock(cur_process.lock);
|
|
|
|
|
|
- /* now we have to discover the leader */
|
|
+ // Send out an IPC message to find out the namespace information.
|
|
- if (!NS_SEND(findns)(block))
|
|
+ // If the call is non-blocking, can't expect the answer when the function finishes.
|
|
- return;
|
|
+ if (!NS_SEND(findns)(block)) {
|
|
|
|
+ ipc_pending = !block; // There is still some unfinished business with IPC
|
|
|
|
+ lock(cur_process.lock);
|
|
|
|
+ assert(NS_LEADER);
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
lock(cur_process.lock);
|
|
lock(cur_process.lock);
|
|
|
|
|
|
if (NS_LEADER && (!need_locate || !qstrempty(&NS_LEADER->uri)))
|
|
if (NS_LEADER && (!need_locate || !qstrempty(&NS_LEADER->uri)))
|
|
- return;
|
|
+ goto out;
|
|
|
|
|
|
- /* if all other ways failed, the process become a manager */
|
|
+ // If all other ways failed, the current process becomes the leader
|
|
if (!need_locate) {
|
|
if (!need_locate) {
|
|
NS_LEADER = get_new_ipc_info(cur_process.vmid, NULL, 0);
|
|
NS_LEADER = get_new_ipc_info(cur_process.vmid, NULL, 0);
|
|
- return;
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
if (NS_LEADER)
|
|
if (NS_LEADER)
|
|
put_ipc_info(NS_LEADER);
|
|
put_ipc_info(NS_LEADER);
|
|
|
|
|
|
if (!(NS_LEADER = create_ipc_port(cur_process.vmid, true)))
|
|
if (!(NS_LEADER = create_ipc_port(cur_process.vmid, true)))
|
|
- return;
|
|
+ goto out;
|
|
|
|
|
|
- add_ipc_port(NS_LEADER->port, NS_LEADER->vmid, IPC_PORT_CLT,
|
|
+ // Finally, set the IPC port as a leadership port
|
|
- &ipc_leader_exit);
|
|
+ add_ipc_port(NS_LEADER->port, 0, IPC_PORT_CLT, &ipc_leader_exit);
|
|
|
|
+
|
|
|
|
+out:
|
|
|
|
+ if (NS_LEADER && !ipc_pending) {
|
|
|
|
+ // Assertions for checking the correctness of __discover_ns()
|
|
|
|
+ assert(NS_LEADER->vmid == cur_process.vmid // The current process is the leader;
|
|
|
|
+ || NS_LEADER->port // Or there is a connected port
|
|
|
|
+ || !qstrempty(&NS_LEADER->uri)); // Or there is a known URI
|
|
|
|
+ if (need_locate)
|
|
|
|
+ assert(!qstrempty(&NS_LEADER->uri)); // A known URI is needed
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ unlock(cur_process.lock);
|
|
}
|
|
}
|
|
|
|
|
|
static int connect_ns (IDTYPE * vmid, struct shim_ipc_port ** portptr)
|
|
static int connect_ns (IDTYPE * vmid, struct shim_ipc_port ** portptr)
|
|
{
|
|
{
|
|
|
|
+ __discover_ns(true, false); // Should not hold cur_process.lock
|
|
lock(cur_process.lock);
|
|
lock(cur_process.lock);
|
|
- __discover_ns(true, true, false);
|
|
|
|
|
|
|
|
if (!NS_LEADER) {
|
|
if (!NS_LEADER) {
|
|
unlock(cur_process.lock);
|
|
unlock(cur_process.lock);
|
|
@@ -861,14 +892,11 @@ static int disconnect_ns(struct shim_ipc_port * port)
|
|
int CONCAT3(prepare, NS, leader) (void)
|
|
int CONCAT3(prepare, NS, leader) (void)
|
|
{
|
|
{
|
|
lock(cur_process.lock);
|
|
lock(cur_process.lock);
|
|
-
|
|
+ bool need_discover = (!NS_LEADER || qstrempty(&NS_LEADER->uri));
|
|
- if (!NS_LEADER) {
|
|
|
|
- unlock(cur_process.lock);
|
|
|
|
- return 0;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- __discover_ns(true, true, true);
|
|
|
|
unlock(cur_process.lock);
|
|
unlock(cur_process.lock);
|
|
|
|
+
|
|
|
|
+ if (need_discover)
|
|
|
|
+ __discover_ns(true, true); // Should not hold cur_process.lock
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -986,13 +1014,14 @@ int NS_CALLBACK(findns) (IPC_CALLBACK_ARGS)
|
|
msg->src);
|
|
msg->src);
|
|
|
|
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
+ __discover_ns(false, true); // Non-blocking discovery; should not hold cur_process.lock
|
|
lock(cur_process.lock);
|
|
lock(cur_process.lock);
|
|
- __discover_ns(false, true, true);
|
|
+
|
|
- if (NS_LEADER) {
|
|
+ if (NS_LEADER && !qstrempty(&NS_LEADER->uri)) {
|
|
- /* After __discover_ns, the leader should has its own port */
|
|
+ // Got the answer! Send back the discovery now.
|
|
- assert(!qstrempty(&NS_LEADER->uri));
|
|
|
|
ret = NS_SEND(tellns)(port, msg->src, NS_LEADER, msg->seq);
|
|
ret = NS_SEND(tellns)(port, msg->src, NS_LEADER, msg->seq);
|
|
} else {
|
|
} else {
|
|
|
|
+ // Don't know the answer yet, set up a callback for sending the discovery later.
|
|
struct ns_query * query = malloc(sizeof(struct ns_query));
|
|
struct ns_query * query = malloc(sizeof(struct ns_query));
|
|
if (query) {
|
|
if (query) {
|
|
query->dest = msg->src;
|
|
query->dest = msg->src;
|
|
@@ -1057,6 +1086,9 @@ int NS_CALLBACK(tellns) (IPC_CALLBACK_ARGS)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ assert(NS_LEADER->vmid != 0);
|
|
|
|
+ assert(!qstrempty(&NS_LEADER->uri));
|
|
|
|
+
|
|
struct ns_query * query, * pos;
|
|
struct ns_query * query, * pos;
|
|
|
|
|
|
listp_for_each_entry_safe(query, pos, &ns_queries, list) {
|
|
listp_for_each_entry_safe(query, pos, &ns_queries, list) {
|