From e8b7db38449ac5b950a3f00519171c4be3e226ff Mon Sep 17 00:00:00 2001 From: Andres Beltran Date: Mon, 9 Nov 2020 11:04:00 +0100 Subject: Drivers: hv: vmbus: Add vmbus_requestor data structure for VMBus hardening Currently, VMbus drivers use pointers into guest memory as request IDs for interactions with Hyper-V. To be more robust in the face of errors or malicious behavior from a compromised Hyper-V, avoid exposing guest memory addresses to Hyper-V. Also avoid Hyper-V giving back a bad request ID that is then treated as the address of a guest data structure with no validation. Instead, encapsulate these memory addresses and provide small integers as request IDs. Signed-off-by: Andres Beltran Co-developed-by: Andrea Parri (Microsoft) Signed-off-by: Andrea Parri (Microsoft) Reviewed-by: Michael Kelley Reviewed-by: Wei Liu Link: https://lore.kernel.org/r/20201109100402.8946-2-parri.andrea@gmail.com Signed-off-by: Wei Liu --- drivers/hv/channel.c | 174 ++++++++++++++++++++++++++++++++++++++++++++-- drivers/hv/hyperv_vmbus.h | 3 +- drivers/hv/ring_buffer.c | 29 +++++++- 3 files changed, 197 insertions(+), 9 deletions(-) (limited to 'drivers/hv') diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index fbdda9938039..6fb0c76bfbf8 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -503,6 +503,70 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer, } EXPORT_SYMBOL_GPL(vmbus_establish_gpadl); +/** + * request_arr_init - Allocates memory for the requestor array. Each slot + * keeps track of the next available slot in the array. Initially, each + * slot points to the next one (as in a Linked List). The last slot + * does not point to anything, so its value is U64_MAX by default. + * @size The size of the array + */ +static u64 *request_arr_init(u32 size) +{ + int i; + u64 *req_arr; + + req_arr = kcalloc(size, sizeof(u64), GFP_KERNEL); + if (!req_arr) + return NULL; + + for (i = 0; i < size - 1; i++) + req_arr[i] = i + 1; + + /* Last slot (no more available slots) */ + req_arr[i] = U64_MAX; + + return req_arr; +} + +/* + * vmbus_alloc_requestor - Initializes @rqstor's fields. + * Index 0 is the first free slot + * @size: Size of the requestor array + */ +static int vmbus_alloc_requestor(struct vmbus_requestor *rqstor, u32 size) +{ + u64 *rqst_arr; + unsigned long *bitmap; + + rqst_arr = request_arr_init(size); + if (!rqst_arr) + return -ENOMEM; + + bitmap = bitmap_zalloc(size, GFP_KERNEL); + if (!bitmap) { + kfree(rqst_arr); + return -ENOMEM; + } + + rqstor->req_arr = rqst_arr; + rqstor->req_bitmap = bitmap; + rqstor->size = size; + rqstor->next_request_id = 0; + spin_lock_init(&rqstor->req_lock); + + return 0; +} + +/* + * vmbus_free_requestor - Frees memory allocated for @rqstor + * @rqstor: Pointer to the requestor struct + */ +static void vmbus_free_requestor(struct vmbus_requestor *rqstor) +{ + kfree(rqstor->req_arr); + bitmap_free(rqstor->req_bitmap); +} + static int __vmbus_open(struct vmbus_channel *newchannel, void *userdata, u32 userdatalen, void (*onchannelcallback)(void *context), void *context) @@ -523,6 +587,12 @@ static int __vmbus_open(struct vmbus_channel *newchannel, if (newchannel->state != CHANNEL_OPEN_STATE) return -EINVAL; + /* Create and init requestor */ + if (newchannel->rqstor_size) { + if (vmbus_alloc_requestor(&newchannel->requestor, newchannel->rqstor_size)) + return -ENOMEM; + } + newchannel->state = CHANNEL_OPENING_STATE; newchannel->onchannel_callback = onchannelcallback; newchannel->channel_callback_context = context; @@ -626,6 +696,7 @@ error_free_gpadl: error_clean_ring: hv_ringbuffer_cleanup(&newchannel->outbound); hv_ringbuffer_cleanup(&newchannel->inbound); + vmbus_free_requestor(&newchannel->requestor); newchannel->state = CHANNEL_OPEN_STATE; return err; } @@ -808,6 +879,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel) channel->ringbuffer_gpadlhandle = 0; } + if (!ret) + vmbus_free_requestor(&channel->requestor); + return ret; } @@ -888,7 +962,7 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, /* in 8-bytes granularity */ desc.offset8 = sizeof(struct vmpacket_descriptor) >> 3; desc.len8 = (u16)(packetlen_aligned >> 3); - desc.trans_id = requestid; + desc.trans_id = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */ bufferlist[0].iov_base = &desc; bufferlist[0].iov_len = sizeof(struct vmpacket_descriptor); @@ -897,7 +971,7 @@ int vmbus_sendpacket(struct vmbus_channel *channel, void *buffer, bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); - return hv_ringbuffer_write(channel, bufferlist, num_vecs); + return hv_ringbuffer_write(channel, bufferlist, num_vecs, requestid); } EXPORT_SYMBOL(vmbus_sendpacket); @@ -939,7 +1013,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, desc.flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; desc.dataoffset8 = descsize >> 3; /* in 8-bytes granularity */ desc.length8 = (u16)(packetlen_aligned >> 3); - desc.transactionid = requestid; + desc.transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */ desc.reserved = 0; desc.rangecount = pagecount; @@ -956,7 +1030,7 @@ int vmbus_sendpacket_pagebuffer(struct vmbus_channel *channel, bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); - return hv_ringbuffer_write(channel, bufferlist, 3); + return hv_ringbuffer_write(channel, bufferlist, 3, requestid); } EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer); @@ -983,7 +1057,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED; desc->dataoffset8 = desc_size >> 3; /* in 8-bytes granularity */ desc->length8 = (u16)(packetlen_aligned >> 3); - desc->transactionid = requestid; + desc->transactionid = VMBUS_RQST_ERROR; /* will be updated in hv_ringbuffer_write() */ desc->reserved = 0; desc->rangecount = 1; @@ -994,7 +1068,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel, bufferlist[2].iov_base = &aligned_data; bufferlist[2].iov_len = (packetlen_aligned - packetlen); - return hv_ringbuffer_write(channel, bufferlist, 3); + return hv_ringbuffer_write(channel, bufferlist, 3, requestid); } EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc); @@ -1042,3 +1116,91 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, buffer_actual_len, requestid, true); } EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); + +/* + * vmbus_next_request_id - Returns a new request id. It is also + * the index at which the guest memory address is stored. + * Uses a spin lock to avoid race conditions. + * @rqstor: Pointer to the requestor struct + * @rqst_add: Guest memory address to be stored in the array + */ +u64 vmbus_next_request_id(struct vmbus_requestor *rqstor, u64 rqst_addr) +{ + unsigned long flags; + u64 current_id; + const struct vmbus_channel *channel = + container_of(rqstor, const struct vmbus_channel, requestor); + + /* Check rqstor has been initialized */ + if (!channel->rqstor_size) + return VMBUS_NO_RQSTOR; + + spin_lock_irqsave(&rqstor->req_lock, flags); + current_id = rqstor->next_request_id; + + /* Requestor array is full */ + if (current_id >= rqstor->size) { + spin_unlock_irqrestore(&rqstor->req_lock, flags); + return VMBUS_RQST_ERROR; + } + + rqstor->next_request_id = rqstor->req_arr[current_id]; + rqstor->req_arr[current_id] = rqst_addr; + + /* The already held spin lock provides atomicity */ + bitmap_set(rqstor->req_bitmap, current_id, 1); + + spin_unlock_irqrestore(&rqstor->req_lock, flags); + + /* + * Cannot return an ID of 0, which is reserved for an unsolicited + * message from Hyper-V. + */ + return current_id + 1; +} +EXPORT_SYMBOL_GPL(vmbus_next_request_id); + +/* + * vmbus_request_addr - Returns the memory address stored at @trans_id + * in @rqstor. Uses a spin lock to avoid race conditions. + * @rqstor: Pointer to the requestor struct + * @trans_id: Request id sent back from Hyper-V. Becomes the requestor's + * next request id. + */ +u64 vmbus_request_addr(struct vmbus_requestor *rqstor, u64 trans_id) +{ + unsigned long flags; + u64 req_addr; + const struct vmbus_channel *channel = + container_of(rqstor, const struct vmbus_channel, requestor); + + /* Check rqstor has been initialized */ + if (!channel->rqstor_size) + return VMBUS_NO_RQSTOR; + + /* Hyper-V can send an unsolicited message with ID of 0 */ + if (!trans_id) + return trans_id; + + spin_lock_irqsave(&rqstor->req_lock, flags); + + /* Data corresponding to trans_id is stored at trans_id - 1 */ + trans_id--; + + /* Invalid trans_id */ + if (trans_id >= rqstor->size || !test_bit(trans_id, rqstor->req_bitmap)) { + spin_unlock_irqrestore(&rqstor->req_lock, flags); + return VMBUS_RQST_ERROR; + } + + req_addr = rqstor->req_arr[trans_id]; + rqstor->req_arr[trans_id] = rqstor->next_request_id; + rqstor->next_request_id = trans_id; + + /* The already held spin lock provides atomicity */ + bitmap_clear(rqstor->req_bitmap, trans_id, 1); + + spin_unlock_irqrestore(&rqstor->req_lock, flags); + return req_addr; +} +EXPORT_SYMBOL_GPL(vmbus_request_addr); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 40e2b9f91163..02f3e8988836 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -179,7 +179,8 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info); int hv_ringbuffer_write(struct vmbus_channel *channel, - const struct kvec *kv_list, u32 kv_count); + const struct kvec *kv_list, u32 kv_count, + u64 requestid); int hv_ringbuffer_read(struct vmbus_channel *channel, void *buffer, u32 buflen, u32 *buffer_actual_len, diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 356e22159e83..35833d4d1a1d 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -248,7 +248,8 @@ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) /* Write to the ring buffer. */ int hv_ringbuffer_write(struct vmbus_channel *channel, - const struct kvec *kv_list, u32 kv_count) + const struct kvec *kv_list, u32 kv_count, + u64 requestid) { int i; u32 bytes_avail_towrite; @@ -258,6 +259,8 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, u64 prev_indices; unsigned long flags; struct hv_ring_buffer_info *outring_info = &channel->outbound; + struct vmpacket_descriptor *desc = kv_list[0].iov_base; + u64 rqst_id = VMBUS_NO_RQSTOR; if (channel->rescind) return -ENODEV; @@ -300,6 +303,23 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, kv_list[i].iov_len); } + /* + * Allocate the request ID after the data has been copied into the + * ring buffer. Once this request ID is allocated, the completion + * path could find the data and free it. + */ + + if (desc->flags == VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED) { + rqst_id = vmbus_next_request_id(&channel->requestor, requestid); + if (rqst_id == VMBUS_RQST_ERROR) { + spin_unlock_irqrestore(&outring_info->ring_lock, flags); + pr_err("No request id available\n"); + return -EAGAIN; + } + } + desc = hv_get_ring_buffer(outring_info) + old_write; + desc->trans_id = (rqst_id == VMBUS_NO_RQSTOR) ? requestid : rqst_id; + /* Set previous packet start */ prev_indices = hv_get_ring_bufferindices(outring_info); @@ -319,8 +339,13 @@ int hv_ringbuffer_write(struct vmbus_channel *channel, hv_signal_on_write(old_write, channel); - if (channel->rescind) + if (channel->rescind) { + if (rqst_id != VMBUS_NO_RQSTOR) { + /* Reclaim request ID to avoid leak of IDs */ + vmbus_request_addr(&channel->requestor, rqst_id); + } return -ENODEV; + } return 0; } -- cgit v1.2.3 From b18e3589722c864576a3dbeb742a742d9453f633 Mon Sep 17 00:00:00 2001 From: Matheus Castello Date: Sun, 15 Nov 2020 16:57:29 -0300 Subject: drivers: hv: Fix hyperv_record_panic_msg path on comment Fix the kernel parameter path in the comment, in the documentation the parameter is correct but if someone who is studying the code and see this first can get confused and try to access the wrong path/parameter Signed-off-by: Matheus Castello Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20201115195734.8338-2-matheus@castello.eng.br Signed-off-by: Wei Liu --- drivers/hv/vmbus_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hv') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 4fad3e6745e5..9ed7e3b1d654 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -55,7 +55,7 @@ int vmbus_interrupt; /* * Boolean to control whether to report panic messages over Hyper-V. * - * It can be set via /proc/sys/kernel/hyperv/record_panic_msg + * It can be set via /proc/sys/kernel/hyperv_record_panic_msg */ static int sysctl_record_panic_msg = 1; -- cgit v1.2.3 From f0434de41adc2c6dabfaa2f59882f1ca2d644fe9 Mon Sep 17 00:00:00 2001 From: Matheus Castello Date: Sun, 15 Nov 2020 16:57:30 -0300 Subject: drivers: hv: vmbus: Replace symbolic permissions by octal permissions This fixed the below checkpatch issue: WARNING: Symbolic permissions 'S_IRUGO' are not preferred. Consider using octal permissions '0444'. Signed-off-by: Matheus Castello Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20201115195734.8338-3-matheus@castello.eng.br Signed-off-by: Wei Liu --- drivers/hv/vmbus_drv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/hv') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 9ed7e3b1d654..52c1407c1849 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1812,7 +1812,7 @@ static ssize_t channel_pending_show(struct vmbus_channel *channel, channel_pending(channel, vmbus_connection.monitor_pages[1])); } -static VMBUS_CHAN_ATTR(pending, S_IRUGO, channel_pending_show, NULL); +static VMBUS_CHAN_ATTR(pending, 0444, channel_pending_show, NULL); static ssize_t channel_latency_show(struct vmbus_channel *channel, char *buf) @@ -1821,19 +1821,19 @@ static ssize_t channel_latency_show(struct vmbus_channel *channel, channel_latency(channel, vmbus_connection.monitor_pages[1])); } -static VMBUS_CHAN_ATTR(latency, S_IRUGO, channel_latency_show, NULL); +static VMBUS_CHAN_ATTR(latency, 0444, channel_latency_show, NULL); static ssize_t channel_interrupts_show(struct vmbus_channel *channel, char *buf) { return sprintf(buf, "%llu\n", channel->interrupts); } -static VMBUS_CHAN_ATTR(interrupts, S_IRUGO, channel_interrupts_show, NULL); +static VMBUS_CHAN_ATTR(interrupts, 0444, channel_interrupts_show, NULL); static ssize_t channel_events_show(struct vmbus_channel *channel, char *buf) { return sprintf(buf, "%llu\n", channel->sig_events); } -static VMBUS_CHAN_ATTR(events, S_IRUGO, channel_events_show, NULL); +static VMBUS_CHAN_ATTR(events, 0444, channel_events_show, NULL); static ssize_t channel_intr_in_full_show(struct vmbus_channel *channel, char *buf) @@ -1872,7 +1872,7 @@ static ssize_t subchannel_monitor_id_show(struct vmbus_channel *channel, { return sprintf(buf, "%u\n", channel->offermsg.monitorid); } -static VMBUS_CHAN_ATTR(monitor_id, S_IRUGO, subchannel_monitor_id_show, NULL); +static VMBUS_CHAN_ATTR(monitor_id, 0444, subchannel_monitor_id_show, NULL); static ssize_t subchannel_id_show(struct vmbus_channel *channel, char *buf) -- cgit v1.2.3 From e4f2212e53c265ed9fb2f5b936b63cd57acb70ff Mon Sep 17 00:00:00 2001 From: Matheus Castello Date: Sun, 15 Nov 2020 16:57:31 -0300 Subject: drivers: hv: vmbus: Fix checkpatch LINE_SPACING Fixed checkpatch warning: Missing a blank line after declarations checkpatch(LINE_SPACING) Signed-off-by: Matheus Castello Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20201115195734.8338-4-matheus@castello.eng.br Signed-off-by: Wei Liu --- drivers/hv/vmbus_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/hv') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 52c1407c1849..61d28c743263 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -156,6 +156,7 @@ static u32 channel_conn_id(struct vmbus_channel *channel, { u8 monitor_group = channel_monitor_group(channel); u8 monitor_offset = channel_monitor_offset(channel); + return monitor_page->parameter[monitor_group][monitor_offset].connectionid.u.id; } @@ -550,6 +551,7 @@ static ssize_t vendor_show(struct device *dev, char *buf) { struct hv_device *hv_dev = device_to_hv_device(dev); + return sprintf(buf, "0x%x\n", hv_dev->vendor_id); } static DEVICE_ATTR_RO(vendor); @@ -559,6 +561,7 @@ static ssize_t device_show(struct device *dev, char *buf) { struct hv_device *hv_dev = device_to_hv_device(dev); + return sprintf(buf, "0x%x\n", hv_dev->device_id); } static DEVICE_ATTR_RO(device); -- cgit v1.2.3 From 14c685d9eb361768bb5ca452b999e43498f15746 Mon Sep 17 00:00:00 2001 From: Matheus Castello Date: Sun, 15 Nov 2020 16:57:34 -0300 Subject: drivers: hv: vmbus: Fix call msleep using < 20ms Fixed checkpatch warning: MSLEEP: msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.rst Signed-off-by: Matheus Castello Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20201115195734.8338-7-matheus@castello.eng.br Signed-off-by: Wei Liu --- drivers/hv/vmbus_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hv') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 61d28c743263..0a2711aa63a1 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -2380,7 +2380,7 @@ static int vmbus_bus_suspend(struct device *dev) * We wait here until the completion of any channel * offers that are currently in progress. */ - msleep(1); + usleep_range(1000, 2000); } mutex_lock(&vmbus_connection.channel_mutex); -- cgit v1.2.3 From b0c03eff79a67aa43f17249dd42fac58e96718dc Mon Sep 17 00:00:00 2001 From: Matheus Castello Date: Wed, 25 Nov 2020 00:29:26 -0300 Subject: drivers: hv: vmbus: Fix checkpatch SPLIT_STRING Checkpatch emits WARNING: quoted string split across lines. To keep the code clean and with the 80 column length indentation the check and registration code for kmsg_dump_register has been transferred to a new function hv_kmsg_dump_register. Signed-off-by: Matheus Castello Reviewed-by: Michael Kelley Link: https://lore.kernel.org/r/20201125032926.17002-1-matheus@castello.eng.br Signed-off-by: Wei Liu --- drivers/hv/vmbus_drv.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) (limited to 'drivers/hv') diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 0a2711aa63a1..502f8cd95f6d 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1387,6 +1387,24 @@ static struct kmsg_dumper hv_kmsg_dumper = { .dump = hv_kmsg_dump, }; +static void hv_kmsg_dump_register(void) +{ + int ret; + + hv_panic_page = hv_alloc_hyperv_zeroed_page(); + if (!hv_panic_page) { + pr_err("Hyper-V: panic message page memory allocation failed\n"); + return; + } + + ret = kmsg_dump_register(&hv_kmsg_dumper); + if (ret) { + pr_err("Hyper-V: kmsg dump register error 0x%x\n", ret); + hv_free_hyperv_page((unsigned long)hv_panic_page); + hv_panic_page = NULL; + } +} + static struct ctl_table_header *hv_ctl_table_hdr; /* @@ -1477,21 +1495,8 @@ static int vmbus_bus_init(void) * capability is supported by the hypervisor. */ hv_get_crash_ctl(hyperv_crash_ctl); - if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) { - hv_panic_page = (void *)hv_alloc_hyperv_zeroed_page(); - if (hv_panic_page) { - ret = kmsg_dump_register(&hv_kmsg_dumper); - if (ret) { - pr_err("Hyper-V: kmsg dump register " - "error 0x%x\n", ret); - hv_free_hyperv_page( - (unsigned long)hv_panic_page); - hv_panic_page = NULL; - } - } else - pr_err("Hyper-V: panic message page memory " - "allocation failed"); - } + if (hyperv_crash_ctl & HV_CRASH_CTL_CRASH_NOTIFY_MSG) + hv_kmsg_dump_register(); register_die_notifier(&hyperv_die_block); } -- cgit v1.2.3 From 5c641fee4ccfd27520b7863bf4a66491faea6d2a Mon Sep 17 00:00:00 2001 From: Stefan Eschenbacher Date: Sun, 6 Dec 2020 11:48:50 +0100 Subject: drivers/hv: remove obsolete TODO and fix misleading typo in comment Removes an obsolete TODO in the VMBus module and fixes a misleading typo in the comment for the macro MAX_NUM_CHANNELS, where two digits have been twisted. Signed-off-by: Stefan Eschenbacher Co-developed-by: Max Stolze Signed-off-by: Max Stolze Link: https://lore.kernel.org/r/20201206104850.24843-1-stefan.eschenbacher@fau.de Signed-off-by: Wei Liu --- drivers/hv/hyperv_vmbus.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/hv') diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 02f3e8988836..9416e09ebd58 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -187,14 +187,13 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, u64 *requestid, bool raw); /* - * The Maximum number of channels (16348) is determined by the size of the + * The Maximum number of channels (16384) is determined by the size of the * interrupt page, which is HV_HYP_PAGE_SIZE. 1/2 of HV_HYP_PAGE_SIZE is to * send endpoint interrupts, and the other is to receive endpoint interrupts. */ #define MAX_NUM_CHANNELS ((HV_HYP_PAGE_SIZE >> 1) << 3) /* The value here must be in multiple of 32 */ -/* TODO: Need to make this configurable */ #define MAX_NUM_CHANNELS_SUPPORTED 256 #define MAX_CHANNEL_RELIDS \ -- cgit v1.2.3 From 7f3f227b41e81f8669e906c49a240c1678c65cfe Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 2 Dec 2020 17:12:44 +0100 Subject: hv_balloon: simplify math in alloc_balloon_pages() 'alloc_unit' in alloc_balloon_pages() is either '512' for 2M allocations or '1' for 4k allocations. So 1 << get_order(alloc_unit << PAGE_SHIFT) equals to 'alloc_unit' and the for loop basically sets all them offline. Simplify the math to improve the readability. Signed-off-by: Vitaly Kuznetsov Reviewed-by: David Hildenbrand Link: https://lore.kernel.org/r/20201202161245.2406143-2-vkuznets@redhat.com Signed-off-by: Wei Liu --- drivers/hv/hv_balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/hv') diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index eb56e09ae15f..da3b6bd2367c 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1238,7 +1238,7 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm, split_page(pg, get_order(alloc_unit << PAGE_SHIFT)); /* mark all pages offline */ - for (j = 0; j < (1 << get_order(alloc_unit << PAGE_SHIFT)); j++) + for (j = 0; j < alloc_unit; j++) __SetPageOffline(pg + j); bl_resp->range_count++; -- cgit v1.2.3 From d1df458cbfdb0c3384c03c7fbcb1689bc02a746c Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Wed, 2 Dec 2020 17:12:45 +0100 Subject: hv_balloon: do adjust_managed_page_count() when ballooning/un-ballooning Unlike virtio_balloon/virtio_mem/xen balloon drivers, Hyper-V balloon driver does not adjust managed pages count when ballooning/un-ballooning and this leads to incorrect stats being reported, e.g. unexpected 'free' output. Note, the calculation in post_status() seems to remain correct: ballooned out pages are never 'available' and we manually add dm->num_pages_ballooned to 'commited'. Suggested-by: David Hildenbrand Signed-off-by: Vitaly Kuznetsov Reviewed-by: David Hildenbrand Link: https://lore.kernel.org/r/20201202161245.2406143-3-vkuznets@redhat.com Signed-off-by: Wei Liu --- drivers/hv/hv_balloon.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/hv') diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c index da3b6bd2367c..8c471823a5af 100644 --- a/drivers/hv/hv_balloon.c +++ b/drivers/hv/hv_balloon.c @@ -1198,6 +1198,7 @@ static void free_balloon_pages(struct hv_dynmem_device *dm, __ClearPageOffline(pg); __free_page(pg); dm->num_pages_ballooned--; + adjust_managed_page_count(pg, 1); } } @@ -1238,8 +1239,10 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm, split_page(pg, get_order(alloc_unit << PAGE_SHIFT)); /* mark all pages offline */ - for (j = 0; j < alloc_unit; j++) + for (j = 0; j < alloc_unit; j++) { __SetPageOffline(pg + j); + adjust_managed_page_count(pg + j, -1); + } bl_resp->range_count++; bl_resp->range_array[i].finfo.start_page = -- cgit v1.2.3