Commit 52e5070f authored by Linus Torvalds's avatar Linus Torvalds

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

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
parents 00dcf5d8 30d18df6
...@@ -105,7 +105,7 @@ static bool cpu_is_self(int cpu) ...@@ -105,7 +105,7 @@ static bool cpu_is_self(int cpu)
* IPI implementation on Hyper-V. * IPI implementation on Hyper-V.
*/ */
static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector, 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; struct hv_send_ipi_ex *ipi_arg;
unsigned long flags; unsigned long flags;
...@@ -132,8 +132,8 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector, ...@@ -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) { if (!cpumask_equal(mask, cpu_present_mask) || exclude_self) {
ipi_arg->vp_set.format = HV_GENERIC_SET_SPARSE_4K; ipi_arg->vp_set.format = HV_GENERIC_SET_SPARSE_4K;
nr_bank = cpumask_to_vpset_skip(&(ipi_arg->vp_set), mask, nr_bank = cpumask_to_vpset_skip(&ipi_arg->vp_set, mask,
exclude_self ? cpu_is_self : NULL); exclude_self ? cpu_is_self : NULL);
/* /*
* 'nr_bank <= 0' means some CPUs in cpumask can't be * '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, ...@@ -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, status = hv_do_rep_hypercall(HVCALL_SEND_IPI_EX, 0, nr_bank,
ipi_arg, NULL); ipi_arg, NULL);
ipi_mask_ex_done: ipi_mask_ex_done:
local_irq_restore(flags); local_irq_restore(flags);
...@@ -155,7 +155,7 @@ static bool __send_ipi_mask_ex(const struct cpumask *mask, int vector, ...@@ -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, 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(); int cur_cpu, vcpu, this_cpu = smp_processor_id();
struct hv_send_ipi ipi_arg; struct hv_send_ipi ipi_arg;
...@@ -181,7 +181,7 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector, ...@@ -181,7 +181,7 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector,
return false; 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; return false;
/* /*
...@@ -218,7 +218,7 @@ static bool __send_ipi_mask(const struct cpumask *mask, int vector, ...@@ -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, status = hv_do_fast_hypercall16(HVCALL_SEND_IPI, ipi_arg.vector,
ipi_arg.cpu_mask); ipi_arg.cpu_mask);
return hv_result_success(status); return hv_result_success(status);
do_ex_hypercall: do_ex_hypercall:
...@@ -241,7 +241,7 @@ static bool __send_ipi_one(int cpu, int vector) ...@@ -241,7 +241,7 @@ static bool __send_ipi_one(int cpu, int vector)
return false; 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; return false;
if (vp >= 64) if (vp >= 64)
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/acpi.h>
#include <linux/hyperv.h> #include <linux/hyperv.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpuhotplug.h> #include <linux/cpuhotplug.h>
...@@ -116,12 +115,11 @@ int hv_call_deposit_pages(int node, u64 partition_id, u32 num_pages) ...@@ -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) int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
{ {
struct hv_add_logical_processor_in *input; struct hv_input_add_logical_processor *input;
struct hv_add_logical_processor_out *output; struct hv_output_add_logical_processor *output;
u64 status; u64 status;
unsigned long flags; unsigned long flags;
int ret = HV_STATUS_SUCCESS; int ret = HV_STATUS_SUCCESS;
int pxm = node_to_pxm(node);
/* /*
* When adding a logical processor, the hypervisor may return * 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) ...@@ -137,11 +135,7 @@ int hv_call_add_logical_proc(int node, u32 lp_index, u32 apic_id)
input->lp_index = lp_index; input->lp_index = lp_index;
input->apic_id = apic_id; input->apic_id = apic_id;
input->flags = 0; input->proximity_domain_info = hv_numa_node_to_pxm_info(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;
status = hv_do_hypercall(HVCALL_ADD_LOGICAL_PROCESSOR, status = hv_do_hypercall(HVCALL_ADD_LOGICAL_PROCESSOR,
input, output); input, output);
local_irq_restore(flags); local_irq_restore(flags);
...@@ -166,7 +160,6 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags) ...@@ -166,7 +160,6 @@ int hv_call_create_vp(int node, u64 partition_id, u32 vp_index, u32 flags)
u64 status; u64 status;
unsigned long irq_flags; unsigned long irq_flags;
int ret = HV_STATUS_SUCCESS; int ret = HV_STATUS_SUCCESS;
int pxm = node_to_pxm(node);
/* Root VPs don't seem to need pages deposited */ /* Root VPs don't seem to need pages deposited */
if (partition_id != hv_current_partition_id) { 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) ...@@ -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->vp_index = vp_index;
input->flags = flags; input->flags = flags;
input->subnode_type = HvSubnodeAny; input->subnode_type = HvSubnodeAny;
if (node != NUMA_NO_NODE) { input->proximity_domain_info = hv_numa_node_to_pxm_info(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;
}
status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL); status = hv_do_hypercall(HVCALL_CREATE_VP, input, NULL);
local_irq_restore(irq_flags); local_irq_restore(irq_flags);
......
...@@ -153,7 +153,9 @@ void vmbus_free_ring(struct vmbus_channel *channel) ...@@ -153,7 +153,9 @@ void vmbus_free_ring(struct vmbus_channel *channel)
hv_ringbuffer_cleanup(&channel->inbound); hv_ringbuffer_cleanup(&channel->inbound);
if (channel->ringbuffer_page) { 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 get_order(channel->ringbuffer_pagecount
<< PAGE_SHIFT)); << PAGE_SHIFT));
channel->ringbuffer_page = NULL; channel->ringbuffer_page = NULL;
...@@ -436,9 +438,18 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, ...@@ -436,9 +438,18 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
(atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1); (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
ret = create_gpadl_header(type, kbuffer, size, send_offset, &msginfo); ret = create_gpadl_header(type, kbuffer, size, send_offset, &msginfo);
if (ret) if (ret) {
gpadl->decrypted = false;
return ret; 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, ret = set_memory_decrypted((unsigned long)kbuffer,
PFN_UP(size)); PFN_UP(size));
if (ret) { if (ret) {
...@@ -527,9 +538,15 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel, ...@@ -527,9 +538,15 @@ static int __vmbus_establish_gpadl(struct vmbus_channel *channel,
kfree(msginfo); kfree(msginfo);
if (ret) if (ret) {
set_memory_encrypted((unsigned long)kbuffer, /*
PFN_UP(size)); * 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; return ret;
} }
...@@ -850,6 +867,8 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, struct vmbus_gpadl *gpad ...@@ -850,6 +867,8 @@ int vmbus_teardown_gpadl(struct vmbus_channel *channel, struct vmbus_gpadl *gpad
if (ret) if (ret)
pr_warn("Fail to set mem host visibility in GPADL teardown %d.\n", ret); pr_warn("Fail to set mem host visibility in GPADL teardown %d.\n", ret);
gpadl->decrypted = ret;
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl); EXPORT_SYMBOL_GPL(vmbus_teardown_gpadl);
......
...@@ -237,8 +237,17 @@ int vmbus_connect(void) ...@@ -237,8 +237,17 @@ int vmbus_connect(void)
vmbus_connection.monitor_pages[0], 1); vmbus_connection.monitor_pages[0], 1);
ret |= set_memory_decrypted((unsigned long) ret |= set_memory_decrypted((unsigned long)
vmbus_connection.monitor_pages[1], 1); 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; goto cleanup;
}
/* /*
* Set_memory_decrypted() will change the memory contents if * Set_memory_decrypted() will change the memory contents if
...@@ -337,13 +346,19 @@ void vmbus_disconnect(void) ...@@ -337,13 +346,19 @@ void vmbus_disconnect(void)
vmbus_connection.int_page = NULL; vmbus_connection.int_page = NULL;
} }
set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[0], 1); if (vmbus_connection.monitor_pages[0]) {
set_memory_encrypted((unsigned long)vmbus_connection.monitor_pages[1], 1); 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]); if (vmbus_connection.monitor_pages[1]) {
hv_free_hyperv_page(vmbus_connection.monitor_pages[1]); if (!set_memory_encrypted(
vmbus_connection.monitor_pages[0] = NULL; (unsigned long)vmbus_connection.monitor_pages[1], 1))
vmbus_connection.monitor_pages[1] = NULL; 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, ...@@ -131,7 +131,7 @@ static ssize_t id_show(struct device *dev, struct device_attribute *dev_attr,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; 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); static DEVICE_ATTR_RO(id);
...@@ -142,7 +142,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *dev_attr, ...@@ -142,7 +142,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *dev_attr,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; 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); static DEVICE_ATTR_RO(state);
...@@ -153,7 +153,7 @@ static ssize_t monitor_id_show(struct device *dev, ...@@ -153,7 +153,7 @@ static ssize_t monitor_id_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; 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); static DEVICE_ATTR_RO(monitor_id);
...@@ -164,8 +164,8 @@ static ssize_t class_id_show(struct device *dev, ...@@ -164,8 +164,8 @@ static ssize_t class_id_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "{%pUl}\n", return sysfs_emit(buf, "{%pUl}\n",
&hv_dev->channel->offermsg.offer.if_type); &hv_dev->channel->offermsg.offer.if_type);
} }
static DEVICE_ATTR_RO(class_id); static DEVICE_ATTR_RO(class_id);
...@@ -176,8 +176,8 @@ static ssize_t device_id_show(struct device *dev, ...@@ -176,8 +176,8 @@ static ssize_t device_id_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "{%pUl}\n", return sysfs_emit(buf, "{%pUl}\n",
&hv_dev->channel->offermsg.offer.if_instance); &hv_dev->channel->offermsg.offer.if_instance);
} }
static DEVICE_ATTR_RO(device_id); static DEVICE_ATTR_RO(device_id);
...@@ -186,7 +186,7 @@ static ssize_t modalias_show(struct device *dev, ...@@ -186,7 +186,7 @@ static ssize_t modalias_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_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); static DEVICE_ATTR_RO(modalias);
...@@ -199,7 +199,7 @@ static ssize_t numa_node_show(struct device *dev, ...@@ -199,7 +199,7 @@ static ssize_t numa_node_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; 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); static DEVICE_ATTR_RO(numa_node);
#endif #endif
...@@ -212,9 +212,8 @@ static ssize_t server_monitor_pending_show(struct device *dev, ...@@ -212,9 +212,8 @@ static ssize_t server_monitor_pending_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "%d\n", return sysfs_emit(buf, "%d\n", channel_pending(hv_dev->channel,
channel_pending(hv_dev->channel, vmbus_connection.monitor_pages[0]));
vmbus_connection.monitor_pages[0]));
} }
static DEVICE_ATTR_RO(server_monitor_pending); static DEVICE_ATTR_RO(server_monitor_pending);
...@@ -226,9 +225,8 @@ static ssize_t client_monitor_pending_show(struct device *dev, ...@@ -226,9 +225,8 @@ static ssize_t client_monitor_pending_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "%d\n", return sysfs_emit(buf, "%d\n", channel_pending(hv_dev->channel,
channel_pending(hv_dev->channel, vmbus_connection.monitor_pages[1]));
vmbus_connection.monitor_pages[1]));
} }
static DEVICE_ATTR_RO(client_monitor_pending); static DEVICE_ATTR_RO(client_monitor_pending);
...@@ -240,9 +238,8 @@ static ssize_t server_monitor_latency_show(struct device *dev, ...@@ -240,9 +238,8 @@ static ssize_t server_monitor_latency_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "%d\n", return sysfs_emit(buf, "%d\n", channel_latency(hv_dev->channel,
channel_latency(hv_dev->channel, vmbus_connection.monitor_pages[0]));
vmbus_connection.monitor_pages[0]));
} }
static DEVICE_ATTR_RO(server_monitor_latency); static DEVICE_ATTR_RO(server_monitor_latency);
...@@ -254,9 +251,8 @@ static ssize_t client_monitor_latency_show(struct device *dev, ...@@ -254,9 +251,8 @@ static ssize_t client_monitor_latency_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "%d\n", return sysfs_emit(buf, "%d\n", channel_latency(hv_dev->channel,
channel_latency(hv_dev->channel, vmbus_connection.monitor_pages[1]));
vmbus_connection.monitor_pages[1]));
} }
static DEVICE_ATTR_RO(client_monitor_latency); static DEVICE_ATTR_RO(client_monitor_latency);
...@@ -268,9 +264,8 @@ static ssize_t server_monitor_conn_id_show(struct device *dev, ...@@ -268,9 +264,8 @@ static ssize_t server_monitor_conn_id_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "%d\n", return sysfs_emit(buf, "%d\n", channel_conn_id(hv_dev->channel,
channel_conn_id(hv_dev->channel, vmbus_connection.monitor_pages[0]));
vmbus_connection.monitor_pages[0]));
} }
static DEVICE_ATTR_RO(server_monitor_conn_id); static DEVICE_ATTR_RO(server_monitor_conn_id);
...@@ -282,9 +277,8 @@ static ssize_t client_monitor_conn_id_show(struct device *dev, ...@@ -282,9 +277,8 @@ static ssize_t client_monitor_conn_id_show(struct device *dev,
if (!hv_dev->channel) if (!hv_dev->channel)
return -ENODEV; return -ENODEV;
return sprintf(buf, "%d\n", return sysfs_emit(buf, "%d\n", channel_conn_id(hv_dev->channel,
channel_conn_id(hv_dev->channel, vmbus_connection.monitor_pages[1]));
vmbus_connection.monitor_pages[1]));
} }
static DEVICE_ATTR_RO(client_monitor_conn_id); static DEVICE_ATTR_RO(client_monitor_conn_id);
...@@ -303,7 +297,7 @@ static ssize_t out_intr_mask_show(struct device *dev, ...@@ -303,7 +297,7 @@ static ssize_t out_intr_mask_show(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(out_intr_mask);
...@@ -321,7 +315,7 @@ static ssize_t out_read_index_show(struct device *dev, ...@@ -321,7 +315,7 @@ static ssize_t out_read_index_show(struct device *dev,
&outbound); &outbound);
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(out_read_index);
...@@ -340,7 +334,7 @@ static ssize_t out_write_index_show(struct device *dev, ...@@ -340,7 +334,7 @@ static ssize_t out_write_index_show(struct device *dev,
&outbound); &outbound);
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(out_write_index);
...@@ -359,7 +353,7 @@ static ssize_t out_read_bytes_avail_show(struct device *dev, ...@@ -359,7 +353,7 @@ static ssize_t out_read_bytes_avail_show(struct device *dev,
&outbound); &outbound);
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(out_read_bytes_avail);
...@@ -378,7 +372,7 @@ static ssize_t out_write_bytes_avail_show(struct device *dev, ...@@ -378,7 +372,7 @@ static ssize_t out_write_bytes_avail_show(struct device *dev,
&outbound); &outbound);
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(out_write_bytes_avail);
...@@ -396,7 +390,7 @@ static ssize_t in_intr_mask_show(struct device *dev, ...@@ -396,7 +390,7 @@ static ssize_t in_intr_mask_show(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(in_intr_mask);
...@@ -414,7 +408,7 @@ static ssize_t in_read_index_show(struct device *dev, ...@@ -414,7 +408,7 @@ static ssize_t in_read_index_show(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(in_read_index);
...@@ -432,7 +426,7 @@ static ssize_t in_write_index_show(struct device *dev, ...@@ -432,7 +426,7 @@ static ssize_t in_write_index_show(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(in_write_index);
...@@ -451,7 +445,7 @@ static ssize_t in_read_bytes_avail_show(struct device *dev, ...@@ -451,7 +445,7 @@ static ssize_t in_read_bytes_avail_show(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(in_read_bytes_avail);
...@@ -470,7 +464,7 @@ static ssize_t in_write_bytes_avail_show(struct device *dev, ...@@ -470,7 +464,7 @@ static ssize_t in_write_bytes_avail_show(struct device *dev,
if (ret < 0) if (ret < 0)
return ret; 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); static DEVICE_ATTR_RO(in_write_bytes_avail);
...@@ -480,7 +474,7 @@ static ssize_t channel_vp_mapping_show(struct device *dev, ...@@ -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 hv_device *hv_dev = device_to_hv_device(dev);
struct vmbus_channel *channel = hv_dev->channel, *cur_sc; 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; struct list_head *cur;
if (!channel) if (!channel)
...@@ -488,25 +482,21 @@ static ssize_t channel_vp_mapping_show(struct device *dev, ...@@ -488,25 +482,21 @@ static ssize_t channel_vp_mapping_show(struct device *dev,
mutex_lock(&vmbus_connection.channel_mutex); mutex_lock(&vmbus_connection.channel_mutex);
tot_written = snprintf(buf, buf_size, "%u:%u\n", n_written = sysfs_emit(buf, "%u:%u\n",
channel->offermsg.child_relid, channel->target_cpu); channel->offermsg.child_relid,
channel->target_cpu);
list_for_each(cur, &channel->sc_list) { list_for_each(cur, &channel->sc_list) {
if (tot_written >= buf_size - 1)
break;
cur_sc = list_entry(cur, struct vmbus_channel, sc_list); cur_sc = list_entry(cur, struct vmbus_channel, sc_list);
n_written = scnprintf(buf + tot_written, n_written += sysfs_emit_at(buf, n_written, "%u:%u\n",
buf_size - tot_written, cur_sc->offermsg.child_relid,
"%u:%u\n", cur_sc->target_cpu);
cur_sc->offermsg.child_relid,
cur_sc->target_cpu);
tot_written += n_written;
} }
mutex_unlock(&vmbus_connection.channel_mutex); mutex_unlock(&vmbus_connection.channel_mutex);
return tot_written; return n_written;
} }
static DEVICE_ATTR_RO(channel_vp_mapping); static DEVICE_ATTR_RO(channel_vp_mapping);
...@@ -516,7 +506,7 @@ static ssize_t vendor_show(struct device *dev, ...@@ -516,7 +506,7 @@ static ssize_t vendor_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_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); static DEVICE_ATTR_RO(vendor);
...@@ -526,7 +516,7 @@ static ssize_t device_show(struct device *dev, ...@@ -526,7 +516,7 @@ static ssize_t device_show(struct device *dev,
{ {
struct hv_device *hv_dev = device_to_hv_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); static DEVICE_ATTR_RO(device);
...@@ -551,7 +541,7 @@ static ssize_t driver_override_show(struct device *dev, ...@@ -551,7 +541,7 @@ static ssize_t driver_override_show(struct device *dev,
ssize_t len; ssize_t len;
device_lock(dev); 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); device_unlock(dev);
return len; return len;
......
...@@ -154,8 +154,11 @@ static void free_netvsc_device(struct rcu_head *head) ...@@ -154,8 +154,11 @@ static void free_netvsc_device(struct rcu_head *head)
int i; int i;
kfree(nvdev->extension); 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); bitmap_free(nvdev->send_section_map);
for (i = 0; i < VRSS_CHANNEL_MAX; i++) { 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) ...@@ -181,12 +181,14 @@ hv_uio_cleanup(struct hv_device *dev, struct hv_uio_private_data *pdata)
{ {
if (pdata->send_gpadl.gpadl_handle) { if (pdata->send_gpadl.gpadl_handle) {
vmbus_teardown_gpadl(dev->channel, &pdata->send_gpadl); 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) { if (pdata->recv_gpadl.gpadl_handle) {
vmbus_teardown_gpadl(dev->channel, &pdata->recv_gpadl); 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, ...@@ -295,7 +297,8 @@ hv_uio_probe(struct hv_device *dev,
ret = vmbus_establish_gpadl(channel, pdata->recv_buf, ret = vmbus_establish_gpadl(channel, pdata->recv_buf,
RECV_BUFFER_SIZE, &pdata->recv_gpadl); RECV_BUFFER_SIZE, &pdata->recv_gpadl);
if (ret) { if (ret) {
vfree(pdata->recv_buf); if (!pdata->recv_gpadl.decrypted)
vfree(pdata->recv_buf);
goto fail_close; goto fail_close;
} }
...@@ -317,7 +320,8 @@ hv_uio_probe(struct hv_device *dev, ...@@ -317,7 +320,8 @@ hv_uio_probe(struct hv_device *dev,
ret = vmbus_establish_gpadl(channel, pdata->send_buf, ret = vmbus_establish_gpadl(channel, pdata->send_buf,
SEND_BUFFER_SIZE, &pdata->send_gpadl); SEND_BUFFER_SIZE, &pdata->send_gpadl);
if (ret) { if (ret) {
vfree(pdata->send_buf); if (!pdata->send_gpadl.decrypted)
vfree(pdata->send_buf);
goto fail_close; goto fail_close;
} }
......
...@@ -512,13 +512,9 @@ struct hv_proximity_domain_flags { ...@@ -512,13 +512,9 @@ struct hv_proximity_domain_flags {
u32 proximity_info_valid : 1; u32 proximity_info_valid : 1;
} __packed; } __packed;
/* Not a union in windows but useful for zeroing */ struct hv_proximity_domain_info {
union hv_proximity_domain_info { u32 domain_id;
struct { struct hv_proximity_domain_flags flags;
u32 domain_id;
struct hv_proximity_domain_flags flags;
};
u64 as_uint64;
} __packed; } __packed;
struct hv_lp_startup_status { struct hv_lp_startup_status {
...@@ -532,14 +528,13 @@ struct hv_lp_startup_status { ...@@ -532,14 +528,13 @@ struct hv_lp_startup_status {
} __packed; } __packed;
/* HvAddLogicalProcessor hypercall */ /* HvAddLogicalProcessor hypercall */
struct hv_add_logical_processor_in { struct hv_input_add_logical_processor {
u32 lp_index; u32 lp_index;
u32 apic_id; u32 apic_id;
union hv_proximity_domain_info proximity_domain_info; struct hv_proximity_domain_info proximity_domain_info;
u64 flags;
} __packed; } __packed;
struct hv_add_logical_processor_out { struct hv_output_add_logical_processor {
struct hv_lp_startup_status startup_status; struct hv_lp_startup_status startup_status;
} __packed; } __packed;
...@@ -560,7 +555,7 @@ struct hv_create_vp { ...@@ -560,7 +555,7 @@ struct hv_create_vp {
u8 padding[3]; u8 padding[3];
u8 subnode_type; u8 subnode_type;
u64 subnode_id; u64 subnode_id;
union hv_proximity_domain_info proximity_domain_info; struct hv_proximity_domain_info proximity_domain_info;
u64 flags; u64 flags;
} __packed; } __packed;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/atomic.h> #include <linux/atomic.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <acpi/acpi_numa.h>
#include <linux/cpumask.h> #include <linux/cpumask.h>
#include <linux/nmi.h> #include <linux/nmi.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
...@@ -67,6 +68,19 @@ extern u64 hv_do_fast_hypercall8(u16 control, u64 input8); ...@@ -67,6 +68,19 @@ extern u64 hv_do_fast_hypercall8(u16 control, u64 input8);
bool hv_isolation_type_snp(void); bool hv_isolation_type_snp(void);
bool hv_isolation_type_tdx(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. */ /* Helper functions that provide a consistent pattern for checking Hyper-V hypercall status. */
static inline int hv_result(u64 status) static inline int hv_result(u64 status)
{ {
......
...@@ -832,6 +832,7 @@ struct vmbus_gpadl { ...@@ -832,6 +832,7 @@ struct vmbus_gpadl {
u32 gpadl_handle; u32 gpadl_handle;
u32 size; u32 size;
void *buffer; void *buffer;
bool decrypted;
}; };
struct vmbus_channel { struct vmbus_channel {
......
...@@ -76,6 +76,12 @@ enum { ...@@ -76,6 +76,12 @@ enum {
DNS DNS
}; };
enum {
IPV4 = 1,
IPV6,
IP_TYPE_MAX
};
static int in_hand_shake; static int in_hand_shake;
static char *os_name = ""; static char *os_name = "";
...@@ -102,6 +108,11 @@ static struct utsname uts_buf; ...@@ -102,6 +108,11 @@ static struct utsname uts_buf;
#define MAX_FILE_NAME 100 #define MAX_FILE_NAME 100
#define ENTRIES_PER_BLOCK 50 #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 { struct kvp_record {
char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE]; char key[HV_KVP_EXCHANGE_MAX_KEY_SIZE];
...@@ -1171,6 +1182,18 @@ static int process_ip_string(FILE *f, char *ip_string, int type) ...@@ -1171,6 +1182,18 @@ static int process_ip_string(FILE *f, char *ip_string, int type)
return 0; 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 * Only IPv4 subnet strings needs to be converted to plen
* For IPv6 the subnet is already privided in plen format * For IPv6 the subnet is already privided in plen format
...@@ -1197,14 +1220,75 @@ static int kvp_subnet_to_plen(char *subnet_addr_str) ...@@ -1197,14 +1220,75 @@ static int kvp_subnet_to_plen(char *subnet_addr_str)
return plen; 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, static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
int is_ipv6) int ip_sec)
{ {
char addr[INET6_ADDRSTRLEN]; char addr[INET6_ADDRSTRLEN];
char subnet_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 ip_offset = 0, subnet_offset = 0;
int plen; int plen, ip_ver;
memset(addr, 0, sizeof(addr)); memset(addr, 0, sizeof(addr));
memset(subnet_addr, 0, sizeof(subnet_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, ...@@ -1216,10 +1300,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
subnet_addr, subnet_addr,
(MAX_IP_ADDR_SIZE * (MAX_IP_ADDR_SIZE *
2))) { 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); plen = kvp_subnet_to_plen((char *)subnet_addr);
else else if (ip_ver == IPV6 && ip_sec == IPV6)
plen = atoi(subnet_addr); plen = atoi(subnet_addr);
else
continue;
if (plen < 0) if (plen < 0)
return plen; return plen;
...@@ -1233,17 +1323,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet, ...@@ -1233,17 +1323,16 @@ static int process_ip_string_nm(FILE *f, char *ip_string, char *subnet,
memset(subnet_addr, 0, sizeof(subnet_addr)); 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) 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 if_filename[PATH_MAX];
char nm_filename[PATH_MAX]; char nm_filename[PATH_MAX];
FILE *ifcfg_file, *nmfile; FILE *ifcfg_file, *nmfile;
char cmd[PATH_MAX]; char cmd[PATH_MAX];
int is_ipv6 = 0;
char *mac_addr; char *mac_addr;
int str_len; int str_len;
...@@ -1421,52 +1510,94 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val) ...@@ -1421,52 +1510,94 @@ static int kvp_set_ip_info(char *if_name, struct hv_kvp_ipaddr_value *new_val)
if (error) if (error)
goto setval_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 * 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
if (error < 0) * name services
goto setval_error; */
} else { error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr,
error = kvp_write_file(nmfile, "method", "", "manual"); (char *)new_val->sub_net,
ip_ver);
if (error < 0) if (error < 0)
goto setval_error; goto setval_error;
}
/* /*
* Write the configuration for ipaddress, netmask, gateway and * As dhcp_enabled is only valid for ipv4, we do not set dhcp
* name services * methods for ipv6 based on dhcp_enabled flag.
*/ *
error = process_ip_string_nm(nmfile, (char *)new_val->ip_addr, * For ipv4, set method to manual only when dhcp_enabled is
(char *)new_val->sub_net, is_ipv6); * false and specific ipv4 addresses are configured. If neither
if (error < 0) * dhcp_enabled is true and no ipv4 addresses are configured,
goto setval_error; * 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;
}
}
/* we do not want ipv4 addresses in ipv6 section and vice versa */ error = process_dns_gateway_nm(nmfile,
if (is_ipv6 != is_ipv4((char *)new_val->gate_way)) { (char *)new_val->gate_way,
error = fprintf(nmfile, "gateway=%s\n", (char *)new_val->gate_way); GATEWAY, ip_ver);
if (error < 0) if (error < 0)
goto setval_error; goto setval_error;
}
if (is_ipv6 != is_ipv4((char *)new_val->dns_addr)) { error = process_dns_gateway_nm(nmfile,
error = fprintf(nmfile, "dns=%s\n", (char *)new_val->dns_addr); (char *)new_val->dns_addr, DNS,
ip_ver);
if (error < 0) if (error < 0)
goto setval_error; goto setval_error;
}
ip_ver++;
} while (ip_ver < IP_TYPE_MAX);
fclose(nmfile); fclose(nmfile);
fclose(ifcfg_file); fclose(ifcfg_file);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment