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.

[PATCH] raw1394: fix locking in the presence of SMP and interrupts

Changes all spinlocks that can be held during an irq handler to disable
interrupts while the lock is held. Changes spin_[un]lock_irq to use the
irqsave/irqrestore variants for robustness and readability.

In raw1394.c:handle_iso_listen(), don't grab host_info_lock at all -- we're
not accessing host_info_list or host_count, and holding this lock while
trying to tasklet_kill the iso tasklet this can cause an ABBA deadlock if
ohci:dma_rcv_tasklet is running and tries to grab host_info_lock in
raw1394.c:receive_iso. Test program attached reliably deadlocks all SMP
machines I have been able to test without this patch.

Signed-off-by: Andy Wingo <wingo@pobox.com>
Acked-by: Ben Collins <bcollins@ubuntu.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Andy Wingo and committed by
Linus Torvalds
4a9949d7 c367c21c

+57 -49
+3 -3
drivers/ieee1394/ohci1394.c
··· 2283 2283 { 2284 2284 struct ohci1394_iso_tasklet *t; 2285 2285 unsigned long mask; 2286 + unsigned long flags; 2286 2287 2287 - spin_lock(&ohci->iso_tasklet_list_lock); 2288 + spin_lock_irqsave(&ohci->iso_tasklet_list_lock, flags); 2288 2289 2289 2290 list_for_each_entry(t, &ohci->iso_tasklet_list, link) { 2290 2291 mask = 1 << t->context; ··· 2296 2295 tasklet_schedule(&t->tasklet); 2297 2296 } 2298 2297 2299 - spin_unlock(&ohci->iso_tasklet_list_lock); 2300 - 2298 + spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags); 2301 2299 } 2302 2300 2303 2301 static irqreturn_t ohci_irq_handler(int irq, void *dev_id,
+54 -46
drivers/ieee1394/raw1394.c
··· 412 412 static ssize_t raw1394_read(struct file *file, char __user * buffer, 413 413 size_t count, loff_t * offset_is_ignored) 414 414 { 415 + unsigned long flags; 415 416 struct file_info *fi = (struct file_info *)file->private_data; 416 417 struct list_head *lh; 417 418 struct pending_request *req; ··· 436 435 } 437 436 } 438 437 439 - spin_lock_irq(&fi->reqlists_lock); 438 + spin_lock_irqsave(&fi->reqlists_lock, flags); 440 439 lh = fi->req_complete.next; 441 440 list_del(lh); 442 - spin_unlock_irq(&fi->reqlists_lock); 441 + spin_unlock_irqrestore(&fi->reqlists_lock, flags); 443 442 444 443 req = list_entry(lh, struct pending_request, list); 445 444 ··· 487 486 488 487 static int state_initialized(struct file_info *fi, struct pending_request *req) 489 488 { 489 + unsigned long flags; 490 490 struct host_info *hi; 491 491 struct raw1394_khost_list *khl; 492 492 ··· 501 499 502 500 switch (req->req.type) { 503 501 case RAW1394_REQ_LIST_CARDS: 504 - spin_lock_irq(&host_info_lock); 502 + spin_lock_irqsave(&host_info_lock, flags); 505 503 khl = kmalloc(sizeof(struct raw1394_khost_list) * host_count, 506 504 SLAB_ATOMIC); 507 505 ··· 515 513 khl++; 516 514 } 517 515 } 518 - spin_unlock_irq(&host_info_lock); 516 + spin_unlock_irqrestore(&host_info_lock, flags); 519 517 520 518 if (khl != NULL) { 521 519 req->req.error = RAW1394_ERROR_NONE; ··· 530 528 break; 531 529 532 530 case RAW1394_REQ_SET_CARD: 533 - spin_lock_irq(&host_info_lock); 531 + spin_lock_irqsave(&host_info_lock, flags); 534 532 if (req->req.misc < host_count) { 535 533 list_for_each_entry(hi, &host_info_list, list) { 536 534 if (!req->req.misc--) ··· 552 550 } else { 553 551 req->req.error = RAW1394_ERROR_INVALID_ARG; 554 552 } 555 - spin_unlock_irq(&host_info_lock); 553 + spin_unlock_irqrestore(&host_info_lock, flags); 556 554 557 555 req->req.length = 0; 558 556 break; ··· 571 569 { 572 570 int channel = req->req.misc; 573 571 574 - spin_lock_irq(&host_info_lock); 575 572 if ((channel > 63) || (channel < -64)) { 576 573 req->req.error = RAW1394_ERROR_INVALID_ARG; 577 574 } else if (channel >= 0) { ··· 602 601 603 602 req->req.length = 0; 604 603 queue_complete_req(req); 605 - spin_unlock_irq(&host_info_lock); 606 604 } 607 605 608 606 static void handle_fcp_listen(struct file_info *fi, struct pending_request *req) ··· 627 627 static int handle_async_request(struct file_info *fi, 628 628 struct pending_request *req, int node) 629 629 { 630 + unsigned long flags; 630 631 struct hpsb_packet *packet = NULL; 631 632 u64 addr = req->req.address & 0xffffffffffffULL; 632 633 ··· 762 761 hpsb_set_packet_complete_task(packet, 763 762 (void (*)(void *))queue_complete_cb, req); 764 763 765 - spin_lock_irq(&fi->reqlists_lock); 764 + spin_lock_irqsave(&fi->reqlists_lock, flags); 766 765 list_add_tail(&req->list, &fi->req_pending); 767 - spin_unlock_irq(&fi->reqlists_lock); 766 + spin_unlock_irqrestore(&fi->reqlists_lock, flags); 768 767 769 768 packet->generation = req->req.generation; 770 769 ··· 780 779 static int handle_iso_send(struct file_info *fi, struct pending_request *req, 781 780 int channel) 782 781 { 782 + unsigned long flags; 783 783 struct hpsb_packet *packet; 784 784 785 785 packet = hpsb_make_isopacket(fi->host, req->req.length, channel & 0x3f, ··· 806 804 (void (*)(void *))queue_complete_req, 807 805 req); 808 806 809 - spin_lock_irq(&fi->reqlists_lock); 807 + spin_lock_irqsave(&fi->reqlists_lock, flags); 810 808 list_add_tail(&req->list, &fi->req_pending); 811 - spin_unlock_irq(&fi->reqlists_lock); 809 + spin_unlock_irqrestore(&fi->reqlists_lock, flags); 812 810 813 811 /* Update the generation of the packet just before sending. */ 814 812 packet->generation = req->req.generation; ··· 823 821 824 822 static int handle_async_send(struct file_info *fi, struct pending_request *req) 825 823 { 824 + unsigned long flags; 826 825 struct hpsb_packet *packet; 827 826 int header_length = req->req.misc & 0xffff; 828 827 int expect_response = req->req.misc >> 16; ··· 870 867 hpsb_set_packet_complete_task(packet, 871 868 (void (*)(void *))queue_complete_cb, req); 872 869 873 - spin_lock_irq(&fi->reqlists_lock); 870 + spin_lock_irqsave(&fi->reqlists_lock, flags); 874 871 list_add_tail(&req->list, &fi->req_pending); 875 - spin_unlock_irq(&fi->reqlists_lock); 872 + spin_unlock_irqrestore(&fi->reqlists_lock, flags); 876 873 877 874 /* Update the generation of the packet just before sending. */ 878 875 packet->generation = req->req.generation; ··· 888 885 static int arm_read(struct hpsb_host *host, int nodeid, quadlet_t * buffer, 889 886 u64 addr, size_t length, u16 flags) 890 887 { 888 + unsigned long irqflags; 891 889 struct pending_request *req; 892 890 struct host_info *hi; 893 891 struct file_info *fi = NULL; ··· 903 899 "addr: %4.4x %8.8x length: %Zu", nodeid, 904 900 (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), 905 901 length); 906 - spin_lock(&host_info_lock); 902 + spin_lock_irqsave(&host_info_lock, irqflags); 907 903 hi = find_host_info(host); /* search address-entry */ 908 904 if (hi != NULL) { 909 905 list_for_each_entry(fi, &hi->file_info_list, list) { ··· 928 924 if (!found) { 929 925 printk(KERN_ERR "raw1394: arm_read FAILED addr_entry not found" 930 926 " -> rcode_address_error\n"); 931 - spin_unlock(&host_info_lock); 927 + spin_unlock_irqrestore(&host_info_lock, irqflags); 932 928 return (RCODE_ADDRESS_ERROR); 933 929 } else { 934 930 DBGMSG("arm_read addr_entry FOUND"); ··· 958 954 req = __alloc_pending_request(SLAB_ATOMIC); 959 955 if (!req) { 960 956 DBGMSG("arm_read -> rcode_conflict_error"); 961 - spin_unlock(&host_info_lock); 957 + spin_unlock_irqrestore(&host_info_lock, irqflags); 962 958 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 963 959 The request may be retried */ 964 960 } ··· 978 974 if (!(req->data)) { 979 975 free_pending_request(req); 980 976 DBGMSG("arm_read -> rcode_conflict_error"); 981 - spin_unlock(&host_info_lock); 977 + spin_unlock_irqrestore(&host_info_lock, irqflags); 982 978 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 983 979 The request may be retried */ 984 980 } ··· 1035 1031 sizeof(struct arm_request)); 1036 1032 queue_complete_req(req); 1037 1033 } 1038 - spin_unlock(&host_info_lock); 1034 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1039 1035 return (rcode); 1040 1036 } 1041 1037 1042 1038 static int arm_write(struct hpsb_host *host, int nodeid, int destid, 1043 1039 quadlet_t * data, u64 addr, size_t length, u16 flags) 1044 1040 { 1041 + unsigned long irqflags; 1045 1042 struct pending_request *req; 1046 1043 struct host_info *hi; 1047 1044 struct file_info *fi = NULL; ··· 1057 1052 "addr: %4.4x %8.8x length: %Zu", nodeid, 1058 1053 (u16) ((addr >> 32) & 0xFFFF), (u32) (addr & 0xFFFFFFFF), 1059 1054 length); 1060 - spin_lock(&host_info_lock); 1055 + spin_lock_irqsave(&host_info_lock, irqflags); 1061 1056 hi = find_host_info(host); /* search address-entry */ 1062 1057 if (hi != NULL) { 1063 1058 list_for_each_entry(fi, &hi->file_info_list, list) { ··· 1082 1077 if (!found) { 1083 1078 printk(KERN_ERR "raw1394: arm_write FAILED addr_entry not found" 1084 1079 " -> rcode_address_error\n"); 1085 - spin_unlock(&host_info_lock); 1080 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1086 1081 return (RCODE_ADDRESS_ERROR); 1087 1082 } else { 1088 1083 DBGMSG("arm_write addr_entry FOUND"); ··· 1111 1106 req = __alloc_pending_request(SLAB_ATOMIC); 1112 1107 if (!req) { 1113 1108 DBGMSG("arm_write -> rcode_conflict_error"); 1114 - spin_unlock(&host_info_lock); 1109 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1115 1110 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 1116 1111 The request my be retried */ 1117 1112 } ··· 1123 1118 if (!(req->data)) { 1124 1119 free_pending_request(req); 1125 1120 DBGMSG("arm_write -> rcode_conflict_error"); 1126 - spin_unlock(&host_info_lock); 1121 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1127 1122 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 1128 1123 The request may be retried */ 1129 1124 } ··· 1170 1165 sizeof(struct arm_request)); 1171 1166 queue_complete_req(req); 1172 1167 } 1173 - spin_unlock(&host_info_lock); 1168 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1174 1169 return (rcode); 1175 1170 } 1176 1171 ··· 1178 1173 u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, 1179 1174 u16 flags) 1180 1175 { 1176 + unsigned long irqflags; 1181 1177 struct pending_request *req; 1182 1178 struct host_info *hi; 1183 1179 struct file_info *fi = NULL; ··· 1204 1198 (u32) (addr & 0xFFFFFFFF), ext_tcode & 0xFF, 1205 1199 be32_to_cpu(data), be32_to_cpu(arg)); 1206 1200 } 1207 - spin_lock(&host_info_lock); 1201 + spin_lock_irqsave(&host_info_lock, irqflags); 1208 1202 hi = find_host_info(host); /* search address-entry */ 1209 1203 if (hi != NULL) { 1210 1204 list_for_each_entry(fi, &hi->file_info_list, list) { ··· 1230 1224 if (!found) { 1231 1225 printk(KERN_ERR "raw1394: arm_lock FAILED addr_entry not found" 1232 1226 " -> rcode_address_error\n"); 1233 - spin_unlock(&host_info_lock); 1227 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1234 1228 return (RCODE_ADDRESS_ERROR); 1235 1229 } else { 1236 1230 DBGMSG("arm_lock addr_entry FOUND"); ··· 1313 1307 req = __alloc_pending_request(SLAB_ATOMIC); 1314 1308 if (!req) { 1315 1309 DBGMSG("arm_lock -> rcode_conflict_error"); 1316 - spin_unlock(&host_info_lock); 1310 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1317 1311 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 1318 1312 The request may be retried */ 1319 1313 } ··· 1322 1316 if (!(req->data)) { 1323 1317 free_pending_request(req); 1324 1318 DBGMSG("arm_lock -> rcode_conflict_error"); 1325 - spin_unlock(&host_info_lock); 1319 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1326 1320 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 1327 1321 The request may be retried */ 1328 1322 } ··· 1388 1382 sizeof(struct arm_response) + 2 * sizeof(*store)); 1389 1383 queue_complete_req(req); 1390 1384 } 1391 - spin_unlock(&host_info_lock); 1385 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1392 1386 return (rcode); 1393 1387 } 1394 1388 ··· 1396 1390 u64 addr, octlet_t data, octlet_t arg, int ext_tcode, 1397 1391 u16 flags) 1398 1392 { 1393 + unsigned long irqflags; 1399 1394 struct pending_request *req; 1400 1395 struct host_info *hi; 1401 1396 struct file_info *fi = NULL; ··· 1429 1422 (u32) ((be64_to_cpu(arg) >> 32) & 0xFFFFFFFF), 1430 1423 (u32) (be64_to_cpu(arg) & 0xFFFFFFFF)); 1431 1424 } 1432 - spin_lock(&host_info_lock); 1425 + spin_lock_irqsave(&host_info_lock, irqflags); 1433 1426 hi = find_host_info(host); /* search addressentry in file_info's for host */ 1434 1427 if (hi != NULL) { 1435 1428 list_for_each_entry(fi, &hi->file_info_list, list) { ··· 1456 1449 printk(KERN_ERR 1457 1450 "raw1394: arm_lock64 FAILED addr_entry not found" 1458 1451 " -> rcode_address_error\n"); 1459 - spin_unlock(&host_info_lock); 1452 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1460 1453 return (RCODE_ADDRESS_ERROR); 1461 1454 } else { 1462 1455 DBGMSG("arm_lock64 addr_entry FOUND"); ··· 1540 1533 DBGMSG("arm_lock64 -> entering notification-section"); 1541 1534 req = __alloc_pending_request(SLAB_ATOMIC); 1542 1535 if (!req) { 1543 - spin_unlock(&host_info_lock); 1536 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1544 1537 DBGMSG("arm_lock64 -> rcode_conflict_error"); 1545 1538 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 1546 1539 The request may be retried */ ··· 1549 1542 req->data = kmalloc(size, SLAB_ATOMIC); 1550 1543 if (!(req->data)) { 1551 1544 free_pending_request(req); 1552 - spin_unlock(&host_info_lock); 1545 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1553 1546 DBGMSG("arm_lock64 -> rcode_conflict_error"); 1554 1547 return (RCODE_CONFLICT_ERROR); /* A resource conflict was detected. 1555 1548 The request may be retried */ ··· 1616 1609 sizeof(struct arm_response) + 2 * sizeof(*store)); 1617 1610 queue_complete_req(req); 1618 1611 } 1619 - spin_unlock(&host_info_lock); 1612 + spin_unlock_irqrestore(&host_info_lock, irqflags); 1620 1613 return (rcode); 1621 1614 } 1622 1615 ··· 1987 1980 struct hpsb_packet *packet = NULL; 1988 1981 int retval = 0; 1989 1982 quadlet_t data; 1983 + unsigned long flags; 1990 1984 1991 1985 data = be32_to_cpu((u32) req->req.sendb); 1992 1986 DBGMSG("write_phypacket called - quadlet 0x%8.8x ", data); ··· 1998 1990 req->packet = packet; 1999 1991 hpsb_set_packet_complete_task(packet, 2000 1992 (void (*)(void *))queue_complete_cb, req); 2001 - spin_lock_irq(&fi->reqlists_lock); 1993 + spin_lock_irqsave(&fi->reqlists_lock, flags); 2002 1994 list_add_tail(&req->list, &fi->req_pending); 2003 - spin_unlock_irq(&fi->reqlists_lock); 1995 + spin_unlock_irqrestore(&fi->reqlists_lock, flags); 2004 1996 packet->generation = req->req.generation; 2005 1997 retval = hpsb_send_packet(packet); 2006 1998 DBGMSG("write_phypacket send_packet called => retval: %d ", retval); ··· 2667 2659 { 2668 2660 struct file_info *fi = file->private_data; 2669 2661 unsigned int mask = POLLOUT | POLLWRNORM; 2662 + unsigned long flags; 2670 2663 2671 2664 poll_wait(file, &fi->poll_wait_complete, pt); 2672 2665 2673 - spin_lock_irq(&fi->reqlists_lock); 2666 + spin_lock_irqsave(&fi->reqlists_lock, flags); 2674 2667 if (!list_empty(&fi->req_complete)) { 2675 2668 mask |= POLLIN | POLLRDNORM; 2676 2669 } 2677 - spin_unlock_irq(&fi->reqlists_lock); 2670 + spin_unlock_irqrestore(&fi->reqlists_lock, flags); 2678 2671 2679 2672 return mask; 2680 2673 } ··· 2719 2710 struct arm_addr *arm_addr = NULL; 2720 2711 int another_host; 2721 2712 int csr_mod = 0; 2713 + unsigned long flags; 2722 2714 2723 2715 if (fi->iso_state != RAW1394_ISO_INACTIVE) 2724 2716 raw1394_iso_shutdown(fi); ··· 2730 2720 } 2731 2721 } 2732 2722 2733 - spin_lock_irq(&host_info_lock); 2723 + spin_lock_irqsave(&host_info_lock, flags); 2734 2724 fi->listen_channels = 0; 2735 - spin_unlock_irq(&host_info_lock); 2736 2725 2737 2726 fail = 0; 2738 2727 /* set address-entries invalid */ 2739 - spin_lock_irq(&host_info_lock); 2740 2728 2741 2729 while (!list_empty(&fi->addr_list)) { 2742 2730 another_host = 0; ··· 2785 2777 vfree(addr->addr_space_buffer); 2786 2778 kfree(addr); 2787 2779 } /* while */ 2788 - spin_unlock_irq(&host_info_lock); 2780 + spin_unlock_irqrestore(&host_info_lock, flags); 2789 2781 if (fail > 0) { 2790 2782 printk(KERN_ERR "raw1394: during addr_list-release " 2791 2783 "error(s) occurred \n"); 2792 2784 } 2793 2785 2794 2786 while (!done) { 2795 - spin_lock_irq(&fi->reqlists_lock); 2787 + spin_lock_irqsave(&fi->reqlists_lock, flags); 2796 2788 2797 2789 while (!list_empty(&fi->req_complete)) { 2798 2790 lh = fi->req_complete.next; ··· 2806 2798 if (list_empty(&fi->req_pending)) 2807 2799 done = 1; 2808 2800 2809 - spin_unlock_irq(&fi->reqlists_lock); 2801 + spin_unlock_irqrestore(&fi->reqlists_lock, flags); 2810 2802 2811 2803 if (!done) 2812 2804 down_interruptible(&fi->complete_sem); ··· 2836 2828 fi->host->id); 2837 2829 2838 2830 if (fi->state == connected) { 2839 - spin_lock_irq(&host_info_lock); 2831 + spin_lock_irqsave(&host_info_lock, flags); 2840 2832 list_del(&fi->list); 2841 - spin_unlock_irq(&host_info_lock); 2833 + spin_unlock_irqrestore(&host_info_lock, flags); 2842 2834 2843 2835 put_device(&fi->host->device); 2844 2836 }