Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

firewire: core: use spin lock specific to topology map

At present, the operation for read transaction to topology map register is
not protected by any kind of lock primitives. This causes a potential
problem to result in the mixed content of topology map.

This commit adds and uses spin lock specific to topology map.

Link: https://lore.kernel.org/r/20250915234747.915922-4-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>

+24 -10
+14 -8
drivers/firewire/core-topology.c
··· 435 435 } 436 436 } 437 437 438 - static void update_topology_map(struct fw_card *card, 439 - u32 *self_ids, int self_id_count) 438 + static void update_topology_map(__be32 *buffer, size_t buffer_size, int root_node_id, 439 + const u32 *self_ids, int self_id_count) 440 440 { 441 - int node_count = (card->root_node->node_id & 0x3f) + 1; 442 - __be32 *map = card->topology_map; 441 + __be32 *map = buffer; 442 + int node_count = (root_node_id & 0x3f) + 1; 443 + 444 + memset(map, 0, buffer_size); 443 445 444 446 *map++ = cpu_to_be32((self_id_count + 2) << 16); 445 - *map++ = cpu_to_be32(be32_to_cpu(card->topology_map[1]) + 1); 447 + *map++ = cpu_to_be32(be32_to_cpu(buffer[1]) + 1); 446 448 *map++ = cpu_to_be32((node_count << 16) | self_id_count); 447 449 448 450 while (self_id_count--) 449 451 *map++ = cpu_to_be32p(self_ids++); 450 452 451 - fw_compute_block_crc(card->topology_map); 453 + fw_compute_block_crc(buffer); 452 454 } 453 455 454 456 void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, ··· 481 479 482 480 local_node = build_tree(card, self_ids, self_id_count, generation); 483 481 484 - update_topology_map(card, self_ids, self_id_count); 485 - 486 482 card->color++; 487 483 488 484 if (local_node == NULL) { ··· 492 492 } else { 493 493 update_tree(card, local_node); 494 494 } 495 + } 496 + 497 + // Just used by transaction layer. 498 + scoped_guard(spinlock, &card->topology_map.lock) { 499 + update_topology_map(card->topology_map.buffer, sizeof(card->topology_map.buffer), 500 + card->root_node->node_id, self_ids, self_id_count); 495 501 } 496 502 } 497 503 EXPORT_SYMBOL(fw_core_handle_bus_reset);
+5 -1
drivers/firewire/core-transaction.c
··· 1196 1196 } 1197 1197 1198 1198 start = (offset - topology_map_region.start) / 4; 1199 - memcpy(payload, &card->topology_map[start], length); 1199 + 1200 + // NOTE: This can be without irqsave when we can guarantee that fw_send_request() for local 1201 + // destination never runs in any type of IRQ context. 1202 + scoped_guard(spinlock_irqsave, &card->topology_map.lock) 1203 + memcpy(payload, &card->topology_map.buffer[start], length); 1200 1204 1201 1205 fw_send_response(card, request, RCODE_COMPLETE); 1202 1206 }
+5 -1
include/linux/firewire.h
··· 129 129 130 130 bool broadcast_channel_allocated; 131 131 u32 broadcast_channel; 132 - __be32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4]; 132 + 133 + struct { 134 + __be32 buffer[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4]; 135 + spinlock_t lock; 136 + } topology_map; 133 137 134 138 __be32 maint_utility_register; 135 139