diff options
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r-- | drivers/firewire/core-transaction.c | 33 |
1 files changed, 19 insertions, 14 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 87d6f2d2f02d..28a94c7ec6e5 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 | } |
@@ -518,7 +519,7 @@ static struct fw_address_handler *lookup_enclosing_address_handler( | |||
518 | return NULL; | 519 | return NULL; |
519 | } | 520 | } |
520 | 521 | ||
521 | static DEFINE_SPINLOCK(address_handler_lock); | 522 | static DEFINE_SPINLOCK(address_handler_list_lock); |
522 | static LIST_HEAD(address_handler_list); | 523 | static LIST_HEAD(address_handler_list); |
523 | 524 | ||
524 | const struct fw_address_region fw_high_memory_region = | 525 | const struct fw_address_region fw_high_memory_region = |
@@ -555,6 +556,7 @@ static bool is_in_fcp_region(u64 offset, size_t length) | |||
555 | * the specified callback is invoked. The parameters passed to the callback | 556 | * the specified callback is invoked. The parameters passed to the callback |
556 | * give the details of the particular request. | 557 | * give the details of the particular request. |
557 | * | 558 | * |
559 | * To be called in process context. | ||
558 | * Return value: 0 on success, non-zero otherwise. | 560 | * Return value: 0 on success, non-zero otherwise. |
559 | * | 561 | * |
560 | * The start offset of the handler's address region is determined by | 562 | * The start offset of the handler's address region is determined by |
@@ -575,7 +577,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler, | |||
575 | handler->length == 0) | 577 | handler->length == 0) |
576 | return -EINVAL; | 578 | return -EINVAL; |
577 | 579 | ||
578 | spin_lock_bh(&address_handler_lock); | 580 | spin_lock(&address_handler_list_lock); |
579 | 581 | ||
580 | handler->offset = region->start; | 582 | handler->offset = region->start; |
581 | while (handler->offset + handler->length <= region->end) { | 583 | while (handler->offset + handler->length <= region->end) { |
@@ -588,13 +590,13 @@ int fw_core_add_address_handler(struct fw_address_handler *handler, | |||
588 | if (other != NULL) { | 590 | if (other != NULL) { |
589 | handler->offset += other->length; | 591 | handler->offset += other->length; |
590 | } else { | 592 | } else { |
591 | list_add_tail(&handler->link, &address_handler_list); | 593 | list_add_tail_rcu(&handler->link, &address_handler_list); |
592 | ret = 0; | 594 | ret = 0; |
593 | break; | 595 | break; |
594 | } | 596 | } |
595 | } | 597 | } |
596 | 598 | ||
597 | spin_unlock_bh(&address_handler_lock); | 599 | spin_unlock(&address_handler_list_lock); |
598 | 600 | ||
599 | return ret; | 601 | return ret; |
600 | } | 602 | } |
@@ -603,14 +605,17 @@ EXPORT_SYMBOL(fw_core_add_address_handler); | |||
603 | /** | 605 | /** |
604 | * fw_core_remove_address_handler() - unregister an address handler | 606 | * fw_core_remove_address_handler() - unregister an address handler |
605 | * | 607 | * |
608 | * To be called in process context. | ||
609 | * | ||
606 | * When fw_core_remove_address_handler() returns, @handler->callback() is | 610 | * When fw_core_remove_address_handler() returns, @handler->callback() is |
607 | * guaranteed to not run on any CPU anymore. | 611 | * guaranteed to not run on any CPU anymore. |
608 | */ | 612 | */ |
609 | void fw_core_remove_address_handler(struct fw_address_handler *handler) | 613 | void fw_core_remove_address_handler(struct fw_address_handler *handler) |
610 | { | 614 | { |
611 | spin_lock_bh(&address_handler_lock); | 615 | spin_lock(&address_handler_list_lock); |
612 | list_del(&handler->link); | 616 | list_del_rcu(&handler->link); |
613 | spin_unlock_bh(&address_handler_lock); | 617 | spin_unlock(&address_handler_list_lock); |
618 | synchronize_rcu(); | ||
614 | } | 619 | } |
615 | EXPORT_SYMBOL(fw_core_remove_address_handler); | 620 | EXPORT_SYMBOL(fw_core_remove_address_handler); |
616 | 621 | ||
@@ -844,7 +849,7 @@ static void handle_exclusive_region_request(struct fw_card *card, | |||
844 | if (tcode == TCODE_LOCK_REQUEST) | 849 | if (tcode == TCODE_LOCK_REQUEST) |
845 | tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); | 850 | tcode = 0x10 + HEADER_GET_EXTENDED_TCODE(p->header[3]); |
846 | 851 | ||
847 | spin_lock_bh(&address_handler_lock); | 852 | rcu_read_lock(); |
848 | handler = lookup_enclosing_address_handler(&address_handler_list, | 853 | handler = lookup_enclosing_address_handler(&address_handler_list, |
849 | offset, request->length); | 854 | offset, request->length); |
850 | if (handler) | 855 | if (handler) |
@@ -853,7 +858,7 @@ static void handle_exclusive_region_request(struct fw_card *card, | |||
853 | p->generation, offset, | 858 | p->generation, offset, |
854 | request->data, request->length, | 859 | request->data, request->length, |
855 | handler->callback_data); | 860 | handler->callback_data); |
856 | spin_unlock_bh(&address_handler_lock); | 861 | rcu_read_unlock(); |
857 | 862 | ||
858 | if (!handler) | 863 | if (!handler) |
859 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); | 864 | fw_send_response(card, request, RCODE_ADDRESS_ERROR); |
@@ -886,8 +891,8 @@ static void handle_fcp_region_request(struct fw_card *card, | |||
886 | return; | 891 | return; |
887 | } | 892 | } |
888 | 893 | ||
889 | spin_lock_bh(&address_handler_lock); | 894 | rcu_read_lock(); |
890 | list_for_each_entry(handler, &address_handler_list, link) { | 895 | list_for_each_entry_rcu(handler, &address_handler_list, link) { |
891 | if (is_enclosing_handler(handler, offset, request->length)) | 896 | if (is_enclosing_handler(handler, offset, request->length)) |
892 | handler->address_callback(card, NULL, tcode, | 897 | handler->address_callback(card, NULL, tcode, |
893 | destination, source, | 898 | destination, source, |
@@ -896,7 +901,7 @@ static void handle_fcp_region_request(struct fw_card *card, | |||
896 | request->length, | 901 | request->length, |
897 | handler->callback_data); | 902 | handler->callback_data); |
898 | } | 903 | } |
899 | spin_unlock_bh(&address_handler_lock); | 904 | rcu_read_unlock(); |
900 | 905 | ||
901 | fw_send_response(card, request, RCODE_COMPLETE); | 906 | fw_send_response(card, request, RCODE_COMPLETE); |
902 | } | 907 | } |