[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20250728015125.17825-4-o-takashi@sakamocchi.jp>
Date: Mon, 28 Jul 2025 10:51:25 +0900
From: Takashi Sakamoto <o-takashi@...amocchi.jp>
To: linux1394-devel@...ts.sourceforge.net
Cc: linux-kernel@...r.kernel.org
Subject: [PATCH 3/3] firewire: core: call FCP address handlers outside RCU read-side critical section
The previous commit added reference counting to ensure safe invocations of
address handlers.
This commit moves the invocation of FCP address handlers outside of the
RCU read critical section. Unlike the exclusive-region address handlers,
all FCP address handlers should be called on receiving an FCP request.
An XArray is used to collect the FCP address handlers during the RCU
read-side critical section, after which they are invoked. Reference
counting ensures that each FCP address handler is called safely.
Signed-off-by: Takashi Sakamoto <o-takashi@...amocchi.jp>
---
drivers/firewire/core-transaction.c | 30 +++++++++++++++++++++++------
1 file changed, 24 insertions(+), 6 deletions(-)
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index a742971c65fa..c5408c83709c 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -956,13 +956,14 @@ static void handle_fcp_region_request(struct fw_card *card,
unsigned long long offset)
{
struct fw_address_handler *handler;
+ DEFINE_XARRAY_ALLOC(handlers);
int tcode, destination, source;
+ unsigned long id;
if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
request->length > 0x200) {
fw_send_response(card, request, RCODE_ADDRESS_ERROR);
-
return;
}
@@ -973,22 +974,39 @@ static void handle_fcp_region_request(struct fw_card *card,
if (tcode != TCODE_WRITE_QUADLET_REQUEST &&
tcode != TCODE_WRITE_BLOCK_REQUEST) {
fw_send_response(card, request, RCODE_TYPE_ERROR);
+ return;
+ }
+ // Reserve an entry outside the RCU read-side critical section to cover most cases.
+ id = 0;
+ if (xa_reserve(&handlers, id, GFP_KERNEL) < 0) {
+ fw_send_response(card, request, RCODE_CONFLICT_ERROR);
return;
}
scoped_guard(rcu) {
list_for_each_entry_rcu(handler, &address_handler_list, link) {
if (is_enclosing_handler(handler, offset, request->length)) {
- get_address_handler(handler);
- handler->address_callback(card, request, tcode, destination, source,
- p->generation, offset, request->data,
- request->length, handler->callback_data);
- put_address_handler(handler);
+ // FCP is used for purposes unrelated to significant system
+ // resources (e.g. storage or networking), so allocation
+ // failures are not considered so critical.
+ void *ptr = xa_store(&handlers, id, handler, GFP_ATOMIC);
+ if (!xa_is_err(ptr)) {
+ ++id;
+ get_address_handler(handler);
+ }
}
}
}
+ xa_for_each(&handlers, id, handler) {
+ // Outside the RCU read-side critical section. Without spinlock. With reference count.
+ handler->address_callback(card, request, tcode, destination, source, p->generation,
+ offset, request->data, request->length, handler->callback_data);
+ put_address_handler(handler);
+ }
+
+ xa_destroy(&handlers);
fw_send_response(card, request, RCODE_COMPLETE);
}
--
2.48.1
Powered by blists - more mailing lists