From d81762285e95c0268052eadd6b813fd9fefb0335 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Tue, 6 May 2025 10:47:21 +0200 Subject: [PATCH 01/11] Declare max number of pgrants in netback --- drivers/net/xen-netback/netback.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 0d51c900c5538..0392c9c27a22c 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -73,6 +73,12 @@ module_param_named(max_queues, xenvif_max_queues, uint, 0644); MODULE_PARM_DESC(max_queues, "Maximum number of queues per virtual interface"); +/* + * Maximum number of grants to map persistently in netback. + * L17 TODO: test performance with different values. + */ +unsigned int xenvif_max_pgrants = XEN_NETIF_RX_RING_SIZE; + /* * This is the maximum slots a skb can have. If a guest sends a skb * which exceeds this limit it is considered malicious. @@ -1758,6 +1764,8 @@ static int __init netback_init(void) xenvif_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT, num_online_cpus()); + pr_info("max persistent grants: %d\n", xenvif_max_pgrants); + if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX); From f355334f0bc956c2ca6f04ae5200ac3d696a0c97 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Tue, 6 May 2025 15:43:54 +0200 Subject: [PATCH 02/11] Exported max number of pgrants as module param --- drivers/net/xen-netback/common.h | 1 + drivers/net/xen-netback/netback.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 1fcbd83f7ff2e..2c5a62cfba228 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -408,6 +408,7 @@ extern bool provides_xdp_headroom; extern unsigned int rx_drain_timeout_msecs; extern unsigned int rx_stall_timeout_msecs; extern unsigned int xenvif_max_queues; +extern unsigned int xenvif_max_pgrants; extern unsigned int xenvif_hash_cache_size; #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 0392c9c27a22c..0e500125600a6 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -78,6 +78,9 @@ MODULE_PARM_DESC(max_queues, * L17 TODO: test performance with different values. */ unsigned int xenvif_max_pgrants = XEN_NETIF_RX_RING_SIZE; +module_param_named(max_persistent_grants, xenvif_max_pgrants, int, 0644); +MODULE_PARM_DESC(max_persistent_grants, + "Maximum number of grants to map persistently"); /* * This is the maximum slots a skb can have. If a guest sends a skb @@ -1764,8 +1767,6 @@ static int __init netback_init(void) xenvif_max_queues = min_t(unsigned int, MAX_QUEUES_DEFAULT, num_online_cpus()); - pr_info("max persistent grants: %d\n", xenvif_max_pgrants); - if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", fatal_skb_slots, XEN_NETBK_LEGACY_SLOTS_MAX); From 60e16b47faa3b639d5160df54a62d6109765a9d6 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Tue, 6 May 2025 16:16:35 +0200 Subject: [PATCH 03/11] Write feature-persistent to backend xenstore --- drivers/net/xen-netback/netback.c | 2 +- drivers/net/xen-netback/xenbus.c | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 0e500125600a6..d3498c7029780 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -75,7 +75,7 @@ MODULE_PARM_DESC(max_queues, /* * Maximum number of grants to map persistently in netback. - * L17 TODO: test performance with different values. + * L17 TODO: test performance with higher values. */ unsigned int xenvif_max_pgrants = XEN_NETIF_RX_RING_SIZE; module_param_named(max_persistent_grants, xenvif_max_pgrants, int, 0644); diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index c1ba4294f3647..595809a145426 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -1116,6 +1116,12 @@ static int netback_probe(struct xenbus_device *dev, if (err) pr_debug("Error writing feature-split-event-channels\n"); + /* Persistent grants support, this is an optional feature */ + err = xenbus_printf(XBT_NIL, dev->nodename, + "feature-persistent", "%d", xenvif_max_pgrants > 0); + if (err) + pr_debug("Error writing feature-persistent\n"); + /* Multi-queue support: This is an optional feature. */ err = xenbus_printf(XBT_NIL, dev->nodename, "multi-queue-max-queues", "%u", xenvif_max_queues); From 7a842b00b344daf1a6254db626b853b10d472c36 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Wed, 7 May 2025 11:36:48 +0200 Subject: [PATCH 04/11] Persistent grants feature negotiation --- drivers/net/xen-netback/common.h | 1 + drivers/net/xen-netback/xenbus.c | 3 +++ drivers/net/xen-netfront.c | 14 ++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 2c5a62cfba228..159ff90862b3d 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -291,6 +291,7 @@ struct xenvif { u8 can_sg:1; u8 ip_csum:1; u8 ipv6_csum:1; + u8 persistent_grants:1; u8 multicast_control:1; /* headroom requested by xen-netfront */ diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 595809a145426..a6c4d9a218a9b 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -972,6 +972,9 @@ static int read_xenbus_vif_flags(struct backend_info *be) vif->ipv6_csum = !!xenbus_read_unsigned(dev->otherend, "feature-ipv6-csum-offload", 0); + vif->persistent_grants = xenvif_max_pgrants && + xenbus_read_unsigned(dev->otherend, "feature-persistent", 0); + read_xenbus_frontend_xdp(be, dev); return 0; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 8425226c09f0d..f4551c971a0c3 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -174,6 +174,9 @@ struct netfront_info { bool netback_has_xdp_headroom; bool netfront_xdp_enabled; + /* Persistent grants */ + bool persistent_grants; + /* Is device behaving sane? */ bool broken; @@ -2268,6 +2271,10 @@ static int talk_to_netback(struct xenbus_device *dev, info->bounce = !xennet_trusted || !xenbus_read_unsigned(dev->nodename, "trusted", 1); + /* Check if backend supports persistent grants */ + info->persistent_grants = !!xenbus_read_unsigned(info->xbdev->otherend, + "feature-persistent", 0); + /* Check if backend supports multiple queues */ max_queues = xenbus_read_unsigned(info->xbdev->otherend, "multi-queue-max-queues", 1); @@ -2391,6 +2398,13 @@ static int talk_to_netback(struct xenbus_device *dev, goto abort_transaction; } + // L17 TODO: decide if having a persistent mod param like netback is useful + err = xenbus_write(xbt, dev->nodename, "feature-persistent", "1"); + if (err) { + message = "writing feature-persistent"; + goto abort_transaction; + } + err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) From a0cec980ad9ca5b2cd65748853df0162c0377dc6 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Wed, 25 Jun 2025 16:53:54 +0200 Subject: [PATCH 05/11] Persistent TX in netfront --- drivers/net/xen-netfront.c | 57 ++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f4551c971a0c3..21cabb6509e76 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -434,17 +434,22 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue) queue->tx_link[id] = TX_LINK_NONE; skb = queue->tx_skbs[id]; queue->tx_skbs[id] = NULL; - if (unlikely(!gnttab_end_foreign_access_ref( - queue->grant_tx_ref[id]))) { - dev_alert(dev, - "Grant still in use by backend domain\n"); - goto err; + + if (!queue->info->persistent_grants) { + if (unlikely(!gnttab_end_foreign_access_ref( + queue->grant_tx_ref[id]))) { + dev_alert(dev, + "Grant still in use by backend domain\n"); + goto err; + } + gnttab_release_grant_reference( + &queue->gref_tx_head, queue->grant_tx_ref[id]); + printk("[queue %d] xennet_tx_buf_gc(): ungranted and released with gref %u\n", queue->id, queue->grant_tx_ref[id]); + queue->grant_tx_ref[id] = INVALID_GRANT_REF; + queue->grant_tx_page[id] = NULL; } - gnttab_release_grant_reference( - &queue->gref_tx_head, queue->grant_tx_ref[id]); - queue->grant_tx_ref[id] = INVALID_GRANT_REF; - queue->grant_tx_page[id] = NULL; add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, id); + printk("[queue %d] xennet_tx_buf_gc(): added id %u to freelist\n", queue->id, id); dev_kfree_skb_irq(skb); } @@ -486,19 +491,35 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, struct sk_buff *skb = info->skb; id = get_id_from_list(&queue->tx_skb_freelist, queue->tx_link); + printk("[queue %d] xennet_tx_setup_grant(): got id %u from freelist\n", queue->id, id); tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); - ref = gnttab_claim_grant_reference(&queue->gref_tx_head); - WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref)); - gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, - gfn, GNTMAP_readonly); + /* Reuse claimed grants */ + if (queue->grant_tx_ref[id] == INVALID_GRANT_REF) { + ref = gnttab_claim_grant_reference(&queue->gref_tx_head); + WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref)); + + gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, + gfn, GNTMAP_readonly); + + queue->grant_tx_ref[id] = ref; + printk("[queue %d] xennet_tx_setup_grant(): claimed and granted with gref %u\n", queue->id, queue->grant_tx_ref[id]); + } + + if (queue->info->persistent_grants) { + /* Reuse granted pages */ + memcpy(pfn_to_kaddr(page_to_pfn(queue->grant_tx_page[id])) + offset, + pfn_to_kaddr(page_to_pfn(page)) + offset, len); + printk("[queue %d] xennet_tx_setup_grant(): memcpy'd client buf into page\n", + queue->id); + } else { + queue->grant_tx_page[id] = page; + } queue->tx_skbs[id] = skb; - queue->grant_tx_page[id] = page; - queue->grant_tx_ref[id] = ref; info->tx_local.id = id; - info->tx_local.gref = ref; + info->tx_local.gref = queue->grant_tx_ref[id]; info->tx_local.offset = offset; info->tx_local.size = len; info->tx_local.flags = 0; @@ -2043,8 +2064,10 @@ static int xennet_init_queue(struct netfront_queue *queue) for (i = 0; i < NET_TX_RING_SIZE; i++) { queue->tx_link[i] = i + 1; queue->grant_tx_ref[i] = INVALID_GRANT_REF; - queue->grant_tx_page[i] = NULL; + queue->grant_tx_page[i] = queue->info->persistent_grants ? + alloc_page(GFP_NOIO) : NULL; } + printk("[queue %d] xennet_init_queue(): refs and pool pages initialized\n", queue->id); queue->tx_link[NET_TX_RING_SIZE - 1] = TX_LINK_NONE; /* Clear out rx_skbs */ From 13d4a36b6896945ced63a3dd1b6153e28323ca1c Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Fri, 27 Jun 2025 16:18:37 +0200 Subject: [PATCH 06/11] WIP Persistent TX in netback ignoring header pgrants --- drivers/net/xen-netback/common.h | 20 +- drivers/net/xen-netback/interface.c | 16 +- drivers/net/xen-netback/netback.c | 438 ++++++++++++++++++++++++++-- drivers/net/xen-netfront.c | 4 +- 4 files changed, 444 insertions(+), 34 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 159ff90862b3d..420250ca5b3ff 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -132,6 +132,14 @@ struct xenvif_copy_state { struct sk_buff_head *completed; }; +struct persistent_gnt { + struct page *page; + grant_ref_t gnt; + grant_handle_t handle; + bool active; + struct rb_node node; +}; + struct xenvif_queue { /* Per-queue data for xenvif */ unsigned int id; /* Queue ID, 0-based */ char name[QUEUE_NAME_SIZE]; /* DEVNAME-qN */ @@ -213,6 +221,12 @@ struct xenvif_queue { /* Per-queue data for xenvif */ u64 credit_window_start; bool rate_limited; + /* Persistent grants */ + struct rb_root persistent_gnts; + unsigned int persistent_gnt_c; + struct gnttab_page_cache persistent_pages; + struct persistent_gnt *tx_pgrants[MAX_PENDING_REQS]; + /* Statistics */ struct xenvif_stats stats; }; @@ -418,12 +432,16 @@ extern struct dentry *xen_netback_dbg_root; void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue, struct sk_buff *skb); -void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue); +void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue, + unsigned int pending_dealloc); /* Multicast control */ bool xenvif_mcast_match(struct xenvif *vif, const u8 *addr); void xenvif_mcast_addr_list_free(struct xenvif *vif); +/* Persistent grants */ +void xenvif_pgrants_destroy(struct xenvif_queue *queue); + /* Hash */ void xenvif_init_hash(struct xenvif *vif); void xenvif_deinit_hash(struct xenvif *vif); diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index fc3bb63b9ac3e..a5af4d19fe7fd 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -56,7 +56,8 @@ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue, atomic_inc(&queue->inflight_packets); } -void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue) +void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue, + unsigned int pending_dealloc) { atomic_dec(&queue->inflight_packets); @@ -64,7 +65,8 @@ void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue) * that if kthread_stop() has already been called, the dealloc thread * does not wait forever with nothing to wake it. */ - wake_up(&queue->dealloc_wq); + if (pending_dealloc) + wake_up(&queue->dealloc_wq); } static int xenvif_schedulable(struct xenvif *vif) @@ -588,12 +590,18 @@ int xenvif_init_queue(struct xenvif_queue *queue) return -ENOMEM; } + if (queue->vif->persistent_grants) { + queue->persistent_gnts.rb_node = NULL; + queue->persistent_gnt_c = 0; + } + for (i = 0; i < MAX_PENDING_REQS; i++) { queue->pending_tx_info[i].callback_struct = (struct ubuf_info_msgzc) { { .callback = xenvif_zerocopy_callback }, { { .ctx = NULL, .desc = i } } }; queue->grant_tx_handle[i] = NETBACK_INVALID_HANDLE; + queue->tx_pgrants[i] = NULL; } return 0; @@ -696,6 +704,10 @@ static void xenvif_disconnect_queue(struct xenvif_queue *queue) } xenvif_unmap_frontend_data_rings(queue); + + if (queue->vif->persistent_grants) { + xenvif_pgrants_destroy(queue); + } } int xenvif_connect_data(struct xenvif_queue *queue, diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index d3498c7029780..65ad1f39b1228 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -73,11 +73,11 @@ module_param_named(max_queues, xenvif_max_queues, uint, 0644); MODULE_PARM_DESC(max_queues, "Maximum number of queues per virtual interface"); +// L17 TODO: test performance with higher values like blkback's hardcoded 1056 /* * Maximum number of grants to map persistently in netback. - * L17 TODO: test performance with higher values. */ -unsigned int xenvif_max_pgrants = XEN_NETIF_RX_RING_SIZE; +unsigned int xenvif_max_pgrants = XEN_NETIF_TX_RING_SIZE; module_param_named(max_persistent_grants, xenvif_max_pgrants, int, 0644); MODULE_PARM_DESC(max_persistent_grants, "Maximum number of grants to map persistently"); @@ -136,9 +136,21 @@ static inline unsigned long idx_to_kaddr(struct xenvif_queue *queue, return (unsigned long)pfn_to_kaddr(idx_to_pfn(queue, idx)); } +static inline unsigned long page_to_kaddr(struct page *page) +{ + return (unsigned long)pfn_to_kaddr(page_to_pfn(page)); +} + #define callback_param(vif, pending_idx) \ (vif->pending_tx_info[pending_idx].callback_struct) +#define foreach_grant_safe(pos, n, rbtree, node) \ + for ((pos) = container_of(rb_first((rbtree)), typeof(*(pos)), node), \ + (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL; \ + &(pos)->node != NULL; \ + (pos) = container_of(n, typeof(*(pos)), node), \ + (n) = (&(pos)->node != NULL) ? rb_next(&(pos)->node) : NULL) + /* Find the containing VIF's structure from a pointer in pending_tx_info array */ static inline struct xenvif_queue *ubuf_to_queue(const struct ubuf_info_msgzc *ubuf) @@ -166,6 +178,238 @@ static inline pending_ring_idx_t pending_index(unsigned i) return i & (MAX_PENDING_REQS-1); } +static struct page *get_free_page(struct xenvif_queue *queue, + int persistent, + u16 pending_idx) +{ + struct page *page; + + if (!persistent || gnttab_page_cache_get(&queue->persistent_pages, &page)) { + WARN_ON(persistent); // shouldn't map with mmap page (without errors) + page = queue->mmap_pages[pending_idx]; + } + + return page; +} + +static int add_persistent_gnt(struct xenvif_queue *queue, + struct persistent_gnt *pgrant) +{ + struct rb_node **new = NULL, *parent = NULL; + struct persistent_gnt *this; + + WARN_ON(!pgrant); + + if (queue->persistent_gnt_c >= xenvif_max_pgrants) { + pr_alert_ratelimited("trying to add a gref when pgrant limit has been reached\n"); + return -EBUSY; + } + /* Figure out where to put new node */ + new = &queue->persistent_gnts.rb_node; + while (*new) { + this = container_of(*new, struct persistent_gnt, node); + + parent = *new; + if (pgrant->gnt < this->gnt) + new = &((*new)->rb_left); + else if (pgrant->gnt > this->gnt) + new = &((*new)->rb_right); + else { + pr_alert_ratelimited("trying to add a gref that's already in the tree\n"); + return -EINVAL; + } + } + pgrant->active = true; + printk("[queue %u] add_persistent_gnt(): gref %u added to the tree\n", queue->id, pgrant->gnt); + + /* Add new node and rebalance tree. */ + rb_link_node(&(pgrant->node), parent, new); + rb_insert_color(&(pgrant->node), &queue->persistent_gnts); + queue->persistent_gnt_c++; + //idk what it's for... atomic_inc(&queue->persistent_gnt_in_use); + printk("[queue %u] add_persistent_gnt(): now %d pgrants in the tree\n", queue->id, queue->persistent_gnt_c); + + return 0; +} + +static struct persistent_gnt *get_persistent_gnt(struct xenvif_queue *queue, + grant_ref_t gref) +{ + struct persistent_gnt *pgrant; + struct rb_node *node = NULL; + + node = queue->persistent_gnts.rb_node; + while (node) { + pgrant = container_of(node, struct persistent_gnt, node); + + if (gref < pgrant->gnt) + node = node->rb_left; + else if (gref > pgrant->gnt) + node = node->rb_right; + else { + printk("[queue %u] get_persistent_gnt(): getting gref %u from the tree\n", queue->id, pgrant->gnt); + if (pgrant->active) { + pr_alert_ratelimited("requesting a grant already in use\n"); + return ERR_PTR(-EBUSY); + } + pgrant->active = true; + //idk what it's for... atomic_inc(&queue->persistent_gnt_in_use); + return pgrant; + } + } + printk("[queue %u] get_persistent_gnt(): gref %u isn't in the tree\n", queue->id, gref); + return NULL; +} + +static void put_persistent_gnt(struct xenvif_queue *queue, + struct persistent_gnt *pgrant) +{ + WARN_ON(!pgrant); + + if (!pgrant->active) + pr_alert_ratelimited("freeing a grant already unused\n"); + + pgrant->active = false; + //idk what it's for... atomic_dec(&ring->persistent_gnt_in_use); + printk("[queue %u] put_persistent_gnt(): put pgrant with gref %u\n", queue->id, pgrant->gnt); +} + +static void free_persistent_gnts(struct xenvif_queue *queue, + struct rb_root *root, + unsigned int num) +{ + struct gnttab_unmap_grant_ref unmap[FATAL_SKB_SLOTS_DEFAULT]; + struct page *pages[FATAL_SKB_SLOTS_DEFAULT]; + struct persistent_gnt *pgrant; + struct rb_node *n; + int segs_to_unmap = 0; + struct gntab_unmap_queue_data unmap_data; + + unmap_data.pages = pages; + unmap_data.unmap_ops = unmap; + unmap_data.kunmap_ops = NULL; + + foreach_grant_safe(pgrant, n, root, node) { + BUG_ON(pgrant->handle == INVALID_GRANT_HANDLE); + + gnttab_set_unmap_op(&unmap[segs_to_unmap], + (unsigned long) pfn_to_kaddr(page_to_pfn(pgrant->page)), + GNTMAP_host_map, + pgrant->handle); + + pages[segs_to_unmap] = pgrant->page; + + if (++segs_to_unmap == FATAL_SKB_SLOTS_DEFAULT || + !rb_next(&pgrant->node)) { + + unmap_data.count = segs_to_unmap; + BUG_ON(gnttab_unmap_refs_sync(&unmap_data)); + gnttab_page_cache_put(&queue->persistent_pages, pages, + segs_to_unmap); + segs_to_unmap = 0; + } + + rb_erase(&pgrant->node, root); + kfree(pgrant); + num--; + } + BUG_ON(num != 0); + printk("[queue %u] free_persistent_gnts(): freed all pgrants from the tree\n", queue->id); +} + +static inline void xenvif_pgrant_set(struct xenvif_queue *queue, + u16 pending_idx, + struct persistent_gnt *pgrant) +{ + WARN_ON(!pgrant); + + if (unlikely(queue->tx_pgrants[pending_idx])) { + netdev_err(queue->vif->dev, + "Trying to overwrite an active persistent grant! pending_idx: 0x%x\n", + pending_idx); + BUG(); + } + queue->tx_pgrants[pending_idx] = pgrant; + + WARN_ON(!pgrant->active); // don't set a pgrant marked inactive + + printk("[queue %u] xenvif_pgrant_set(): set pgrant with gref %u at index %u\n", + queue->id, pgrant->gnt, pending_idx); +} + +static inline void xenvif_pgrant_reset(struct xenvif_queue *queue, + u16 pending_idx) +{ + struct persistent_gnt *pgrant = queue->tx_pgrants[pending_idx]; + + if (unlikely(!pgrant)) { + netdev_err(queue->vif->dev, + "Trying to release an inactive persistent_grant! pending_idx: 0x%x\n", + pending_idx); + BUG(); + } + put_persistent_gnt(queue, pgrant); + queue->tx_pgrants[pending_idx] = NULL; + + printk("[queue %u] xenvif_pgrant_reset(): reset pgrant at index %u\n", + queue->id, pending_idx); +} + +/* + * Create a new persistent grant and add it to the tree. + */ +static struct persistent_gnt *xenvif_pgrant_new(struct xenvif_queue *queue, + struct gnttab_map_grant_ref *gop) +{ + struct persistent_gnt *pgrant; + + WARN_ON(!gop); + + pgrant = kmalloc(sizeof(struct persistent_gnt), GFP_KERNEL); + if (!pgrant) + BUG(); // not handling errors yet + // return NULL; + + pgrant->page = virt_to_page(gop->host_addr); + pgrant->gnt = gop->ref; + pgrant->handle = gop->handle; + + if (unlikely(add_persistent_gnt(queue, pgrant))) { + kfree(pgrant); + BUG(); // not handling errors yet + //return NULL; + } + + printk("[queue %u] xenvif_pgrant_new(): new pgrant with gref %u, handle %u\n", + queue->id, pgrant->gnt, pgrant->handle); + + return pgrant; +} + +/* + * Free all persistent grants data and empty the pool of free pages. + */ +void xenvif_pgrants_destroy(struct xenvif_queue *queue) +{ + int i; + + if (!RB_EMPTY_ROOT(&queue->persistent_gnts)) + free_persistent_gnts(queue, &queue->persistent_gnts, + queue->persistent_gnt_c); + + BUG_ON(!RB_EMPTY_ROOT(&queue->persistent_gnts)); + queue->persistent_gnts.rb_node = NULL; + queue->persistent_gnt_c = 0; + + gnttab_page_cache_shrink(&queue->persistent_pages, 0 /* All */); + + // L17 TEST remove when tests are done + for (i = 0; i < MAX_PENDING_REQS; i++) { + if (queue->tx_pgrants[i] != NULL) + printk("[queue %u] xenvif_pgrants_destroy(): tx_pgrants still contains grants when freeing!\n", queue->id); + } +} + void xenvif_kick_thread(struct xenvif_queue *queue) { wake_up(&queue->wq); @@ -339,6 +583,7 @@ struct xenvif_tx_cb { u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1]; u8 copy_count; u32 split_mask; + u8 header_map_count; }; #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb) @@ -346,19 +591,18 @@ struct xenvif_tx_cb { #define copy_count(skb) (XENVIF_TX_CB(skb)->copy_count) static inline void xenvif_tx_create_map_op(struct xenvif_queue *queue, - u16 pending_idx, struct xen_netif_tx_request *txp, - unsigned int extra_count, + struct page *page, struct gnttab_map_grant_ref *mop) { - queue->pages_to_map[mop-queue->tx_map_ops] = queue->mmap_pages[pending_idx]; - gnttab_set_map_op(mop, idx_to_kaddr(queue, pending_idx), + WARN_ON(!page); + queue->pages_to_map[mop-queue->tx_map_ops] = page; + gnttab_set_map_op(mop, page_to_kaddr(page), GNTMAP_host_map | GNTMAP_readonly, txp->gref, queue->vif->domid); - memcpy(&queue->pending_tx_info[pending_idx].req, txp, - sizeof(*txp)); - queue->pending_tx_info[pending_idx].extra_count = extra_count; + printk("[queue %u] xenvif_tx_create_map_op(): created map op with gref %u\n", + queue->id, mop->ref); } static inline struct sk_buff *xenvif_alloc_skb(unsigned int size) @@ -399,16 +643,39 @@ static void xenvif_get_requests(struct xenvif_queue *queue, struct gnttab_copy *cop = queue->tx_copy_ops + *copy_ops; struct gnttab_map_grant_ref *gop = queue->tx_map_ops + *map_ops; struct xen_netif_tx_request *txp = first; + struct page *page; + int use_pgrants = queue->vif->persistent_grants; + struct persistent_gnt *pgrant = NULL; nr_slots = shinfo->nr_frags + frag_overflow + 1; copy_count(skb) = 0; XENVIF_TX_CB(skb)->split_mask = 0; + XENVIF_TX_CB(skb)->header_map_count = 0; + + //printk("=============== data_len: %u bytes to copy\n", data_len); + //printk("=============== first request size: %u bytes, gref: %u\n", txp->size, txp->gref); + + if (use_pgrants) { + pgrant = get_persistent_gnt(queue, txp->gref); + if (pgrant) + put_persistent_gnt(queue, pgrant); + } /* Create copy ops for exactly data_len bytes into the skb head. */ __skb_put(skb, data_len); while (data_len > 0) { int amount = data_len > txp->size ? txp->size : data_len; + index = pending_index(queue->pending_cons); + pending_idx = queue->pending_ring[index]; + + if (use_pgrants && !pgrant && (amount == txp->size)) { + printk("[queue %u] xenvif_get_requests(): request with gref %u will be covered by copies and isn't a pgrant\n", queue->id, txp->gref); + page = get_free_page(queue, use_pgrants, pending_idx); + xenvif_tx_create_map_op(queue, txp, page, gop++); + XENVIF_TX_CB(skb)->header_map_count++; + } + bool split = false; cop->source.u.ref = txp->gref; @@ -417,10 +684,10 @@ static void xenvif_get_requests(struct xenvif_queue *queue, cop->dest.domid = DOMID_SELF; cop->dest.offset = (offset_in_page(skb->data + - skb_headlen(skb) - - data_len)) & ~XEN_PAGE_MASK; + skb_headlen(skb) - + data_len)) & ~XEN_PAGE_MASK; cop->dest.u.gmfn = virt_to_gfn(skb->data + skb_headlen(skb) - - data_len); + - data_len); /* Don't cross local page boundary! */ if (cop->dest.offset + amount > XEN_PAGE_SIZE) { @@ -432,8 +699,6 @@ static void xenvif_get_requests(struct xenvif_queue *queue, cop->len = amount; cop->flags = GNTCOPY_source_gref; - index = pending_index(queue->pending_cons); - pending_idx = queue->pending_ring[index]; callback_param(queue, pending_idx).ctx = NULL; copy_pending_idx(skb, copy_count(skb)) = pending_idx; if (!split) @@ -444,28 +709,43 @@ static void xenvif_get_requests(struct xenvif_queue *queue, if (amount == txp->size) { /* The copy op covered the full tx_request */ - + printk("[queue %u] xenvif_get_requests(): request with gref %u covered with copies\n", + queue->id, txp->gref); memcpy(&queue->pending_tx_info[pending_idx].req, txp, sizeof(*txp)); queue->pending_tx_info[pending_idx].extra_count = (txp == first) ? extra_count : 0; - if (txp == first) + if (txp == first) { txp = txfrags; - else + //printk("=============== first request covered with copies, next request size: %u bytes, gref: %u, %u bytes left to copy\n", txp->size, txp->gref, data_len); + } else { txp++; + //printk("=============== another request covered with copies, next request size: %u bytes, gref: %u, %u bytes left to copy\n", txp->size, txp->gref, data_len); + } queue->pending_cons++; nr_slots--; + if (use_pgrants && nr_slots > 0) { + pgrant = get_persistent_gnt(queue, txp->gref); + if (pgrant) + put_persistent_gnt(queue, pgrant); + } } else { /* The copy op partially covered the tx_request. * The remainder will be mapped or copied in the next * iteration. */ + printk("[queue %u] xenvif_get_requests(): request with gref %u partially covered with copies\n", + queue->id, txp->gref); txp->offset += amount; txp->size -= amount; + //printk("=============== request partially covered with copies, %u bytes left to copy\n", data_len); } } + printk("[queue %u] xenvif_get_requests(): finished creating copies! %d slots remaining\n", queue->id, nr_slots); + + /* Create map ops for the skb frags */ for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS; nr_slots--) { if (unlikely(!txp->size)) { @@ -476,11 +756,26 @@ static void xenvif_get_requests(struct xenvif_queue *queue, index = pending_index(queue->pending_cons++); pending_idx = queue->pending_ring[index]; - xenvif_tx_create_map_op(queue, pending_idx, txp, - txp == first ? extra_count : 0, gop); + + if (use_pgrants) + pgrant = get_persistent_gnt(queue, txp->gref); + + if (!use_pgrants || !pgrant) { + page = get_free_page(queue, use_pgrants, pending_idx); + xenvif_tx_create_map_op(queue, txp, page, gop++); + } else { + /* No map op needed for this frag */ + xenvif_pgrant_set(queue, pending_idx, pgrant); + } + + printk("[queue %u] xenvif_get_requests(): request with gref %u covered with mapping\n", + queue->id, txp->gref); + memcpy(&queue->pending_tx_info[pending_idx].req, txp, sizeof(*txp)); + queue->pending_tx_info[pending_idx].extra_count = + (txp == first) ? extra_count : 0; + frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); ++shinfo->nr_frags; - ++gop; if (txp == first) txp = txfrags; @@ -488,6 +783,7 @@ static void xenvif_get_requests(struct xenvif_queue *queue, txp++; } + /* Create map ops for the nskb frags */ if (nr_slots > 0) { shinfo = skb_shinfo(nskb); @@ -502,12 +798,24 @@ static void xenvif_get_requests(struct xenvif_queue *queue, index = pending_index(queue->pending_cons++); pending_idx = queue->pending_ring[index]; - xenvif_tx_create_map_op(queue, pending_idx, txp, 0, - gop); + + if (use_pgrants) + pgrant = get_persistent_gnt(queue, txp->gref); + + if (!use_pgrants || !pgrant) { + page = get_free_page(queue, use_pgrants, pending_idx); + xenvif_tx_create_map_op(queue, txp, page, gop++); + } else { + /* No map op needed for this frag */ + xenvif_pgrant_set(queue, pending_idx, pgrant); + } + + memcpy(&queue->pending_tx_info[pending_idx].req, txp, sizeof(*txp)); + queue->pending_tx_info[pending_idx].extra_count = 0; + frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); ++shinfo->nr_frags; - ++gop; } if (shinfo->nr_frags) { @@ -526,6 +834,8 @@ static void xenvif_get_requests(struct xenvif_queue *queue, (*copy_ops) = cop - queue->tx_copy_ops; (*map_ops) = gop - queue->tx_map_ops; + + printk("[queue %u] xenvif_get_requests(): finished creating maps! (%u for skb header)\n", queue->id, XENVIF_TX_CB(skb)->header_map_count); } static inline void xenvif_grant_handle_set(struct xenvif_queue *queue, @@ -540,6 +850,8 @@ static inline void xenvif_grant_handle_set(struct xenvif_queue *queue, BUG(); } queue->grant_tx_handle[pending_idx] = handle; + printk("[queue %u] xenvif_grant_handle_set(): set grant handle %u at index %u\n", + queue->id, handle, pending_idx); } static inline void xenvif_grant_handle_reset(struct xenvif_queue *queue, @@ -553,6 +865,8 @@ static inline void xenvif_grant_handle_reset(struct xenvif_queue *queue, BUG(); } queue->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE; + printk("[queue %u] xenvif_grant_handle_reset(): reset grant handle at index %u\n", + queue->id, pending_idx); } static int xenvif_tx_check_gop(struct xenvif_queue *queue, @@ -574,14 +888,14 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, const bool sharedslot = nr_frags && frag_get_pending_idx(&shinfo->frags[0]) == copy_pending_idx(skb, copy_count(skb) - 1); - int i, err = 0; + struct persistent_gnt *pgrant; + int i, newerr, err = 0; for (i = 0; i < copy_count(skb); i++) { int newerr; /* Check status of header. */ pending_idx = copy_pending_idx(skb, i); - newerr = (*gopp_copy)->status; /* Split copies need to be handled together. */ @@ -591,6 +905,7 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, newerr = (*gopp_copy)->status; } if (likely(!newerr)) { + printk("[queue %u] xenvif_tx_check_gop(): header copy at pending_idx %u was successful\n", queue->id, pending_idx); /* The first frag might still have this slot mapped */ if (i < copy_count(skb) - 1 || !sharedslot) xenvif_idx_release(queue, pending_idx, @@ -611,19 +926,50 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, (*gopp_copy)++; } + // the first gop_maps could be for the first requests, use a counter in skb->cb + // to know how many gop_maps are not for the frags to create pgrants here + // and increment gop_map to the right value for check_frags + for (i = 0; i < XENVIF_TX_CB(skb)->header_map_count; i++, gop_map++) { + newerr = gop_map->status; + WARN_ON(newerr); // not handling errors yet + printk("[queue %u] xenvif_tx_check_gop(): header map with gref %u was successful\n", queue->id, gop_map->ref); + pgrant = xenvif_pgrant_new(queue, gop_map); + if (pgrant) + put_persistent_gnt(queue, pgrant); + } + check_frags: for (i = 0; i < nr_frags; i++, gop_map++) { - int j, newerr; + int j; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); + // if there is a pgrant at pending_idx, set grant handle and continue + pgrant = queue->tx_pgrants[pending_idx]; + if (pgrant) { + printk("[queue %u] xenvif_tx_check_gop(): pgrant with gref %u found for frag at pending_idx %u\n", queue->id, pgrant->gnt, pending_idx); + xenvif_grant_handle_set(queue, + pending_idx, + pgrant->handle); + // don't skip current map op to check + gop_map--; + continue; + } /* Check error status: if okay then remember grant handle. */ + printk("[queue %u] xenvif_tx_check_gop(): frag map at pending_index %u with gref %u was successful\n", queue->id, pending_idx, gop_map->ref); newerr = gop_map->status; if (likely(!newerr)) { xenvif_grant_handle_set(queue, pending_idx, gop_map->handle); + // if the page used to map is a persistent page, make a new pgrant + // and set the pgrant to tx_pgrants at pending_idx + if (virt_to_page(gop_map->host_addr) != queue->mmap_pages[pending_idx]) { + pgrant = xenvif_pgrant_new(queue, gop_map); + xenvif_pgrant_set(queue, pending_idx, pgrant); + } + /* Had a previous error? Invalidate this fragment. */ if (unlikely(err)) { xenvif_idx_unmap(queue, pending_idx); @@ -703,9 +1049,11 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb) skb_frag_t *frag = shinfo->frags + i; struct xen_netif_tx_request *txp; struct page *page; + struct persistent_gnt *pgrant; u16 pending_idx; pending_idx = frag_get_pending_idx(frag); + printk("[queue %u] xenvif_fill_frags(): frag pending_idx: %u\n", queue->id, pending_idx); /* If this is not the first frag, chain it to the previous*/ if (prev_pending_idx == INVALID_PENDING_IDX) @@ -719,14 +1067,22 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb) prev_pending_idx = pending_idx; txp = &queue->pending_tx_info[pending_idx].req; - page = virt_to_page(idx_to_kaddr(queue, pending_idx)); + printk("[queue %u] xenvif_fill_frags(): associated request: gref %u, offset %u, size %u\n", queue->id, txp->gref, txp->offset, txp->size); + // if there is a pgrant at pending_idx, get the page from the pgrant + pgrant = queue->tx_pgrants[pending_idx]; + if (pgrant) + printk("[queue %u] xenvif_fill_frags(): associated pgrant: gref %u, handle %u\n", queue->id, pgrant->gnt, pgrant->handle); + else + printk("[queue %u] xenvif_fill_frags(): associated pgrant: NONE\n", queue->id); + page = pgrant ? pgrant->page : virt_to_page(idx_to_kaddr(queue, pending_idx)); __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); skb->len += txp->size; skb->data_len += txp->size; skb->truesize += txp->size; /* Take an extra reference to offset network stack's put_page */ - get_page(queue->mmap_pages[pending_idx]); + // use already existing var *page* instead + get_page(page); } } @@ -955,6 +1311,8 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, if (!work_to_do) break; + printk("[queue %u] ///////////////////////// SKB START\n", queue->id); + idx = queue->tx.req_cons; rmb(); /* Ensure that we see the request before we copy it. */ RING_COPY_REQUEST(&queue->tx, idx, &txreq); @@ -1064,6 +1422,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, "Can't allocate the frag_list skb.\n"); break; } + printk("WE HAVE A FRAG_LIST SKB\n"); } if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { @@ -1106,6 +1465,12 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, type); } + printk("[queue %u] xenvif_tx_build_gops(): skb uses %d slots, %u bytes to copy\n", + queue->id, skb_shinfo(skb)->nr_frags + frag_overflow + 1, data_len); + printk("[queue %u] xenvif_tx_build_gops(): gref of all requests: %u", queue->id, txreq.gref); + for (int i = 0; i < ret; i++) + printk(", %u", txfrags[i].gref); + xenvif_get_requests(queue, skb, &txreq, txfrags, copy_ops, map_ops, frag_overflow, nskb, extra_count, data_len); @@ -1293,6 +1658,8 @@ static int xenvif_tx_submit(struct xenvif_queue *queue) } netif_receive_skb(skb); + + printk("[queue %u] ///////////////////////// SKB SENT\n", queue->id); } return work_done; @@ -1302,7 +1669,7 @@ void xenvif_zerocopy_callback(struct sk_buff *skb, struct ubuf_info *ubuf_base, bool zerocopy_success) { unsigned long flags; - pending_ring_idx_t index; + pending_ring_idx_t index, dealloc_prod_save; struct ubuf_info_msgzc *ubuf = uarg_to_msgzc(ubuf_base); struct xenvif_queue *queue = ubuf_to_queue(ubuf); @@ -1310,9 +1677,18 @@ void xenvif_zerocopy_callback(struct sk_buff *skb, struct ubuf_info *ubuf_base, * from each other. */ spin_lock_irqsave(&queue->callback_lock, flags); + dealloc_prod_save = queue->dealloc_prod; do { u16 pending_idx = ubuf->desc; ubuf = (struct ubuf_info_msgzc *) ubuf->ctx; + + if (queue->tx_pgrants[pending_idx]) { + // release stuff without unmapping + xenvif_pgrant_reset(queue, pending_idx); + xenvif_grant_handle_reset(queue, pending_idx); + xenvif_idx_release(queue, pending_idx, XEN_NETIF_RSP_OKAY); + continue; + } BUG_ON(queue->dealloc_prod - queue->dealloc_cons >= MAX_PENDING_REQS); index = pending_index(queue->dealloc_prod); @@ -1329,7 +1705,8 @@ void xenvif_zerocopy_callback(struct sk_buff *skb, struct ubuf_info *ubuf_base, queue->stats.tx_zerocopy_success++; else queue->stats.tx_zerocopy_fail++; - xenvif_skb_zerocopy_complete(queue); + // if dealloc_prod didn't move, skip only the wake_up call (see function) + xenvif_skb_zerocopy_complete(queue, dealloc_prod_save - queue->dealloc_prod); } static inline void xenvif_tx_dealloc_action(struct xenvif_queue *queue) @@ -1410,6 +1787,7 @@ int xenvif_tx_action(struct xenvif_queue *queue, int budget) xenvif_tx_build_gops(queue, budget, &nr_cops, &nr_mops); + // L17 TODO it may be normal when we will memcpy using pgrants in copy loop if (nr_cops == 0) return 0; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 21cabb6509e76..020e05f8cb513 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2301,7 +2301,9 @@ static int talk_to_netback(struct xenbus_device *dev, /* Check if backend supports multiple queues */ max_queues = xenbus_read_unsigned(info->xbdev->otherend, "multi-queue-max-queues", 1); - num_queues = min(max_queues, xennet_max_queues); + //num_queues = min(max_queues, xennet_max_queues); + // L17 TEST remove when it works with a single queue + num_queues = 1; /* Check feature-split-event-channels */ feature_split_evtchn = xenbus_read_unsigned(info->xbdev->otherend, From d042bfb8effacac1e86898dd734c5164e7835853 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Wed, 2 Jul 2025 10:57:26 +0200 Subject: [PATCH 07/11] Grant persistent pages to netback --- drivers/net/xen-netback/netback.c | 2 +- drivers/net/xen-netfront.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 65ad1f39b1228..86d1990e973c4 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -956,10 +956,10 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, } /* Check error status: if okay then remember grant handle. */ - printk("[queue %u] xenvif_tx_check_gop(): frag map at pending_index %u with gref %u was successful\n", queue->id, pending_idx, gop_map->ref); newerr = gop_map->status; if (likely(!newerr)) { + printk("[queue %u] xenvif_tx_check_gop(): frag map at pending_index %u with gref %u was successful\n", queue->id, pending_idx, gop_map->ref); xenvif_grant_handle_set(queue, pending_idx, gop_map->handle); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 020e05f8cb513..53b898466949b 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -499,6 +499,9 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, ref = gnttab_claim_grant_reference(&queue->gref_tx_head); WARN_ON_ONCE(IS_ERR_VALUE((unsigned long)(int)ref)); + if (queue->info->persistent_grants) + gfn = pfn_to_gfn(page_to_xen_pfn(queue->grant_tx_page[id])); + gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, gfn, GNTMAP_readonly); @@ -508,8 +511,9 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, if (queue->info->persistent_grants) { /* Reuse granted pages */ - memcpy(pfn_to_kaddr(page_to_pfn(queue->grant_tx_page[id])) + offset, + memcpy(pfn_to_kaddr(page_to_pfn(queue->grant_tx_page[id])), pfn_to_kaddr(page_to_pfn(page)) + offset, len); + offset = 0; // worried that offsets will introduce bleeding printk("[queue %d] xennet_tx_setup_grant(): memcpy'd client buf into page\n", queue->id); } else { @@ -2301,9 +2305,7 @@ static int talk_to_netback(struct xenbus_device *dev, /* Check if backend supports multiple queues */ max_queues = xenbus_read_unsigned(info->xbdev->otherend, "multi-queue-max-queues", 1); - //num_queues = min(max_queues, xennet_max_queues); - // L17 TEST remove when it works with a single queue - num_queues = 1; + num_queues = min(max_queues, xennet_max_queues); /* Check feature-split-event-channels */ feature_split_evtchn = xenbus_read_unsigned(info->xbdev->otherend, From 33be96d2a4ce4bfc22662feb08a4f50b93019b8c Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Thu, 3 Jul 2025 11:08:53 +0200 Subject: [PATCH 08/11] Remove header pgrants handling --- drivers/net/xen-netback/netback.c | 56 +++++-------------------------- 1 file changed, 9 insertions(+), 47 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 86d1990e973c4..7e8bbc9f5f7c5 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -583,7 +583,6 @@ struct xenvif_tx_cb { u16 copy_pending_idx[XEN_NETBK_LEGACY_SLOTS_MAX + 1]; u8 copy_count; u32 split_mask; - u8 header_map_count; }; #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb) @@ -651,31 +650,11 @@ static void xenvif_get_requests(struct xenvif_queue *queue, copy_count(skb) = 0; XENVIF_TX_CB(skb)->split_mask = 0; - XENVIF_TX_CB(skb)->header_map_count = 0; - - //printk("=============== data_len: %u bytes to copy\n", data_len); - //printk("=============== first request size: %u bytes, gref: %u\n", txp->size, txp->gref); - - if (use_pgrants) { - pgrant = get_persistent_gnt(queue, txp->gref); - if (pgrant) - put_persistent_gnt(queue, pgrant); - } /* Create copy ops for exactly data_len bytes into the skb head. */ __skb_put(skb, data_len); while (data_len > 0) { int amount = data_len > txp->size ? txp->size : data_len; - index = pending_index(queue->pending_cons); - pending_idx = queue->pending_ring[index]; - - if (use_pgrants && !pgrant && (amount == txp->size)) { - printk("[queue %u] xenvif_get_requests(): request with gref %u will be covered by copies and isn't a pgrant\n", queue->id, txp->gref); - page = get_free_page(queue, use_pgrants, pending_idx); - xenvif_tx_create_map_op(queue, txp, page, gop++); - XENVIF_TX_CB(skb)->header_map_count++; - } - bool split = false; cop->source.u.ref = txp->gref; @@ -699,6 +678,9 @@ static void xenvif_get_requests(struct xenvif_queue *queue, cop->len = amount; cop->flags = GNTCOPY_source_gref; + index = pending_index(queue->pending_cons); + pending_idx = queue->pending_ring[index]; + callback_param(queue, pending_idx).ctx = NULL; copy_pending_idx(skb, copy_count(skb)) = pending_idx; if (!split) @@ -716,20 +698,13 @@ static void xenvif_get_requests(struct xenvif_queue *queue, queue->pending_tx_info[pending_idx].extra_count = (txp == first) ? extra_count : 0; - if (txp == first) { + if (txp == first) txp = txfrags; - //printk("=============== first request covered with copies, next request size: %u bytes, gref: %u, %u bytes left to copy\n", txp->size, txp->gref, data_len); - } else { + else txp++; - //printk("=============== another request covered with copies, next request size: %u bytes, gref: %u, %u bytes left to copy\n", txp->size, txp->gref, data_len); - } + queue->pending_cons++; nr_slots--; - if (use_pgrants && nr_slots > 0) { - pgrant = get_persistent_gnt(queue, txp->gref); - if (pgrant) - put_persistent_gnt(queue, pgrant); - } } else { /* The copy op partially covered the tx_request. * The remainder will be mapped or copied in the next @@ -739,7 +714,6 @@ static void xenvif_get_requests(struct xenvif_queue *queue, queue->id, txp->gref); txp->offset += amount; txp->size -= amount; - //printk("=============== request partially covered with copies, %u bytes left to copy\n", data_len); } } @@ -835,7 +809,7 @@ static void xenvif_get_requests(struct xenvif_queue *queue, (*copy_ops) = cop - queue->tx_copy_ops; (*map_ops) = gop - queue->tx_map_ops; - printk("[queue %u] xenvif_get_requests(): finished creating maps! (%u for skb header)\n", queue->id, XENVIF_TX_CB(skb)->header_map_count); + printk("[queue %u] xenvif_get_requests(): finished creating maps!\n", queue->id); } static inline void xenvif_grant_handle_set(struct xenvif_queue *queue, @@ -889,7 +863,7 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, frag_get_pending_idx(&shinfo->frags[0]) == copy_pending_idx(skb, copy_count(skb) - 1); struct persistent_gnt *pgrant; - int i, newerr, err = 0; + int i, err = 0; for (i = 0; i < copy_count(skb); i++) { int newerr; @@ -926,21 +900,9 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, (*gopp_copy)++; } - // the first gop_maps could be for the first requests, use a counter in skb->cb - // to know how many gop_maps are not for the frags to create pgrants here - // and increment gop_map to the right value for check_frags - for (i = 0; i < XENVIF_TX_CB(skb)->header_map_count; i++, gop_map++) { - newerr = gop_map->status; - WARN_ON(newerr); // not handling errors yet - printk("[queue %u] xenvif_tx_check_gop(): header map with gref %u was successful\n", queue->id, gop_map->ref); - pgrant = xenvif_pgrant_new(queue, gop_map); - if (pgrant) - put_persistent_gnt(queue, pgrant); - } - check_frags: for (i = 0; i < nr_frags; i++, gop_map++) { - int j; + int j, newerr; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); // if there is a pgrant at pending_idx, set grant handle and continue From 9683f8a65adfa13b2d95afbfd72132fa70688d18 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Thu, 3 Jul 2025 11:59:14 +0200 Subject: [PATCH 09/11] Corrections from Anthoine's review --- drivers/net/xen-netback/netback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 7e8bbc9f5f7c5..faddf5625ed80 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1036,7 +1036,7 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb) printk("[queue %u] xenvif_fill_frags(): associated pgrant: gref %u, handle %u\n", queue->id, pgrant->gnt, pgrant->handle); else printk("[queue %u] xenvif_fill_frags(): associated pgrant: NONE\n", queue->id); - page = pgrant ? pgrant->page : virt_to_page(idx_to_kaddr(queue, pending_idx)); + page = pgrant ? pgrant->page : queue->mmap_pages[pending_idx]; __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); skb->len += txp->size; skb->data_len += txp->size; From 88eb2ab783b1f89999d485f8beab815b30e21a87 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Wed, 16 Jul 2025 16:26:41 +0200 Subject: [PATCH 10/11] Remove spurious flag and printks --- drivers/net/xen-netback/netback.c | 73 +------------------------------ drivers/net/xen-netfront.c | 13 ++---- 2 files changed, 4 insertions(+), 82 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index faddf5625ed80..1b92bbe58cc43 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -185,7 +185,6 @@ static struct page *get_free_page(struct xenvif_queue *queue, struct page *page; if (!persistent || gnttab_page_cache_get(&queue->persistent_pages, &page)) { - WARN_ON(persistent); // shouldn't map with mmap page (without errors) page = queue->mmap_pages[pending_idx]; } @@ -198,8 +197,6 @@ static int add_persistent_gnt(struct xenvif_queue *queue, struct rb_node **new = NULL, *parent = NULL; struct persistent_gnt *this; - WARN_ON(!pgrant); - if (queue->persistent_gnt_c >= xenvif_max_pgrants) { pr_alert_ratelimited("trying to add a gref when pgrant limit has been reached\n"); return -EBUSY; @@ -220,14 +217,12 @@ static int add_persistent_gnt(struct xenvif_queue *queue, } } pgrant->active = true; - printk("[queue %u] add_persistent_gnt(): gref %u added to the tree\n", queue->id, pgrant->gnt); /* Add new node and rebalance tree. */ rb_link_node(&(pgrant->node), parent, new); rb_insert_color(&(pgrant->node), &queue->persistent_gnts); queue->persistent_gnt_c++; //idk what it's for... atomic_inc(&queue->persistent_gnt_in_use); - printk("[queue %u] add_persistent_gnt(): now %d pgrants in the tree\n", queue->id, queue->persistent_gnt_c); return 0; } @@ -247,7 +242,6 @@ static struct persistent_gnt *get_persistent_gnt(struct xenvif_queue *queue, else if (gref > pgrant->gnt) node = node->rb_right; else { - printk("[queue %u] get_persistent_gnt(): getting gref %u from the tree\n", queue->id, pgrant->gnt); if (pgrant->active) { pr_alert_ratelimited("requesting a grant already in use\n"); return ERR_PTR(-EBUSY); @@ -257,21 +251,18 @@ static struct persistent_gnt *get_persistent_gnt(struct xenvif_queue *queue, return pgrant; } } - printk("[queue %u] get_persistent_gnt(): gref %u isn't in the tree\n", queue->id, gref); + return NULL; } static void put_persistent_gnt(struct xenvif_queue *queue, struct persistent_gnt *pgrant) { - WARN_ON(!pgrant); - if (!pgrant->active) pr_alert_ratelimited("freeing a grant already unused\n"); pgrant->active = false; //idk what it's for... atomic_dec(&ring->persistent_gnt_in_use); - printk("[queue %u] put_persistent_gnt(): put pgrant with gref %u\n", queue->id, pgrant->gnt); } static void free_persistent_gnts(struct xenvif_queue *queue, @@ -314,15 +305,12 @@ static void free_persistent_gnts(struct xenvif_queue *queue, num--; } BUG_ON(num != 0); - printk("[queue %u] free_persistent_gnts(): freed all pgrants from the tree\n", queue->id); } static inline void xenvif_pgrant_set(struct xenvif_queue *queue, u16 pending_idx, struct persistent_gnt *pgrant) { - WARN_ON(!pgrant); - if (unlikely(queue->tx_pgrants[pending_idx])) { netdev_err(queue->vif->dev, "Trying to overwrite an active persistent grant! pending_idx: 0x%x\n", @@ -330,11 +318,6 @@ static inline void xenvif_pgrant_set(struct xenvif_queue *queue, BUG(); } queue->tx_pgrants[pending_idx] = pgrant; - - WARN_ON(!pgrant->active); // don't set a pgrant marked inactive - - printk("[queue %u] xenvif_pgrant_set(): set pgrant with gref %u at index %u\n", - queue->id, pgrant->gnt, pending_idx); } static inline void xenvif_pgrant_reset(struct xenvif_queue *queue, @@ -350,9 +333,6 @@ static inline void xenvif_pgrant_reset(struct xenvif_queue *queue, } put_persistent_gnt(queue, pgrant); queue->tx_pgrants[pending_idx] = NULL; - - printk("[queue %u] xenvif_pgrant_reset(): reset pgrant at index %u\n", - queue->id, pending_idx); } /* @@ -363,8 +343,6 @@ static struct persistent_gnt *xenvif_pgrant_new(struct xenvif_queue *queue, { struct persistent_gnt *pgrant; - WARN_ON(!gop); - pgrant = kmalloc(sizeof(struct persistent_gnt), GFP_KERNEL); if (!pgrant) BUG(); // not handling errors yet @@ -380,9 +358,6 @@ static struct persistent_gnt *xenvif_pgrant_new(struct xenvif_queue *queue, //return NULL; } - printk("[queue %u] xenvif_pgrant_new(): new pgrant with gref %u, handle %u\n", - queue->id, pgrant->gnt, pgrant->handle); - return pgrant; } @@ -391,8 +366,6 @@ static struct persistent_gnt *xenvif_pgrant_new(struct xenvif_queue *queue, */ void xenvif_pgrants_destroy(struct xenvif_queue *queue) { - int i; - if (!RB_EMPTY_ROOT(&queue->persistent_gnts)) free_persistent_gnts(queue, &queue->persistent_gnts, queue->persistent_gnt_c); @@ -402,12 +375,6 @@ void xenvif_pgrants_destroy(struct xenvif_queue *queue) queue->persistent_gnt_c = 0; gnttab_page_cache_shrink(&queue->persistent_pages, 0 /* All */); - - // L17 TEST remove when tests are done - for (i = 0; i < MAX_PENDING_REQS; i++) { - if (queue->tx_pgrants[i] != NULL) - printk("[queue %u] xenvif_pgrants_destroy(): tx_pgrants still contains grants when freeing!\n", queue->id); - } } void xenvif_kick_thread(struct xenvif_queue *queue) @@ -594,14 +561,10 @@ static inline void xenvif_tx_create_map_op(struct xenvif_queue *queue, struct page *page, struct gnttab_map_grant_ref *mop) { - WARN_ON(!page); queue->pages_to_map[mop-queue->tx_map_ops] = page; gnttab_set_map_op(mop, page_to_kaddr(page), GNTMAP_host_map | GNTMAP_readonly, txp->gref, queue->vif->domid); - - printk("[queue %u] xenvif_tx_create_map_op(): created map op with gref %u\n", - queue->id, mop->ref); } static inline struct sk_buff *xenvif_alloc_skb(unsigned int size) @@ -691,8 +654,6 @@ static void xenvif_get_requests(struct xenvif_queue *queue, if (amount == txp->size) { /* The copy op covered the full tx_request */ - printk("[queue %u] xenvif_get_requests(): request with gref %u covered with copies\n", - queue->id, txp->gref); memcpy(&queue->pending_tx_info[pending_idx].req, txp, sizeof(*txp)); queue->pending_tx_info[pending_idx].extra_count = @@ -710,15 +671,11 @@ static void xenvif_get_requests(struct xenvif_queue *queue, * The remainder will be mapped or copied in the next * iteration. */ - printk("[queue %u] xenvif_get_requests(): request with gref %u partially covered with copies\n", - queue->id, txp->gref); txp->offset += amount; txp->size -= amount; } } - printk("[queue %u] xenvif_get_requests(): finished creating copies! %d slots remaining\n", queue->id, nr_slots); - /* Create map ops for the skb frags */ for (shinfo->nr_frags = 0; nr_slots > 0 && shinfo->nr_frags < MAX_SKB_FRAGS; nr_slots--) { @@ -742,8 +699,6 @@ static void xenvif_get_requests(struct xenvif_queue *queue, xenvif_pgrant_set(queue, pending_idx, pgrant); } - printk("[queue %u] xenvif_get_requests(): request with gref %u covered with mapping\n", - queue->id, txp->gref); memcpy(&queue->pending_tx_info[pending_idx].req, txp, sizeof(*txp)); queue->pending_tx_info[pending_idx].extra_count = (txp == first) ? extra_count : 0; @@ -808,8 +763,6 @@ static void xenvif_get_requests(struct xenvif_queue *queue, (*copy_ops) = cop - queue->tx_copy_ops; (*map_ops) = gop - queue->tx_map_ops; - - printk("[queue %u] xenvif_get_requests(): finished creating maps!\n", queue->id); } static inline void xenvif_grant_handle_set(struct xenvif_queue *queue, @@ -824,8 +777,6 @@ static inline void xenvif_grant_handle_set(struct xenvif_queue *queue, BUG(); } queue->grant_tx_handle[pending_idx] = handle; - printk("[queue %u] xenvif_grant_handle_set(): set grant handle %u at index %u\n", - queue->id, handle, pending_idx); } static inline void xenvif_grant_handle_reset(struct xenvif_queue *queue, @@ -839,8 +790,6 @@ static inline void xenvif_grant_handle_reset(struct xenvif_queue *queue, BUG(); } queue->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE; - printk("[queue %u] xenvif_grant_handle_reset(): reset grant handle at index %u\n", - queue->id, pending_idx); } static int xenvif_tx_check_gop(struct xenvif_queue *queue, @@ -879,7 +828,6 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, newerr = (*gopp_copy)->status; } if (likely(!newerr)) { - printk("[queue %u] xenvif_tx_check_gop(): header copy at pending_idx %u was successful\n", queue->id, pending_idx); /* The first frag might still have this slot mapped */ if (i < copy_count(skb) - 1 || !sharedslot) xenvif_idx_release(queue, pending_idx, @@ -908,7 +856,6 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, // if there is a pgrant at pending_idx, set grant handle and continue pgrant = queue->tx_pgrants[pending_idx]; if (pgrant) { - printk("[queue %u] xenvif_tx_check_gop(): pgrant with gref %u found for frag at pending_idx %u\n", queue->id, pgrant->gnt, pending_idx); xenvif_grant_handle_set(queue, pending_idx, pgrant->handle); @@ -921,7 +868,6 @@ static int xenvif_tx_check_gop(struct xenvif_queue *queue, newerr = gop_map->status; if (likely(!newerr)) { - printk("[queue %u] xenvif_tx_check_gop(): frag map at pending_index %u with gref %u was successful\n", queue->id, pending_idx, gop_map->ref); xenvif_grant_handle_set(queue, pending_idx, gop_map->handle); @@ -1015,7 +961,6 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb) u16 pending_idx; pending_idx = frag_get_pending_idx(frag); - printk("[queue %u] xenvif_fill_frags(): frag pending_idx: %u\n", queue->id, pending_idx); /* If this is not the first frag, chain it to the previous*/ if (prev_pending_idx == INVALID_PENDING_IDX) @@ -1029,13 +974,8 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb) prev_pending_idx = pending_idx; txp = &queue->pending_tx_info[pending_idx].req; - printk("[queue %u] xenvif_fill_frags(): associated request: gref %u, offset %u, size %u\n", queue->id, txp->gref, txp->offset, txp->size); // if there is a pgrant at pending_idx, get the page from the pgrant pgrant = queue->tx_pgrants[pending_idx]; - if (pgrant) - printk("[queue %u] xenvif_fill_frags(): associated pgrant: gref %u, handle %u\n", queue->id, pgrant->gnt, pgrant->handle); - else - printk("[queue %u] xenvif_fill_frags(): associated pgrant: NONE\n", queue->id); page = pgrant ? pgrant->page : queue->mmap_pages[pending_idx]; __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); skb->len += txp->size; @@ -1273,8 +1213,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, if (!work_to_do) break; - printk("[queue %u] ///////////////////////// SKB START\n", queue->id); - idx = queue->tx.req_cons; rmb(); /* Ensure that we see the request before we copy it. */ RING_COPY_REQUEST(&queue->tx, idx, &txreq); @@ -1384,7 +1322,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, "Can't allocate the frag_list skb.\n"); break; } - printk("WE HAVE A FRAG_LIST SKB\n"); } if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { @@ -1427,12 +1364,6 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, type); } - printk("[queue %u] xenvif_tx_build_gops(): skb uses %d slots, %u bytes to copy\n", - queue->id, skb_shinfo(skb)->nr_frags + frag_overflow + 1, data_len); - printk("[queue %u] xenvif_tx_build_gops(): gref of all requests: %u", queue->id, txreq.gref); - for (int i = 0; i < ret; i++) - printk(", %u", txfrags[i].gref); - xenvif_get_requests(queue, skb, &txreq, txfrags, copy_ops, map_ops, frag_overflow, nskb, extra_count, data_len); @@ -1620,8 +1551,6 @@ static int xenvif_tx_submit(struct xenvif_queue *queue) } netif_receive_skb(skb); - - printk("[queue %u] ///////////////////////// SKB SENT\n", queue->id); } return work_done; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 53b898466949b..08dc1a3756378 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -444,12 +444,10 @@ static bool xennet_tx_buf_gc(struct netfront_queue *queue) } gnttab_release_grant_reference( &queue->gref_tx_head, queue->grant_tx_ref[id]); - printk("[queue %d] xennet_tx_buf_gc(): ungranted and released with gref %u\n", queue->id, queue->grant_tx_ref[id]); queue->grant_tx_ref[id] = INVALID_GRANT_REF; queue->grant_tx_page[id] = NULL; } add_id_to_list(&queue->tx_skb_freelist, queue->tx_link, id); - printk("[queue %d] xennet_tx_buf_gc(): added id %u to freelist\n", queue->id, id); dev_kfree_skb_irq(skb); } @@ -491,7 +489,6 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, struct sk_buff *skb = info->skb; id = get_id_from_list(&queue->tx_skb_freelist, queue->tx_link); - printk("[queue %d] xennet_tx_setup_grant(): got id %u from freelist\n", queue->id, id); tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++); /* Reuse claimed grants */ @@ -506,7 +503,6 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, gfn, GNTMAP_readonly); queue->grant_tx_ref[id] = ref; - printk("[queue %d] xennet_tx_setup_grant(): claimed and granted with gref %u\n", queue->id, queue->grant_tx_ref[id]); } if (queue->info->persistent_grants) { @@ -514,8 +510,6 @@ static void xennet_tx_setup_grant(unsigned long gfn, unsigned int offset, memcpy(pfn_to_kaddr(page_to_pfn(queue->grant_tx_page[id])), pfn_to_kaddr(page_to_pfn(page)) + offset, len); offset = 0; // worried that offsets will introduce bleeding - printk("[queue %d] xennet_tx_setup_grant(): memcpy'd client buf into page\n", - queue->id); } else { queue->grant_tx_page[id] = page; } @@ -1553,7 +1547,7 @@ static bool xennet_handle_tx(struct netfront_queue *queue, unsigned int *eoi) static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id) { - unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; + unsigned int eoiflag = 0; if (likely(xennet_handle_tx(dev_id, &eoiflag))) xen_irq_lateeoi(irq, eoiflag); @@ -1593,7 +1587,7 @@ static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi) static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id) { - unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; + unsigned int eoiflag = 0; if (likely(xennet_handle_rx(dev_id, &eoiflag))) xen_irq_lateeoi(irq, eoiflag); @@ -1603,7 +1597,7 @@ static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id) static irqreturn_t xennet_interrupt(int irq, void *dev_id) { - unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; + unsigned int eoiflag = 0; if (xennet_handle_tx(dev_id, &eoiflag) && xennet_handle_rx(dev_id, &eoiflag)) @@ -2071,7 +2065,6 @@ static int xennet_init_queue(struct netfront_queue *queue) queue->grant_tx_page[i] = queue->info->persistent_grants ? alloc_page(GFP_NOIO) : NULL; } - printk("[queue %d] xennet_init_queue(): refs and pool pages initialized\n", queue->id); queue->tx_link[NET_TX_RING_SIZE - 1] = TX_LINK_NONE; /* Clear out rx_skbs */ From 1e35bd1ce45efb6e1a58db26d9e583be15de8350 Mon Sep 17 00:00:00 2001 From: LuKP17 Date: Mon, 21 Jul 2025 10:43:20 +0200 Subject: [PATCH 11/11] Apply Anthoine's spurious patch --- drivers/net/xen-netfront.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 08dc1a3756378..81d09fd25d0e0 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -659,8 +659,6 @@ static int xennet_xdp_xmit_one(struct net_device *dev, tx_stats->packets++; u64_stats_update_end(&tx_stats->syncp); - xennet_tx_buf_gc(queue); - return 0; } @@ -870,9 +868,6 @@ static netdev_tx_t xennet_start_xmit(struct sk_buff *skb, struct net_device *dev tx_stats->packets++; u64_stats_update_end(&tx_stats->syncp); - /* Note: It is not safe to access skb after xennet_tx_buf_gc()! */ - xennet_tx_buf_gc(queue); - if (!netfront_tx_slot_available(queue)) netif_tx_stop_queue(netdev_get_tx_queue(dev, queue->id)); @@ -1547,7 +1542,7 @@ static bool xennet_handle_tx(struct netfront_queue *queue, unsigned int *eoi) static irqreturn_t xennet_tx_interrupt(int irq, void *dev_id) { - unsigned int eoiflag = 0; + unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; if (likely(xennet_handle_tx(dev_id, &eoiflag))) xen_irq_lateeoi(irq, eoiflag); @@ -1587,7 +1582,7 @@ static bool xennet_handle_rx(struct netfront_queue *queue, unsigned int *eoi) static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id) { - unsigned int eoiflag = 0; + unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; if (likely(xennet_handle_rx(dev_id, &eoiflag))) xen_irq_lateeoi(irq, eoiflag); @@ -1597,7 +1592,7 @@ static irqreturn_t xennet_rx_interrupt(int irq, void *dev_id) static irqreturn_t xennet_interrupt(int irq, void *dev_id) { - unsigned int eoiflag = 0; + unsigned int eoiflag = XEN_EOI_FLAG_SPURIOUS; if (xennet_handle_tx(dev_id, &eoiflag) && xennet_handle_rx(dev_id, &eoiflag))