diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 11:13:10 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-08 11:13:10 -0500 |
| commit | bb592cf474404e51cbf3c419fb72fda83c4b7d72 (patch) | |
| tree | 05823f536d5f095857a7aff732e205d249e4b7a1 /drivers/firewire/core-cdev.c | |
| parent | 79c9601c2e0dbbe69895d302de4d19f3a31fbd30 (diff) | |
| parent | af0940dac37545b1e7900b19c464fb6367d3f82f (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.c | 113 |
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 | ||
| 133 | static void schedule_iso_resource(struct iso_resource *); | ||
| 134 | static void release_iso_resource(struct client *, struct client_resource *); | 133 | static void release_iso_resource(struct client *, struct client_resource *); |
| 135 | 134 | ||
| 135 | static 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 | |||
| 142 | static 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 | ||
| 167 | struct iso_resource_event { | 180 | struct 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 | ||
| 172 | static inline void __user *u64_to_uptr(__u64 value) | 185 | static inline void __user *u64_to_uptr(__u64 value) |
| @@ -314,11 +327,8 @@ static void for_each_client(struct fw_device *device, | |||
| 314 | 327 | ||
| 315 | static int schedule_reallocations(int id, void *p, void *data) | 328 | static 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 | ||
| 429 | static int release_client_resource(struct client *client, u32 handle, | 437 | static 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 | ||
| 720 | static int ioctl_initiate_bus_reset(struct client *client, void *buffer) | 733 | static 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 | ||
| 1117 | static 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 | |||
| 1124 | static void release_iso_resource(struct client *client, | 1129 | static 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) = { | |||
| 1295 | static int dispatch_ioctl(struct client *client, | 1300 | static 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 | ||
| 1391 | static int shutdown_resource(int id, void *p, void *data) | 1412 | static 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) | |||
| 1402 | static int fw_device_op_release(struct inode *inode, struct file *file) | 1423 | static 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 | ||
