From: Emerson Busson <emersonbusson@gmail.com>
To: mhklinux@outlook.com
Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
decui@microsoft.com, andrew+netdev@lunn.ch, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
gregkh@linuxfoundation.org, linux-kernel@vger.kernel.org,
linux-hyperv@vger.kernel.org, netdev@vger.kernel.org
Subject: [PATCH v2 12/14] hv: netvsc: allocate RNDIS request descriptors with kvzalloc_obj()
Date: Wed, 7 Oct 2026 16:07:50 -0300 [thread overview]
Message-ID: <20261007190752.336426-13-emersonbusson@gmail.com> (raw)
In-Reply-To: <20261007190752.336426-1-emersonbusson@gmail.com>
struct rndis_request embeds two RNDIS_EXT_LEN protocol tails.
RNDIS_EXT_LEN is HV_HYP_PAGE_SIZE, so the two tails alone are 8 KiB and
the struct is just over KMALLOC_MAX_CACHE_SIZE. kzalloc_obj() therefore
needs an order-2 compound page for every RNDIS control request, which can
fail under buddy fragmentation.
Use kvzalloc_obj() and kvfree() so allocation can fall back to vmalloc.
RNDIS control payloads are sent as GPA-direct page buffers, however, so a
vmalloc-backed descriptor cannot be described by one virt_to_phys() PFN.
Build one hv_page_buffer per Linux/Hyper-V page and resolve vmalloc backing
with vmalloc_to_page(). Linear allocations use virt_to_page(). This keeps
the GPA list valid and preserves the existing per-range DMA mapping for
isolated guests.
Keep both protocol tails unchanged. The response is copied after
request->response_msg into response_ext, within the existing
sizeof(struct rndis_message) + RNDIS_EXT_LEN bound.
Adds a fifth named RNDIS request KUnit case. It builds GPA descriptors from
a vmalloc buffer that crosses a page boundary and checks every PFN, offset,
and length against the backing pages. The existing cases retain the
allocation-size, response-layout, zeroing, request-id, and cleanup checks.
Rollback trigger: revert if the vmalloc page-buffer KUnit case fails or an
exact-source fragmented rebind shows malformed GPA descriptors from this
path.
Fixes: 5b54dac856cb ("hyperv: Add support for virtual Receive Side Scaling (vRSS)")
Signed-off-by: Emerson Busson <emersonbusson@gmail.com>
---
drivers/net/hyperv/Kconfig | 12 ++
drivers/net/hyperv/Makefile | 1 +
drivers/net/hyperv/hyperv_net.h | 43 ++++-
drivers/net/hyperv/rndis_filter.c | 117 ++++++++-----
drivers/net/hyperv/rndis_request_test.c | 216 ++++++++++++++++++++++++
5 files changed, 349 insertions(+), 40 deletions(-)
create mode 100644 drivers/net/hyperv/rndis_request_test.c
diff --git a/drivers/net/hyperv/Kconfig b/drivers/net/hyperv/Kconfig
index 982964c1a9fb..226728fd77d7 100644
--- a/drivers/net/hyperv/Kconfig
+++ b/drivers/net/hyperv/Kconfig
@@ -6,3 +6,15 @@ config HYPERV_NET
select NLS
help
Select this option to enable the Hyper-V virtual network driver.
+
+config HYPERV_NET_KUNIT_TEST
+ bool "Build Hyper-V netvsc KUnit tests"
+ depends on HYPERV_NET && KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Build the netvsc KUnit test suites into the hv_netvsc object.
+ Built into the module rather than as a separate one so the
+ cases can reach the internal helpers declared in hyperv_net.h
+ without exporting them.
+
+ If unsure, say N.
diff --git a/drivers/net/hyperv/Makefile b/drivers/net/hyperv/Makefile
index 0db7ccaec4a4..6f1abc756fde 100644
--- a/drivers/net/hyperv/Makefile
+++ b/drivers/net/hyperv/Makefile
@@ -2,3 +2,4 @@
obj-$(CONFIG_HYPERV_NET) += hv_netvsc.o
hv_netvsc-y := netvsc_drv.o netvsc.o rndis_filter.o netvsc_trace.o netvsc_bpf.o
+hv_netvsc-$(CONFIG_HYPERV_NET_KUNIT_TEST) += rndis_request_test.o
diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h
index a15cb2460344..6492e7e93ded 100644
--- a/drivers/net/hyperv/hyperv_net.h
+++ b/drivers/net/hyperv/hyperv_net.h
@@ -210,14 +210,25 @@ struct rndis_device {
u8 rss_key[NETVSC_HASH_KEYLEN];
};
+#define RNDIS_EXT_LEN HV_HYP_PAGE_SIZE
-/* Interface */
+/* Full definitions are below, after the RNDIS message format. */
+struct rndis_request;
struct rndis_message;
+
+/* Interface */
struct ndis_offload_params;
struct netvsc_device;
struct netvsc_channel;
struct net_device_context;
+struct rndis_request *get_rndis_request(struct rndis_device *dev,
+ u32 msg_type, u32 msg_len);
+void put_rndis_request(struct rndis_device *dev, struct rndis_request *req);
+int rndis_build_page_buffers(const void *data, u32 len,
+ struct hv_page_buffer *page_bufs,
+ u32 *page_buf_cnt);
+
extern u32 netvsc_ring_bytes;
int netvsc_workqueue_init(void);
@@ -1779,6 +1790,36 @@ struct rndis_message {
union rndis_message_container msg;
};
+/*
+ * RNDIS request descriptor. Declared here so the KUnit cases can reach
+ * the layout the response-copy bound in rndis_filter_receive_resp()
+ * relies on. The two RNDIS_EXT_LEN tails are what make the object
+ * larger than KMALLOC_MAX_CACHE_SIZE.
+ */
+struct rndis_request {
+ struct list_head list_ent;
+ struct completion wait_event;
+
+ struct rndis_message response_msg;
+ /*
+ * The buffer for extended info after the RNDIS response message. It's
+ * referenced based on the data offset in the RNDIS message. Its size
+ * is enough for current needs, and should be sufficient for the near
+ * future.
+ */
+ u8 response_ext[RNDIS_EXT_LEN];
+
+ /* Simplify allocation by having a netvsc packet inline */
+ struct hv_netvsc_packet pkt;
+
+ struct rndis_message request_msg;
+ /*
+ * The buffer for the extended info after the RNDIS request message.
+ * It is referenced and sized in a similar way as response_ext.
+ */
+ u8 request_ext[RNDIS_EXT_LEN];
+};
+
/* Handy macros */
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index 9b6c44979b4e..1ce40baa2d23 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -16,6 +16,7 @@
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/if_vlan.h>
+#include <linux/mm.h>
#include <linux/nls.h>
#include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
@@ -27,31 +28,6 @@
static void rndis_set_multicast(struct work_struct *w);
-#define RNDIS_EXT_LEN HV_HYP_PAGE_SIZE
-struct rndis_request {
- struct list_head list_ent;
- struct completion wait_event;
-
- struct rndis_message response_msg;
- /*
- * The buffer for extended info after the RNDIS response message. It's
- * referenced based on the data offset in the RNDIS message. Its size
- * is enough for current needs, and should be sufficient for the near
- * future.
- */
- u8 response_ext[RNDIS_EXT_LEN];
-
- /* Simplify allocation by having a netvsc packet inline */
- struct hv_netvsc_packet pkt;
-
- struct rndis_message request_msg;
- /*
- * The buffer for the extended info after the RNDIS request message.
- * It is referenced and sized in a similar way as response_ext.
- */
- u8 request_ext[RNDIS_EXT_LEN];
-};
-
static const u8 netvsc_hash_key[NETVSC_HASH_KEYLEN] = {
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0,
@@ -78,16 +54,27 @@ static struct rndis_device *get_rndis_device(void)
return device;
}
-static struct rndis_request *get_rndis_request(struct rndis_device *dev,
- u32 msg_type,
- u32 msg_len)
+struct rndis_request *get_rndis_request(struct rndis_device *dev,
+ u32 msg_type,
+ u32 msg_len)
{
struct rndis_request *request;
struct rndis_message *rndis_msg;
struct rndis_set_request *set;
unsigned long flags;
- request = kzalloc_obj(struct rndis_request);
+ /*
+ * struct rndis_request embeds two RNDIS_EXT_LEN (4 KiB) protocol
+ * tails and is larger than KMALLOC_MAX_CACHE_SIZE, so
+ * kzalloc_obj() needs an order-2 compound page. That high-order
+ * allocation can fail under buddy fragmentation. kvzalloc_obj()
+ * keeps the zeroing semantics while allowing vmalloc backing when
+ * a suitable kmalloc allocation is unavailable. The request payload
+ * is sent as GPADL-direct page buffers, so rndis_filter_send_request()
+ * must describe each backing page instead of assuming virt_to_phys()
+ * yields one contiguous physical range.
+ */
+ request = kvzalloc_obj(struct rndis_request);
if (!request)
return NULL;
@@ -115,8 +102,8 @@ static struct rndis_request *get_rndis_request(struct rndis_device *dev,
return request;
}
-static void put_rndis_request(struct rndis_device *dev,
- struct rndis_request *req)
+void put_rndis_request(struct rndis_device *dev,
+ struct rndis_request *req)
{
unsigned long flags;
@@ -124,7 +111,8 @@ static void put_rndis_request(struct rndis_device *dev,
list_del(&req->list_ent);
spin_unlock_irqrestore(&dev->request_lock, flags);
- kfree(req);
+ /* Paired with the kvzalloc_obj() in get_rndis_request(). */
+ kvfree(req);
}
static void dump_rndis_message(struct net_device *netdev,
@@ -221,27 +209,78 @@ static void dump_rndis_message(struct net_device *netdev,
}
}
+int rndis_build_page_buffers(const void *data, u32 len,
+ struct hv_page_buffer *page_bufs,
+ u32 *page_buf_cnt)
+{
+ const u8 *addr = data;
+ u32 count = 0;
+
+ if (!data || !len || !page_bufs || !page_buf_cnt)
+ return -EINVAL;
+
+ *page_buf_cnt = 0;
+
+ while (len) {
+ struct page *page;
+ phys_addr_t phys;
+ u32 offset, chunk;
+ unsigned long page_offset = offset_in_page(addr);
+
+ if (count == MAX_PAGE_BUFFER_COUNT)
+ return -E2BIG;
+
+ if (is_vmalloc_addr(addr))
+ page = vmalloc_to_page(addr);
+ else if (virt_addr_valid(addr))
+ page = virt_to_page(addr);
+ else
+ return -EFAULT;
+
+ if (!page)
+ return -EFAULT;
+
+ phys = page_to_phys(page) + page_offset;
+ offset = offset_in_hvpage(phys);
+ chunk = min_t(u32, len, PAGE_SIZE - page_offset);
+ chunk = min_t(u32, chunk, HV_HYP_PAGE_SIZE - offset);
+
+ page_bufs[count].pfn = phys >> HV_HYP_PAGE_SHIFT;
+ page_bufs[count].offset = offset;
+ page_bufs[count].len = chunk;
+
+ addr += chunk;
+ len -= chunk;
+ count++;
+ }
+
+ *page_buf_cnt = count;
+ return 0;
+}
+
static int rndis_filter_send_request(struct rndis_device *dev,
struct rndis_request *req)
{
struct hv_netvsc_packet *packet;
- struct hv_page_buffer pb;
+ struct hv_page_buffer page_bufs[MAX_PAGE_BUFFER_COUNT];
+ u32 page_buf_cnt;
int ret;
/* Setup the packet to send it */
packet = &req->pkt;
packet->total_data_buflen = req->request_msg.msg_len;
- packet->page_buf_cnt = 1;
-
- pb.pfn = virt_to_phys(&req->request_msg) >> HV_HYP_PAGE_SHIFT;
- pb.len = req->request_msg.msg_len;
- pb.offset = offset_in_hvpage(&req->request_msg);
+ ret = rndis_build_page_buffers(&req->request_msg,
+ req->request_msg.msg_len,
+ page_bufs, &page_buf_cnt);
+ if (ret)
+ return ret;
+ packet->page_buf_cnt = page_buf_cnt;
trace_rndis_send(dev->ndev, 0, &req->request_msg);
rcu_read_lock_bh();
- ret = netvsc_send(dev->ndev, packet, NULL, &pb, NULL, false);
+ ret = netvsc_send(dev->ndev, packet, NULL, page_bufs, NULL, false);
rcu_read_unlock_bh();
return ret;
diff --git a/drivers/net/hyperv/rndis_request_test.c b/drivers/net/hyperv/rndis_request_test.c
new file mode 100644
index 000000000000..6affa916e74e
--- /dev/null
+++ b/drivers/net/hyperv/rndis_request_test.c
@@ -0,0 +1,216 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KUnit tests for RNDIS request descriptor allocation.
+ *
+ * Built into the hv_netvsc object rather than a separate module so the
+ * cases can reach the internal helpers declared in hyperv_net.h
+ * without exporting them.
+ */
+#include <kunit/test.h>
+#include <linux/hyperv.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/vmalloc.h>
+
+#include "hyperv_net.h"
+
+static int rndis_test_device_init(struct rndis_device *dev)
+{
+ memset(dev, 0, sizeof(*dev));
+ atomic_set(&dev->new_req_id, 0);
+ spin_lock_init(&dev->request_lock);
+ INIT_LIST_HEAD(&dev->req_list);
+ return 0;
+}
+
+/*
+ * The premise of the kvzalloc_obj() conversion: the descriptor embeds
+ * two RNDIS_EXT_LEN protocol tails and sits past
+ * KMALLOC_MAX_CACHE_SIZE, so kzalloc_obj() reached kmalloc_large() and
+ * took an order-2 compound page on the subchannel open path. If the
+ * struct ever drops back inside the cache, the conversion stops being
+ * about high-order allocation and this assertion is the reminder.
+ */
+static void rndis_request_size_premise_test(struct kunit *test)
+{
+ KUNIT_EXPECT_GT(test, sizeof(struct rndis_request),
+ (size_t)KMALLOC_MAX_CACHE_SIZE);
+ /*
+ * The copy bound in rndis_filter_receive_resp() is
+ * sizeof(struct rndis_message) + RNDIS_EXT_LEN. That is exactly
+ * the response_msg + response_ext tail of the object. A reorder
+ * or a resize of either member makes the bound lie.
+ */
+ KUNIT_EXPECT_EQ(test,
+ offsetofend(struct rndis_request, response_ext),
+ offsetof(struct rndis_request, response_msg) +
+ sizeof(struct rndis_message) + RNDIS_EXT_LEN);
+ KUNIT_EXPECT_EQ(test,
+ offsetofend(struct rndis_request, request_ext),
+ offsetof(struct rndis_request, request_msg) +
+ sizeof(struct rndis_message) + RNDIS_EXT_LEN);
+}
+
+/*
+ * kvzalloc_obj() keeps the zeroing kzalloc_obj() provided. The two
+ * protocol tails are the fields a response is copied into; a stale
+ * tail is a stale response.
+ */
+static void rndis_request_alloc_zeroed_test(struct kunit *test)
+{
+ struct rndis_device dev;
+ struct rndis_request *req;
+
+ KUNIT_ASSERT_EQ(test, rndis_test_device_init(&dev), 0);
+ req = get_rndis_request(&dev, RNDIS_MSG_INIT, 0x20);
+ KUNIT_ASSERT_NOT_NULL(test, req);
+
+ KUNIT_EXPECT_EQ(test, req->response_ext[0], 0);
+ KUNIT_EXPECT_EQ(test, req->response_ext[RNDIS_EXT_LEN - 1], 0);
+ KUNIT_EXPECT_EQ(test, req->request_ext[0], 0);
+ KUNIT_EXPECT_EQ(test, req->request_ext[RNDIS_EXT_LEN - 1], 0);
+ KUNIT_EXPECT_EQ(test, req->response_msg.msg_len, 0U);
+
+ put_rndis_request(&dev, req);
+}
+
+/* Request ids come from a per-device counter and the list tracks the live set. */
+static void rndis_request_id_lifecycle_test(struct kunit *test)
+{
+ struct rndis_device dev;
+ struct rndis_request *req0, *req1;
+ struct rndis_request *cursor;
+ unsigned int n = 0;
+
+ KUNIT_ASSERT_EQ(test, rndis_test_device_init(&dev), 0);
+
+ req0 = get_rndis_request(&dev, RNDIS_MSG_INIT, 0x20);
+ KUNIT_ASSERT_NOT_NULL(test, req0);
+ req1 = get_rndis_request(&dev, RNDIS_MSG_QUERY, 0x20);
+ KUNIT_ASSERT_NOT_NULL(test, req1);
+
+ /*
+ * get_rndis_request() stamps the id through the set_req template,
+ * which shares the union slot with every other request body. Read
+ * it back through the same member the producer used.
+ */
+ KUNIT_EXPECT_EQ(test,
+ req0->request_msg.msg.set_req.req_id, 1U);
+ KUNIT_EXPECT_EQ(test,
+ req1->request_msg.msg.set_req.req_id, 2U);
+
+ list_for_each_entry(cursor, &dev.req_list, list_ent)
+ n++;
+ KUNIT_EXPECT_EQ(test, n, 2U);
+
+ /*
+ * put_rndis_request() is the cleanup path every error and
+ * timeout branch takes. It unlinks before it frees.
+ */
+ put_rndis_request(&dev, req0);
+ n = 0;
+ list_for_each_entry(cursor, &dev.req_list, list_ent)
+ n++;
+ KUNIT_EXPECT_EQ(test, n, 1U);
+ KUNIT_EXPECT_TRUE(test,
+ list_first_entry(&dev.req_list, struct rndis_request,
+ list_ent) == req1);
+
+ put_rndis_request(&dev, req1);
+ KUNIT_EXPECT_TRUE(test, list_empty(&dev.req_list));
+}
+
+/*
+ * A request left on the list after a completed exchange is a leak of
+ * the descriptor and of its slot in the outstanding set. Repeated
+ * get/put cycles must return to the empty list every time.
+ */
+static void rndis_request_put_cleanup_test(struct kunit *test)
+{
+ struct rndis_device dev;
+ struct rndis_request *req;
+ int i;
+
+ KUNIT_ASSERT_EQ(test, rndis_test_device_init(&dev), 0);
+
+ for (i = 0; i < 4; i++) {
+ req = get_rndis_request(&dev, RNDIS_MSG_INIT, 0x20);
+ KUNIT_ASSERT_NOT_NULL(test, req);
+ KUNIT_EXPECT_FALSE(test, list_empty(&dev.req_list));
+ put_rndis_request(&dev, req);
+ KUNIT_EXPECT_TRUE(test, list_empty(&dev.req_list));
+ }
+}
+
+/*
+ * kvzalloc_obj() may return a vmalloc address under fragmentation. RNDIS
+ * requests are GPA-direct packets, so each backing page must be represented
+ * explicitly instead of deriving a single PFN with virt_to_phys().
+ */
+static void rndis_request_vmalloc_page_buffers_test(struct kunit *test)
+{
+ struct hv_page_buffer page_bufs[MAX_PAGE_BUFFER_COUNT];
+ const u32 data_len = 16;
+ u8 *allocation = vzalloc(2 * PAGE_SIZE);
+ const u8 *cursor;
+ phys_addr_t phys;
+ u32 count = 0, remaining = data_len, i;
+ int ret;
+
+ if (!allocation) {
+ KUNIT_FAIL(test, "could not allocate vmalloc test buffer");
+ return;
+ }
+
+ cursor = allocation + PAGE_SIZE - 8;
+ ret = rndis_build_page_buffers(cursor, data_len, page_bufs, &count);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+ if (ret)
+ goto out;
+
+ KUNIT_EXPECT_EQ(test, count, 2U);
+ for (i = 0; i < count; i++) {
+ struct page *page = vmalloc_to_page(cursor);
+ unsigned long page_offset = offset_in_page(cursor);
+ u32 offset, chunk;
+
+ if (!page) {
+ KUNIT_FAIL(test, "vmalloc test buffer has no backing page");
+ goto out;
+ }
+
+ phys = page_to_phys(page) + page_offset;
+ offset = offset_in_hvpage(phys);
+ chunk = min_t(u32, remaining, PAGE_SIZE - page_offset);
+ chunk = min_t(u32, chunk, HV_HYP_PAGE_SIZE - offset);
+
+ KUNIT_EXPECT_EQ(test, page_bufs[i].pfn,
+ (u64)(phys >> HV_HYP_PAGE_SHIFT));
+ KUNIT_EXPECT_EQ(test, page_bufs[i].offset, offset);
+ KUNIT_EXPECT_EQ(test, page_bufs[i].len, chunk);
+
+ cursor += chunk;
+ remaining -= chunk;
+ }
+ KUNIT_EXPECT_EQ(test, remaining, 0U);
+
+out:
+ vfree(allocation);
+}
+
+static struct kunit_case rndis_request_test_cases[] = {
+ KUNIT_CASE(rndis_request_size_premise_test),
+ KUNIT_CASE(rndis_request_alloc_zeroed_test),
+ KUNIT_CASE(rndis_request_id_lifecycle_test),
+ KUNIT_CASE(rndis_request_put_cleanup_test),
+ KUNIT_CASE(rndis_request_vmalloc_page_buffers_test),
+ {}
+};
+
+static struct kunit_suite rndis_request_test_suite = {
+ .name = "hyperv-rndis-request",
+ .test_cases = rndis_request_test_cases,
+};
+
+kunit_test_suite(rndis_request_test_suite);
--
2.43.0
next prev parent reply other threads:[~2026-10-07 19:09 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-07 19:07 [PATCH v2 0/14] hv: vmbus: make rings and host-visible buffers survive buddy fragmentation Emerson Busson
2026-10-07 19:07 ` [PATCH v2 01/14] hv: vmbus: convert ring backing through the chunk allocator Emerson Busson
2026-10-07 19:07 ` [PATCH v2 02/14] hv: vmbus: validate chunk buffer allocation and cleanup Emerson Busson
2026-10-08 21:17 ` kernel test robot
2026-10-07 19:07 ` [PATCH v2 03/14] uio: hv_generic: describe buffers for owned allocation Emerson Busson
2026-10-07 19:07 ` [PATCH v2 04/14] hv: vmbus: add KUnit tests for GPADL post failure injection Emerson Busson
2026-10-07 19:07 ` [PATCH v2 05/14] hv: vmbus: add KUnit test for order-zero allocation fallback Emerson Busson
2026-10-07 19:07 ` [PATCH v2 06/14] hv: vmbus: cover all shared-page policy combinations Emerson Busson
2026-10-07 19:07 ` [PATCH v2 07/14] hv: vmbus: distinguish host rescind from local channel unload Emerson Busson
2026-10-07 19:07 ` [PATCH v2 08/14] hv: vmbus: retain backing until ownership and references clear Emerson Busson
2026-10-07 19:07 ` [PATCH v2 09/14] hv: use owned VMBus buffers in NetVSC and UIO Emerson Busson
2026-10-07 19:07 ` [PATCH v2 10/14] hv: vmbus: pin buffer pages across UIO mmap to close the reclaim race Emerson Busson
2026-10-08 16:49 ` kernel test robot
2026-10-08 17:51 ` Nathan Chancellor
2026-10-08 17:02 ` kernel test robot
2026-10-07 19:07 ` [PATCH v2 11/14] hv: vmbus: vmalloc requestor metadata Emerson Busson
2026-10-07 19:07 ` Emerson Busson [this message]
2026-10-07 19:07 ` [PATCH v2 13/14] hv: netvsc: handle a NULL request address on empty completions Emerson Busson
2026-10-07 19:07 ` [PATCH v2 14/14] hv: netvsc: use kvzalloc for device state Emerson Busson
2026-10-08 16:55 ` [PATCH v2 0/14] hv: vmbus: make rings and host-visible buffers survive buddy fragmentation Easwar Hariharan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261007190752.336426-13-emersonbusson@gmail.com \
--to=emersonbusson@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=decui@microsoft.com \
--cc=edumazet@google.com \
--cc=gregkh@linuxfoundation.org \
--cc=haiyangz@microsoft.com \
--cc=kuba@kernel.org \
--cc=kys@microsoft.com \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mhklinux@outlook.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=wei.liu@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox