diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-06 15:03:43 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-06 15:03:43 -0400 |
| commit | a14ad05f47b55ea84136eb4da43ea96fa469326a (patch) | |
| tree | 1197659a31b5c0b1a9c3db4d90a083eaca7fad4d | |
| parent | 0016fe9d8a1ca99a4642735f41a7753d7c1f7e2b (diff) | |
| parent | 8401d92ba46a1e859464cbd9c9ee304f6e361da3 (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:
firewire: Preserve response data alignment bug when it is harmless
| -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) |
