Commit 411aba3c authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'hyperv-fixes-signed' of...

Merge tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux into char-misc-linus

Sasha writes:

Three bug fixes for different parts of the hyper-v code:

 - Fix for a lockup when changing NIC's MTU from Dexuan.
 - Fix of use of uninitialized memory from Dexuan.
 - Fix for memory corruption caused by ballooning from Vitaly.

All 3 were tested internally.

* tag 'hyperv-fixes-signed' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux:
  vmbus: fix subchannel removal
  hv_balloon: avoid touching uninitialized struct page during tail onlining
  Drivers: hv: vmbus: Check for ring when getting debug info
parents 36bdf3ca b5679ceb
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -701,19 +701,12 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
int vmbus_disconnect_ring(struct vmbus_channel *channel)
{
	struct vmbus_channel *cur_channel, *tmp;
	unsigned long flags;
	LIST_HEAD(list);
	int ret;

	if (channel->primary_channel != NULL)
		return -EINVAL;

	/* Snapshot the list of subchannels */
	spin_lock_irqsave(&channel->lock, flags);
	list_splice_init(&channel->sc_list, &list);
	spin_unlock_irqrestore(&channel->lock, flags);

	list_for_each_entry_safe(cur_channel, tmp, &list, sc_list) {
	list_for_each_entry_safe(cur_channel, tmp, &channel->sc_list, sc_list) {
		if (cur_channel->rescind)
			wait_for_completion(&cur_channel->rescind_event);

+6 −4
Original line number Diff line number Diff line
@@ -888,12 +888,14 @@ static unsigned long handle_pg_range(unsigned long pg_start,
			pfn_cnt -= pgs_ol;
			/*
			 * Check if the corresponding memory block is already
			 * online by checking its last previously backed page.
			 * In case it is we need to bring rest (which was not
			 * backed previously) online too.
			 * online. It is possible to observe struct pages still
			 * being uninitialized here so check section instead.
			 * In case the section is online we need to bring the
			 * rest of pfns (which were not backed previously)
			 * online too.
			 */
			if (start_pfn > has->start_pfn &&
			    !PageReserved(pfn_to_page(start_pfn - 1)))
			    online_section_nr(pfn_to_section_nr(start_pfn)))
				hv_bring_pgs_online(has, start_pfn, pgs_ol);

		}
+15 −16
Original line number Diff line number Diff line
@@ -164,26 +164,25 @@ hv_get_ringbuffer_availbytes(const struct hv_ring_buffer_info *rbi,
}

/* Get various debug metrics for the specified ring buffer. */
void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
				struct hv_ring_buffer_debug_info *debug_info)
{
	u32 bytes_avail_towrite;
	u32 bytes_avail_toread;

	if (ring_info->ring_buffer) {
	if (!ring_info->ring_buffer)
		return -EINVAL;

	hv_get_ringbuffer_availbytes(ring_info,
				     &bytes_avail_toread,
				     &bytes_avail_towrite);

	debug_info->bytes_avail_toread = bytes_avail_toread;
	debug_info->bytes_avail_towrite = bytes_avail_towrite;
		debug_info->current_read_index =
			ring_info->ring_buffer->read_index;
		debug_info->current_write_index =
			ring_info->ring_buffer->write_index;
		debug_info->current_interrupt_mask =
			ring_info->ring_buffer->interrupt_mask;
	}
	debug_info->current_read_index = ring_info->ring_buffer->read_index;
	debug_info->current_write_index = ring_info->ring_buffer->write_index;
	debug_info->current_interrupt_mask
		= ring_info->ring_buffer->interrupt_mask;
	return 0;
}
EXPORT_SYMBOL_GPL(hv_ringbuffer_get_debuginfo);

+61 −30
Original line number Diff line number Diff line
@@ -313,12 +313,16 @@ static ssize_t out_intr_mask_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info outbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
					  &outbound);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%d\n", outbound.current_interrupt_mask);
}
static DEVICE_ATTR_RO(out_intr_mask);
@@ -328,12 +332,15 @@ static ssize_t out_read_index_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info outbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
					  &outbound);
	if (ret < 0)
		return ret;
	return sprintf(buf, "%d\n", outbound.current_read_index);
}
static DEVICE_ATTR_RO(out_read_index);
@@ -344,12 +351,15 @@ static ssize_t out_write_index_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info outbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
					  &outbound);
	if (ret < 0)
		return ret;
	return sprintf(buf, "%d\n", outbound.current_write_index);
}
static DEVICE_ATTR_RO(out_write_index);
@@ -360,12 +370,15 @@ static ssize_t out_read_bytes_avail_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info outbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
					  &outbound);
	if (ret < 0)
		return ret;
	return sprintf(buf, "%d\n", outbound.bytes_avail_toread);
}
static DEVICE_ATTR_RO(out_read_bytes_avail);
@@ -376,12 +389,15 @@ static ssize_t out_write_bytes_avail_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info outbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound, &outbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->outbound,
					  &outbound);
	if (ret < 0)
		return ret;
	return sprintf(buf, "%d\n", outbound.bytes_avail_towrite);
}
static DEVICE_ATTR_RO(out_write_bytes_avail);
@@ -391,12 +407,15 @@ static ssize_t in_intr_mask_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info inbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%d\n", inbound.current_interrupt_mask);
}
static DEVICE_ATTR_RO(in_intr_mask);
@@ -406,12 +425,15 @@ static ssize_t in_read_index_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info inbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%d\n", inbound.current_read_index);
}
static DEVICE_ATTR_RO(in_read_index);
@@ -421,12 +443,15 @@ static ssize_t in_write_index_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info inbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%d\n", inbound.current_write_index);
}
static DEVICE_ATTR_RO(in_write_index);
@@ -437,12 +462,15 @@ static ssize_t in_read_bytes_avail_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info inbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%d\n", inbound.bytes_avail_toread);
}
static DEVICE_ATTR_RO(in_read_bytes_avail);
@@ -453,12 +481,15 @@ static ssize_t in_write_bytes_avail_show(struct device *dev,
{
	struct hv_device *hv_dev = device_to_hv_device(dev);
	struct hv_ring_buffer_debug_info inbound;
	int ret;

	if (!hv_dev->channel)
		return -ENODEV;
	if (hv_dev->channel->state != CHANNEL_OPENED_STATE)
		return -EINVAL;
	hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);

	ret = hv_ringbuffer_get_debuginfo(&hv_dev->channel->inbound, &inbound);
	if (ret < 0)
		return ret;

	return sprintf(buf, "%d\n", inbound.bytes_avail_towrite);
}
static DEVICE_ATTR_RO(in_write_bytes_avail);
+3 −2
Original line number Diff line number Diff line
@@ -1159,7 +1159,8 @@ struct hv_ring_buffer_debug_info {
	u32 bytes_avail_towrite;
};

void hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,

int hv_ringbuffer_get_debuginfo(const struct hv_ring_buffer_info *ring_info,
				struct hv_ring_buffer_debug_info *debug_info);

/* Vmbus interface */