aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-08-06 15:03:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-08-06 15:03:43 -0400
commita14ad05f47b55ea84136eb4da43ea96fa469326a (patch)
tree1197659a31b5c0b1a9c3db4d90a083eaca7fad4d
parent0016fe9d8a1ca99a4642735f41a7753d7c1f7e2b (diff)
parent8401d92ba46a1e859464cbd9c9ee304f6e361da3 (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.c29
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
390static int ioctl_send_request(struct client *client, void *buffer) 401static int ioctl_send_request(struct client *client, void *buffer)