All of lore.kernel.org
 help / color / mirror / Atom feed
From: netdev-bot+sashiko@kernel.org
To: james@codeconstruct.com.au
Cc: jk@codeconstruct.com.au, matt@codeconstruct.com.au,
	andrew+netdev@lunn.ch, davem@davemloft.net, edumazet@google.com,
	kuba@kernel.org, pabeni@redhat.com, kees@kernel.org,
	gustavoars@kernel.org, netdev@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-hardening@vger.kernel.org
Subject: Re: [7/7] net: mctp: usblib: Add test for failing append
Date: Thu, 03 Sep 2026 21:46:07 +0000	[thread overview]
Message-ID: <178847196753.3394541.3220481383964170252@kernel.org> (raw)
In-Reply-To: <20260831-dev-mctp-usb-lib-test-v1-7-79699bf67a18@codeconstruct.com.au>

Thank you for your contribution! Sashiko AI review found 4 potential
issue(s) to consider:

Critical: 0 · High: 0 · Medium: 3 · Low: 1

- [Medium] The new KUnit test `mctp_usblib_test_tx_overflow()`
  (drivers/net/mctp/mctp-usblib-test.c) does not exercise the append-…
- [Medium] Preempt-count leak in the new test:
  `mctp_usblib_test_tx_overflow()` calls `dstats =…
- [Medium] `mctp_usblib_test_tx_overflow()` verifies the drop accounting
  by reading `tx_drops` from only one CPU's per-CPU `pcpu_dstats` — the…
- [Low] The patch adds `#include "linux/percpu-defs.h"` at
  drivers/net/mctp/mctp-usblib-test.c:9 — a quoted (local-path) include…

--

net: mctp: usblib: Add test for failing append

Adds a KUnit case, mctp_usblib_test_tx_overflow(), which pushes three
200-byte packets through mctp_usblib_tx_push() with a failing send op and
then checks that tx_drops was incremented three times.  A few questions
about the new test below.

> diff --git a/drivers/net/mctp/mctp-usblib-test.c b/drivers/net/mctp/mctp-usblib-test.c
> index 7dc382caffc1..b3a2cc5cbd99 100644
> --- a/drivers/net/mctp/mctp-usblib-test.c
> +++ b/drivers/net/mctp/mctp-usblib-test.c
> @@ -6,6 +6,7 @@
>   * Copyright (C) 2026 Code Construct Pty Ltd
>   */
>  
> +#include "linux/percpu-defs.h"

[Severity: Low]
This isn't a bug, but is this include intentional?  It uses the quoted
form for a kernel header and sits ahead of the sorted <linux/...> block,
and it appears redundant: the file already includes <linux/netdevice.h>,
which pulls in <linux/percpu.h> and therefore percpu-defs.h, and which is
where struct pcpu_dstats comes from.  Could it be dropped, or at least
switched to the angle-bracket form in the sorted position?  The commit
message doesn't mention this hunk.

>  #include <linux/array_size.h>
>  #include <uapi/linux/netdevice.h>
>  #include <linux/netdevice.h>

[ ... ]

> @@ -871,6 +872,46 @@ static void mctp_usblib_test_tx_multi_push(struct kunit *test)
>  	KUNIT_EXPECT_EQ(test, i, ARRAY_SIZE(sends));
>  }
>  
> +static void mctp_usblib_test_tx_overflow(struct kunit *test)
> +{

[ ... ]

> +	len = 200;
> +
> +	ctx = mctp_usblib_test_init(test);
> +	ndev = ctx->dev->ndev;
> +
> +	ops.send = mctp_usblib_test_tx_send_fail;
> +
> +	tx = mctp_usblib_test_tx_init(test, &ops, ctx, false);

[Severity: Medium]
Does this test actually reach the append-overflow path it is named for?
The span = false argument is discarded by the helper, which hardcodes
true:

drivers/net/mctp/mctp-usblib-test.c:mctp_usblib_test_tx_init() {
	...
	mctp_usblib_tx_init(tx, ops, priv, true);
	...
}

With span forced on, mctp_usblib_tx_ctx_create() picks the large buffer:

drivers/net/mctp/mctp-usblib.c:mctp_usblib_tx_ctx_create() {
	...
	sz = tx->span ? TX_SPAN_MAX : MCTP_USB_1_0_XFER_SIZE;
	...
}

Each skb here is 200 bytes plus the 4-byte struct mctp_usb_hdr pushed by
mctp_usblib_tx_skb_prepare(), so 3 x 204 bytes fit in the ~4040-byte
spanning buffer and this check never fires:

drivers/net/mctp/mctp-usblib.c:mctp_usblib_tx_append() {
	...
	if (mctp_usblib_tx_avail(ctx) < skb->len)
		return -ENOBUFS;
	...
}

So only the single !more send at i == 2 fails, and
mctp_usblib_tx_stats_update() adds ctx->skbs.qlen == 3 in one go.

> +	buf = mctp_usblib_test_init_buf(test, len);
> +
> +	for (i = 0; i < 3; i++) {
> +		skb = mctp_usblib_test_init_skb(test, len, ndev, buf);
> +
> +		rc = mctp_usblib_tx_push(ndev, tx, skb, i != 2);
> +		KUNIT_EXPECT_EQ(test, rc, 0);
> +	}
> +
> +	dstats = get_cpu_ptr(ndev->dstats);

[Severity: Medium]
Is the missing put_cpu_ptr() here a problem?  get_cpu_ptr() expands to
preempt_disable() plus this_cpu_ptr(), and mctp_usblib_test_tx_overflow()
returns without re-enabling preemption, so the case leaves preempt_count
elevated by one.

Two effects follow.  The KUNIT_EXPECT_EQ() below now runs in atomic
context, and on failure it reaches a sleeping allocation:

lib/kunit/test.c:kunit_fail() {
	...
	stream = kunit_alloc_string_stream(test, GFP_KERNEL);
	...
}

which gives "BUG: sleeping function called from invalid context" with
CONFIG_DEBUG_ATOMIC_SLEEP.  On the passing path the kunit try-thread exits
with preempt_count 1, so do_exit() complains and force-resets the count.

The driver pairs these calls in both of its stats helpers, e.g.:

drivers/net/mctp/mctp-usblib.c:mctp_usblib_tx_stats_update() {
	struct pcpu_dstats *dstats = get_cpu_ptr(dev->dstats);
	...
	put_cpu_ptr(dev->dstats);
}

Could this read use per_cpu_ptr() instead, given it does not need
preemption disabled at all?

> +	do {
> +		start = u64_stats_fetch_begin(&dstats->syncp);
> +		stats = u64_stats_read(&dstats->tx_drops);
> +	} while (u64_stats_fetch_retry(&dstats->syncp, start));
> +
> +	KUNIT_EXPECT_EQ(test, stats, 3);

[Severity: Medium]
Can this expectation fail spuriously on an SMP preemptible kernel?

The three mctp_usblib_tx_push() calls above run in the kunit try-thread
with preemption enabled and no migrate_disable(), and each writer picks
the current CPU inside its own short window:

drivers/net/mctp/mctp-usblib.c:mctp_usblib_tx_stats_single_drop() {
	struct pcpu_dstats *dstats = get_cpu_ptr(dev->dstats);
	...
	put_cpu_ptr(dev->dstats);
}

If the thread migrates between pushes, the increments are spread over
several CPUs while this code samples only one, so stats comes back below
3 and the failure looks like a driver accounting bug.  Would aggregating
over for_each_possible_cpu() (each with its own fetch_begin/retry loop),
or calling dev_get_stats(), be more robust here?

[Severity: Medium]
A related question on this assertion: both control flows produce
tx_drops == 3.  In the intended non-spanning case the third append fails
with -ENOBUFS (avail 512 - 408 = 104 < 204), the pending 2-skb context
fails to send (+2), and the new single-packet context fails to send (+1).
In the spanning case actually exercised, one context of 3 skbs fails to
send (+3).

Since the aggregate is identical, would this test still pass if the
append-failure accounting were broken?  As written it looks like it
duplicates mctp_usblib_test_tx_failing_send() rather than adding new
coverage.

> +}
> +
>  static struct kunit_case mctp_usblib_test_cases[] = {

[ ... ]

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831-dev-mctp-usb-lib-test-v1-0-79699bf67a18%40codeconstruct.com.au

      reply	other threads:[~2026-09-03 21:46 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31  3:43 [PATCH 0/7] net: mctp: usblib: Increase coverage of kunit testing James Lee
2026-08-31  3:43 ` [PATCH 1/7] net: mctp: usblib: Add to parameterized kunit tests James Lee
2026-08-31  3:43 ` [PATCH 2/7] net: mctp: usblib: Add test for splits inside headers James Lee
2026-09-03 21:46   ` [2/7] " netdev-bot+sashiko
2026-08-31  3:43 ` [PATCH 3/7] net: mctp: usblib: Add tests of invalid headers James Lee
2026-09-03 21:46   ` [3/7] " netdev-bot+sashiko
2026-08-31  3:43 ` [PATCH 4/7] net: mctp: usblib: Complete rx tests James Lee
2026-08-31  3:43 ` [PATCH 5/7] net: mctp: usblib: Simplify allocation logic in mctp_usblib_test_rx_init James Lee
2026-08-31  3:43 ` [PATCH 6/7] net: mctp: usblib: Add initial kunit tx tests James Lee
2026-09-03 21:46   ` [6/7] " netdev-bot+sashiko
2026-08-31  3:43 ` [PATCH 7/7] net: mctp: usblib: Add test for failing append James Lee
2026-09-03 21:46   ` netdev-bot+sashiko [this message]

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=178847196753.3394541.3220481383964170252@kernel.org \
    --to=netdev-bot+sashiko@kernel.org \
    --cc=andrew+netdev@lunn.ch \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=gustavoars@kernel.org \
    --cc=james@codeconstruct.com.au \
    --cc=jk@codeconstruct.com.au \
    --cc=kees@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=matt@codeconstruct.com.au \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.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.