mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net] net: plip: quiesce private work when stopping the interface
@ 2026-09-28 13:41 Hongyan Xu
  2026-09-28 13:46 ` netdev-bot+sinfo
  2026-10-01 13:42 ` netdev-bot+sashiko
  0 siblings, 2 replies; 3+ messages in thread
From: Hongyan Xu @ 2026-09-28 13:41 UTC (permalink / raw)
  To: andrew+netdev, davem
  Cc: edumazet, kuba, pabeni, netdev, linux-kernel, jianhao.xu, Hongyan Xu

PLIP interrupt, transmit, and work paths schedule the immediate and
deferred work items embedded in netdev private state. plip_close() stops
IRQ or polling publication, but it releases the parport and pending skbs
without draining those work items first. A callback can therefore continue
using resources released by an ordinary interface close or device teardown.

Initialize both work items disabled. On open, reset protocol state before
enabling the work and its IRQ or polling publishers. On close, stop those
publishers and then disable and drain the work before releasing resources.
The balanced enable and disable operations support later interface reopen.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Hongyan Xu <getshell@seu.edu.cn>
---
 drivers/net/plip/plip.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)

diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
index d81163bc910a..97bbac0b95da 100644
--- a/drivers/net/plip/plip.c
+++ b/drivers/net/plip/plip.c
@@ -308,6 +308,8 @@ plip_init_netdev(struct net_device *dev)
 	/* Initialize task queue structures */
 	INIT_WORK(&nl->immediate, plip_bh);
 	INIT_DELAYED_WORK(&nl->deferred, plip_kick_bh);
+	disable_work(&nl->immediate);
+	disable_delayed_work(&nl->deferred);
 
 	if (dev->irq == -1)
 		INIT_DELAYED_WORK(&nl->timer, plip_timer_bh);
@@ -1077,6 +1079,17 @@ plip_open(struct net_device *dev)
 
 	nl->should_relinquish = 0;
 
+	/* Initialize the state machine. */
+	nl->rcv_data.state = PLIP_PK_DONE;
+	nl->snd_data.state = PLIP_PK_DONE;
+	nl->rcv_data.skb = NULL;
+	nl->snd_data.skb = NULL;
+	nl->connection = PLIP_CN_NONE;
+	nl->is_deferred = 0;
+
+	enable_work(&nl->immediate);
+	enable_work(&nl->deferred.work);
+
 	/* Clear the data port. */
 	write_data (dev, 0x00);
 
@@ -1088,12 +1101,6 @@ plip_open(struct net_device *dev)
 		schedule_delayed_work(&nl->timer, 1);
 	}
 
-	/* Initialize the state machine. */
-	nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
-	nl->rcv_data.skb = nl->snd_data.skb = NULL;
-	nl->connection = PLIP_CN_NONE;
-	nl->is_deferred = 0;
-
 	/* Fill in the MAC-level header.
 	   We used to abuse dev->broadcast to store the point-to-point
 	   MAC address, but we no longer do it. Instead, we fetch the
@@ -1141,6 +1148,9 @@ plip_close(struct net_device *dev)
 		wait_for_completion(&nl->killed_timer_cmp);
 	}
 
+	disable_work_sync(&nl->immediate);
+	disable_delayed_work_sync(&nl->deferred);
+
 #ifdef NOTDEF
 	outb(0x00, PAR_DATA(dev));
 #endif
-- 
2.50.1.windows.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH net] net: plip: quiesce private work when stopping the interface
  2026-09-28 13:41 [PATCH net] net: plip: quiesce private work when stopping the interface Hongyan Xu
@ 2026-09-28 13:46 ` netdev-bot+sinfo
  2026-10-01 13:42 ` netdev-bot+sashiko
  1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sinfo @ 2026-09-28 13:46 UTC (permalink / raw)
  To: Hongyan Xu
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, netdev,
	linux-kernel, jianhao.xu

Hi!

This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:

 - How the issue was discovered, e.g. hit in production, hit during
   development, syzbot report, manual code inspection, LLM or static
   analysis tool scan.

 - Whether the issue was actually triggered, or is only theoretical
   (e.g. found by code inspection). If it was triggered please include
   the symptoms, like the stack trace or error messages.

Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.

The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH net] net: plip: quiesce private work when stopping the interface
  2026-09-28 13:41 [PATCH net] net: plip: quiesce private work when stopping the interface Hongyan Xu
  2026-09-28 13:46 ` netdev-bot+sinfo
@ 2026-10-01 13:42 ` netdev-bot+sashiko
  1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sashiko @ 2026-10-01 13:42 UTC (permalink / raw)
  To: getshell
  Cc: andrew+netdev, davem, edumazet, kuba, pabeni, netdev,
	linux-kernel, jianhao.xu

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

Critical: 0 · High: 0 (1) · Medium: 1 · Low: 0 (1)

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] The IRQ publisher is already live when plip_open() resets its
  state, so a peer trigger can be lost and receive stays stuck.

Pre-existing issues:
- [High] This problem wasn't introduced by this patch, but it defeats the
  reopen support the commit message claims.
- [Low] Parallel-port data lines can be left mid-handshake after close
  (baseline: pre-existing, low impact).

--

net: plip: quiesce private work when stopping the interface

This patch initializes the immediate and deferred PLIP work items as
disabled. plip_open() now resets the protocol state and then enables the
work items. plip_close() disables and drains both work items before it
releases the parport and any pending skbs.

> diff --git a/drivers/net/plip/plip.c b/drivers/net/plip/plip.c
> index d81163bc910a..97bbac0b95da 100644
> --- a/drivers/net/plip/plip.c
> +++ b/drivers/net/plip/plip.c

[ ... ]

> @@ -1077,6 +1079,17 @@ plip_open(struct net_device *dev)
>  
>  	nl->should_relinquish = 0;
>  
> +	/* Initialize the state machine. */
> +	nl->rcv_data.state = PLIP_PK_DONE;
> +	nl->snd_data.state = PLIP_PK_DONE;
> +	nl->rcv_data.skb = NULL;
> +	nl->snd_data.skb = NULL;
> +	nl->connection = PLIP_CN_NONE;
> +	nl->is_deferred = 0;
> +
> +	enable_work(&nl->immediate);
> +	enable_work(&nl->deferred.work);

[Severity: Medium]
In IRQ mode, can a trigger interrupt from the peer get lost here?

The commit message says open will "reset protocol state before enabling
the work and its IRQ or polling publishers". However, the parport_claim()
call at the top of plip_open() already makes plip_interrupt() reachable.

parport_claim() sets port->cad to the PLIP pardev and calls
restore_state(). For parport_pc, the saved CONTROL value already has
ackIntEn set:

drivers/parport/parport_pc.c:parport_pc_init_state() {
    ...
	if (dev->irq_func && dev->port->irq != PARPORT_IRQ_NONE)
		/* Set ackIntEn */
		s->u.pc.ctr |= 0x10;
    ...
}

Suppose the interrupt lands after nl->connection = PLIP_CN_NONE but before
enable_work(&nl->immediate) finishes. plip_interrupt() then does:

	case PLIP_CN_NONE:
	case PLIP_CN_SEND:
		rcv->state = PLIP_PK_TRIGGER;
		nl->connection = PLIP_CN_RECEIVE;
		nl->timeout_count = 0;
		schedule_work(&nl->immediate);
		break;

The work is still disabled from plip_init_netdev(), so this schedule_work()
is silently dropped. enable_work() does not replay it.

Every later trigger then hits:

	case PLIP_CN_RECEIVE:
		...
		break;

Receive stays stuck until a local transmit happens to queue plip_bh().
Before this patch the work was always enabled, so this interrupt would
always have queued plip_bh().

Would it work to do the state reset and the enable_work() calls before
parport_claim()? Another option is to keep the port interrupt masked, and
do the reset under nl->lock, until the work is enabled.

> +
>  	/* Clear the data port. */
>  	write_data (dev, 0x00);
>  

[ ... ]

> @@ -1141,6 +1148,9 @@ plip_close(struct net_device *dev)
>  		wait_for_completion(&nl->killed_timer_cmp);
>  	}
>  
> +	disable_work_sync(&nl->immediate);
> +	disable_delayed_work_sync(&nl->deferred);
> +

[Severity: High]
This isn't a bug introduced by this patch, but does reopen work in IRQ
mode? The commit message says "The balanced enable and disable operations
support later interface reopen". However, plip_close() does an
unconditional, counted disable_irq() earlier in the function:

	netif_stop_queue (dev);
	DISABLE(dev->irq);
	synchronize_irq(dev->irq);

where:

#define DISABLE(irq) if (irq != -1) disable_irq(irq)

plip_open() never calls ENABLE(dev->irq). It only calls
enable_parport_interrupts(), which for parport_pc ends up in
parport_pc_enable_irq():

	__parport_pc_frob_control (p, 0x10, 0x10);

That sets the chip's IRQ enable bit, but it does not unmask the Linux IRQ
line. The other DISABLE/ENABLE pairs in the transfer and recovery paths
balance each other, and none of them undoes the disable in close.

After an ifdown/ifup, the IRQ disable depth stays at one or more. As a
result, plip_interrupt() is never delivered and the interface can't
receive.

dev->irq is the parport controller's IRQ (plip_attach() sets it from
port->irq), and PCI parport cards request it with IRQF_SHARED. Doesn't
this also leave the line masked for other parport clients and for any
device sharing that IRQ?

>  #ifdef NOTDEF
>  	outb(0x00, PAR_DATA(dev));
>  #endif

[Severity: Low]
This is a pre-existing issue, but plip_close() never sets the data
register back to idle before parport_release(). The only reset is the
outb() above, which is compiled out.

If the interface is closed mid-transfer, the last handshake value stays on
the wire. Examples are the 0x08 trigger from plip_send_packet() or the ACK
from plip_receive_packet():

	write_data (dev, 0x01); /* send ACK */

parport_pc_save_state() and parport_pc_restore_state() only handle CTR and
ECR. The data value therefore stays in place until this side reopens and
plip_open() writes 0x00. Until then the peer may stay in PLIP_CN_ERROR.

This patch doesn't change that behaviour. Before it, any work still
pending after close was already a no-op: close sets nl->is_deferred = 0
and nl->connection = PLIP_CN_NONE. So plip_kick_bh() returned early and
plip_bh() ran plip_none(), and neither of them writes the data register.

Would a write_data(dev, 0x00) after the work is drained and before
parport_release() be a reasonable cleanup here?

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260928134136.1213-1-getshell%40seu.edu.cn

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-01 13:42 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-28 13:41 [PATCH net] net: plip: quiesce private work when stopping the interface Hongyan Xu
2026-09-28 13:46 ` netdev-bot+sinfo
2026-10-01 13:42 ` netdev-bot+sashiko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®