From f9543d0ab6392a9a5bff0034622688dc10d9d225 Mon Sep 17 00:00:00 2001 From: JiSheng Zhang Date: Sat, 19 Jul 2008 15:35:41 +0800 Subject: firewire: queue the right number of data There will be 4 padding bytes in struct fw_cdev_event_response on some platforms The member:__u32 data will point to these padding bytes. While queue the response and data in complete_transaction in fw-cdev.c, it will queue like this: |response(excluding padding bytes)|4 padding bytes|4 padding bytes|data. It queue 4 extra bytes. That is to say it use "&response + sizeof(response)" while other place of kernel and userspace library use "&response + offsetof (typeof(response), data)". So it will lost the last 4 bytes of data. This patch can fix it while not changing the struct definition. Signed-off-by: JiSheng Zhang This fixes responses to outbound block read requests on 64bit architectures. Tested on i686, x86-64, and x86-64 with i686 userland, using firecontrol and gscanbus. Signed-off-by: Stefan Richter --- drivers/firewire/fw-cdev.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/firewire/fw-cdev.c') diff --git a/drivers/firewire/fw-cdev.c b/drivers/firewire/fw-cdev.c index c639915fc3cb..bc81d6fcd2fd 100644 --- a/drivers/firewire/fw-cdev.c +++ b/drivers/firewire/fw-cdev.c @@ -382,9 +382,9 @@ complete_transaction(struct fw_card *card, int rcode, response->response.type = FW_CDEV_EVENT_RESPONSE; response->response.rcode = rcode; - queue_event(client, &response->event, - &response->response, sizeof(response->response), - response->response.data, response->response.length); + queue_event(client, &response->event, &response->response, + sizeof(response->response) + response->response.length, + NULL, 0); } static int ioctl_send_request(struct client *client, void *buffer) -- cgit v1.2.3 From 8401d92ba46a1e859464cbd9c9ee304f6e361da3 Mon Sep 17 00:00:00 2001 From: David Moore Date: Tue, 29 Jul 2008 23:46:25 -0700 Subject: firewire: Preserve response data alignment bug when it is harmless Recently, a bug having to do with the alignment of transaction response data was fixed. However, some apps such as libdc1394 relied on the presence of that bug in order to function correctly. In order to stay compatible with old versions of those apps, this patch preserves the bug in cases where it is harmless to normal operation (such as the single quadlet read) due to a simple duplication of data. This guarantees maximum compatability for those users who are using the old app with the fixed kernel. Signed-off-by: David Moore Signed-off-by: Stefan Richter --- drivers/firewire/fw-cdev.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers/firewire/fw-cdev.c') 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) -- cgit v1.2.3