From: mingming cao <mmc@linux.ibm.com>
To: Jakub Kicinski <kuba@kernel.org>
Cc: netdev@vger.kernel.org, davem@davemloft.net, edumazet@google.com,
pabeni@redhat.com, andrew+netdev@lunn.ch, nnac123@linux.ibm.com,
maddy@linux.ibm.com, mpe@ellerman.id.au,
linuxppc-dev@lists.ozlabs.org, haren@linux.ibm.com,
ricklind@linux.ibm.com, davemarq@linux.ibm.com,
bjking1@linux.ibm.com, shaik.abdulla1@ibm.com
Subject: Re: [PATCH net-next v5 09/15] ibmveth: Harden RX poll path with helpers
Date: Mon, 31 Aug 2026 12:06:42 -0700 [thread overview]
Message-ID: <c1785619-ec00-4d68-848b-3bad0b4fc35a@linux.ibm.com> (raw)
In-Reply-To: <20260818014729.3854228-1-kuba@kernel.org>
On 8/17/26 6:47 PM, Jakub Kicinski wrote:
> This is an AI-generated review of your patch. The human sending this
> email has considered the AI review valid, or at least plausible.
> ---
> ibmveth: Harden RX poll path with helpers
>
> This splits the inline RX slot handling in ibmveth_poll() into a set of
> small helpers (stopping / harvest_slot / recycle_invalid /
> skip_bad_correlator / drop_oversize / deliver_frame / bump_invalid) so the
> NAPI callback stays a budget loop. It also moves the reset escalation out
> of ibmveth_rxq_get_buffer() into ibmveth_poll_skip_bad_correlator() and
> adds stopping checks so close/napi_disable does not re-arm PHYP.
>
> A few questions below.
>
>> diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
>> index 58a639a962a67..86299c62d4ecf 100644
>> --- a/drivers/net/ethernet/ibm/ibmveth.c
>> +++ b/drivers/net/ethernet/ibm/ibmveth.c
>> @@ -1346,10 +1346,8 @@ ibmveth_rxq_get_buffer(struct ibmveth_adapter *adapter,
>> unsigned int pool = correlator >> 32;
>> unsigned int index = correlator & 0xffffffffUL;
>>
>> - if (!ibmveth_rxq_correlator_valid(adapter, queue_index, correlator)) {
>> - schedule_work(&adapter->work);
>> + if (!ibmveth_rxq_correlator_valid(adapter, queue_index, correlator))
>> return NULL;
>> - }
>>
>> return adapter->rx_buff_pool[queue_index][pool].skbuff[index];
>> }
>> @@ -2338,125 +2336,230 @@ static void ibmveth_rx_csum_helper(struct sk_buff *skb,
>> }
>> }
>>
>> +static void ibmveth_poll_bump_invalid(struct ibmveth_adapter *adapter,
>> + int queue_index)
>> +{
>> + adapter->rx_invalid_buffer++;
>> +}
>> +
>> +static bool ibmveth_poll_stopping(struct net_device *netdev,
>> + struct napi_struct *napi)
>> +{
>> + return !netif_running(netdev) || napi_disable_pending(napi);
>> +}
>> +
>> +static bool ibmveth_poll_harvest_slot(struct ibmveth_adapter *adapter,
>> + int queue_index, bool reuse)
>> +{
>> + int rc = ibmveth_rxq_harvest_buffer(adapter, queue_index, reuse);
>> +
>> + return !rc || rc == -EINVAL || rc == -EFAULT;
>> +}
>> +
>> +static bool ibmveth_poll_recycle_invalid(struct net_device *netdev,
>> + struct ibmveth_adapter *adapter,
>> + int queue_index)
>> +{
>> + netdev_dbg(netdev, "recycling invalid buffer\n");
>> + ibmveth_poll_bump_invalid(adapter, queue_index);
>> + return ibmveth_poll_harvest_slot(adapter, queue_index, true);
>> +}
>> +
>> +static bool ibmveth_poll_skip_bad_correlator(struct net_device *netdev,
>> + struct ibmveth_adapter *adapter,
>> + int queue_index)
>> +{
>> + if (net_ratelimit())
>> + netdev_err(netdev,
>> + "bad correlator on queue %d, skipping slot\n",
>> + queue_index);
>> + /* Residual stale slot after resize: recover via reset rather
>> + * than spinning forever. Always escalate; only the log is
>> + * rate-limited.
>> + */
>> + schedule_work(&adapter->work);
>> + ibmveth_poll_bump_invalid(adapter, queue_index);
>> + return ibmveth_poll_harvest_slot(adapter, queue_index, true);
>> +}
>> +
>> +static bool ibmveth_poll_drop_oversize(struct net_device *netdev,
>> + struct ibmveth_adapter *adapter,
>> + int queue_index, unsigned int off,
>> + unsigned int len, unsigned int room)
>> +{
>> + if (net_ratelimit())
>> + netdev_err(netdev,
>> + "RX frame %u+%u exceeds buffer %u on queue %d, dropping\n",
>> + off, len, room, queue_index);
>> + ibmveth_poll_bump_invalid(adapter, queue_index);
>> + return ibmveth_poll_harvest_slot(adapter, queue_index, true);
>> +}
> [Severity: Medium]
> The changelog describes this as splitting a nested switchyard into helpers,
> but a few behaviour changes appear to ride along. Could they be called out
> in the changelog, or split out?
>
> First, ibmveth_poll_bump_invalid() is now called from both
> ibmveth_poll_drop_oversize() and ibmveth_poll_skip_bad_correlator(), so the
> exported rx_invalid_buffer counter also counts oversize frames and skipped
> slots. Is that intended, and should it be mentioned?
>
> Second, before this patch schedule_work() ran only when
> ibmveth_rxq_correlator_valid() failed, and the poll loop simply broke out.
> Now ibmveth_poll_skip_bad_correlator() escalates unconditionally, so it also
> covers the valid-correlator-with-NULL-skbuff case, which returns -EFAULT
> from ibmveth_remove_buffer_from_pool(). ibmveth_reset() does:
>
> rtnl_lock();
>
> dev_close(adapter->netdev);
> dev_open(adapter->netdev, NULL);
>
> so does this turn a condition that previously cost one aborted poll into a
> full close/open link flap? The changelog says "skip_bad_correlator owns
> reset escalation", which reads as parity, but the escalation scope looks
> strictly larger.
>
> Third, the new off/len test in ibmveth_poll_deliver_frame() below appears to
> be the first bound check applied to the PHYP-supplied offset and length
> before skb_reserve()/skb_put(). Should that carry a Fixes: tag? As it
> stands it is mixed into roughly 190 lines of code motion, which makes it
> hard to pick up on its own.
Yes, not pure motion. v6 names those three in the commit message
rather than splitting them out: they are the reason the peel exists
and cannot precede it — the helpers are not available before the
split.
bump_invalid counting oversize and skipped slots is intended.
skip_bad's scope is larger: a valid correlator with a NULL skb now
resets instead of aborting one poll. That is a close/open, not
parity with “valid() failed only.” The other choice is spinning on
the same pending slot in softirq, so v6 keeps the wider reset.
No Fixes: on the off/len check. The driver never validated the
PHYP-supplied offset and length, so there is no parent SHA to name,
and the test lives in the new helper. Happy to send a standalone if
you would rather pick it up that way.
>> +
>> +/**
>> + * ibmveth_poll_deliver_frame - Build SKB from one valid RX slot and GRO it
>> + * @napi: NAPI context for this RX queue
>> + * @adapter: ibmveth adapter
>> + * @netdev: net_device for @adapter
>> + * @queue_index: RX queue index
>> + *
>> + * Return: 1 frame delivered, 0 if the slot was skipped cleanly, -1 on error.
>> + */
>> +static int ibmveth_poll_deliver_frame(struct napi_struct *napi,
>> + struct ibmveth_adapter *adapter,
>> + struct net_device *netdev,
>> + int queue_index)
>> +{
>> + struct sk_buff *skb, *new_skb;
>> + unsigned int room, off, len;
>> + int length, offset, csum_good, lrg_pkt;
>> + __sum16 iph_check = 0;
>> + u16 mss = 0;
>> + int rc;
>> +
>> + length = ibmveth_rxq_frame_length(adapter, queue_index);
>> + offset = ibmveth_rxq_frame_offset(adapter, queue_index);
>> + csum_good = ibmveth_rxq_csum_good(adapter, queue_index);
>> + lrg_pkt = ibmveth_rxq_large_packet(adapter, queue_index);
>> +
>> + skb = ibmveth_rxq_get_buffer(adapter, queue_index);
>> + if (unlikely(!skb)) {
>> + if (!ibmveth_poll_skip_bad_correlator(netdev, adapter,
>> + queue_index))
>> + return -1;
>> + return 0;
>> + }
>> +
>> + room = skb_tailroom(skb);
>> + off = offset;
>> + len = length;
>> + if (unlikely(off >= room || len > room - off)) {
>> + if (!ibmveth_poll_drop_oversize(netdev, adapter, queue_index,
>> + off, len, room))
>> + return -1;
>> + return 0;
>> + }
> [ ... ]
>
>> + skb_put(skb, length);
>> + skb->protocol = eth_type_trans(skb, netdev);
>> +
>> + if (skb->protocol == cpu_to_be16(ETH_P_IP))
>> + iph_check = ip_hdr(skb)->check;
>> +
>> + if ((length > netdev->mtu + ETH_HLEN) || lrg_pkt ||
>> + iph_check == 0xffff) {
>> + ibmveth_rx_mss_helper(skb, mss, lrg_pkt);
>> + adapter->rx_large_packets++;
>> + }
> [Severity: High]
> Is skb->network_header set for this skb at this point? The old code read
> the checksum through skb->data:
>
> if (skb->protocol == cpu_to_be16(ETH_P_IP)) {
> struct iphdr *iph = (struct iphdr *)skb->data;
>
> iph_check = iph->check;
> }
>
> ip_hdr(skb) resolves to skb_network_header(skb), which is
> skb->head + skb->network_header, and there is no was-it-set validation.
>
> eth_type_trans() only does skb_reset_mac_header() plus eth_skb_pull_mac(),
> and the driver's single skb_reset_network_header() call sits inside
> ibmveth_rx_csum_helper(), which runs after this read. For skbs from
> netdev_alloc_skb(), __finalize_skb_around() poisons mac_header and
> transport_header to ~0U but leaves network_header at 0.
>
> If that reading is right, ip_hdr(skb) points at skb->head and iph_check
> comes out of the uninitialized headroom rather than the received IP header.
> Two effects follow:
>
> A PHYP-without-PLSO large-send frame whose IP checksum is 0xffff, whose
> length is within mtu + ETH_HLEN, and whose large packet bit is clear is no
> longer recognised, so gso_size and gso_segs are never set.
>
> When the stale headroom bytes happen to be 0xffff, ibmveth_rx_mss_helper()
> runs on an ordinary frame with lrg_pkt == 0 and takes the offset branch:
>
> } else if (offset) {
> skb_shinfo(skb)->gso_size = ntohs(tcph->check);
> tcph->check = 0;
> }
>
> which zeroes the real TCP checksum and marks the frame as GSO with a
> gso_size taken from that checksum, before napi_gro_receive().
>
> Would keeping (struct iphdr *)skb->data here be better, matching what
> ibmveth_rx_mss_helper() and ibmveth_rx_csum_helper() do for the same skb at
> the same stage? This same line is still present in the later patches of the
> series.
Yes. network_header is still 0 here, so ip_hdr() reads skb->head,
producing both corruption effects you described: PLSO frames with
iph_check == 0xffff are missed, and stale headroom bytes of 0xffff
corrupt TCP checksums via ibmveth_rx_mss_helper(). That was a v5
peel regression — the baseline loop used (struct iphdr *)skb->data.
v6 restores that, matching ibmveth_rx_mss_helper() and
ibmveth_rx_csum_helper() which both read through skb->data at this
stage.
>> +
>> + if (csum_good) {
>> + skb->ip_summed = CHECKSUM_UNNECESSARY;
>> + ibmveth_rx_csum_helper(skb, adapter);
>> + }
>> +
>> + napi_gro_receive(napi, skb);
>> +
>> + netdev->stats.rx_packets++;
>> + netdev->stats.rx_bytes += length;
>> +
>> + return 1;
>> +}
>> +
>> static int ibmveth_poll(struct napi_struct *napi, int budget)
>> {
>> struct net_device *netdev = napi->dev;
>> struct ibmveth_adapter *adapter = netdev_priv(netdev);
>> int frames_processed = 0;
>> int queue_index, rc;
>> - u16 mss = 0;
>>
>> queue_index = napi - adapter->napi;
>>
>> + if (WARN_ON(queue_index < 0 ||
>> + queue_index >= adapter->num_rx_queues)) {
>> + napi_complete_done(napi, 0);
>> + return 0;
>> + }
>> +
>> + if (ibmveth_poll_stopping(netdev, napi)) {
>> + napi_complete_done(napi, 0);
>> + return 0;
>> + }
>> +
>> restart_poll:
>> while (frames_processed < budget) {
>> + if (ibmveth_poll_stopping(netdev, napi))
>> + break;
>> +
>> if (!ibmveth_rxq_pending_buffer(adapter, queue_index))
>> break;
>>
>> smp_rmb();
>> if (!ibmveth_rxq_buffer_valid(adapter, queue_index)) {
>> wmb(); /* suggested by larson1 */
>> - adapter->rx_invalid_buffer++;
>> - netdev_dbg(netdev, "recycling invalid buffer\n");
>> - rc = ibmveth_rxq_harvest_buffer(adapter,
>> - queue_index, true);
>> - if (unlikely(rc))
>> + if (!ibmveth_poll_recycle_invalid(netdev, adapter,
>> + queue_index))
>> break;
>> } else {
> [ ... ]
>
>> - skb = ibmveth_rxq_get_buffer(adapter, queue_index);
>> - if (unlikely(!skb))
>> + rc = ibmveth_poll_deliver_frame(napi, adapter, netdev,
>> + queue_index);
>> + if (rc < 0)
>> break;
> [ ... ]
>
>> - netdev->stats.rx_packets++;
>> - netdev->stats.rx_bytes += length;
>> - frames_processed++;
>> + if (rc > 0)
>> + frames_processed++;
>> }
>> }
> [Severity: Medium]
> Since skipped slots return 0 and only rc > 0 bumps frames_processed, does
> while (frames_processed < budget) still bound the work done in one poll
> call?
>
> Where the pre-patch code did:
>
> skb = ibmveth_rxq_get_buffer(adapter, queue_index);
> if (unlikely(!skb))
> break;
>
> a run of stale or oversize descriptors now walks every pending slot in the
> ring while reporting zero work. rxq_entries is 1 plus the sum of all pool
> sizes, so that is on the order of a thousand slots per invocation, with
> schedule_work(&adapter->work) called once per skipped slot from
> ibmveth_poll_skip_bad_correlator().
>
> The recycle-invalid branch already had this shape before the patch, but this
> extends it to the bad-correlator and oversize outcomes and adds the per-slot
> schedule_work().
No. The loop caps delivered frames, not slots walked. That is the
NAPI budget we want. A burst of stale or oversize descriptors can
walk the pending ring with frames_processed still 0; harvest still
advances each slot, so the walk stops at rxq_entries. skip_bad
calls schedule_work per skipped slot, but adapter->work coalesces,
so that is one reset, not N close/open flaps. Oversize harvests
without a reset.
>>
>> ibmveth_replenish_task(adapter, queue_index);
>>
>> + if (ibmveth_poll_stopping(netdev, napi)) {
>> + napi_complete_done(napi, frames_processed);
>> + /* After complete, must not return budget (NAPI resched). */
>> + if (frames_processed < budget)
>> + return frames_processed;
>> + return budget - 1;
>> + }
> [Severity: Medium]
> This branch hands frames_processed to napi_complete_done() but returns a
> different value to the core. With budget == 0, frames_processed is 0, so
> 0 < budget is false and the callback returns -1.
>
> budget == 0 is a real caller value, and ibmveth registers
> .ndo_poll_controller:
>
> net/core/netpoll.c:poll_one_napi() {
> work = napi->poll(napi, 0);
> WARN_ONCE(work, "%pS exceeded budget in poll\n", napi->poll);
> trace_napi_poll(napi, work, 0);
> }
>
> so a -1 return would trip that WARN_ONCE and record work = -1 in the
> tracepoint.
>
> Documentation/networking/napi.rst also states:
>
> If the ``budget`` is 0 napi_complete_done() should never be called.
>
> which this branch and the two new entry-time paths above (the WARN_ON
> queue_index path and the first ibmveth_poll_stopping() path, both calling
> napi_complete_done(napi, 0)) do without checking budget. Would the
> documented form fit better here:
>
> if (budget && napi_complete_done(napi, work_done))
> return min(work_done, budget - 1);
>
> Reaching the -1 case needs ibmveth_poll_stopping() to be false at the entry
> check and true after the loop. netpoll_poll_dev() requires
> netif_running(dev), so the flip would come from napi_disable_pending(), which
> ibmveth_change_mtu() and veth_pool_store() produce via ibmveth_close() ->
> ibmveth_cleanup_rx_interrupts() -> napi_disable() while IFF_UP is still set.
>
> Separately, returning budget - 1 on a full-budget stopping exit under-counts
> the work by one frame. The return budget - 1 is still present in the later
> patches of the series.
Yes. budget == 0 is real here: netpoll calls poll(napi, 0), and
v5 could complete and return -1. v6 never calls napi_complete_done()
when budget is 0 (the two entry paths and the post-loop stop path)
and returns 0 there.
min(..., budget - 1) on a stopping complete when budget > 0 is the
NAPI “completed, no more work” signal, not an under-count. Kept.
>>
>> if (frames_processed == budget)
>> goto out;
>>
>> if (!napi_complete_done(napi, frames_processed))
>> goto out;
>>
>> - /* We think we are done - reenable interrupts,
>> - * then check once more to make sure we are done.
>> + /*
>> + * napi_disable() sets DISABLE then waits for this poll. Without a
>> + * second stopping check here, enable_irq() can re-arm PHYP after
>> + * resize already masked the queue — late IRQs then hit the handler
>> + * after num_rx_queues was published lower (lab WARN at interrupt).
>> */
>> + if (ibmveth_poll_stopping(netdev, napi))
>> + goto out;
>> +
>> rc = ibmveth_enable_irq(adapter, queue_index);
> [Severity: Medium]
> This is a pre-existing pattern and not introduced by this patch, since the
> baseline calls ibmveth_enable_irq() and ibmveth_rxq_pending_buffer() after
> napi_complete_done() with no check at all. Still, the new check is a
> check-then-act on NAPI_STATE_DISABLE and __LINK_STATE_START: once
> napi_complete_done() has cleared NAPI_STATE_SCHED, napi_disable() can return
> and the close path can proceed while this poll instance is still executing
> its tail.
>
> Looking at ibmveth_close(), the synchronize_net() that sits after
> ibmveth_cleanup_rx_interrupts() and before ibmveth_free_all_queues():
>
> ibmveth_cleanup_rx_interrupts(adapter);
> /* Wait for softirq/poll that already passed shutdown checks. */
> synchronize_net();
>
> ibmveth_update_rx_no_buffer(adapter);
> ibmveth_free_all_queues(adapter);
>
> appears to order the freeing after the in-flight poll, since NAPI polls run
> with BH disabled and a BH-disabled region blocks a grace period. On that
> reading the residual effect is a PHYP re-arm on a queue about to be
> released, whose interrupt is then discarded by napi_schedule_prep() or
> free_irq(), rather than a use-after-free.
>
> Does the comment's claim about the late-IRQ WARN hold as written, or does
> the check only narrow the window?
Pre-existing, and your synchronize_net() reading is right: poll
runs with BH disabled, so the grace period waits out this tail and
close does not free the ring under us. Residual is a PHYP re-arm,
not a UAF.
The new check only narrows the window. It is not exclusion. The
comment overclaimed the late-IRQ WARN. Scale-down still remasks
after napi_disable for a poll that re-armed while disable waited.
Thanks,
Mingming
next prev parent reply other threads:[~2026-08-31 19:07 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 7:36 [PATCH net-next v5 00/15] ibmveth: Add multi-queue RX support Mingming Cao
2026-08-14 7:36 ` [PATCH net-next v5 01/15] ibmveth: Add MQ RX hypercall wrappers and call definitions Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 17:58 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 02/15] ibmveth: Prepare MQ RX adapter data structures Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 18:03 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 03/15] ibmveth: Refactor RX resource allocation for MQ RX bring-up Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 18:12 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 04/15] ibmveth: Refactor buffer pool management for per-queue MQ RX Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 18:20 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 05/15] ibmveth: Refactor RX interrupt control for MQ RX queues Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 18:24 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 06/15] ibmveth: Refactor TX resource allocation in open/close paths Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 18:46 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 07/15] ibmveth: Add RX queue register helpers for MQ Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 18:54 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 08/15] ibmveth: Add queue-aware RX buffer submit helper " Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:00 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 09/15] ibmveth: Harden RX poll path with helpers Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:06 ` mingming cao [this message]
2026-08-14 7:36 ` [PATCH net-next v5 10/15] ibmveth: Enable multi-queue RX receive path Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:10 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 11/15] ibmveth: Add per-queue RX and TX statistics collection Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:12 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 12/15] ibmveth: Report MQ-aware RX counts in ethtool get_channels Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:19 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 13/15] ibmveth: Expose per-queue buffer pool details via debugfs Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:20 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 14/15] ibmveth: Implement incremental MQ RX queue resize Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:22 ` mingming cao
2026-08-14 7:36 ` [PATCH net-next v5 15/15] ibmveth: Wire ethtool set_channels to " Mingming Cao
2026-08-18 1:47 ` Jakub Kicinski
2026-08-31 19:24 ` mingming cao
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=c1785619-ec00-4d68-848b-3bad0b4fc35a@linux.ibm.com \
--to=mmc@linux.ibm.com \
--cc=andrew+netdev@lunn.ch \
--cc=bjking1@linux.ibm.com \
--cc=davem@davemloft.net \
--cc=davemarq@linux.ibm.com \
--cc=edumazet@google.com \
--cc=haren@linux.ibm.com \
--cc=kuba@kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=mpe@ellerman.id.au \
--cc=netdev@vger.kernel.org \
--cc=nnac123@linux.ibm.com \
--cc=pabeni@redhat.com \
--cc=ricklind@linux.ibm.com \
--cc=shaik.abdulla1@ibm.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.