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 /drivers/firewire | |
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
Diffstat (limited to 'drivers/firewire')
-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 bc81d6fcd2f..2e6d5848d21 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) |