aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorIvo van Doorn <ivdoorn@gmail.com>2008-03-09 17:44:30 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-03-13 16:02:35 -0400
commit5f46c4d0537a870f9d9c1fd998aa9d6dac682595 (patch)
tree8a745b5dd824a803a0dacc62b3433ab906a0eda9 /drivers/net
parent61191fb272dfa413763416ee828aae28bfd9746e (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.c5
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c17
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
73void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) 74void 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}
96EXPORT_SYMBOL_GPL(rt2x00queue_index_inc); 99EXPORT_SYMBOL_GPL(rt2x00queue_index_inc);
97 100
98static void rt2x00queue_reset(struct data_queue *queue) 101static 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
109void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev) 114void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev)