svn commit: r302818 - head/sys/dev/hyperv/vmbus
Sepherosa Ziehau
sephe at FreeBSD.org
Thu Jul 14 07:59:02 UTC 2016
Author: sephe
Date: Thu Jul 14 07:59:01 2016
New Revision: 302818
URL: https://svnweb.freebsd.org/changeset/base/302818
Log:
hyperv/vmbus: Fix the racy channel close.
It is not safe to iterate the sub-channel list w/o lock on the
close path, while it's even more difficult to hold the lock
and iterate the sub-channel list. We leverage the
vmbua_{get,rel}_subchan() functions to solve this dilemma.
MFC after: 1 week
Sponsored by: Microsoft OSTC
Differential Revision: https://reviews.freebsd.org/D7112
Modified:
head/sys/dev/hyperv/vmbus/hv_channel.c
Modified: head/sys/dev/hyperv/vmbus/hv_channel.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel.c Thu Jul 14 07:48:26 2016 (r302817)
+++ head/sys/dev/hyperv/vmbus/hv_channel.c Thu Jul 14 07:59:01 2016 (r302818)
@@ -542,35 +542,40 @@ hv_vmbus_channel_close_internal(hv_vmbus
M_DEVBUF);
}
-/**
- * @brief Close the specified channel
+/*
+ * Caller should make sure that all sub-channels have
+ * been added to 'chan' and all to-be-closed channels
+ * are not being opened.
*/
void
-hv_vmbus_channel_close(hv_vmbus_channel *channel)
+hv_vmbus_channel_close(struct hv_vmbus_channel *chan)
{
- hv_vmbus_channel* sub_channel;
+ int subchan_cnt;
- if (channel->primary_channel != NULL) {
+ if (!VMBUS_CHAN_ISPRIMARY(chan)) {
/*
- * We only close multi-channels when the primary is
- * closed.
+ * Sub-channel is closed when its primary channel
+ * is closed; done.
*/
return;
}
/*
- * Close all multi-channels first.
+ * Close all sub-channels, if any.
*/
- TAILQ_FOREACH(sub_channel, &channel->sc_list_anchor,
- sc_list_entry) {
- if ((sub_channel->ch_stflags & VMBUS_CHAN_ST_OPENED) == 0)
- continue;
- hv_vmbus_channel_close_internal(sub_channel);
+ subchan_cnt = chan->subchan_cnt;
+ if (subchan_cnt > 0) {
+ struct hv_vmbus_channel **subchan;
+ int i;
+
+ subchan = vmbus_get_subchan(chan, subchan_cnt);
+ for (i = 0; i < subchan_cnt; ++i)
+ hv_vmbus_channel_close_internal(subchan[i]);
+ vmbus_rel_subchan(subchan, subchan_cnt);
}
- /*
- * Then close the primary channel.
- */
- hv_vmbus_channel_close_internal(channel);
+
+ /* Then close the primary channel. */
+ hv_vmbus_channel_close_internal(chan);
}
/**
More information about the svn-src-all
mailing list