spin_lock_init(&channel->sc_lock);
INIT_LIST_HEAD(&channel->sc_list);
+ INIT_LIST_HEAD(&channel->percpu_list);
channel->controlwq = create_workqueue("hv_vmbus_ctl");
if (!channel->controlwq) {
queue_work(vmbus_connection.work_queue, &channel->work);
}
+static void percpu_channel_enq(void *arg)
+{
+ struct vmbus_channel *channel = arg;
+ int cpu = smp_processor_id();
+
+ list_add_tail(&channel->percpu_list, &hv_context.percpu_list[cpu]);
+}
+static void percpu_channel_deq(void *arg)
+{
+ struct vmbus_channel *channel = arg;
+
+ list_del(&channel->percpu_list);
+}
/*
* vmbus_process_rescind_offer -
msg.header.msgtype = CHANNELMSG_RELID_RELEASED;
vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
+ if (channel->target_cpu != smp_processor_id())
+ smp_call_function_single(channel->target_cpu,
+ percpu_channel_deq, channel, true);
+ else
+ percpu_channel_deq(channel);
+
if (channel->primary_channel == NULL) {
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
list_del(&channel->listentry);
work);
struct vmbus_channel *channel;
bool fnew = true;
+ bool enq = false;
int ret;
unsigned long flags;
}
}
- if (fnew)
+ if (fnew) {
list_add_tail(&newchannel->listentry,
&vmbus_connection.chn_list);
+ enq = true;
+ }
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
+ if (enq) {
+ if (newchannel->target_cpu != smp_processor_id())
+ smp_call_function_single(newchannel->target_cpu,
+ percpu_channel_enq,
+ newchannel, true);
+ else
+ percpu_channel_enq(newchannel);
+ }
if (!fnew) {
/*
* Check to see if this is a sub-channel.
spin_lock_irqsave(&channel->sc_lock, flags);
list_add_tail(&newchannel->sc_list, &channel->sc_list);
spin_unlock_irqrestore(&channel->sc_lock, flags);
+
+ if (newchannel->target_cpu != smp_processor_id())
+ smp_call_function_single(newchannel->target_cpu,
+ percpu_channel_enq,
+ newchannel, true);
+ else
+ percpu_channel_enq(newchannel);
+
newchannel->state = CHANNEL_OPEN_STATE;
if (channel->sc_creation_callback != NULL)
channel->sc_creation_callback(newchannel);
return ret;
}
+/*
+ * Map the given relid to the corresponding channel based on the
+ * per-cpu list of channels that have been affinitized to this CPU.
+ * This will be used in the channel callback path as we can do this
+ * mapping in a lock-free fashion.
+ */
+static struct vmbus_channel *pcpu_relid2channel(u32 relid)
+{
+ struct vmbus_channel *channel;
+ struct vmbus_channel *found_channel = NULL;
+ int cpu = smp_processor_id();
+ struct list_head *pcpu_head = &hv_context.percpu_list[cpu];
+
+ list_for_each_entry(channel, pcpu_head, percpu_list) {
+ if (channel->offermsg.child_relid == relid) {
+ found_channel = channel;
+ break;
+ }
+ }
+
+ return found_channel;
+}
/*
* relid2channel - Get the channel object given its
* Find the channel based on this relid and invokes the
* channel callback to process the event
*/
- channel = relid2channel(relid);
+ channel = pcpu_relid2channel(relid);
if (!channel) {
pr_err("channel not found for relid - %u\n", relid);