aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ieee1394
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2007-08-11 05:52:08 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-10-16 17:59:55 -0400
commit261b5f664c6c68c5209656a71c41823eda0d938b (patch)
tree52045ab3beb1564b248a8389c241ac825b14c1bd /drivers/ieee1394
parentc4f3d41fed11c9050aa93bbaeed9f7f06bcc93ba (diff)
ieee1394: sbp2: fix unsafe iteration over list of devices
sbp2_host_reset and sbp2_handle_status_write are not serialized against sbp2_alloc_device and sbp2_remove_device. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/ieee1394')
-rw-r--r--drivers/ieee1394/sbp2.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index a81ba8fca0db..1b353b964b33 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -242,6 +242,8 @@ static int sbp2_max_speed_and_size(struct sbp2_lu *);
242 242
243static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC }; 243static const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };
244 244
245static DEFINE_RWLOCK(sbp2_hi_logical_units_lock);
246
245static struct hpsb_highlevel sbp2_highlevel = { 247static struct hpsb_highlevel sbp2_highlevel = {
246 .name = SBP2_DEVICE_NAME, 248 .name = SBP2_DEVICE_NAME,
247 .host_reset = sbp2_host_reset, 249 .host_reset = sbp2_host_reset,
@@ -732,6 +734,7 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
732 struct sbp2_fwhost_info *hi; 734 struct sbp2_fwhost_info *hi;
733 struct Scsi_Host *shost = NULL; 735 struct Scsi_Host *shost = NULL;
734 struct sbp2_lu *lu = NULL; 736 struct sbp2_lu *lu = NULL;
737 unsigned long flags;
735 738
736 lu = kzalloc(sizeof(*lu), GFP_KERNEL); 739 lu = kzalloc(sizeof(*lu), GFP_KERNEL);
737 if (!lu) { 740 if (!lu) {
@@ -784,7 +787,9 @@ static struct sbp2_lu *sbp2_alloc_device(struct unit_directory *ud)
784 787
785 lu->hi = hi; 788 lu->hi = hi;
786 789
790 write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
787 list_add_tail(&lu->lu_list, &hi->logical_units); 791 list_add_tail(&lu->lu_list, &hi->logical_units);
792 write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
788 793
789 /* Register the status FIFO address range. We could use the same FIFO 794 /* Register the status FIFO address range. We could use the same FIFO
790 * for targets at different nodes. However we need different FIFOs per 795 * for targets at different nodes. However we need different FIFOs per
@@ -828,16 +833,20 @@ static void sbp2_host_reset(struct hpsb_host *host)
828{ 833{
829 struct sbp2_fwhost_info *hi; 834 struct sbp2_fwhost_info *hi;
830 struct sbp2_lu *lu; 835 struct sbp2_lu *lu;
836 unsigned long flags;
831 837
832 hi = hpsb_get_hostinfo(&sbp2_highlevel, host); 838 hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
833 if (!hi) 839 if (!hi)
834 return; 840 return;
841
842 read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
835 list_for_each_entry(lu, &hi->logical_units, lu_list) 843 list_for_each_entry(lu, &hi->logical_units, lu_list)
836 if (likely(atomic_read(&lu->state) != 844 if (likely(atomic_read(&lu->state) !=
837 SBP2LU_STATE_IN_SHUTDOWN)) { 845 SBP2LU_STATE_IN_SHUTDOWN)) {
838 atomic_set(&lu->state, SBP2LU_STATE_IN_RESET); 846 atomic_set(&lu->state, SBP2LU_STATE_IN_RESET);
839 scsi_block_requests(lu->shost); 847 scsi_block_requests(lu->shost);
840 } 848 }
849 read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
841} 850}
842 851
843static int sbp2_start_device(struct sbp2_lu *lu) 852static int sbp2_start_device(struct sbp2_lu *lu)
@@ -919,6 +928,7 @@ alloc_fail:
919static void sbp2_remove_device(struct sbp2_lu *lu) 928static void sbp2_remove_device(struct sbp2_lu *lu)
920{ 929{
921 struct sbp2_fwhost_info *hi; 930 struct sbp2_fwhost_info *hi;
931 unsigned long flags;
922 932
923 if (!lu) 933 if (!lu)
924 return; 934 return;
@@ -933,7 +943,9 @@ static void sbp2_remove_device(struct sbp2_lu *lu)
933 flush_scheduled_work(); 943 flush_scheduled_work();
934 sbp2util_remove_command_orb_pool(lu, hi->host); 944 sbp2util_remove_command_orb_pool(lu, hi->host);
935 945
946 write_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
936 list_del(&lu->lu_list); 947 list_del(&lu->lu_list);
948 write_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
937 949
938 if (lu->login_response) 950 if (lu->login_response)
939 dma_free_coherent(hi->host->device.parent, 951 dma_free_coherent(hi->host->device.parent,
@@ -1707,6 +1719,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
1707 } 1719 }
1708 1720
1709 /* Find the unit which wrote the status. */ 1721 /* Find the unit which wrote the status. */
1722 read_lock_irqsave(&sbp2_hi_logical_units_lock, flags);
1710 list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) { 1723 list_for_each_entry(lu_tmp, &hi->logical_units, lu_list) {
1711 if (lu_tmp->ne->nodeid == nodeid && 1724 if (lu_tmp->ne->nodeid == nodeid &&
1712 lu_tmp->status_fifo_addr == addr) { 1725 lu_tmp->status_fifo_addr == addr) {
@@ -1714,6 +1727,8 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
1714 break; 1727 break;
1715 } 1728 }
1716 } 1729 }
1730 read_unlock_irqrestore(&sbp2_hi_logical_units_lock, flags);
1731
1717 if (unlikely(!lu)) { 1732 if (unlikely(!lu)) {
1718 SBP2_ERR("lu is NULL - device is gone?"); 1733 SBP2_ERR("lu is NULL - device is gone?");
1719 return RCODE_ADDRESS_ERROR; 1734 return RCODE_ADDRESS_ERROR;