diff options
Diffstat (limited to 'drivers/firewire/core-cdev.c')
-rw-r--r-- | drivers/firewire/core-cdev.c | 43 |
1 files changed, 17 insertions, 26 deletions
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c index 958aa4662ccb..2c16ee8fd842 100644 --- a/drivers/firewire/core-cdev.c +++ b/drivers/firewire/core-cdev.c @@ -111,6 +111,7 @@ struct inbound_transaction_resource { struct client_resource resource; struct fw_card *card; struct fw_request *request; + bool is_fcp; void *data; size_t length; }; @@ -643,19 +644,14 @@ static int ioctl_send_request(struct client *client, union ioctl_arg *arg) client->device->max_speed); } -static inline bool is_fcp_request(struct fw_request *request) -{ - return request == NULL; -} - static void release_request(struct client *client, struct client_resource *resource) { struct inbound_transaction_resource *r = container_of(resource, struct inbound_transaction_resource, resource); - if (is_fcp_request(r->request)) - kfree(r->data); + if (r->is_fcp) + fw_request_put(r->request); else fw_send_response(r->card, r->request, RCODE_CONFLICT_ERROR); @@ -669,15 +665,20 @@ static void handle_request(struct fw_card *card, struct fw_request *request, void *payload, size_t length, void *callback_data) { struct address_handler_resource *handler = callback_data; + bool is_fcp = is_in_fcp_region(offset, length); struct inbound_transaction_resource *r; struct inbound_transaction_event *e; size_t event_size0; - void *fcp_frame = NULL; int ret; /* card may be different from handler->client->device->card */ fw_card_get(card); + // Extend the lifetime of data for request so that its payload is safely accessible in + // the process context for the client. + if (is_fcp) + fw_request_get(request); + r = kmalloc(sizeof(*r), GFP_ATOMIC); e = kmalloc(sizeof(*e), GFP_ATOMIC); if (r == NULL || e == NULL) @@ -685,21 +686,10 @@ static void handle_request(struct fw_card *card, struct fw_request *request, r->card = card; r->request = request; + r->is_fcp = is_fcp; r->data = payload; r->length = length; - if (is_fcp_request(request)) { - /* - * FIXME: Let core-transaction.c manage a - * single reference-counted copy? - */ - fcp_frame = kmemdup(payload, length, GFP_ATOMIC); - if (fcp_frame == NULL) - goto failed; - - r->data = fcp_frame; - } - r->resource.release = release_request; ret = add_client_resource(handler->client, &r->resource, GFP_ATOMIC); if (ret < 0) @@ -741,10 +731,11 @@ static void handle_request(struct fw_card *card, struct fw_request *request, failed: kfree(r); kfree(e); - kfree(fcp_frame); - if (!is_fcp_request(request)) + if (!is_fcp) fw_send_response(card, request, RCODE_CONFLICT_ERROR); + else + fw_request_put(request); fw_card_put(card); } @@ -819,19 +810,19 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg) r = container_of(resource, struct inbound_transaction_resource, resource); - if (is_fcp_request(r->request)) { - kfree(r->data); + if (r->is_fcp) { + fw_request_put(r->request); goto out; } if (a->length != fw_get_response_length(r->request)) { ret = -EINVAL; - kfree(r->request); + fw_request_put(r->request); goto out; } if (copy_from_user(r->data, u64_to_uptr(a->data), a->length)) { ret = -EFAULT; - kfree(r->request); + fw_request_put(r->request); goto out; } fw_send_response(r->card, r->request, a->rcode); |