Skip to content

Commit 0342273

Browse files
committed
firewire: core: reallocate buffer for FCP address handlers when more than 4 are registered
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. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Sakamoto <[email protected]>
1 parent e884a8a commit 0342273

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

drivers/firewire/core-transaction.c

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -960,7 +960,7 @@ static void handle_fcp_region_request(struct fw_card *card,
960960
{
961961
struct fw_address_handler *buffer_on_kernel_stack[BUFFER_ON_KERNEL_STACK_SIZE];
962962
struct fw_address_handler *handler, **handlers;
963-
int tcode, destination, source, i, count;
963+
int tcode, destination, source, i, count, buffer_size;
964964

965965
if ((offset != (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
966966
offset != (CSR_REGISTER_BASE | CSR_FCP_RESPONSE)) ||
@@ -983,13 +983,38 @@ static void handle_fcp_region_request(struct fw_card *card,
983983

984984
count = 0;
985985
handlers = buffer_on_kernel_stack;
986+
buffer_size = ARRAY_SIZE(buffer_on_kernel_stack);
986987
scoped_guard(rcu) {
987988
list_for_each_entry_rcu(handler, &address_handler_list, link) {
988989
if (is_enclosing_handler(handler, offset, request->length)) {
990+
if (count >= buffer_size) {
991+
int next_size = buffer_size * 2;
992+
struct fw_address_handler **buffer_on_kernel_heap;
993+
994+
if (handlers == buffer_on_kernel_stack)
995+
buffer_on_kernel_heap = NULL;
996+
else
997+
buffer_on_kernel_heap = handlers;
998+
999+
buffer_on_kernel_heap =
1000+
krealloc_array(buffer_on_kernel_heap, next_size,
1001+
sizeof(*buffer_on_kernel_heap), GFP_ATOMIC);
1002+
// FCP is used for purposes unrelated to significant system
1003+
// resources (e.g. storage or networking), so allocation
1004+
// failures are not considered so critical.
1005+
if (!buffer_on_kernel_heap)
1006+
break;
1007+
1008+
if (handlers == buffer_on_kernel_stack) {
1009+
memcpy(buffer_on_kernel_heap, buffer_on_kernel_stack,
1010+
sizeof(buffer_on_kernel_stack));
1011+
}
1012+
1013+
handlers = buffer_on_kernel_heap;
1014+
buffer_size = next_size;
1015+
}
9891016
get_address_handler(handler);
990-
handlers[count] = handler;
991-
if (++count >= ARRAY_SIZE(buffer_on_kernel_stack))
992-
break;
1017+
handlers[count++] = handler;
9931018
}
9941019
}
9951020
}
@@ -1002,6 +1027,9 @@ static void handle_fcp_region_request(struct fw_card *card,
10021027
put_address_handler(handler);
10031028
}
10041029

1030+
if (handlers != buffer_on_kernel_stack)
1031+
kfree(handlers);
1032+
10051033
fw_send_response(card, request, RCODE_COMPLETE);
10061034
}
10071035

0 commit comments

Comments
 (0)