mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
To: linux1394-devel@lists.sourceforge.net
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH] firewire: core: invoke packet callback from workqueue when removing card instance
Date: Sat, 17 Oct 2026 13:02:16 +0900	[thread overview]
Message-ID: <20261017040216.GA145683@sakamocchi.jp> (raw)
In-Reply-To: <20261016135948.85343-1-o-takashi@sakamocchi.jp>

I found that some issues are reported by Sashiko.dev[1].

On Fri, Oct 16, 2026 at 10:59:48PM +0900, Takashi Sakamoto wrote:
> Current implementation switches the underlying driver of a card instance
> to the dummy driver in the kernel stack when removing the card. The dummy
> driver simply invokes callbacks when sending request and response
> packets.
> 
> Recent changes for the 1394 OHCI driver and core transaction layer ensure
> that callbacks are invoked in process context from a workqueue. This
> guarantees a consistent execution context for callbacks. However, card
> removel is currently an exception.
> 
> Invoke packet callbacks from a workqueue during card removal.
> 
> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> ---
>  drivers/firewire/core-card.c | 57 +++++++++++++++++++++++++++++++-----
>  1 file changed, 49 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
> index be6f18d67ece..a26b5e380c6c 100644
> --- a/drivers/firewire/core-card.c
> +++ b/drivers/firewire/core-card.c
> @@ -688,6 +688,15 @@ EXPORT_SYMBOL(fw_card_add);
>   * .set_config_rom() is never called since the card is taken out of card_list
>   * before switching to the dummy driver.
>   */
> +struct fw_card_driver_closer {
> +	struct fw_card_driver driver;
> +
> +	// For closing operations.
> +	struct fw_card *card;
> +	struct list_head packet_list;
> +	spinlock_t packet_list_lock;
> +	struct work_struct work;
> +};
>  
>  static int dummy_read_phy_reg(struct fw_card *card, int address)
>  {
> @@ -700,14 +709,39 @@ static int dummy_update_phy_reg(struct fw_card *card, int address,
>  	return -ENODEV;
>  }
>  
> +static void dummy_packet_callback_work(struct work_struct *work)
> +{
> +	struct fw_card_driver_closer *closer = container_of(work, typeof(*closer), work);
> +	struct fw_packet *p;
> +
> +	spin_lock(&closer->packet_list_lock);
> +	while ((p = list_first_entry_or_null(&closer->packet_list, typeof(*p), link_for_local))) {
> +		list_del(&p->link_for_local);
> +		spin_unlock(&closer->packet_list_lock);
> +
> +		p->callback(p, closer->card, RCODE_CANCELLED);
> +
> +		spin_lock(&closer->packet_list_lock);
> +	}
> +	spin_unlock(&closer->packet_list_lock);
> +}

They should be 'spinlock_irqsave' since the packet_list_lock is acquired
by dummy_send_request(), which can run in interrupt context.

Additionally, an issue has been reported that the packet cancelling and
the transaction cancelling by fw_cancel_pending_transactions() would conflict, since
the fw_packet structure is the part of the fw_transaction structure.

>  static void dummy_send_request(struct fw_card *card, struct fw_packet *packet)
>  {
> -	packet->callback(packet, card, RCODE_CANCELLED);
> +	struct fw_card_driver_closer *closer = container_of(card->driver, typeof(*closer), driver);
> +
> +	scoped_guard(spinlock_irqsave, &closer->packet_list_lock)
> +		list_add_tail(&packet->link_for_local, &closer->packet_list);
> +	queue_work(card->async_wq, &closer->work);
>  }
>  
>  static void dummy_send_response(struct fw_card *card, struct fw_packet *packet)
>  {
> -	packet->callback(packet, card, RCODE_CANCELLED);
> +	struct fw_card_driver_closer *closer = container_of(card->driver, typeof(*closer), driver);
> +
> +	scoped_guard(spinlock_irqsave, &closer->packet_list_lock)
> +		list_add_tail(&packet->link_for_local, &closer->packet_list);
> +	queue_work(card->async_wq, &closer->work);
>  }
>  
>  static int dummy_cancel_packet(struct fw_card *card, struct fw_packet *packet)
> @@ -789,7 +823,7 @@ EXPORT_SYMBOL_GPL(fw_card_release);
>  
>  void fw_core_remove_card(struct fw_card *card)
>  {
> -	struct fw_card_driver dummy_driver = dummy_driver_template;
> +	struct fw_card_driver_closer closer;
>  
>  	might_sleep();
>  
> @@ -800,11 +834,17 @@ void fw_core_remove_card(struct fw_card *card)
>  	scoped_guard(mutex, &card_mutex)
>  		list_del_init(&card->link);
>  
> -	/* Switch off most of the card driver interface. */
> -	dummy_driver.free_iso_context	= card->driver->free_iso_context;
> -	dummy_driver.stop_iso		= card->driver->stop_iso;
> -	dummy_driver.disable		= card->driver->disable;
> -	card->driver = &dummy_driver;
> +	closer.card = card;
> +	INIT_LIST_HEAD(&closer.packet_list);
> +	spin_lock_init(&closer.packet_list_lock);
> +	INIT_WORK(&closer.work, dummy_packet_callback_work);
> +
> +	// Switch off most of the card driver interface.
> +	closer.driver = dummy_driver_template;
> +	closer.driver.free_iso_context	= card->driver->free_iso_context;
> +	closer.driver.stop_iso = card->driver->stop_iso;
> +	closer.driver.disable = card->driver->disable;
> +	card->driver = &closer.driver;

There is a concern about the reordering. When the assigned pointer
value of card->driver is visible in any processor core, there is no
guarantee that the content of fw_card_driver_closer structure is filled
as expected.

Here any memory barrier is required. It is a potential problem that
the original code has.

>  	drain_workqueue(card->isoc_wq);
>  	drain_workqueue(card->async_wq);
> @@ -821,6 +861,7 @@ void fw_core_remove_card(struct fw_card *card)
>  	destroy_workqueue(card->isoc_wq);
>  	destroy_workqueue(card->async_wq);
>  
> +	WARN_ON(!list_empty(&closer.packet_list));
>  	WARN_ON(!list_empty(&card->transactions.list));
>  }
>  EXPORT_SYMBOL(fw_core_remove_card);

Although we are nearing the end of the current release cycle, let me put
in some more work on them.


[1] https://sashiko.dev/#/patchset/20261016135948.85343-1-o-takashi%40sakamocchi.jp


Regards

Takashi Sakamoto

      reply	other threads:[~2026-10-17  4:02 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-16 13:59 Takashi Sakamoto
2026-10-17  4:02 ` Takashi Sakamoto [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=20261017040216.GA145683@sakamocchi.jp \
    --to=o-takashi@sakamocchi.jp \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux1394-devel@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®