firewire: core: use kref structure to maintain lifetime of data for fw_request structure

Developers have acknowledged that maintenance of lifetime for
fw_transaction structure is effective when handling asynchronous
transaction to IEC 61883-1 FCP region, since the core function allows
multiples listeners to the region. Some of them needs to access to the
payload of request in process context after the callback to listener,
while the core function releases the object for the structure just after
completing the callbacks to listeners.

One of the listeners is character device. Current implementation of the
character device duplicates the object for the payload of transaction,
while it's a cost in kernel memory consumption. The lifetime management
can reduce it.

The typical way to maintain the lifetime is reference count. This commit
uses kref structure as a first step for the purpose.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Link: https://lore.kernel.org/r/20230120090344.296451-2-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Sakamoto 2023-01-20 18:03:42 +09:00 коммит произвёл Takashi Iwai
Родитель 87978e6ad4
Коммит 13a55d6bb1
3 изменённых файлов: 34 добавлений и 6 удалений

Просмотреть файл

@ -826,12 +826,12 @@ static int ioctl_send_response(struct client *client, union ioctl_arg *arg)
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);

Просмотреть файл

@ -617,6 +617,7 @@ void fw_core_remove_address_handler(struct fw_address_handler *handler)
EXPORT_SYMBOL(fw_core_remove_address_handler);
struct fw_request {
struct kref kref;
struct fw_packet response;
u32 request_header[4];
int ack;
@ -625,13 +626,33 @@ struct fw_request {
u32 data[];
};
void fw_request_get(struct fw_request *request)
{
kref_get(&request->kref);
}
static void release_request(struct kref *kref)
{
struct fw_request *request = container_of(kref, struct fw_request, kref);
kfree(request);
}
void fw_request_put(struct fw_request *request)
{
kref_put(&request->kref, release_request);
}
static void free_response_callback(struct fw_packet *packet,
struct fw_card *card, int status)
{
struct fw_request *request;
struct fw_request *request = container_of(packet, struct fw_request, response);
request = container_of(packet, struct fw_request, response);
kfree(request);
// Decrease the reference count since not at in-flight.
fw_request_put(request);
// Decrease the reference count to release the object.
fw_request_put(request);
}
int fw_get_response_length(struct fw_request *r)
@ -782,6 +803,7 @@ static struct fw_request *allocate_request(struct fw_card *card,
request = kmalloc(sizeof(*request) + length, GFP_ATOMIC);
if (request == NULL)
return NULL;
kref_init(&request->kref);
request->response.speed = p->speed;
request->response.timestamp =
@ -809,7 +831,7 @@ void fw_send_response(struct fw_card *card,
/* unified transaction or broadcast transaction: don't respond */
if (request->ack != ACK_PENDING ||
HEADER_DESTINATION_IS_BROADCAST(request->request_header[0])) {
kfree(request);
fw_request_put(request);
return;
}
@ -821,6 +843,9 @@ void fw_send_response(struct fw_card *card,
fw_fill_response(&request->response, request->request_header,
rcode, NULL, 0);
// Increase the reference count so that the object is kept during in-flight.
fw_request_get(request);
card->driver->send_response(card, &request->response);
}
EXPORT_SYMBOL(fw_send_response);

Просмотреть файл

@ -244,6 +244,9 @@ int fw_get_response_length(struct fw_request *request);
void fw_fill_response(struct fw_packet *response, u32 *request_header,
int rcode, void *payload, size_t length);
void fw_request_get(struct fw_request *request);
void fw_request_put(struct fw_request *request);
#define FW_PHY_CONFIG_NO_NODE_ID -1
#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1
void fw_send_phy_config(struct fw_card *card,