diff options
Diffstat (limited to 'drivers/firewire/fw-cdev.c')
| -rw-r--r-- | drivers/firewire/fw-cdev.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index bc81d6fcd2fd..2e6d5848d217 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c | |||
| @@ -369,22 +369,33 @@ complete_transaction(struct fw_card *card, int rcode, | |||
| 369 | struct response *response = data; | 369 | struct response *response = data; |
| 370 | struct client *client = response->client; | 370 | struct client *client = response->client; |
| 371 | unsigned long flags; | 371 | unsigned long flags; |
| 372 | struct fw_cdev_event_response *r = &response->response; | ||
| 372 | 373 | ||
| 373 | if (length < response->response.length) | 374 | if (length < r->length) |
| 374 | response->response.length = length; | 375 | r->length = length; |
| 375 | if (rcode == RCODE_COMPLETE) | 376 | if (rcode == RCODE_COMPLETE) |
| 376 | memcpy(response->response.data, payload, | 377 | memcpy(r->data, payload, r->length); |
| 377 | response->response.length); | ||
| 378 | 378 | ||
| 379 | spin_lock_irqsave(&client->lock, flags); | 379 | spin_lock_irqsave(&client->lock, flags); |
| 380 | list_del(&response->resource.link); | 380 | list_del(&response->resource.link); |
| 381 | spin_unlock_irqrestore(&client->lock, flags); | 381 | spin_unlock_irqrestore(&client->lock, flags); |
| 382 | 382 | ||
| 383 | response->response.type = FW_CDEV_EVENT_RESPONSE; | 383 | r->type = FW_CDEV_EVENT_RESPONSE; |
| 384 | response->response.rcode = rcode; | 384 | r->rcode = rcode; |
| 385 | queue_event(client, &response->event, &response->response, | 385 | |
| 386 | sizeof(response->response) + response->response.length, | 386 | /* |
| 387 | NULL, 0); | 387 | * In the case that sizeof(*r) doesn't align with the position of the |
| 388 | * data, and the read is short, preserve an extra copy of the data | ||
| 389 | * to stay compatible with a pre-2.6.27 bug. Since the bug is harmless | ||
| 390 | * for short reads and some apps depended on it, this is both safe | ||
| 391 | * and prudent for compatibility. | ||
| 392 | */ | ||
| 393 | if (r->length <= sizeof(*r) - offsetof(typeof(*r), data)) | ||
| 394 | queue_event(client, &response->event, r, sizeof(*r), | ||
| 395 | r->data, r->length); | ||
| 396 | else | ||
| 397 | queue_event(client, &response->event, r, sizeof(*r) + r->length, | ||
| 398 | NULL, 0); | ||
| 388 | } | 399 | } |
| 389 | 400 | ||
| 390 | static int ioctl_send_request(struct client *client, void *buffer) | 401 | static int ioctl_send_request(struct client *client, void *buffer) |
