aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2012-08-19 02:50:02 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2012-09-28 05:47:41 -0400
commit35202f7d8420fff586b372422a2419affeaba8ef (patch)
tree617a3f8c13fa06e46432029ad172c172db8d4dd3 /drivers/firewire
parent52439d605d6604c15954281a1d2831471dbd024c (diff)
firewire: remove global lock around address handlers, convert to RCU
Upper-layer handlers for inbound requests were called with a spinlock held by firewire-core. Calling into upper layers with a lower layer lock held is generally a bad idea. What's more, since commit ea102d0ec475 "firewire: core: convert AR-req handler lock from _irqsave to _bh", a caller of fw_send_request() i.e. initiator of outbound request could no longer do that while having interrupts disabled, if the local node was addressed by that request. In order to make all this more flexible, convert the management of address ranges and handlers from a global lock around readers and writers to RCU (and a remaining global lock for writers). As a minor side effect, handling of inbound requests at different cards and of local requests is now no longer serialized. (There is still per-card serialization of remote requests since firewire-ohci uses a single DMA tasklet for inbound request events.) In other words, address handlers are now called in an RCU read-side critical section instead of from within a spin_lock_bh serialized section. (Changelog rewritten by Stefan R.) Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-transaction.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 87d6f2d2f02d..d39cfa45817a 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -31,6 +31,7 @@
31#include <linux/kernel.h> 31#include <linux/kernel.h>
32#include <linux/list.h> 32#include <linux/list.h>
33#include <linux/module.h> 33#include <linux/module.h>
34#include <linux/rculist.h>
34#include <linux/slab.h> 35#include <linux/slab.h>
35#include <linux/spinlock.h> 36#include <linux/spinlock.h>
36#include <linux/string.h> 37#include <linux/string.h>
@@ -489,7 +490,7 @@ static struct fw_address_handler *lookup_overlapping_address_handler(
489{ 490{
490 struct fw_address_handler *handler; 491 struct fw_address_handler *handler;
491 492
492 list_for_each_entry(handler, list, link) { 493 list_for_each_entry_rcu(handler, list, link) {
493 if (handler->offset < offset + length && 494 if (handler->offset < offset + length &&
494 offset < handler->offset + handler->length) 495 offset < handler->offset + handler->length)
495 return handler; 496 return handler;
@@ -510,7 +511,7 @@ static struct fw_address_handler *lookup_enclosing_address_handler(
510{ 511{
511 struct fw_address_handler *handler; 512 struct fw_address_handler *handler;
512 513
513 list_for_each_entry(handler, list, link) { 514 list_for_each_entry_rcu(handler, list, link) {
514 if (is_enclosing_handler(handler, offset, length)) 515 if (is_enclosing_handler(handler, offset, length))
515 return handler; 516 return handler;
516 } 517 }
@@ -588,7 +589,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
588 if (other != NULL) { 589 if (other != NULL) {
589 handler->offset += other->length; 590 handler->offset += other->length;
590 } else { 591 } else {
591 list_add_tail(&handler->link, &address_handler_list); 592 list_add_tail_rcu(&handler->link, &address_handler_list);
592 ret = 0; 593 ret = 0;
593 break; 594 break;
594 } 595 }
@@ -609,8 +610,9 @@ EXPORT_SYMBOL(fw_core_add_address_handler);
609void fw_core_remove_address_handler(struct fw_address_handler *handler) 610void fw_core_remove_address_handler(struct fw_address_handler *handler)
610{ 611{
611 spin_lock_bh(&address_handler_lock); 612 spin_lock_bh(&address_handler_lock);
612 list_del(&handler->link); 613 list_del_rcu(&handler->link);
613 spin_unlock_bh(&address_handler_lock); 614 spin_unlock_bh(&address_handler_lock);
615 synchronize_rcu();
614} 616}
615EXPORT_SYMBOL(fw_core_remove_address_handler); 617EXPORT_SYMBOL(fw_core_remove_address_handler);
616 618
@@ -844,7 +846,7 @@ static void handle_exclusive_region_request(struct fw_card *card,
844 if (tcode == TCODE_LOCK_REQUEST) 846 if (tcode == TCODE_LOCK_REQUEST)
845 tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); 847 tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]);
846 848
847 spin_lock_bh(&address_handler_lock); 849 rcu_read_lock();
848 handler = lookup_enclosing_address_handler(&address_handler_list, 850 handler = lookup_enclosing_address_handler(&address_handler_list,
849 offset, request->length); 851 offset, request->length);
850 if (handler) 852 if (handler)
@@ -853,7 +855,7 @@ static void handle_exclusive_region_request(struct fw_card *card,
853 p->generation, offset, 855 p->generation, offset,
854 request->data, request->length, 856 request->data, request->length,
855 handler->callback_data); 857 handler->callback_data);
856 spin_unlock_bh(&address_handler_lock); 858 rcu_read_unlock();
857 859
858 if (!handler) 860 if (!handler)
859 fw_send_response(card, request, RCODE_ADDRESS_ERROR); 861 fw_send_response(card, request, RCODE_ADDRESS_ERROR);
@@ -886,8 +888,8 @@ static void handle_fcp_region_request(struct fw_card *card,
886 return; 888 return;
887 } 889 }
888 890
889 spin_lock_bh(&address_handler_lock); 891 rcu_read_lock();
890 list_for_each_entry(handler, &address_handler_list, link) { 892 list_for_each_entry_rcu(handler, &address_handler_list, link) {
891 if (is_enclosing_handler(handler, offset, request->length)) 893 if (is_enclosing_handler(handler, offset, request->length))
892 handler->address_callback(card, NULL, tcode, 894 handler->address_callback(card, NULL, tcode,
893 destination, source, 895 destination, source,
@@ -896,7 +898,7 @@ static void handle_fcp_region_request(struct fw_card *card,
896 request->length, 898 request->length,
897 handler->callback_data); 899 handler->callback_data);
898 } 900 }
899 spin_unlock_bh(&address_handler_lock); 901 rcu_read_unlock();
900 902
901 fw_send_response(card, request, RCODE_COMPLETE); 903 fw_send_response(card, request, RCODE_COMPLETE);
902} 904}