aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorJay Fenlason <fenlason@redhat.com>2010-05-18 14:02:45 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-06-20 17:11:56 -0400
commit08bd34c98d631fe85744d4c920c80f48a1d95f54 (patch)
treecebfda304248a705e2b46f9d105b3c22705169f1 /drivers/firewire
parentbdfe273ee54b29498851fc8058516037d284270c (diff)
firewire: cdev: fix responses to nodes at different card
My box has two firewire cards in it: card0 and card1. My application opens /dev/fw0 (card 0) and allocates an address space. The core makes the address space available on both cards. Along comes the remote device, which sends a READ_QUADLET_REQUEST to card1. The request gets passed up to my application, which calls ioctl_send_response(). ioctl_send_response() then calls fw_send_response() with card0, because that's the card it's bound to. Card0's driver drops the response, because it isn't part of a transaction that it has outstanding. So in core-cdev: handle_request(), we need to stash the card of the inbound request in the struct inbound_transaction_resource and use that card to send the response to. The hard part will be refcounting the card correctly so it can't get deallocated while we hold a pointer to it. Here's a trivial patch, which does not do the card refcounting, but at least demonstrates what the problem is. Note that we can't depend on the fact that the core-cdev:client structure holds a card open, because in this case the card it holds open is not the card the request came in on. ..and there's no way for the core to tell cdev "this card is gone, kill any inbound transactions on it", while cdev holds the transaction open until userspace issues a SEND_RESPONSE ioctl, which may be a very, very long time. But when it does, it calls fw_send_response(), which will dereference the card... So how unhappy are we about userspace potentially holding a fw_card open forever? Signed-off-by: Jay Fenlason <fenlason@redhat.com> Reference counting to be addressed in a separate change. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (whitespace)
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-cdev.c7
1 files changed, 4 insertions, 3 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index ce8cb6fcbbcd..8cbc2b8a8272 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -106,6 +106,7 @@ struct outbound_transaction_resource {
106 106
107struct inbound_transaction_resource { 107struct inbound_transaction_resource {
108 struct client_resource resource; 108 struct client_resource resource;
109 struct fw_card *card;
109 struct fw_request *request; 110 struct fw_request *request;
110 void *data; 111 void *data;
111 size_t length; 112 size_t length;
@@ -625,8 +626,7 @@ static void release_request(struct client *client,
625 if (is_fcp_request(r->request)) 626 if (is_fcp_request(r->request))
626 kfree(r->data); 627 kfree(r->data);
627 else 628 else
628 fw_send_response(client->device->card, r->request, 629 fw_send_response(r->card, r->request, RCODE_CONFLICT_ERROR);
629 RCODE_CONFLICT_ERROR);
630 kfree(r); 630 kfree(r);
631} 631}
632 632
@@ -646,6 +646,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
646 if (r == NULL || e == NULL) 646 if (r == NULL || e == NULL)
647 goto failed; 647 goto failed;
648 648
649 r->card = card;
649 r->request = request; 650 r->request = request;
650 r->data = payload; 651 r->data = payload;
651 r->length = length; 652 r->length = length;
@@ -765,7 +766,7 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
765 kfree(r->request); 766 kfree(r->request);
766 goto out; 767 goto out;
767 } 768 }
768 fw_send_response(client->device->card, r->request, a->rcode); 769 fw_send_response(r->card, r->request, a->rcode);
769 out: 770 out:
770 kfree(r); 771 kfree(r);
771 772