firewire: cdev: obsolete NULL check to detect IEC 61883-1 FCP region

In the character device, the listener to address space should distinguish
whether the request is to IEC 61883-1 FCP region or not. The user space
application needs to access to the object of request in enough later by
read(2), while the core function releases the object of request in the FCP
case after completing the callback to handler.

The handler guarantees the access safe by some way. It's done by
duplication of the object after NULL check to the request, since core
function passes NULL in the FCP case. It's inconvenient since the object
of request includes some helpful information. It's better to add another
way to check whether the request is to FCP region or not.

Conveniently the file of transaction layer includes local implementation
for the purpose. This commit moves it to module local file and use it
instead of the NULL check, then the result of check is stored to
per-client data for the inbound transaction so that the result can be
referred by later to release the data.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20230120090344.296451-3-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Sakamoto 2023-01-20 18:03:43 +09:00 committed by Takashi Iwai
parent 13a55d6bb1
commit e699600232
4 changed files with 25 additions and 22 deletions

View File

@ -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,18 +644,13 @@ 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))
if (r->is_fcp)
kfree(r->data);
else
fw_send_response(r->card, r->request, RCODE_CONFLICT_ERROR);
@ -669,6 +665,7 @@ 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;
@ -685,10 +682,11 @@ 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)) {
if (is_fcp) {
/*
* FIXME: Let core-transaction.c manage a
* single reference-counted copy?
@ -743,7 +741,7 @@ static void handle_request(struct fw_card *card, struct fw_request *request,
kfree(e);
kfree(fcp_frame);
if (!is_fcp_request(request))
if (!is_fcp)
fw_send_response(card, request, RCODE_CONFLICT_ERROR);
fw_card_put(card);
@ -819,7 +817,7 @@ 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)) {
if (r->is_fcp) {
kfree(r->data);
goto out;
}

View File

@ -535,12 +535,6 @@ const struct fw_address_region fw_unit_space_region =
{ .start = 0xfffff0000900ULL, .end = 0x1000000000000ULL, };
#endif /* 0 */
static bool is_in_fcp_region(u64 offset, size_t length)
{
return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
}
/**
* fw_core_add_address_handler() - register for incoming requests
* @handler: callback
@ -822,12 +816,18 @@ static struct fw_request *allocate_request(struct fw_card *card,
return request;
}
/**
* fw_send_response: - send response packet for asynchronous transaction.
* @card: interface to send the response at.
* @request: firewire request data for the transaction.
* @rcode: response code to send.
*
* Submit a response packet into the asynchronous response transmission queue. The @request
* is going to be released when the transmission successfully finishes later.
*/
void fw_send_response(struct fw_card *card,
struct fw_request *request, int rcode)
{
if (WARN_ONCE(!request, "invalid for FCP address handlers"))
return;
/* unified transaction or broadcast transaction: don't respond */
if (request->ack != ACK_PENDING ||
HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
@ -935,7 +935,7 @@ static void handle_fcp_region_request(struct fw_card *card,
rcu_read_lock();
list_for_each_entry_rcu(handler, &address_handler_list, link) {
if (is_enclosing_handler(handler, offset, request->length))
handler->address_callback(card, NULL, tcode,
handler->address_callback(card, request, tcode,
destination, source,
p->generation, offset,
request->data,

View File

@ -257,4 +257,10 @@ static inline bool is_ping_packet(u32 *data)
return (data[0] & 0xc0ffffff) == 0 && ~data[0] == data[1];
}
static inline bool is_in_fcp_region(u64 offset, size_t length)
{
return offset >= (CSR_REGISTER_BASE | CSR_FCP_COMMAND) &&
offset + length <= (CSR_REGISTER_BASE | CSR_FCP_END);
}
#endif /* _FIREWIRE_CORE_H */

View File

@ -278,9 +278,8 @@ typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
* Otherwise there is a danger of recursion of inbound and outbound
* transactions from and to the local node.
*
* The callback is responsible that either fw_send_response() or kfree()
* is called on the @request, except for FCP registers for which the core
* takes care of that.
* The callback is responsible that fw_send_response() is called on the @request, except for FCP
* registers for which the core takes care of that.
*/
typedef void (*fw_address_callback_t)(struct fw_card *card,
struct fw_request *request,