aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorJay Fenlason <fenlason@redhat.com>2008-10-03 11:19:09 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2009-03-24 15:56:36 -0400
commitcf417e5494582453c033d8cac9e1352e74215435 (patch)
treea1681ef863c8c4219506e16b7982e51dc0718387 /drivers/firewire
parent1aa292bb1c53500e3ab570b955d03afa97a9404d (diff)
firewire: add a client_list_lock
This adds a client_list_lock, which only protects the device's client_list, so that future versions of the driver can call code that takes the card->lock while holding the client_list_lock. Adding this lock is much simpler than adding __ versions of all the functions that the future version may need. The one ordering issue is to make sure code never takes the client_list_lock with card->lock held. Since client_list_lock is only used in three places, that isn't hard. Signed-off-by: Jay Fenlason <fenlason@redhat.com> Update fill_bus_reset_event() accordingly. Include linux/spinlock.h. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/fw-cdev.c28
-rw-r--r--drivers/firewire/fw-device.c2
-rw-r--r--drivers/firewire/fw-device.h3
3 files changed, 18 insertions, 15 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c
index ed03234cbea8..40cc9732dc28 100644
--- a/drivers/firewire/fw-cdev.c
+++ b/drivers/firewire/fw-cdev.c
@@ -27,6 +27,7 @@
27#include <linux/poll.h> 27#include <linux/poll.h>
28#include <linux/preempt.h> 28#include <linux/preempt.h>
29#include <linux/time.h> 29#include <linux/time.h>
30#include <linux/spinlock.h>
30#include <linux/delay.h> 31#include <linux/delay.h>
31#include <linux/mm.h> 32#include <linux/mm.h>
32#include <linux/idr.h> 33#include <linux/idr.h>
@@ -132,9 +133,9 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
132 133
133 file->private_data = client; 134 file->private_data = client;
134 135
135 spin_lock_irqsave(&device->card->lock, flags); 136 spin_lock_irqsave(&device->client_list_lock, flags);
136 list_add_tail(&client->link, &device->client_list); 137 list_add_tail(&client->link, &device->client_list);
137 spin_unlock_irqrestore(&device->card->lock, flags); 138 spin_unlock_irqrestore(&device->client_list_lock, flags);
138 139
139 return 0; 140 return 0;
140} 141}
@@ -205,12 +206,14 @@ fw_device_op_read(struct file *file,
205 return dequeue_event(client, buffer, count); 206 return dequeue_event(client, buffer, count);
206} 207}
207 208
208/* caller must hold card->lock so that node pointers can be dereferenced here */
209static void 209static void
210fill_bus_reset_event(struct fw_cdev_event_bus_reset *event, 210fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
211 struct client *client) 211 struct client *client)
212{ 212{
213 struct fw_card *card = client->device->card; 213 struct fw_card *card = client->device->card;
214 unsigned long flags;
215
216 spin_lock_irqsave(&card->lock, flags);
214 217
215 event->closure = client->bus_reset_closure; 218 event->closure = client->bus_reset_closure;
216 event->type = FW_CDEV_EVENT_BUS_RESET; 219 event->type = FW_CDEV_EVENT_BUS_RESET;
@@ -220,22 +223,23 @@ fill_bus_reset_event(struct fw_cdev_event_bus_reset *event,
220 event->bm_node_id = 0; /* FIXME: We don't track the BM. */ 223 event->bm_node_id = 0; /* FIXME: We don't track the BM. */
221 event->irm_node_id = card->irm_node->node_id; 224 event->irm_node_id = card->irm_node->node_id;
222 event->root_node_id = card->root_node->node_id; 225 event->root_node_id = card->root_node->node_id;
226
227 spin_unlock_irqrestore(&card->lock, flags);
223} 228}
224 229
225static void 230static void
226for_each_client(struct fw_device *device, 231for_each_client(struct fw_device *device,
227 void (*callback)(struct client *client)) 232 void (*callback)(struct client *client))
228{ 233{
229 struct fw_card *card = device->card;
230 struct client *c; 234 struct client *c;
231 unsigned long flags; 235 unsigned long flags;
232 236
233 spin_lock_irqsave(&card->lock, flags); 237 spin_lock_irqsave(&device->client_list_lock, flags);
234 238
235 list_for_each_entry(c, &device->client_list, link) 239 list_for_each_entry(c, &device->client_list, link)
236 callback(c); 240 callback(c);
237 241
238 spin_unlock_irqrestore(&card->lock, flags); 242 spin_unlock_irqrestore(&device->client_list_lock, flags);
239} 243}
240 244
241static void 245static void
@@ -274,11 +278,11 @@ static int ioctl_get_info(struct client *client, void *buffer)
274{ 278{
275 struct fw_cdev_get_info *get_info = buffer; 279 struct fw_cdev_get_info *get_info = buffer;
276 struct fw_cdev_event_bus_reset bus_reset; 280 struct fw_cdev_event_bus_reset bus_reset;
277 struct fw_card *card = client->device->card;
278 unsigned long ret = 0; 281 unsigned long ret = 0;
279 282
280 client->version = get_info->version; 283 client->version = get_info->version;
281 get_info->version = FW_CDEV_VERSION; 284 get_info->version = FW_CDEV_VERSION;
285 get_info->card = client->device->card->index;
282 286
283 down_read(&fw_device_rwsem); 287 down_read(&fw_device_rwsem);
284 288
@@ -300,18 +304,12 @@ static int ioctl_get_info(struct client *client, void *buffer)
300 client->bus_reset_closure = get_info->bus_reset_closure; 304 client->bus_reset_closure = get_info->bus_reset_closure;
301 if (get_info->bus_reset != 0) { 305 if (get_info->bus_reset != 0) {
302 void __user *uptr = u64_to_uptr(get_info->bus_reset); 306 void __user *uptr = u64_to_uptr(get_info->bus_reset);
303 unsigned long flags;
304 307
305 spin_lock_irqsave(&card->lock, flags);
306 fill_bus_reset_event(&bus_reset, client); 308 fill_bus_reset_event(&bus_reset, client);
307 spin_unlock_irqrestore(&card->lock, flags);
308
309 if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset))) 309 if (copy_to_user(uptr, &bus_reset, sizeof(bus_reset)))
310 return -EFAULT; 310 return -EFAULT;
311 } 311 }
312 312
313 get_info->card = card->index;
314
315 return 0; 313 return 0;
316} 314}
317 315
@@ -1009,9 +1007,9 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
1009 list_for_each_entry_safe(e, next_e, &client->event_list, link) 1007 list_for_each_entry_safe(e, next_e, &client->event_list, link)
1010 kfree(e); 1008 kfree(e);
1011 1009
1012 spin_lock_irqsave(&client->device->card->lock, flags); 1010 spin_lock_irqsave(&client->device->client_list_lock, flags);
1013 list_del(&client->link); 1011 list_del(&client->link);
1014 spin_unlock_irqrestore(&client->device->card->lock, flags); 1012 spin_unlock_irqrestore(&client->device->client_list_lock, flags);
1015 1013
1016 fw_device_put(client->device); 1014 fw_device_put(client->device);
1017 kfree(client); 1015 kfree(client);
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index bf53acb45652..ffde1bed46b2 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -29,6 +29,7 @@
29#include <linux/string.h> 29#include <linux/string.h>
30#include <linux/rwsem.h> 30#include <linux/rwsem.h>
31#include <linux/semaphore.h> 31#include <linux/semaphore.h>
32#include <linux/spinlock.h>
32#include <asm/system.h> 33#include <asm/system.h>
33#include <linux/ctype.h> 34#include <linux/ctype.h>
34#include "fw-transaction.h" 35#include "fw-transaction.h"
@@ -1004,6 +1005,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
1004 device->node = fw_node_get(node); 1005 device->node = fw_node_get(node);
1005 device->node_id = node->node_id; 1006 device->node_id = node->node_id;
1006 device->generation = card->generation; 1007 device->generation = card->generation;
1008 spin_lock_init(&device->client_list_lock);
1007 INIT_LIST_HEAD(&device->client_list); 1009 INIT_LIST_HEAD(&device->client_list);
1008 1010
1009 /* 1011 /*
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h
index 8ef6ec2ca21c..008a7908a865 100644
--- a/drivers/firewire/fw-device.h
+++ b/drivers/firewire/fw-device.h
@@ -23,6 +23,7 @@
23#include <linux/cdev.h> 23#include <linux/cdev.h>
24#include <linux/idr.h> 24#include <linux/idr.h>
25#include <linux/rwsem.h> 25#include <linux/rwsem.h>
26#include <linux/spinlock.h>
26#include <asm/atomic.h> 27#include <asm/atomic.h>
27 28
28enum fw_device_state { 29enum fw_device_state {
@@ -64,6 +65,8 @@ struct fw_device {
64 bool cmc; 65 bool cmc;
65 struct fw_card *card; 66 struct fw_card *card;
66 struct device device; 67 struct device device;
68 /* to prevent deadlocks, never take this lock with card->lock held */
69 spinlock_t client_list_lock;
67 struct list_head client_list; 70 struct list_head client_list;
68 u32 *config_rom; 71 u32 *config_rom;
69 size_t config_rom_length; 72 size_t config_rom_length;