diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-06 12:03:43 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-08-06 12:03:43 -0700 |
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 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, struct response *response = data; struct client *client = response->client; unsigned long flags; + struct fw_cdev_event_response *r = &response->response; - if (length < response->response.length) - response->response.length = length; + if (length < r->length) + r->length = length; if (rcode == RCODE_COMPLETE) - memcpy(response->response.data, payload, - response->response.length); + memcpy(r->data, payload, r->length); spin_lock_irqsave(&client->lock, flags); list_del(&response->resource.link); spin_unlock_irqrestore(&client->lock, flags); - response->response.type = FW_CDEV_EVENT_RESPONSE; - response->response.rcode = rcode; - queue_event(client, &response->event, &response->response, - sizeof(response->response) + response->response.length, - NULL, 0); + r->type = FW_CDEV_EVENT_RESPONSE; + r->rcode = rcode; + + /* + * In the case that sizeof(*r) doesn't align with the position of the + * data, and the read is short, preserve an extra copy of the data + * to stay compatible with a pre-2.6.27 bug. Since the bug is harmless + * for short reads and some apps depended on it, this is both safe + * and prudent for compatibility. + */ + if (r->length <= sizeof(*r) - offsetof(typeof(*r), data)) + queue_event(client, &response->event, r, sizeof(*r), + r->data, r->length); + else + queue_event(client, &response->event, r, sizeof(*r) + r->length, + NULL, 0); } static int ioctl_send_request(struct client *client, void *buffer) |