aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-cdev.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 11:13:10 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-08 11:13:10 -0500
commitbb592cf474404e51cbf3c419fb72fda83c4b7d72 (patch)
tree05823f536d5f095857a7aff732e205d249e4b7a1 /drivers/firewire/core-cdev.c
parent79c9601c2e0dbbe69895d302de4d19f3a31fbd30 (diff)
parentaf0940dac37545b1e7900b19c464fb6367d3f82f (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6: ieee1394: Use hweight32 firewire: cdev: reduce stack usage by ioctl_dispatch firewire: ohci: 0 may be a valid DMA address firewire: core: WARN on wrong usage of core transaction functions firewire: core: optimize Topology Map creation firewire: core: clarify generate_config_rom usage firewire: optimize config ROM creation firewire: cdev: normalize variable names firewire: normalize style of queue_work wrappers firewire: cdev: fix memory leak in an error path
Diffstat (limited to 'drivers/firewire/core-cdev.c')
-rw-r--r--drivers/firewire/core-cdev.c113
1 files changed, 67 insertions, 46 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 5089331544ed..231e6ee5ba43 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -130,9 +130,22 @@ struct iso_resource {
130 struct iso_resource_event *e_alloc, *e_dealloc; 130 struct iso_resource_event *e_alloc, *e_dealloc;
131}; 131};
132 132
133static void schedule_iso_resource(struct iso_resource *);
134static void release_iso_resource(struct client *, struct client_resource *); 133static void release_iso_resource(struct client *, struct client_resource *);
135 134
135static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
136{
137 client_get(r->client);
138 if (!schedule_delayed_work(&r->work, delay))
139 client_put(r->client);
140}
141
142static void schedule_if_iso_resource(struct client_resource *resource)
143{
144 if (resource->release == release_iso_resource)
145 schedule_iso_resource(container_of(resource,
146 struct iso_resource, resource), 0);
147}
148
136/* 149/*
137 * dequeue_event() just kfree()'s the event, so the event has to be 150 * dequeue_event() just kfree()'s the event, so the event has to be
138 * the first field in a struct XYZ_event. 151 * the first field in a struct XYZ_event.
@@ -166,7 +179,7 @@ struct iso_interrupt_event {
166 179
167struct iso_resource_event { 180struct iso_resource_event {
168 struct event event; 181 struct event event;
169 struct fw_cdev_event_iso_resource resource; 182 struct fw_cdev_event_iso_resource iso_resource;
170}; 183};
171 184
172static inline void __user *u64_to_uptr(__u64 value) 185static inline void __user *u64_to_uptr(__u64 value)
@@ -314,11 +327,8 @@ static void for_each_client(struct fw_device *device,
314 327
315static int schedule_reallocations(int id, void *p, void *data) 328static int schedule_reallocations(int id, void *p, void *data)
316{ 329{
317 struct client_resource *r = p; 330 schedule_if_iso_resource(p);
318 331
319 if (r->release == release_iso_resource)
320 schedule_iso_resource(container_of(r,
321 struct iso_resource, resource));
322 return 0; 332 return 0;
323} 333}
324 334
@@ -414,9 +424,7 @@ static int add_client_resource(struct client *client,
414 &resource->handle); 424 &resource->handle);
415 if (ret >= 0) { 425 if (ret >= 0) {
416 client_get(client); 426 client_get(client);
417 if (resource->release == release_iso_resource) 427 schedule_if_iso_resource(resource);
418 schedule_iso_resource(container_of(resource,
419 struct iso_resource, resource));
420 } 428 }
421 spin_unlock_irqrestore(&client->lock, flags); 429 spin_unlock_irqrestore(&client->lock, flags);
422 430
@@ -428,26 +436,26 @@ static int add_client_resource(struct client *client,
428 436
429static int release_client_resource(struct client *client, u32 handle, 437static int release_client_resource(struct client *client, u32 handle,
430 client_resource_release_fn_t release, 438 client_resource_release_fn_t release,
431 struct client_resource **resource) 439 struct client_resource **return_resource)
432{ 440{
433 struct client_resource *r; 441 struct client_resource *resource;
434 442
435 spin_lock_irq(&client->lock); 443 spin_lock_irq(&client->lock);
436 if (client->in_shutdown) 444 if (client->in_shutdown)
437 r = NULL; 445 resource = NULL;
438 else 446 else
439 r = idr_find(&client->resource_idr, handle); 447 resource = idr_find(&client->resource_idr, handle);
440 if (r && r->release == release) 448 if (resource && resource->release == release)
441 idr_remove(&client->resource_idr, handle); 449 idr_remove(&client->resource_idr, handle);
442 spin_unlock_irq(&client->lock); 450 spin_unlock_irq(&client->lock);
443 451
444 if (!(r && r->release == release)) 452 if (!(resource && resource->release == release))
445 return -EINVAL; 453 return -EINVAL;
446 454
447 if (resource) 455 if (return_resource)
448 *resource = r; 456 *return_resource = resource;
449 else 457 else
450 r->release(client, r); 458 resource->release(client, resource);
451 459
452 client_put(client); 460 client_put(client);
453 461
@@ -699,6 +707,7 @@ static int ioctl_send_response(struct client *client, void *buffer)
699 struct fw_cdev_send_response *request = buffer; 707 struct fw_cdev_send_response *request = buffer;
700 struct client_resource *resource; 708 struct client_resource *resource;
701 struct inbound_transaction_resource *r; 709 struct inbound_transaction_resource *r;
710 int ret = 0;
702 711
703 if (release_client_resource(client, request->handle, 712 if (release_client_resource(client, request->handle,
704 release_request, &resource) < 0) 713 release_request, &resource) < 0)
@@ -708,13 +717,17 @@ static int ioctl_send_response(struct client *client, void *buffer)
708 resource); 717 resource);
709 if (request->length < r->length) 718 if (request->length < r->length)
710 r->length = request->length; 719 r->length = request->length;
711 if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) 720
712 return -EFAULT; 721 if (copy_from_user(r->data, u64_to_uptr(request->data), r->length)) {
722 ret = -EFAULT;
723 goto out;
724 }
713 725
714 fw_send_response(client->device->card, r->request, request->rcode); 726 fw_send_response(client->device->card, r->request, request->rcode);
727 out:
715 kfree(r); 728 kfree(r);
716 729
717 return 0; 730 return ret;
718} 731}
719 732
720static int ioctl_initiate_bus_reset(struct client *client, void *buffer) 733static int ioctl_initiate_bus_reset(struct client *client, void *buffer)
@@ -1028,8 +1041,7 @@ static void iso_resource_work(struct work_struct *work)
1028 /* Allow 1000ms grace period for other reallocations. */ 1041 /* Allow 1000ms grace period for other reallocations. */
1029 if (todo == ISO_RES_ALLOC && 1042 if (todo == ISO_RES_ALLOC &&
1030 time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) { 1043 time_is_after_jiffies(client->device->card->reset_jiffies + HZ)) {
1031 if (schedule_delayed_work(&r->work, DIV_ROUND_UP(HZ, 3))) 1044 schedule_iso_resource(r, DIV_ROUND_UP(HZ, 3));
1032 client_get(client);
1033 skip = true; 1045 skip = true;
1034 } else { 1046 } else {
1035 /* We could be called twice within the same generation. */ 1047 /* We could be called twice within the same generation. */
@@ -1097,12 +1109,12 @@ static void iso_resource_work(struct work_struct *work)
1097 e = r->e_dealloc; 1109 e = r->e_dealloc;
1098 r->e_dealloc = NULL; 1110 r->e_dealloc = NULL;
1099 } 1111 }
1100 e->resource.handle = r->resource.handle; 1112 e->iso_resource.handle = r->resource.handle;
1101 e->resource.channel = channel; 1113 e->iso_resource.channel = channel;
1102 e->resource.bandwidth = bandwidth; 1114 e->iso_resource.bandwidth = bandwidth;
1103 1115
1104 queue_event(client, &e->event, 1116 queue_event(client, &e->event,
1105 &e->resource, sizeof(e->resource), NULL, 0); 1117 &e->iso_resource, sizeof(e->iso_resource), NULL, 0);
1106 1118
1107 if (free) { 1119 if (free) {
1108 cancel_delayed_work(&r->work); 1120 cancel_delayed_work(&r->work);
@@ -1114,13 +1126,6 @@ static void iso_resource_work(struct work_struct *work)
1114 client_put(client); 1126 client_put(client);
1115} 1127}
1116 1128
1117static void schedule_iso_resource(struct iso_resource *r)
1118{
1119 client_get(r->client);
1120 if (!schedule_delayed_work(&r->work, 0))
1121 client_put(r->client);
1122}
1123
1124static void release_iso_resource(struct client *client, 1129static void release_iso_resource(struct client *client,
1125 struct client_resource *resource) 1130 struct client_resource *resource)
1126{ 1131{
@@ -1129,7 +1134,7 @@ static void release_iso_resource(struct client *client,
1129 1134
1130 spin_lock_irq(&client->lock); 1135 spin_lock_irq(&client->lock);
1131 r->todo = ISO_RES_DEALLOC; 1136 r->todo = ISO_RES_DEALLOC;
1132 schedule_iso_resource(r); 1137 schedule_iso_resource(r, 0);
1133 spin_unlock_irq(&client->lock); 1138 spin_unlock_irq(&client->lock);
1134} 1139}
1135 1140
@@ -1162,10 +1167,10 @@ static int init_iso_resource(struct client *client,
1162 r->e_alloc = e1; 1167 r->e_alloc = e1;
1163 r->e_dealloc = e2; 1168 r->e_dealloc = e2;
1164 1169
1165 e1->resource.closure = request->closure; 1170 e1->iso_resource.closure = request->closure;
1166 e1->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED; 1171 e1->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
1167 e2->resource.closure = request->closure; 1172 e2->iso_resource.closure = request->closure;
1168 e2->resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED; 1173 e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
1169 1174
1170 if (todo == ISO_RES_ALLOC) { 1175 if (todo == ISO_RES_ALLOC) {
1171 r->resource.release = release_iso_resource; 1176 r->resource.release = release_iso_resource;
@@ -1175,7 +1180,7 @@ static int init_iso_resource(struct client *client,
1175 } else { 1180 } else {
1176 r->resource.release = NULL; 1181 r->resource.release = NULL;
1177 r->resource.handle = -1; 1182 r->resource.handle = -1;
1178 schedule_iso_resource(r); 1183 schedule_iso_resource(r, 0);
1179 } 1184 }
1180 request->handle = r->resource.handle; 1185 request->handle = r->resource.handle;
1181 1186
@@ -1295,7 +1300,23 @@ static int (* const ioctl_handlers[])(struct client *client, void *buffer) = {
1295static int dispatch_ioctl(struct client *client, 1300static int dispatch_ioctl(struct client *client,
1296 unsigned int cmd, void __user *arg) 1301 unsigned int cmd, void __user *arg)
1297{ 1302{
1298 char buffer[256]; 1303 char buffer[sizeof(union {
1304 struct fw_cdev_get_info _00;
1305 struct fw_cdev_send_request _01;
1306 struct fw_cdev_allocate _02;
1307 struct fw_cdev_deallocate _03;
1308 struct fw_cdev_send_response _04;
1309 struct fw_cdev_initiate_bus_reset _05;
1310 struct fw_cdev_add_descriptor _06;
1311 struct fw_cdev_remove_descriptor _07;
1312 struct fw_cdev_create_iso_context _08;
1313 struct fw_cdev_queue_iso _09;
1314 struct fw_cdev_start_iso _0a;
1315 struct fw_cdev_stop_iso _0b;
1316 struct fw_cdev_get_cycle_timer _0c;
1317 struct fw_cdev_allocate_iso_resource _0d;
1318 struct fw_cdev_send_stream_packet _13;
1319 })];
1299 int ret; 1320 int ret;
1300 1321
1301 if (_IOC_TYPE(cmd) != '#' || 1322 if (_IOC_TYPE(cmd) != '#' ||
@@ -1390,10 +1411,10 @@ static int fw_device_op_mmap(struct file *file, struct vm_area_struct *vma)
1390 1411
1391static int shutdown_resource(int id, void *p, void *data) 1412static int shutdown_resource(int id, void *p, void *data)
1392{ 1413{
1393 struct client_resource *r = p; 1414 struct client_resource *resource = p;
1394 struct client *client = data; 1415 struct client *client = data;
1395 1416
1396 r->release(client, r); 1417 resource->release(client, resource);
1397 client_put(client); 1418 client_put(client);
1398 1419
1399 return 0; 1420 return 0;
@@ -1402,7 +1423,7 @@ static int shutdown_resource(int id, void *p, void *data)
1402static int fw_device_op_release(struct inode *inode, struct file *file) 1423static int fw_device_op_release(struct inode *inode, struct file *file)
1403{ 1424{
1404 struct client *client = file->private_data; 1425 struct client *client = file->private_data;
1405 struct event *e, *next_e; 1426 struct event *event, *next_event;
1406 1427
1407 mutex_lock(&client->device->client_list_mutex); 1428 mutex_lock(&client->device->client_list_mutex);
1408 list_del(&client->link); 1429 list_del(&client->link);
@@ -1423,8 +1444,8 @@ static int fw_device_op_release(struct inode *inode, struct file *file)
1423 idr_remove_all(&client->resource_idr); 1444 idr_remove_all(&client->resource_idr);
1424 idr_destroy(&client->resource_idr); 1445 idr_destroy(&client->resource_idr);
1425 1446
1426 list_for_each_entry_safe(e, next_e, &client->event_list, link) 1447 list_for_each_entry_safe(event, next_event, &client->event_list, link)
1427 kfree(e); 1448 kfree(event);
1428 1449
1429 client_put(client); 1450 client_put(client);
1430 1451