All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section
@ 2025-08-03 12:20 Takashi Sakamoto
  2025-08-03 12:20 ` [PATCH v2 1/4] firewire: core: use reference counting to invoke address handlers safely Takashi Sakamoto
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-08-03 12:20 UTC (permalink / raw)
  To: linux1394-devel; +Cc: linux-kernel

Hi,

This is an updated version of my previous patchset[1].

In the earlier version, XArray was used to collect FCP address handlers.
However, in typical system, only a few handlers are registered, and
using XArray for this purpose was unnecessarily complex and inefficient.
A simpler and faster approach is more appropriate here.

In this v2 patchset, the kernel stack is used initially to store up to 4
handlers. If more than 4 handlers are registered in the system, a buffer
is dynamically allocated from the kernel heap.

[1] https://lore.kernel.org/lkml/20250728015125.17825-1-o-takashi@sakamocchi.jp/

Takashi Sakamoto (4):
  firewire: core: use reference counting to invoke address handlers
    safely
  firewire: core: call handler for exclusive regions outside RCU
    read-side critical section
  firewire: core: call FCP address handlers outside RCU read-side
    critical section
  firewire: core: reallocate buffer for FCP address handlers when more
    than 4 are registered

 drivers/firewire/core-transaction.c | 91 +++++++++++++++++++++++++----
 include/linux/firewire.h            |  4 ++
 2 files changed, 85 insertions(+), 10 deletions(-)


base-commit: 7061835997daba9e73c723c85bd70bc4c44aef77
-- 
2.48.1


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

* [PATCH v2 1/4] firewire: core: use reference counting to invoke address handlers safely
  2025-08-03 12:20 [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
@ 2025-08-03 12:20 ` Takashi Sakamoto
  2025-08-03 12:20 ` [PATCH v2 2/4] firewire: core: call handler for exclusive regions outside RCU read-side critical section Takashi Sakamoto
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-08-03 12:20 UTC (permalink / raw)
  To: linux1394-devel; +Cc: linux-kernel

The lifetime of address handler has been managed by linked list and RCU.
This approach was introduced in commit 35202f7d8420 ("firewire: remove
global lock around address handlers, convert to RCU"). The invocations of
address handler are performed within RCU read-side critical sections.

In commit 57e6d9f85fff ("firewire: ohci: use workqueue to handle events
of AR request/response contexts"), the invocations are in a workqueue
context. The approach still imposes limitation that sleeping is not
allowed within RCU read-side critical sections. However, since sleeping
is not permitted within RCU read-side critical sections, this approach
still has a limitation.

This commit adds reference counting to decouple handler invocation from
handler discovery. The linked list and RCU is used to discover the
handlers, while the reference counting is used to invoke them safely.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 drivers/firewire/core-transaction.c | 32 +++++++++++++++++++++++++++--
 include/linux/firewire.h            |  4 ++++
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index d28477d84697..29ca9f3f14ce 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -550,6 +550,23 @@ const struct fw_address_region fw_unit_space_region =
 	{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
 #endif  /*  0  */
 
+static void complete_address_handler(struct kref *kref)
+{
+	struct fw_address_handler *handler = container_of(kref, struct fw_address_handler, kref);
+
+	complete(&handler->done);
+}
+
+static void get_address_handler(struct fw_address_handler *handler)
+{
+	kref_get(&handler->kref);
+}
+
+static int put_address_handler(struct fw_address_handler *handler)
+{
+	return kref_put(&handler->kref, complete_address_handler);
+}
+
 /**
  * fw_core_add_address_handler() - register for incoming requests
  * @handler:	callback
@@ -596,6 +613,8 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
 		if (other != NULL) {
 			handler->offset += other->length;
 		} else {
+			init_completion(&handler->done);
+			kref_init(&handler->kref);
 			list_add_tail_rcu(&handler->link, &address_handler_list);
 			ret = 0;
 			break;
@@ -621,6 +640,9 @@ void fw_core_remove_address_handler(struct fw_address_handler *handler)
 		list_del_rcu(&handler->link);
 
 	synchronize_rcu();
+
+	if (!put_address_handler(handler))
+		wait_for_completion(&handler->done);
 }
 EXPORT_SYMBOL(fw_core_remove_address_handler);
 
@@ -913,10 +935,13 @@ static void handle_exclusive_region_request(struct fw_card *card,
 	scoped_guard(rcu) {
 		handler = lookup_enclosing_address_handler(&address_handler_list, offset,
 							   request->length);
-		if (handler)
+		if (handler) {
+			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);
+		}
 	}
 
 	if (!handler)
@@ -952,10 +977,13 @@ static void handle_fcp_region_request(struct fw_card *card,
 
 	scoped_guard(rcu) {
 		list_for_each_entry_rcu(handler, &address_handler_list, link) {
-			if (is_enclosing_handler(handler, offset, request->length))
+			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);
+			}
 		}
 	}
 
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index cceb70415ed2..d38c6e538e5c 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -341,7 +341,11 @@ struct fw_address_handler {
 	u64 length;
 	fw_address_callback_t address_callback;
 	void *callback_data;
+
+	// Only for core functions.
 	struct list_head link;
+	struct kref kref;
+	struct completion done;
 };
 
 struct fw_address_region {
-- 
2.48.1


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

* [PATCH v2 2/4] firewire: core: call handler for exclusive regions outside RCU read-side critical section
  2025-08-03 12:20 [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
  2025-08-03 12:20 ` [PATCH v2 1/4] firewire: core: use reference counting to invoke address handlers safely Takashi Sakamoto
@ 2025-08-03 12:20 ` Takashi Sakamoto
  2025-08-03 12:20 ` [PATCH v2 3/4] firewire: core: call FCP address handlers " Takashi Sakamoto
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-08-03 12:20 UTC (permalink / raw)
  To: linux1394-devel; +Cc: linux-kernel

The previous commit added reference counting to ensure safe invocations of
address handlers.

This commit moves the invocation of handlers for exclusive regions outside
of the RCU read-side critical section. The address handler for the
requested region is selected within the critical section, then invoked
outside of it.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 drivers/firewire/core-transaction.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 29ca9f3f14ce..a742971c65fa 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -935,17 +935,19 @@ static void handle_exclusive_region_request(struct fw_card *card,
 	scoped_guard(rcu) {
 		handler = lookup_enclosing_address_handler(&address_handler_list, offset,
 							   request->length);
-		if (handler) {
+		if (handler)
 			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);
-		}
 	}
 
-	if (!handler)
+	if (!handler) {
 		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+		return;
+	}
+
+	// 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);
 }
 
 static void handle_fcp_region_request(struct fw_card *card,
-- 
2.48.1


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

* [PATCH v2 3/4] firewire: core: call FCP address handlers outside RCU read-side critical section
  2025-08-03 12:20 [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
  2025-08-03 12:20 ` [PATCH v2 1/4] firewire: core: use reference counting to invoke address handlers safely Takashi Sakamoto
  2025-08-03 12:20 ` [PATCH v2 2/4] firewire: core: call handler for exclusive regions outside RCU read-side critical section Takashi Sakamoto
@ 2025-08-03 12:20 ` Takashi Sakamoto
  2025-08-03 12:20 ` [PATCH v2 4/4] firewire: core: reallocate buffer for FCP address handlers when more than 4 are registered Takashi Sakamoto
  2025-08-11 13:28 ` [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
  4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-08-03 12:20 UTC (permalink / raw)
  To: linux1394-devel; +Cc: linux-kernel

The former commit added reference counting to ensure safe invocations of
address handlers. Unlike the exclusive-region address handlers, all FCP
address handlers should be called on receiving an FCP request.

This commit uses the part of kernel stack to collect address handlers up
to 4 within the section, then invoke them outside of the section.
Reference counting ensures that each handler remains valid and safe to
call.

Lifting the limitation of supporting only 4 handlers is left for future
work.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 drivers/firewire/core-transaction.c | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index a742971c65fa..7a62c660e912 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -950,13 +950,17 @@ static void handle_exclusive_region_request(struct fw_card *card,
 	put_address_handler(handler);
 }
 
+// To use kmalloc allocator efficiently, this should be power of two.
+#define BUFFER_ON_KERNEL_STACK_SIZE	4
+
 static void handle_fcp_region_request(struct fw_card *card,
 				      struct fw_packet *p,
 				      struct fw_request *request,
 				      unsigned long long offset)
 {
-	struct fw_address_handler *handler;
-	int tcode, destination, source;
+	struct fw_address_handler *buffer_on_kernel_stack[BUFFER_ON_KERNEL_STACK_SIZE];
+	struct fw_address_handler *handler, **handlers;
+	int tcode, destination, source, i, count;
 
 	if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
 	     offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
@@ -977,18 +981,27 @@ static void handle_fcp_region_request(struct fw_card *card,
 		return;
 	}
 
+	count = 0;
+	handlers = buffer_on_kernel_stack;
 	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);
+				handlers[count] = handler;
+				if (++count >= ARRAY_SIZE(buffer_on_kernel_stack))
+					break;
 			}
 		}
 	}
 
+	for (i = 0; i < count; ++i) {
+		handler = handlers[i];
+		handler->address_callback(card, request, tcode, destination, source,
+					  p->generation, offset, request->data,
+					  request->length, handler->callback_data);
+		put_address_handler(handler);
+	}
+
 	fw_send_response(card, request, RCODE_COMPLETE);
 }
 
-- 
2.48.1


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

* [PATCH v2 4/4] firewire: core: reallocate buffer for FCP address handlers when more than 4 are registered
  2025-08-03 12:20 [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
                   ` (2 preceding siblings ...)
  2025-08-03 12:20 ` [PATCH v2 3/4] firewire: core: call FCP address handlers " Takashi Sakamoto
@ 2025-08-03 12:20 ` Takashi Sakamoto
  2025-08-11 13:28 ` [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
  4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-08-03 12:20 UTC (permalink / raw)
  To: linux1394-devel; +Cc: linux-kernel

The former commit has a limitation that only up to 4 FCP address
handlers could be processed per request. Although it suffices for most
use cases, it is technically a regression.

This commit lifts the restriction by reallocating the buffer from kernel
heap when more than 4 handlers are registered. The allocation is performed
within RCU read-side critical section, thus it uses GCP_ATOMIC flag. The
buffer size is rounded up to the next power of two to align with kmalloc
allocation units.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 drivers/firewire/core-transaction.c | 36 +++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 7a62c660e912..1d1c2d8f85ae 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -960,7 +960,7 @@ static void handle_fcp_region_request(struct fw_card *card,
 {
 	struct fw_address_handler *buffer_on_kernel_stack[BUFFER_ON_KERNEL_STACK_SIZE];
 	struct fw_address_handler *handler, **handlers;
-	int tcode, destination, source, i, count;
+	int tcode, destination, source, i, count, buffer_size;
 
 	if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
 	     offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
@@ -983,13 +983,38 @@ static void handle_fcp_region_request(struct fw_card *card,
 
 	count = 0;
 	handlers = buffer_on_kernel_stack;
+	buffer_size = ARRAY_SIZE(buffer_on_kernel_stack);
 	scoped_guard(rcu) {
 		list_for_each_entry_rcu(handler, &address_handler_list, link) {
 			if (is_enclosing_handler(handler, offset, request->length)) {
+				if (count >= buffer_size) {
+					int next_size = buffer_size * 2;
+					struct fw_address_handler **buffer_on_kernel_heap;
+
+					if (handlers == buffer_on_kernel_stack)
+						buffer_on_kernel_heap = NULL;
+					else
+						buffer_on_kernel_heap = handlers;
+
+					buffer_on_kernel_heap =
+						krealloc_array(buffer_on_kernel_heap, next_size,
+							sizeof(*buffer_on_kernel_heap), GFP_ATOMIC);
+					// FCP is used for purposes unrelated to significant system
+					// resources (e.g. storage or networking), so allocation
+					// failures are not considered so critical.
+					if (!buffer_on_kernel_heap)
+						break;
+
+					if (handlers == buffer_on_kernel_stack) {
+						memcpy(buffer_on_kernel_heap, buffer_on_kernel_stack,
+						       sizeof(buffer_on_kernel_stack));
+					}
+
+					handlers = buffer_on_kernel_heap;
+					buffer_size = next_size;
+				}
 				get_address_handler(handler);
-				handlers[count] = handler;
-				if (++count >= ARRAY_SIZE(buffer_on_kernel_stack))
-					break;
+				handlers[count++] = handler;
 			}
 		}
 	}
@@ -1002,6 +1027,9 @@ static void handle_fcp_region_request(struct fw_card *card,
 		put_address_handler(handler);
 	}
 
+	if (handlers != buffer_on_kernel_stack)
+		kfree(handlers);
+
 	fw_send_response(card, request, RCODE_COMPLETE);
 }
 
-- 
2.48.1


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

* Re: [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section
  2025-08-03 12:20 [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
                   ` (3 preceding siblings ...)
  2025-08-03 12:20 ` [PATCH v2 4/4] firewire: core: reallocate buffer for FCP address handlers when more than 4 are registered Takashi Sakamoto
@ 2025-08-11 13:28 ` Takashi Sakamoto
  4 siblings, 0 replies; 6+ messages in thread
From: Takashi Sakamoto @ 2025-08-11 13:28 UTC (permalink / raw)
  To: linux1394-devel; +Cc: linux-kernel

On Sun, Aug 03, 2025 at 09:20:11PM +0900, Takashi Sakamoto wrote:
> Hi,
> 
> This is an updated version of my previous patchset[1].
> 
> In the earlier version, XArray was used to collect FCP address handlers.
> However, in typical system, only a few handlers are registered, and
> using XArray for this purpose was unnecessarily complex and inefficient.
> A simpler and faster approach is more appropriate here.
> 
> In this v2 patchset, the kernel stack is used initially to store up to 4
> handlers. If more than 4 handlers are registered in the system, a buffer
> is dynamically allocated from the kernel heap.
> 
> [1] https://lore.kernel.org/lkml/20250728015125.17825-1-o-takashi@sakamocchi.jp/
> 
> Takashi Sakamoto (4):
>   firewire: core: use reference counting to invoke address handlers
>     safely
>   firewire: core: call handler for exclusive regions outside RCU
>     read-side critical section
>   firewire: core: call FCP address handlers outside RCU read-side
>     critical section
>   firewire: core: reallocate buffer for FCP address handlers when more
>     than 4 are registered
> 
>  drivers/firewire/core-transaction.c | 91 +++++++++++++++++++++++++----
>  include/linux/firewire.h            |  4 ++
>  2 files changed, 85 insertions(+), 10 deletions(-)
> 
> 
> base-commit: 7061835997daba9e73c723c85bd70bc4c44aef77

Applied to for-linus branch.


Thanks

Takashi Sakamoto

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

end of thread, other threads:[~2025-08-11 13:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-03 12:20 [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto
2025-08-03 12:20 ` [PATCH v2 1/4] firewire: core: use reference counting to invoke address handlers safely Takashi Sakamoto
2025-08-03 12:20 ` [PATCH v2 2/4] firewire: core: call handler for exclusive regions outside RCU read-side critical section Takashi Sakamoto
2025-08-03 12:20 ` [PATCH v2 3/4] firewire: core: call FCP address handlers " Takashi Sakamoto
2025-08-03 12:20 ` [PATCH v2 4/4] firewire: core: reallocate buffer for FCP address handlers when more than 4 are registered Takashi Sakamoto
2025-08-11 13:28 ` [PATCH v2 0/4] firewire: core: call address handlers ouside RCU read-side critical section Takashi Sakamoto

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.