mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
hyperv-fixes for v6.9-rc4
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEIbPD0id6easf0xsudhRwX5BBoF4FAmYYYPkTHHdlaS5saXVA a2VybmVsLm9yZwAKCRB2FHBfkEGgXnxhB/4/8c7lFT53VbujFmVA5sNvpP5Ji5Xg ERhVID7tzDyaVRPr+tpPJIW0Oj/t34SH9seoTYCBCM/UABWe/Gxceg2JaoOzIx+l LHi73T4BBaqExiXbCCFj8N7gLO5P4Xz6ZZRgwHws1KmMXsiWYmYsbv36eSv9x6qK +z/n6p9/ubKFNj2/vsvfiGmY0XHayD3NM4Y4toMbYE/tuRT8uZ7D5sqWdRf+UhW/ goRDA5qppeSfuaQu2LNVoz1e6wRmeJFv8OHgaPvQqAjTRLzPwwss28HICmKc8gh3 HDDUUJCHSs1XItSGDFip6rIFso5X/ZHO0d6pV75hOKCisd7lV0qH6NIZ =k62H -----END PGP SIGNATURE----- Merge tag 'hyperv-fixes-signed-20240411' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux Pull hyperv fixes from Wei Liu: - Some cosmetic changes (Erni Sri Satya Vennela, Li Zhijian) - Introduce hv_numa_node_to_pxm_info() (Nuno Das Neves) - Fix KVP daemon to handle IPv4 and IPv6 combination for keyfile format (Shradha Gupta) - Avoid freeing decrypted memory in a confidential VM (Rick Edgecombe and Michael Kelley) * tag 'hyperv-fixes-signed-20240411' of git://git.kernel.org/pub/scm/linux/kernel/git/hyperv/linux: Drivers: hv: vmbus: Don't free ring buffers that couldn't be re-encrypted uio_hv_generic: Don't free decrypted memory hv_netvsc: Don't free decrypted memory Drivers: hv: vmbus: Track decrypted status in vmbus_gpadl Drivers: hv: vmbus: Leak pages if set_memory_encrypted() fails hv/hv_kvp_daemon: Handle IPv4 and Ipv6 combination for keyfile format hv: vmbus: Convert sprintf() family to sysfs_emit() family mshyperv: Introduce hv_numa_node_to_pxm_info() x86/hyperv: Cosmetic changes for hv_apic.c
This commit is contained in:
commit
52e5070f60
@ -105,7 +105,7 @@ static bool cpu_is_self(int cpu)
|
||||
* IPI implementation on Hyper-V.
|
||||
*/
|
||||
static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector,
|
||||
bool exclude_self)
|
||||
bool exclude_self)
|
||||
{
|
||||
struct hv_send_ipi_ex *ipi_arg;
|
||||
unsigned long flags;
|
||||
@ -132,8 +132,8 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector,
|
||||
if (!cpumask_equal(mask, cpu_present_mask) || exclude_self) {
|
||||
ipi_arg->vp_set.format = HV_GENERIC_SET_SPARSE_4K;
|
||||
|
||||
nr_bank = cpumask_to_vpset_skip(&(ipi_arg->vp_set), mask,
|
||||
exclude_self ? cpu_is_self : NULL);
|
||||
nr_bank = cpumask_to_vpset_skip(&ipi_arg->vp_set, mask,
|
||||
exclude_self ? cpu_is_self : NULL);
|
||||
|
||||
/*
|
||||
* 'nr_bank <= 0' means some CPUs in cpumask can't be
|
||||
@ -147,7 +147,7 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector,
|
||||
}
|
||||
|
||||
status = hv_do_rep_hypercall(HVCALL_SEND_IPI_EX, 0, nr_bank,
|
||||
ipi_arg, NULL);
|
||||
ipi_arg, NULL);
|
||||
|
||||
ipi_mask_ex_done:
|
||||
local_irq_restore(flags);
|
||||
@ -155,7 +155,7 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector,
|
||||
}
|
||||
|
||||
static bool __send_ipi_mask(const struct cpumask *mask, int vector,
|
||||
bool exclude_self)
|
||||
bool exclude_self)
|
||||
{
|
||||
int cur_cpu, vcpu, this_cpu = smp_processor_id();
|
||||
struct hv_send_ipi ipi_arg;
|
||||
@ -181,7 +181,7 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector,
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
|
||||
if (vector < HV_IPI_LOW_VECTOR || vector > HV_IPI_HIGH_VECTOR)
|
||||
return false;
|
||||
|
||||
/*
|
||||
@ -218,7 +218,7 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector,
|
||||
}
|
||||
|
||||
status = hv_do_fast_hypercall16(HVCALL_SEND_IPI, ipi_arg.vector,
|
||||
ipi_arg.cpu_mask);
|
||||
ipi_arg.cpu_mask);
|
||||
return hv_result_success(status);
|
||||
|
||||
do_ex_hypercall:
|
||||
@ -241,7 +241,7 @@ static bool __send_ipi_one(int cpu, int vector)
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((vector < HV_IPI_LOW_VECTOR) || (vector > HV_IPI_HIGH_VECTOR))
|
||||
if (vector < HV_IPI_LOW_VECTOR || vector > HV_IPI_HIGH_VECTOR)
|
||||
return false;
|
||||
|
||||
if (vp >= 64)
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/hyperv.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/cpuhotplug.h>
|
||||
@ -116,12 +115,11 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages)
|
||||
|
||||
int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
|
||||
{
|
||||
struct hv_add_logical_processor_in *input;
|
||||
struct hv_add_logical_processor_out *output;
|
||||
struct hv_input_add_logical_processor *input;
|
||||
struct hv_output_add_logical_processor *output;
|
||||
u64 status;
|
||||
unsigned long flags;
|
||||
int ret = HV_STATUS_SUCCESS;
|
||||
int pxm = node_to_pxm(node);
|
||||
|
||||
/*
|
||||
* When adding a logical processor, the hypervisor may return
|
||||
@ -137,11 +135,7 @@ int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
|
||||
|
||||
input->lp_index = lp_index;
|
||||
input->apic_id = apic_id;
|
||||
input->flags = 0;
|
||||
input->proximity_domain_info.domain_id = pxm;
|
||||
input->proximity_domain_info.flags.reserved = 0;
|
||||
input->proximity_domain_info.flags.proximity_info_valid = 1;
|
||||
input->proximity_domain_info.flags.proximity_preferred = 1;
|
||||
input->proximity_domain_info = hv_numa_node_to_pxm_info(node);
|
||||
status = hv_do_hypercall(HVCALL_ADD_LOGICAL_PROCESSOR,
|
||||
input, output);
|
||||
local_irq_restore(flags);
|
||||
@ -166,7 +160,6 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
|
||||
u64 status;
|
||||
unsigned long irq_flags;
|
||||
int ret = HV_STATUS_SUCCESS;
|
||||
int pxm = node_to_pxm(node);
|
||||
|
||||
/* Root VPs don't seem to need pages deposited */
|
||||
if (partition_id != hv_current_partition_id) {
|
||||
@ -185,14 +178,7 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
|
||||
input->vp_index = vp_index;
|
||||
input->flags = flags;
|
||||
input->subnode_type = HvSubnodeAny;
|
||||
if (node != NUMA_NO_NODE) {
|
||||
input->proximity_domain_info.domain_id = pxm;
|
||||
input->proximity_domain_info.flags.reserved = 0;
|
||||
input->proximity_domain_info.flags.proximity_info_valid = 1;
|
||||
input->proximity_domain_info.flags.proximity_preferred = 1;
|
||||
} else {
|
||||
input->proximity_domain_info.as_uint64 = 0;
|
||||
}
|
||||
input->proximity_domain_info = hv_numa_node_to_pxm_info(node);
|
||||
status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL);
|
||||
local_irq_restore(irq_flags);
|
||||
|
||||
|
@ -153,7 +153,9 @@ void vmbus_free_ring(struct vmbus_channel *channel)
|
||||
hv_ringbuffer_cleanup(&channel->inbound);
|
||||
|
||||
if (channel->ringbuffer_page) {
|
||||
__free_pages(channel->ringbuffer_page,
|
||||
/* In a CoCo VM leak the memory if it didn't get re-encrypted */
|
||||
if (!channel->ringbuffer_gpadlhandle.decrypted)
|
||||
__free_pages(channel->ringbuffer_page,
|
||||
get_order(channel->ringbuffer_pagecount
|
||||
<< PAGE_SHIFT));
|
||||
channel->ringbuffer_page = NULL;
|
||||
@ -436,9 +438,18 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
|
||||
(atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
|
||||
|
||||
ret = create_gpadl_header(type, kbuffer, size, send_offset, &msginfo);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
gpadl->decrypted = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the "decrypted" flag to true for the set_memory_decrypted()
|
||||
* success case. In the failure case, the encryption state of the
|
||||
* memory is unknown. Leave "decrypted" as true to ensure the
|
||||
* memory will be leaked instead of going back on the free list.
|
||||
*/
|
||||
gpadl->decrypted = true;
|
||||
ret = set_memory_decrypted((unsigned long)kbuffer,
|
||||
PFN_UP(size));
|
||||
if (ret) {
|
||||
@ -527,9 +538,15 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
|
||||
|
||||
kfree(msginfo);
|
||||
|
||||
if (ret)
|
||||
set_memory_encrypted((unsigned long)kbuffer,
|
||||
PFN_UP(size));
|
||||
if (ret) {
|
||||
/*
|
||||
* If set_memory_encrypted() fails, the decrypted flag is
|
||||
* left as true so the memory is leaked instead of being
|
||||
* put back on the free list.
|
||||
*/
|
||||
if (!set_memory_encrypted((unsigned long)kbuffer, PFN_UP(size)))
|
||||
gpadl->decrypted = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -850,6 +867,8 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, struct vmbus_gpadl *gpad
|
||||
if (ret)
|
||||
pr_warn("Fail to set mem host visibility in GPADL teardown %d.\n", ret);
|
||||
|
||||
gpadl->decrypted = ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
|
||||
|
@ -237,8 +237,17 @@ int vmbus_connect(void)
|
||||
vmbus_connection.monitor_pages[0], 1);
|
||||
ret |= set_memory_decrypted((unsigned long)
|
||||
vmbus_connection.monitor_pages[1], 1);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
/*
|
||||
* If set_memory_decrypted() fails, the encryption state
|
||||
* of the memory is unknown. So leak the memory instead
|
||||
* of risking returning decrypted memory to the free list.
|
||||
* For simplicity, always handle both pages the same.
|
||||
*/
|
||||
vmbus_connection.monitor_pages[0] = NULL;
|
||||
vmbus_connection.monitor_pages[1] = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set_memory_decrypted() will change the memory contents if
|
||||
@ -337,13 +346,19 @@ void vmbus_disconnect(void)
|
||||
vmbus_connection.int_page = NULL;
|
||||
}
|
||||
|
||||
set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[0], 1);
|
||||
set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[1], 1);
|
||||
if (vmbus_connection.monitor_pages[0]) {
|
||||
if (!set_memory_encrypted(
|
||||
(unsigned long)vmbus_connection.monitor_pages[0], 1))
|
||||
hv_free_hyperv_page(vmbus_connection.monitor_pages[0]);
|
||||
vmbus_connection.monitor_pages[0] = NULL;
|
||||
}
|
||||
|
||||
hv_free_hyperv_page(vmbus_connection.monitor_pages[0]);
|
||||
hv_free_hyperv_page(vmbus_connection.monitor_pages[1]);
|
||||
vmbus_connection.monitor_pages[0] = NULL;
|
||||
vmbus_connection.monitor_pages[1] = NULL;
|
||||
if (vmbus_connection.monitor_pages[1]) {
|
||||
if (!set_memory_encrypted(
|
||||
(unsigned long)vmbus_connection.monitor_pages[1], 1))
|
||||
hv_free_hyperv_page(vmbus_connection.monitor_pages[1]);
|
||||
vmbus_connection.monitor_pages[1] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -131,7 +131,7 @@ static ssize_t id_show(struct device *dev, struct device_attribute *dev_attr,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n", hv_dev->channel->offermsg.child_relid);
|
||||
return sysfs_emit(buf, "%d\n", hv_dev->channel->offermsg.child_relid);
|
||||
}
|
||||
static DEVICE_ATTR_RO(id);
|
||||
|
||||
@ -142,7 +142,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *dev_attr,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n", hv_dev->channel->state);
|
||||
return sysfs_emit(buf, "%d\n", hv_dev->channel->state);
|
||||
}
|
||||
static DEVICE_ATTR_RO(state);
|
||||
|
||||
@ -153,7 +153,7 @@ static ssize_t monitor_id_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n", hv_dev->channel->offermsg.monitorid);
|
||||
return sysfs_emit(buf, "%d\n", hv_dev->channel->offermsg.monitorid);
|
||||
}
|
||||
static DEVICE_ATTR_RO(monitor_id);
|
||||
|
||||
@ -164,8 +164,8 @@ static ssize_t class_id_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "{%pUl}\n",
|
||||
&hv_dev->channel->offermsg.offer.if_type);
|
||||
return sysfs_emit(buf, "{%pUl}\n",
|
||||
&hv_dev->channel->offermsg.offer.if_type);
|
||||
}
|
||||
static DEVICE_ATTR_RO(class_id);
|
||||
|
||||
@ -176,8 +176,8 @@ static ssize_t device_id_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "{%pUl}\n",
|
||||
&hv_dev->channel->offermsg.offer.if_instance);
|
||||
return sysfs_emit(buf, "{%pUl}\n",
|
||||
&hv_dev->channel->offermsg.offer.if_instance);
|
||||
}
|
||||
static DEVICE_ATTR_RO(device_id);
|
||||
|
||||
@ -186,7 +186,7 @@ static ssize_t modalias_show(struct device *dev,
|
||||
{
|
||||
struct hv_device *hv_dev = device_to_hv_device(dev);
|
||||
|
||||
return sprintf(buf, "vmbus:%*phN\n", UUID_SIZE, &hv_dev->dev_type);
|
||||
return sysfs_emit(buf, "vmbus:%*phN\n", UUID_SIZE, &hv_dev->dev_type);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
@ -199,7 +199,7 @@ static ssize_t numa_node_show(struct device *dev,
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
|
||||
return sprintf(buf, "%d\n", cpu_to_node(hv_dev->channel->target_cpu));
|
||||
return sysfs_emit(buf, "%d\n", cpu_to_node(hv_dev->channel->target_cpu));
|
||||
}
|
||||
static DEVICE_ATTR_RO(numa_node);
|
||||
#endif
|
||||
@ -212,9 +212,8 @@ static ssize_t server_monitor_pending_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n",
|
||||
channel_pending(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[0]));
|
||||
return sysfs_emit(buf, "%d\n", channel_pending(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[0]));
|
||||
}
|
||||
static DEVICE_ATTR_RO(server_monitor_pending);
|
||||
|
||||
@ -226,9 +225,8 @@ static ssize_t client_monitor_pending_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n",
|
||||
channel_pending(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[1]));
|
||||
return sysfs_emit(buf, "%d\n", channel_pending(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[1]));
|
||||
}
|
||||
static DEVICE_ATTR_RO(client_monitor_pending);
|
||||
|
||||
@ -240,9 +238,8 @@ static ssize_t server_monitor_latency_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n",
|
||||
channel_latency(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[0]));
|
||||
return sysfs_emit(buf, "%d\n", channel_latency(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[0]));
|
||||
}
|
||||
static DEVICE_ATTR_RO(server_monitor_latency);
|
||||
|
||||
@ -254,9 +251,8 @@ static ssize_t client_monitor_latency_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n",
|
||||
channel_latency(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[1]));
|
||||
return sysfs_emit(buf, "%d\n", channel_latency(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[1]));
|
||||
}
|
||||
static DEVICE_ATTR_RO(client_monitor_latency);
|
||||
|
||||
@ -268,9 +264,8 @@ static ssize_t server_monitor_conn_id_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n",
|
||||
channel_conn_id(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[0]));
|
||||
return sysfs_emit(buf, "%d\n", channel_conn_id(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[0]));
|
||||
}
|
||||
static DEVICE_ATTR_RO(server_monitor_conn_id);
|
||||
|
||||
@ -282,9 +277,8 @@ static ssize_t client_monitor_conn_id_show(struct device *dev,
|
||||
|
||||
if (!hv_dev->channel)
|
||||
return -ENODEV;
|
||||
return sprintf(buf, "%d\n",
|
||||
channel_conn_id(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[1]));
|
||||
return sysfs_emit(buf, "%d\n", channel_conn_id(hv_dev->channel,
|
||||
vmbus_connection.monitor_pages[1]));
|
||||
}
|
||||
static DEVICE_ATTR_RO(client_monitor_conn_id);
|
||||
|
||||
@ -303,7 +297,7 @@ static ssize_t out_intr_mask_show(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", outbound.current_interrupt_mask);
|
||||
return sysfs_emit(buf, "%d\n", outbound.current_interrupt_mask);
|
||||
}
|
||||
static DEVICE_ATTR_RO(out_intr_mask);
|
||||
|
||||
@ -321,7 +315,7 @@ static ssize_t out_read_index_show(struct device *dev,
|
||||
&outbound);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", outbound.current_read_index);
|
||||
return sysfs_emit(buf, "%d\n", outbound.current_read_index);
|
||||
}
|
||||
static DEVICE_ATTR_RO(out_read_index);
|
||||
|
||||
@ -340,7 +334,7 @@ static ssize_t out_write_index_show(struct device *dev,
|
||||
&outbound);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", outbound.current_write_index);
|
||||
return sysfs_emit(buf, "%d\n", outbound.current_write_index);
|
||||
}
|
||||
static DEVICE_ATTR_RO(out_write_index);
|
||||
|
||||
@ -359,7 +353,7 @@ static ssize_t out_read_bytes_avail_show(struct device *dev,
|
||||
&outbound);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", outbound.bytes_avail_toread);
|
||||
return sysfs_emit(buf, "%d\n", outbound.bytes_avail_toread);
|
||||
}
|
||||
static DEVICE_ATTR_RO(out_read_bytes_avail);
|
||||
|
||||
@ -378,7 +372,7 @@ static ssize_t out_write_bytes_avail_show(struct device *dev,
|
||||
&outbound);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return sprintf(buf, "%d\n", outbound.bytes_avail_towrite);
|
||||
return sysfs_emit(buf, "%d\n", outbound.bytes_avail_towrite);
|
||||
}
|
||||
static DEVICE_ATTR_RO(out_write_bytes_avail);
|
||||
|
||||
@ -396,7 +390,7 @@ static ssize_t in_intr_mask_show(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", inbound.current_interrupt_mask);
|
||||
return sysfs_emit(buf, "%d\n", inbound.current_interrupt_mask);
|
||||
}
|
||||
static DEVICE_ATTR_RO(in_intr_mask);
|
||||
|
||||
@ -414,7 +408,7 @@ static ssize_t in_read_index_show(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", inbound.current_read_index);
|
||||
return sysfs_emit(buf, "%d\n", inbound.current_read_index);
|
||||
}
|
||||
static DEVICE_ATTR_RO(in_read_index);
|
||||
|
||||
@ -432,7 +426,7 @@ static ssize_t in_write_index_show(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", inbound.current_write_index);
|
||||
return sysfs_emit(buf, "%d\n", inbound.current_write_index);
|
||||
}
|
||||
static DEVICE_ATTR_RO(in_write_index);
|
||||
|
||||
@ -451,7 +445,7 @@ static ssize_t in_read_bytes_avail_show(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", inbound.bytes_avail_toread);
|
||||
return sysfs_emit(buf, "%d\n", inbound.bytes_avail_toread);
|
||||
}
|
||||
static DEVICE_ATTR_RO(in_read_bytes_avail);
|
||||
|
||||
@ -470,7 +464,7 @@ static ssize_t in_write_bytes_avail_show(struct device *dev,
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", inbound.bytes_avail_towrite);
|
||||
return sysfs_emit(buf, "%d\n", inbound.bytes_avail_towrite);
|
||||
}
|
||||
static DEVICE_ATTR_RO(in_write_bytes_avail);
|
||||
|
||||
@ -480,7 +474,7 @@ static ssize_t channel_vp_mapping_show(struct device *dev,
|
||||
{
|
||||
struct hv_device *hv_dev = device_to_hv_device(dev);
|
||||
struct vmbus_channel *channel = hv_dev->channel, *cur_sc;
|
||||
int buf_size = PAGE_SIZE, n_written, tot_written;
|
||||
int n_written;
|
||||
struct list_head *cur;
|
||||
|
||||
if (!channel)
|
||||
@ -488,25 +482,21 @@ static ssize_t channel_vp_mapping_show(struct device *dev,
|
||||
|
||||
mutex_lock(&vmbus_connection.channel_mutex);
|
||||
|
||||
tot_written = snprintf(buf, buf_size, "%u:%u\n",
|
||||
channel->offermsg.child_relid, channel->target_cpu);
|
||||
n_written = sysfs_emit(buf, "%u:%u\n",
|
||||
channel->offermsg.child_relid,
|
||||
channel->target_cpu);
|
||||
|
||||
list_for_each(cur, &channel->sc_list) {
|
||||
if (tot_written >= buf_size - 1)
|
||||
break;
|
||||
|
||||
cur_sc = list_entry(cur, struct vmbus_channel, sc_list);
|
||||
n_written = scnprintf(buf + tot_written,
|
||||
buf_size - tot_written,
|
||||
"%u:%u\n",
|
||||
cur_sc->offermsg.child_relid,
|
||||
cur_sc->target_cpu);
|
||||
tot_written += n_written;
|
||||
n_written += sysfs_emit_at(buf, n_written, "%u:%u\n",
|
||||
cur_sc->offermsg.child_relid,
|
||||
cur_sc->target_cpu);
|
||||
}
|
||||
|
||||
mutex_unlock(&vmbus_connection.channel_mutex);
|
||||
|
||||
return tot_written;
|
||||
return n_written;
|
||||
}
|
||||
static DEVICE_ATTR_RO(channel_vp_mapping);
|
||||
|
||||
@ -516,7 +506,7 @@ static ssize_t vendor_show(struct device *dev,
|
||||
{
|
||||
struct hv_device *hv_dev = device_to_hv_device(dev);
|
||||
|
||||
return sprintf(buf, "0x%x\n", hv_dev->vendor_id);
|
||||
return sysfs_emit(buf, "0x%x\n", hv_dev->vendor_id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(vendor);
|
||||
|
||||
@ -526,7 +516,7 @@ static ssize_t device_show(struct device *dev,
|
||||
{
|
||||
struct hv_device *hv_dev = device_to_hv_device(dev);
|
||||
|
||||
return sprintf(buf, "0x%x\n", hv_dev->device_id);
|
||||
return sysfs_emit(buf, "0x%x\n", hv_dev->device_id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(device);
|
||||
|
||||
@ -551,7 +541,7 @@ static ssize_t driver_override_show(struct device *dev,
|
||||
ssize_t len;
|
||||
|
||||
device_lock(dev);
|
||||
len = snprintf(buf, PAGE_SIZE, "%s\n", hv_dev->driver_override);
|
||||
len = sysfs_emit(buf, "%s\n", hv_dev->driver_override);
|
||||
device_unlock(dev);
|
||||
|
||||
return len;
|
||||
|
@ -154,8 +154,11 @@ static void free_netvsc_device(struct rcu_head *head)
|
||||
int i;
|
||||
|
||||
kfree(nvdev->extension);
|
||||
vfree(nvdev->recv_buf);
|
||||
vfree(nvdev->send_buf);
|
||||
|
||||
if (!nvdev->recv_buf_gpadl_handle.decrypted)
|
||||
vfree(nvdev->recv_buf);
|
||||
if (!nvdev->send_buf_gpadl_handle.decrypted)
|
||||
vfree(nvdev->send_buf);
|
||||
bitmap_free(nvdev->send_section_map);
|
||||
|
||||
for (i = 0; i < VRSS_CHANNEL_MAX; i++) {
|
||||
|
@ -181,12 +181,14 @@ hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
|
||||
{
|
||||
if (pdata->send_gpadl.gpadl_handle) {
|
||||
vmbus_teardown_gpadl(dev->channel, &pdata->send_gpadl);
|
||||
vfree(pdata->send_buf);
|
||||
if (!pdata->send_gpadl.decrypted)
|
||||
vfree(pdata->send_buf);
|
||||
}
|
||||
|
||||
if (pdata->recv_gpadl.gpadl_handle) {
|
||||
vmbus_teardown_gpadl(dev->channel, &pdata->recv_gpadl);
|
||||
vfree(pdata->recv_buf);
|
||||
if (!pdata->recv_gpadl.decrypted)
|
||||
vfree(pdata->recv_buf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,7 +297,8 @@ hv_uio_probe(struct hv_device *dev,
|
||||
ret = vmbus_establish_gpadl(channel, pdata->recv_buf,
|
||||
RECV_BUFFER_SIZE, &pdata->recv_gpadl);
|
||||
if (ret) {
|
||||
vfree(pdata->recv_buf);
|
||||
if (!pdata->recv_gpadl.decrypted)
|
||||
vfree(pdata->recv_buf);
|
||||
goto fail_close;
|
||||
}
|
||||
|
||||
@ -317,7 +320,8 @@ hv_uio_probe(struct hv_device *dev,
|
||||
ret = vmbus_establish_gpadl(channel, pdata->send_buf,
|
||||
SEND_BUFFER_SIZE, &pdata->send_gpadl);
|
||||
if (ret) {
|
||||
vfree(pdata->send_buf);
|
||||
if (!pdata->send_gpadl.decrypted)
|
||||
vfree(pdata->send_buf);
|
||||
goto fail_close;
|
||||
}
|
||||
|
||||
|
@ -512,13 +512,9 @@ struct hv_proximity_domain_flags {
|
||||
u32 proximity_info_valid : 1;
|
||||
} __packed;
|
||||
|
||||
/* Not a union in windows but useful for zeroing */
|
||||
union hv_proximity_domain_info {
|
||||
struct {
|
||||
u32 domain_id;
|
||||
struct hv_proximity_domain_flags flags;
|
||||
};
|
||||
u64 as_uint64;
|
||||
struct hv_proximity_domain_info {
|
||||
u32 domain_id;
|
||||
struct hv_proximity_domain_flags flags;
|
||||
} __packed;
|
||||
|
||||
struct hv_lp_startup_status {
|
||||
@ -532,14 +528,13 @@ struct hv_lp_startup_status {
|
||||
} __packed;
|
||||
|
||||
/* HvAddLogicalProcessor hypercall */
|
||||
struct hv_add_logical_processor_in {
|
||||
struct hv_input_add_logical_processor {
|
||||
u32 lp_index;
|
||||
u32 apic_id;
|
||||
union hv_proximity_domain_info proximity_domain_info;
|
||||
u64 flags;
|
||||
struct hv_proximity_domain_info proximity_domain_info;
|
||||
} __packed;
|
||||
|
||||
struct hv_add_logical_processor_out {
|
||||
struct hv_output_add_logical_processor {
|
||||
struct hv_lp_startup_status startup_status;
|
||||
} __packed;
|
||||
|
||||
@ -560,7 +555,7 @@ struct hv_create_vp {
|
||||
u8 padding[3];
|
||||
u8 subnode_type;
|
||||
u64 subnode_id;
|
||||
union hv_proximity_domain_info proximity_domain_info;
|
||||
struct hv_proximity_domain_info proximity_domain_info;
|
||||
u64 flags;
|
||||
} __packed;
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <acpi/acpi_numa.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <asm/ptrace.h>
|
||||
@ -67,6 +68,19 @@ extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);
|
||||
bool hv_isolation_type_snp(void);
|
||||
bool hv_isolation_type_tdx(void);
|
||||
|
||||
static inline struct hv_proximity_domain_info hv_numa_node_to_pxm_info(int node)
|
||||
{
|
||||
struct hv_proximity_domain_info pxm_info = {};
|
||||
|
||||
if (node != NUMA_NO_NODE) {
|
||||
pxm_info.domain_id = node_to_pxm(node);
|
||||
pxm_info.flags.proximity_info_valid = 1;
|
||||
pxm_info.flags.proximity_preferred = 1;
|
||||
}
|
||||
|
||||
return pxm_info;
|
||||
}
|
||||
|
||||
/* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */
|
||||
static inline int hv_result(u64 status)
|
||||
{
|
||||
|
@ -832,6 +832,7 @@ struct vmbus_gpadl {
|
||||
u32 gpadl_handle;
|
||||
u32 size;
|
||||
void *buffer;
|
||||
bool decrypted;
|
||||
};
|
||||
|
||||
struct vmbus_channel {
|
||||
|
@ -76,6 +76,12 @@ enum {
|
||||
DNS
|
||||
};
|
||||
|
||||
enum {
|
||||
IPV4 = 1,
|
||||
IPV6,
|
||||
IP_TYPE_MAX
|
||||
};
|
||||
|
||||
static int in_hand_shake;
|
||||
|
||||
static char *os_name = "";
|
||||
@ -102,6 +108,11 @@ static struct utsname uts_buf;
|
||||
|
||||
#define MAX_FILE_NAME 100
|
||||
#define ENTRIES_PER_BLOCK 50
|
||||
/*
|
||||
* Change this entry if the number of addresses increases in future
|
||||
*/
|
||||
#define MAX_IP_ENTRIES 64
|
||||
#define OUTSTR_BUF_SIZE ((INET6_ADDRSTRLEN + 1) * MAX_IP_ENTRIES)
|
||||
|
||||
struct kvp_record {
|
||||
char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
|
||||
@ -1171,6 +1182,18 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ip_version_check(const char *input_addr)
|
||||
{
|
||||
struct in6_addr addr;
|
||||
|
||||
if (inet_pton(AF_INET, input_addr, &addr))
|
||||
return IPV4;
|
||||
else if (inet_pton(AF_INET6, input_addr, &addr))
|
||||
return IPV6;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only IPv4 subnet strings needs to be converted to plen
|
||||
* For IPv6 the subnet is already privided in plen format
|
||||
@ -1197,14 +1220,75 @@ static int kvp_subnet_to_plen(char *subnet_addr_str)
|
||||
return plen;
|
||||
}
|
||||
|
||||
static int process_dns_gateway_nm(FILE *f, char *ip_string, int type,
|
||||
int ip_sec)
|
||||
{
|
||||
char addr[INET6_ADDRSTRLEN], *output_str;
|
||||
int ip_offset = 0, error = 0, ip_ver;
|
||||
char *param_name;
|
||||
|
||||
if (type == DNS)
|
||||
param_name = "dns";
|
||||
else if (type == GATEWAY)
|
||||
param_name = "gateway";
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
output_str = (char *)calloc(OUTSTR_BUF_SIZE, sizeof(char));
|
||||
if (!output_str)
|
||||
return -ENOMEM;
|
||||
|
||||
while (1) {
|
||||
memset(addr, 0, sizeof(addr));
|
||||
|
||||
if (!parse_ip_val_buffer(ip_string, &ip_offset, addr,
|
||||
(MAX_IP_ADDR_SIZE * 2)))
|
||||
break;
|
||||
|
||||
ip_ver = ip_version_check(addr);
|
||||
if (ip_ver < 0)
|
||||
continue;
|
||||
|
||||
if ((ip_ver == IPV4 && ip_sec == IPV4) ||
|
||||
(ip_ver == IPV6 && ip_sec == IPV6)) {
|
||||
/*
|
||||
* do a bound check to avoid out-of bound writes
|
||||
*/
|
||||
if ((OUTSTR_BUF_SIZE - strlen(output_str)) >
|
||||
(strlen(addr) + 1)) {
|
||||
strncat(output_str, addr,
|
||||
OUTSTR_BUF_SIZE -
|
||||
strlen(output_str) - 1);
|
||||
strncat(output_str, ",",
|
||||
OUTSTR_BUF_SIZE -
|
||||
strlen(output_str) - 1);
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(output_str)) {
|
||||
/*
|
||||
* This is to get rid of that extra comma character
|
||||
* in the end of the string
|
||||
*/
|
||||
output_str[strlen(output_str) - 1] = '\0';
|
||||
error = fprintf(f, "%s=%s\n", param_name, output_str);
|
||||
}
|
||||
|
||||
free(output_str);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
|
||||
int is_ipv6)
|
||||
int ip_sec)
|
||||
{
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
char subnet_addr[INET6_ADDRSTRLEN];
|
||||
int error, i = 0;
|
||||
int error = 0, i = 0;
|
||||
int ip_offset = 0, subnet_offset = 0;
|
||||
int plen;
|
||||
int plen, ip_ver;
|
||||
|
||||
memset(addr, 0, sizeof(addr));
|
||||
memset(subnet_addr, 0, sizeof(subnet_addr));
|
||||
@ -1216,10 +1300,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
|
||||
subnet_addr,
|
||||
(MAX_IP_ADDR_SIZE *
|
||||
2))) {
|
||||
if (!is_ipv6)
|
||||
ip_ver = ip_version_check(addr);
|
||||
if (ip_ver < 0)
|
||||
continue;
|
||||
|
||||
if (ip_ver == IPV4 && ip_sec == IPV4)
|
||||
plen = kvp_subnet_to_plen((char *)subnet_addr);
|
||||
else
|
||||
else if (ip_ver == IPV6 && ip_sec == IPV6)
|
||||
plen = atoi(subnet_addr);
|
||||
else
|
||||
continue;
|
||||
|
||||
if (plen < 0)
|
||||
return plen;
|
||||
@ -1233,17 +1323,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
|
||||
memset(subnet_addr, 0, sizeof(subnet_addr));
|
||||
}
|
||||
|
||||
return 0;
|
||||
return error;
|
||||
}
|
||||
|
||||
static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
|
||||
{
|
||||
int error = 0;
|
||||
int error = 0, ip_ver;
|
||||
char if_filename[PATH_MAX];
|
||||
char nm_filename[PATH_MAX];
|
||||
FILE *ifcfg_file, *nmfile;
|
||||
char cmd[PATH_MAX];
|
||||
int is_ipv6 = 0;
|
||||
char *mac_addr;
|
||||
int str_len;
|
||||
|
||||
@ -1421,52 +1510,94 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
|
||||
if (error)
|
||||
goto setval_error;
|
||||
|
||||
if (new_val->addr_family & ADDR_FAMILY_IPV6) {
|
||||
error = fprintf(nmfile, "\n[ipv6]\n");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
is_ipv6 = 1;
|
||||
} else {
|
||||
error = fprintf(nmfile, "\n[ipv4]\n");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now we populate the keyfile format
|
||||
*
|
||||
* The keyfile format expects the IPv6 and IPv4 configuration in
|
||||
* different sections. Therefore we iterate through the list twice,
|
||||
* once to populate the IPv4 section and the next time for IPv6
|
||||
*/
|
||||
ip_ver = IPV4;
|
||||
do {
|
||||
if (ip_ver == IPV4) {
|
||||
error = fprintf(nmfile, "\n[ipv4]\n");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
} else {
|
||||
error = fprintf(nmfile, "\n[ipv6]\n");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
}
|
||||
|
||||
if (new_val->dhcp_enabled) {
|
||||
error = kvp_write_file(nmfile, "method", "", "auto");
|
||||
/*
|
||||
* Write the configuration for ipaddress, netmask, gateway and
|
||||
* name services
|
||||
*/
|
||||
error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
|
||||
(char *)new_val->sub_net,
|
||||
ip_ver);
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
} else {
|
||||
error = kvp_write_file(nmfile, "method", "", "manual");
|
||||
|
||||
/*
|
||||
* As dhcp_enabled is only valid for ipv4, we do not set dhcp
|
||||
* methods for ipv6 based on dhcp_enabled flag.
|
||||
*
|
||||
* For ipv4, set method to manual only when dhcp_enabled is
|
||||
* false and specific ipv4 addresses are configured. If neither
|
||||
* dhcp_enabled is true and no ipv4 addresses are configured,
|
||||
* set method to 'disabled'.
|
||||
*
|
||||
* For ipv6, set method to manual when we configure ipv6
|
||||
* addresses. Otherwise set method to 'auto' so that SLAAC from
|
||||
* RA may be used.
|
||||
*/
|
||||
if (ip_ver == IPV4) {
|
||||
if (new_val->dhcp_enabled) {
|
||||
error = kvp_write_file(nmfile, "method", "",
|
||||
"auto");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
} else if (error) {
|
||||
error = kvp_write_file(nmfile, "method", "",
|
||||
"manual");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
} else {
|
||||
error = kvp_write_file(nmfile, "method", "",
|
||||
"disabled");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
}
|
||||
} else if (ip_ver == IPV6) {
|
||||
if (error) {
|
||||
error = kvp_write_file(nmfile, "method", "",
|
||||
"manual");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
} else {
|
||||
error = kvp_write_file(nmfile, "method", "",
|
||||
"auto");
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
}
|
||||
}
|
||||
|
||||
error = process_dns_gateway_nm(nmfile,
|
||||
(char *)new_val->gate_way,
|
||||
GATEWAY, ip_ver);
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the configuration for ipaddress, netmask, gateway and
|
||||
* name services
|
||||
*/
|
||||
error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
|
||||
(char *)new_val->sub_net, is_ipv6);
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
|
||||
/* we do not want ipv4 addresses in ipv6 section and vice versa */
|
||||
if (is_ipv6 != is_ipv4((char *)new_val->gate_way)) {
|
||||
error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way);
|
||||
error = process_dns_gateway_nm(nmfile,
|
||||
(char *)new_val->dns_addr, DNS,
|
||||
ip_ver);
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
}
|
||||
|
||||
if (is_ipv6 != is_ipv4((char *)new_val->dns_addr)) {
|
||||
error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr);
|
||||
if (error < 0)
|
||||
goto setval_error;
|
||||
}
|
||||
ip_ver++;
|
||||
} while (ip_ver < IP_TYPE_MAX);
|
||||
|
||||
fclose(nmfile);
|
||||
fclose(ifcfg_file);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user