Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8200f208 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Greg Kroah-Hartman
Browse files

vmbus: use rcu for per-cpu channel list



The per-cpu channel list is now referred to in the interrupt
routine. This is mostly safe since the host will not normally generate
an interrupt when channel is being deleted but if it did then there
would be a use after free problem.

To solve, this use RCU protection on ther per-cpu list.

Fixes: 631e63a9 ("vmbus: change to per channel tasklet")

Signed-off-by: default avatarStephen Hemminger <sthemmin@microsoft.com>
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c6240cac
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -350,7 +350,8 @@ static struct vmbus_channel *alloc_channel(void)
static void free_channel(struct vmbus_channel *channel)
{
	tasklet_kill(&channel->callback_event);
	kfree(channel);

	kfree_rcu(channel, rcu);
}

static void percpu_channel_enq(void *arg)
@@ -359,14 +360,14 @@ static void percpu_channel_enq(void *arg)
	struct hv_per_cpu_context *hv_cpu
		= this_cpu_ptr(hv_context.cpu_context);

	list_add_tail(&channel->percpu_list, &hv_cpu->chan_list);
	list_add_tail_rcu(&channel->percpu_list, &hv_cpu->chan_list);
}

static void percpu_channel_deq(void *arg)
{
	struct vmbus_channel *channel = arg;

	list_del(&channel->percpu_list);
	list_del_rcu(&channel->percpu_list);
}


+5 −1
Original line number Diff line number Diff line
@@ -939,8 +939,10 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
		if (relid == 0)
			continue;

		rcu_read_lock();

		/* Find channel based on relid */
		list_for_each_entry(channel, &hv_cpu->chan_list, percpu_list) {
		list_for_each_entry_rcu(channel, &hv_cpu->chan_list, percpu_list) {
			if (channel->offermsg.child_relid != relid)
				continue;

@@ -956,6 +958,8 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
				tasklet_schedule(&channel->callback_event);
			}
		}

		rcu_read_unlock();
	}
}

+7 −0
Original line number Diff line number Diff line
@@ -845,6 +845,13 @@ struct vmbus_channel {
	 * link up channels based on their CPU affinity.
	 */
	struct list_head percpu_list;

	/*
	 * Defer freeing channel until after all cpu's have
	 * gone through grace period.
	 */
	struct rcu_head rcu;

	/*
	 * For performance critical channels (storage, networking
	 * etc,), Hyper-V has a mechanism to enhance the throughput