diff options
author | Ivo van Doorn <ivdoorn@gmail.com> | 2008-03-09 17:44:30 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-03-13 16:02:35 -0400 |
commit | 5f46c4d0537a870f9d9c1fd998aa9d6dac682595 (patch) | |
tree | 8a745b5dd824a803a0dacc62b3433ab906a0eda9 /drivers/net | |
parent | 61191fb272dfa413763416ee828aae28bfd9746e (diff) |
rt2x00: Upgrade queue->lock to use irqsave
The queue->lock could be grabbed from interrupt context,
which could lead to lockdep panic like this:
kernel: ======================================================
kernel: [ INFO: soft-safe -> soft-unsafe lock order detected ]
kernel: 2.6.25-0.95.rc4.fc9 #1
kernel: ------------------------------------------------------
kernel: rt2500pci/1251 [HC0[0]:SC0[1]:HE1:SE0] is trying to acquire:
kernel: (&queue->lock){--..}, at: [<ffffffff88213339>] rt2x00queue_get_entry+0x5a/0x81 [rt2x00lib]
kernel:
kernel: and this task is already holding:
kernel: (_xmit_IEEE80211){-...}, at: [<ffffffff8122e9a3>] __qdisc_run+0x84/0x1a9
kernel: which would create a new lock dependency:
kernel: (_xmit_IEEE80211){-...} -> (&queue->lock){--..}
kernel:
kernel: but this new dependency connects a soft-irq-safe lock:
kernel: (_xmit_ETHER){-+..}
kernel: ... which became soft-irq-safe at:
kernel: [<ffffffffffffffff>] 0xffffffffffffffff
kernel:
kernel: to a soft-irq-unsafe lock:
kernel: (&queue->lock){--..}
kernel: ... which became soft-irq-unsafe at:
kernel: ... [<ffffffff810545a2>] __lock_acquire+0x62d/0xd63
kernel: [<ffffffff81054d36>] lock_acquire+0x5e/0x78
kernel: [<ffffffff812a1497>] _spin_lock+0x26/0x53
kernel: [<ffffffff88212f98>] rt2x00queue_reset+0x16/0x40 [rt2x00lib]
kernel: [<ffffffff88212fd4>] rt2x00queue_alloc_entries+0x12/0xab [rt2x00lib]
kernel: [<ffffffff88213091>] rt2x00queue_initialize+0x24/0xf2 [rt2x00lib]
kernel: [<ffffffff88212036>] rt2x00lib_start+0x3b/0xd4 [rt2x00lib]
kernel: [<ffffffff88212609>] rt2x00mac_start+0x18/0x1a [rt2x00lib]
kernel: [<ffffffff881b9a4b>] ieee80211_open+0x1f3/0x46d [mac80211]
kernel: [<ffffffff8121d980>] dev_open+0x4d/0x8b
kernel: [<ffffffff8121d41e>] dev_change_flags+0xaf/0x172
kernel: [<ffffffff81224fc2>] do_setlink+0x276/0x338
kernel: [<ffffffff81225198>] rtnl_setlink+0x114/0x116
kernel: [<ffffffff812262fc>] rtnetlink_rcv_msg+0x1d8/0x1f9
kernel: [<ffffffff8123649a>] netlink_rcv_skb+0x3e/0xac
kernel: [<ffffffff8122611a>] rtnetlink_rcv+0x29/0x33
kernel: [<ffffffff81235eed>] netlink_unicast+0x1fe/0x26b
kernel: [<ffffffff81236224>] netlink_sendmsg+0x2ca/0x2dd
kernel: [<ffffffff812103b3>] sock_sendmsg+0xfd/0x120
kernel: [<ffffffff812105a8>] sys_sendmsg+0x1d2/0x23c
kernel: [<ffffffff8100c1c7>] tracesys+0xdc/0xe1
kernel: [<ffffffffffffffff>] 0xffffffffffffffff
This can be fixed by using the irqsave/irqrestore versions
during the queue->lock handling.
Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00debug.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00queue.c | 17 |
2 files changed, 14 insertions, 8 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 21af11a97334..bfab3b8780d6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c | |||
@@ -278,6 +278,7 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, | |||
278 | { | 278 | { |
279 | struct rt2x00debug_intf *intf = file->private_data; | 279 | struct rt2x00debug_intf *intf = file->private_data; |
280 | struct data_queue *queue; | 280 | struct data_queue *queue; |
281 | unsigned long irqflags; | ||
281 | unsigned int lines = 1 + intf->rt2x00dev->data_queues; | 282 | unsigned int lines = 1 + intf->rt2x00dev->data_queues; |
282 | size_t size; | 283 | size_t size; |
283 | char *data; | 284 | char *data; |
@@ -294,7 +295,7 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, | |||
294 | sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n"); | 295 | sprintf(data, "qid\tcount\tlimit\tlength\tindex\tdone\tcrypto\n"); |
295 | 296 | ||
296 | queue_for_each(intf->rt2x00dev, queue) { | 297 | queue_for_each(intf->rt2x00dev, queue) { |
297 | spin_lock(&queue->lock); | 298 | spin_lock_irqsave(&queue->lock, irqflags); |
298 | 299 | ||
299 | temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, | 300 | temp += sprintf(temp, "%d\t%d\t%d\t%d\t%d\t%d\t%d\n", queue->qid, |
300 | queue->count, queue->limit, queue->length, | 301 | queue->count, queue->limit, queue->length, |
@@ -302,7 +303,7 @@ static ssize_t rt2x00debug_read_queue_stats(struct file *file, | |||
302 | queue->index[Q_INDEX_DONE], | 303 | queue->index[Q_INDEX_DONE], |
303 | queue->index[Q_INDEX_CRYPTO]); | 304 | queue->index[Q_INDEX_CRYPTO]); |
304 | 305 | ||
305 | spin_unlock(&queue->lock); | 306 | spin_unlock_irqrestore(&queue->lock, irqflags); |
306 | } | 307 | } |
307 | 308 | ||
308 | size = strlen(data); | 309 | size = strlen(data); |
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 9188323f067b..659e9f44c40c 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c | |||
@@ -53,6 +53,7 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, | |||
53 | enum queue_index index) | 53 | enum queue_index index) |
54 | { | 54 | { |
55 | struct queue_entry *entry; | 55 | struct queue_entry *entry; |
56 | unsigned long irqflags; | ||
56 | 57 | ||
57 | if (unlikely(index >= Q_INDEX_MAX)) { | 58 | if (unlikely(index >= Q_INDEX_MAX)) { |
58 | ERROR(queue->rt2x00dev, | 59 | ERROR(queue->rt2x00dev, |
@@ -60,11 +61,11 @@ struct queue_entry *rt2x00queue_get_entry(struct data_queue *queue, | |||
60 | return NULL; | 61 | return NULL; |
61 | } | 62 | } |
62 | 63 | ||
63 | spin_lock(&queue->lock); | 64 | spin_lock_irqsave(&queue->lock, irqflags); |
64 | 65 | ||
65 | entry = &queue->entries[queue->index[index]]; | 66 | entry = &queue->entries[queue->index[index]]; |
66 | 67 | ||
67 | spin_unlock(&queue->lock); | 68 | spin_unlock_irqrestore(&queue->lock, irqflags); |
68 | 69 | ||
69 | return entry; | 70 | return entry; |
70 | } | 71 | } |
@@ -72,13 +73,15 @@ EXPORT_SYMBOL_GPL(rt2x00queue_get_entry); | |||
72 | 73 | ||
73 | void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) | 74 | void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) |
74 | { | 75 | { |
76 | unsigned long irqflags; | ||
77 | |||
75 | if (unlikely(index >= Q_INDEX_MAX)) { | 78 | if (unlikely(index >= Q_INDEX_MAX)) { |
76 | ERROR(queue->rt2x00dev, | 79 | ERROR(queue->rt2x00dev, |
77 | "Index change on invalid index type (%d)\n", index); | 80 | "Index change on invalid index type (%d)\n", index); |
78 | return; | 81 | return; |
79 | } | 82 | } |
80 | 83 | ||
81 | spin_lock(&queue->lock); | 84 | spin_lock_irqsave(&queue->lock, irqflags); |
82 | 85 | ||
83 | queue->index[index]++; | 86 | queue->index[index]++; |
84 | if (queue->index[index] >= queue->limit) | 87 | if (queue->index[index] >= queue->limit) |
@@ -91,19 +94,21 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) | |||
91 | queue->count ++; | 94 | queue->count ++; |
92 | } | 95 | } |
93 | 96 | ||
94 | spin_unlock(&queue->lock); | 97 | spin_unlock_irqrestore(&queue->lock, irqflags); |
95 | } | 98 | } |
96 | EXPORT_SYMBOL_GPL(rt2x00queue_index_inc); | 99 | EXPORT_SYMBOL_GPL(rt2x00queue_index_inc); |
97 | 100 | ||
98 | static void rt2x00queue_reset(struct data_queue *queue) | 101 | static void rt2x00queue_reset(struct data_queue *queue) |
99 | { | 102 | { |
100 | spin_lock(&queue->lock); | 103 | unsigned long irqflags; |
104 | |||
105 | spin_lock_irqsave(&queue->lock, irqflags); | ||
101 | 106 | ||
102 | queue->count = 0; | 107 | queue->count = 0; |
103 | queue->length = 0; | 108 | queue->length = 0; |
104 | memset(queue->index, 0, sizeof(queue->index)); | 109 | memset(queue->index, 0, sizeof(queue->index)); |
105 | 110 | ||
106 | spin_unlock(&queue->lock); | 111 | spin_unlock_irqrestore(&queue->lock, irqflags); |
107 | } | 112 | } |
108 | 113 | ||
109 | void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) | 114 | void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) |