mirror of
https://github.com/torvalds/linux.git
synced 2026-01-25 15:03:52 +08:00
firewire: core: call FCP address handlers outside RCU read-side critical section
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 next work. Link: https://lore.kernel.org/r/20250803122015.236493-4-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user