aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-03-07 12:12:50 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:03:12 -0500
commit28cf6a04c82857d562968dc3a8a89726e6ac3dcb (patch)
treee4513c7e09c7f0bdb77a5358268c17a570e20fab /drivers
parentf319b6a02f12c3712eb64eee6a23584367cb3588 (diff)
firewire: Track pending transactions and cancel them on cdev release.
Without this, pending transactions will dereference freed memory if they complete after the device file has been closed. Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/firewire/fw-device-cdev.c23
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/firewire/fw-device-cdev.c b/drivers/firewire/fw-device-cdev.c
index 2d84284f7605..2946464fec62 100644
--- a/drivers/firewire/fw-device-cdev.c
+++ b/drivers/firewire/fw-device-cdev.c
@@ -60,6 +60,7 @@ struct response {
60 struct event event; 60 struct event event;
61 struct fw_transaction transaction; 61 struct fw_transaction transaction;
62 struct client *client; 62 struct client *client;
63 struct list_head link;
63 struct fw_cdev_event_response response; 64 struct fw_cdev_event_response response;
64}; 65};
65 66
@@ -74,6 +75,7 @@ struct client {
74 spinlock_t lock; 75 spinlock_t lock;
75 struct list_head handler_list; 76 struct list_head handler_list;
76 struct list_head request_list; 77 struct list_head request_list;
78 struct list_head transaction_list;
77 u32 request_serial; 79 u32 request_serial;
78 struct list_head event_list; 80 struct list_head event_list;
79 wait_queue_head_t wait; 81 wait_queue_head_t wait;
@@ -115,6 +117,7 @@ static int fw_device_op_open(struct inode *inode, struct file *file)
115 INIT_LIST_HEAD(&client->event_list); 117 INIT_LIST_HEAD(&client->event_list);
116 INIT_LIST_HEAD(&client->handler_list); 118 INIT_LIST_HEAD(&client->handler_list);
117 INIT_LIST_HEAD(&client->request_list); 119 INIT_LIST_HEAD(&client->request_list);
120 INIT_LIST_HEAD(&client->transaction_list);
118 spin_lock_init(&client->lock); 121 spin_lock_init(&client->lock);
119 init_waitqueue_head(&client->wait); 122 init_waitqueue_head(&client->wait);
120 123
@@ -299,6 +302,7 @@ complete_transaction(struct fw_card *card, int rcode,
299{ 302{
300 struct response *response = data; 303 struct response *response = data;
301 struct client *client = response->client; 304 struct client *client = response->client;
305 unsigned long flags;
302 306
303 if (length < response->response.length) 307 if (length < response->response.length)
304 response->response.length = length; 308 response->response.length = length;
@@ -306,6 +310,10 @@ complete_transaction(struct fw_card *card, int rcode,
306 memcpy(response->response.data, payload, 310 memcpy(response->response.data, payload,
307 response->response.length); 311 response->response.length);
308 312
313 spin_lock_irqsave(&client->lock, flags);
314 list_del(&response->link);
315 spin_unlock_irqrestore(&client->lock, flags);
316
309 response->response.type = FW_CDEV_EVENT_RESPONSE; 317 response->response.type = FW_CDEV_EVENT_RESPONSE;
310 response->response.rcode = rcode; 318 response->response.rcode = rcode;
311 queue_event(client, &response->event, 319 queue_event(client, &response->event,
@@ -318,6 +326,7 @@ static ssize_t ioctl_send_request(struct client *client, void __user *arg)
318 struct fw_device *device = client->device; 326 struct fw_device *device = client->device;
319 struct fw_cdev_send_request request; 327 struct fw_cdev_send_request request;
320 struct response *response; 328 struct response *response;
329 unsigned long flags;
321 330
322 if (copy_from_user(&request, arg, sizeof request)) 331 if (copy_from_user(&request, arg, sizeof request))
323 return -EFAULT; 332 return -EFAULT;
@@ -341,6 +350,10 @@ static ssize_t ioctl_send_request(struct client *client, void __user *arg)
341 return -EFAULT; 350 return -EFAULT;
342 } 351 }
343 352
353 spin_lock_irqsave(&client->lock, flags);
354 list_add_tail(&response->link, &client->transaction_list);
355 spin_unlock_irqrestore(&client->lock, flags);
356
344 fw_send_request(device->card, &response->transaction, 357 fw_send_request(device->card, &response->transaction,
345 request.tcode & 0x1f, 358 request.tcode & 0x1f,
346 device->node->node_id, 359 device->node->node_id,
@@ -752,6 +765,7 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
752 struct address_handler *h, *next_h; 765 struct address_handler *h, *next_h;
753 struct request *r, *next_r; 766 struct request *r, *next_r;
754 struct event *e, *next_e; 767 struct event *e, *next_e;
768 struct response *t, *next_t;
755 unsigned long flags; 769 unsigned long flags;
756 770
757 if (client->buffer.pages) 771 if (client->buffer.pages)
@@ -771,9 +785,12 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
771 kfree(r); 785 kfree(r);
772 } 786 }
773 787
774 /* TODO: wait for all transactions to finish so 788 list_for_each_entry_safe(t, next_t, &client->transaction_list, link)
775 * complete_transaction doesn't try to queue up responses 789 fw_cancel_transaction(client->device->card, &t->transaction);
776 * after we free client. */ 790
791 /* FIXME: We should wait for the async tasklets to stop
792 * running before freeing the memory. */
793
777 list_for_each_entry_safe(e, next_e, &client->event_list, link) 794 list_for_each_entry_safe(e, next_e, &client->event_list, link)
778 kfree(e); 795 kfree(e);
779 796