* [PATCH 0/7] firewire: core: separate iso_resource paths
@ 2026-04-29 9:34 Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 1/7] firewire: core: code refactoring for early return at client resource allocation Takashi Sakamoto
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
Hi,
(Repost since lkml was excluded.)
Dingisoul has reported that a case where the reference count of a
client structure is leaked when handling iso_resource in cdev layer[1].
Fixing the bug immediately s difficult due to the complexity of
per-client resource lifetime.
As a first step toward addressing this issue, this patchset refactors the
existing code for isochronous resource operation. Userspace application
can allocate and deallocate isochronous resources on IEEE 1394 bus in two
ways:
* FW_CDEV_IOC_[DE]ALLOCATE_ISO_RESOURCE
* FW_CDEV_IOC_[DE]ALLOCATE_ISO_RESOURCE_ONCE
With the former, the application delegates the maintenance of the
allocated isochronous resources to kernel and obtain a handle for the
client resource. With the latter, the application should maintain
isochronous resources every time receiving bus reset event, without
relying on a handle.
Currently, both operations are handled by the same code, although they
differ in terms of client resource management.
This patchset separates these two paths. As a result, it becomes clear
that the reported issue only affects client resource allocated via the
former method. While the actual bug fix is deferred, this refactoring
lays the groundwork for it.
[1] https://sourceforge.net/p/linux1394/mailman/linux1394-devel/thread/20260404110936.GA282614%40sakamocchi.jp/#msg59317811
Takashi Sakamoto (7):
firewire: core: code refactoring for early return at client resource
allocation
firewire: core: code refactoring to queue work item for iso_resource
firewire: core: code refactoring for helper function to fill
iso_resource parameters
firewire: core: split functions for iso_resource once operation
firewire: core: code cleanup to remove old implementations for once
operation
firewire: core: append _auto suffix for non-once iso resource
operations
firewire: core: code cleanup for iso resource auto creation
drivers/firewire/core-cdev.c | 285 +++++++++++++++++++++--------------
1 file changed, 176 insertions(+), 109 deletions(-)
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
--
2.53.0
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/7] firewire: core: code refactoring for early return at client resource allocation
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
@ 2026-04-29 9:34 ` Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 2/7] firewire: core: code refactoring to queue work item for iso_resource Takashi Sakamoto
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
The add_client_resource() function returns zero at success or negative
value at error. The critical section is already protected by
scoped_guard() macro. In this case, the programming pattern of early
return improves code readability.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-cdev.c | 35 +++++++++++++++++------------------
1 file changed, 17 insertions(+), 18 deletions(-)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index f791db4c8dff..144625c34be2 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -507,31 +507,30 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
static int add_client_resource(struct client *client, struct client_resource *resource,
gfp_t gfp_mask)
{
- int ret;
-
scoped_guard(spinlock_irqsave, &client->lock) {
u32 index;
+ int ret;
+
+ if (client->in_shutdown)
+ return -ECANCELED;
- if (client->in_shutdown) {
- ret = -ECANCELED;
+ if (gfpflags_allow_blocking(gfp_mask)) {
+ ret = xa_alloc(&client->resource_xa, &index, resource, xa_limit_32b,
+ GFP_NOWAIT);
} else {
- if (gfpflags_allow_blocking(gfp_mask)) {
- ret = xa_alloc(&client->resource_xa, &index, resource, xa_limit_32b,
- GFP_NOWAIT);
- } else {
- ret = xa_alloc_bh(&client->resource_xa, &index, resource,
- xa_limit_32b, GFP_NOWAIT);
- }
- }
- if (ret >= 0) {
- resource->handle = index;
- client_get(client);
- if (is_iso_resource(resource))
- schedule_iso_resource(to_iso_resource(resource), 0);
+ ret = xa_alloc_bh(&client->resource_xa, &index, resource,
+ xa_limit_32b, GFP_NOWAIT);
}
+ if (ret < 0)
+ return ret;
+
+ resource->handle = index;
+ client_get(client);
+ if (is_iso_resource(resource))
+ schedule_iso_resource(to_iso_resource(resource), 0);
}
- return ret < 0 ? ret : 0;
+ return 0;
}
static int release_client_resource(struct client *client, u32 handle,
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/7] firewire: core: code refactoring to queue work item for iso_resource
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 1/7] firewire: core: code refactoring for early return at client resource allocation Takashi Sakamoto
@ 2026-04-29 9:34 ` Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 3/7] firewire: core: code refactoring for helper function to fill iso_resource parameters Takashi Sakamoto
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
The add_client_resource() function checks the type of client resource
every time to be called. If the type is for iso_resource, it schedules
work item.
However, the iso_resource client resource is only added by the call of
init_iso_resource(). There is no need to check the type every time adding
any client resource.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-cdev.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 144625c34be2..8391c7efab2c 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -526,8 +526,6 @@ static int add_client_resource(struct client *client, struct client_resource *re
resource->handle = index;
client_get(client);
- if (is_iso_resource(resource))
- schedule_iso_resource(to_iso_resource(resource), 0);
}
return 0;
@@ -1438,8 +1436,9 @@ static int init_iso_resource(struct client *client,
} else {
r->resource.release = NULL;
r->resource.handle = -1;
- schedule_iso_resource(r, 0);
}
+ schedule_iso_resource(r, 0);
+
request->handle = r->resource.handle;
return 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/7] firewire: core: code refactoring for helper function to fill iso_resource parameters
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 1/7] firewire: core: code refactoring for early return at client resource allocation Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 2/7] firewire: core: code refactoring to queue work item for iso_resource Takashi Sakamoto
@ 2026-04-29 9:34 ` Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 4/7] firewire: core: split functions for iso_resource once operation Takashi Sakamoto
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
This change is a preparation for future changes. The added helper function
will be reused in the changes to fill iso_resource parameters according to
the users' request.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-cdev.c | 45 ++++++++++++++++++++++++------------
1 file changed, 30 insertions(+), 15 deletions(-)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 8391c7efab2c..effa03739679 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -128,6 +128,12 @@ struct descriptor_resource {
u32 data[];
};
+struct iso_resource_params {
+ int generation;
+ u64 channels;
+ s32 bandwidth;
+};
+
struct iso_resource {
struct client_resource resource;
struct client *client;
@@ -135,9 +141,7 @@ struct iso_resource {
struct delayed_work work;
enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,
ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo;
- int generation;
- u64 channels;
- s32 bandwidth;
+ struct iso_resource_params params;
struct iso_resource_event *e_alloc, *e_dealloc;
};
@@ -1290,6 +1294,20 @@ static int ioctl_get_cycle_timer(struct client *client, union ioctl_arg *arg)
return 0;
}
+static int fill_iso_resource_params(struct iso_resource_params *params,
+ struct fw_cdev_allocate_iso_resource *request)
+{
+ if ((request->channels == 0 && request->bandwidth == 0) ||
+ request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL)
+ return -EINVAL;
+
+ params->generation = -1;
+ params->channels = request->channels;
+ params->bandwidth = request->bandwidth;
+
+ return 0;
+}
+
static void iso_resource_work(struct work_struct *work)
{
struct iso_resource_event *e;
@@ -1310,21 +1328,21 @@ static void iso_resource_work(struct work_struct *work)
} else {
// We could be called twice within the same generation.
skip = todo == ISO_RES_REALLOC &&
- r->generation == generation;
+ r->params.generation == generation;
}
free = todo == ISO_RES_DEALLOC ||
todo == ISO_RES_ALLOC_ONCE ||
todo == ISO_RES_DEALLOC_ONCE;
- r->generation = generation;
+ r->params.generation = generation;
}
if (skip)
goto out;
- bandwidth = r->bandwidth;
+ bandwidth = r->params.bandwidth;
fw_iso_resource_manage(client->device->card, generation,
- r->channels, &channel, &bandwidth,
+ r->params.channels, &channel, &bandwidth,
todo == ISO_RES_ALLOC ||
todo == ISO_RES_REALLOC ||
todo == ISO_RES_ALLOC_ONCE);
@@ -1355,7 +1373,7 @@ static void iso_resource_work(struct work_struct *work)
}
if (todo == ISO_RES_ALLOC && channel >= 0)
- r->channels = 1ULL << channel;
+ r->params.channels = 1ULL << channel;
if (todo == ISO_RES_REALLOC && success)
goto out;
@@ -1402,10 +1420,6 @@ static int init_iso_resource(struct client *client,
struct iso_resource *r;
int ret;
- if ((request->channels == 0 && request->bandwidth == 0) ||
- request->bandwidth > BANDWIDTH_AVAILABLE_INITIAL)
- return -EINVAL;
-
r = kmalloc_obj(*r);
e1 = kmalloc_obj(*e1);
e2 = kmalloc_obj(*e2);
@@ -1414,12 +1428,13 @@ static int init_iso_resource(struct client *client,
goto fail;
}
+ ret = fill_iso_resource_params(&r->params, request);
+ if (ret < 0)
+ goto fail;
+
INIT_DELAYED_WORK(&r->work, iso_resource_work);
r->client = client;
r->todo = todo;
- r->generation = -1;
- r->channels = request->channels;
- r->bandwidth = request->bandwidth;
r->e_alloc = e1;
r->e_dealloc = e2;
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/7] firewire: core: split functions for iso_resource once operation
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
` (2 preceding siblings ...)
2026-04-29 9:34 ` [PATCH 3/7] firewire: core: code refactoring for helper function to fill iso_resource parameters Takashi Sakamoto
@ 2026-04-29 9:34 ` Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 5/7] firewire: core: code cleanup to remove old implementations for " Takashi Sakamoto
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
Unlike FW_CDEV_IOC_ALLOCATE_ISO_RESOURCE operation, the operations of
FW_CDEV_IOC_[DE]ALLOCATE_ISO_RESOURCE_ONCE require no client resource,
thus they keeps no handle value.
This commit adds the series of functions to separate these operations,
according to divide-and-conquer methodology.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-cdev.c | 83 ++++++++++++++++++++++++++++++++++--
1 file changed, 79 insertions(+), 4 deletions(-)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index effa03739679..478e8f6400f0 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -145,6 +145,18 @@ struct iso_resource {
struct iso_resource_event *e_alloc, *e_dealloc;
};
+struct iso_resource_once {
+ struct client *client;
+ // Schedule work and access todo only with client->lock held.
+ struct delayed_work work;
+ enum {
+ ISO_RES_ONCE_ALLOC,
+ ISO_RES_ONCE_DEALLOC,
+ } todo;
+ struct iso_resource_params params;
+ struct iso_resource_event *event;
+};
+
static struct address_handler_resource *to_address_handler_resource(struct client_resource *resource)
{
return container_of(resource, struct address_handler_resource, resource);
@@ -1479,18 +1491,81 @@ static int ioctl_deallocate_iso_resource(struct client *client,
arg->deallocate.handle, release_iso_resource, NULL);
}
+#define UNAVAILABLE_HANDLE -1
+
+static void iso_resource_once_work(struct work_struct *work)
+{
+ struct iso_resource_once *r = from_work(r, work, work.work);
+ struct client *client = r->client;
+ struct iso_resource_event *e = r->event;
+ int generation, channel, bandwidth;
+
+ scoped_guard(spinlock_irq, &client->lock)
+ generation = client->device->generation;
+
+ r->params.generation = generation;
+ bandwidth = r->params.bandwidth;
+
+ fw_iso_resource_manage(client->device->card, generation, r->params.channels, &channel,
+ &bandwidth, r->todo == ISO_RES_ONCE_ALLOC);
+
+ e->iso_resource.handle = UNAVAILABLE_HANDLE;
+ e->iso_resource.channel = channel;
+ e->iso_resource.bandwidth = bandwidth;
+
+ queue_event(client, &e->event, &e->iso_resource, sizeof(e->iso_resource), NULL, 0);
+
+ cancel_delayed_work(&r->work);
+ kfree(r);
+
+ client_put(client);
+}
+
+static int init_iso_resource_once(struct client *client,
+ struct fw_cdev_allocate_iso_resource *request, int todo)
+{
+ struct iso_resource_event *e __free(kfree) = kmalloc_obj(*e);
+ struct iso_resource_once *r __free(kfree) = kmalloc_obj(*r);
+ int err;
+
+ if (!r || !e)
+ return -ENOMEM;
+
+ err = fill_iso_resource_params(&r->params, request);
+ if (err < 0)
+ return err;
+
+ INIT_DELAYED_WORK(&r->work, iso_resource_once_work);
+ r->client = client;
+ r->todo = todo;
+
+ if (todo == ISO_RES_ONCE_ALLOC)
+ e->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
+ else
+ e->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
+ e->iso_resource.closure = request->closure;
+ r->event = no_free_ptr(e);
+
+ // Keep the client until work item finishing.
+ client_get(r->client);
+
+ queue_delayed_work(fw_workqueue, &no_free_ptr(r)->work, 0);
+
+ request->handle = UNAVAILABLE_HANDLE;
+
+ return 0;
+}
+
static int ioctl_allocate_iso_resource_once(struct client *client,
union ioctl_arg *arg)
{
- return init_iso_resource(client,
- &arg->allocate_iso_resource, ISO_RES_ALLOC_ONCE);
+ return init_iso_resource_once(client, &arg->allocate_iso_resource, ISO_RES_ONCE_ALLOC);
}
static int ioctl_deallocate_iso_resource_once(struct client *client,
union ioctl_arg *arg)
{
- return init_iso_resource(client,
- &arg->allocate_iso_resource, ISO_RES_DEALLOC_ONCE);
+ return init_iso_resource_once(client, &arg->allocate_iso_resource, ISO_RES_ONCE_DEALLOC);
}
/*
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/7] firewire: core: code cleanup to remove old implementations for once operation
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
` (3 preceding siblings ...)
2026-04-29 9:34 ` [PATCH 4/7] firewire: core: split functions for iso_resource once operation Takashi Sakamoto
@ 2026-04-29 9:34 ` Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 6/7] firewire: core: append _auto suffix for non-once iso resource operations Takashi Sakamoto
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
The helper functions for iso_resource allocation and work item still
include codes for once operation.
This commit refactors them to remove the old implementations.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-cdev.c | 37 +++++++++++++++---------------------
1 file changed, 15 insertions(+), 22 deletions(-)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index 478e8f6400f0..f81a8aa4bcbc 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -139,8 +139,11 @@ struct iso_resource {
struct client *client;
/* Schedule work and access todo only with client->lock held. */
struct delayed_work work;
- enum {ISO_RES_ALLOC, ISO_RES_REALLOC, ISO_RES_DEALLOC,
- ISO_RES_ALLOC_ONCE, ISO_RES_DEALLOC_ONCE,} todo;
+ enum {
+ ISO_RES_ALLOC,
+ ISO_RES_REALLOC,
+ ISO_RES_DEALLOC,
+ } todo;
struct iso_resource_params params;
struct iso_resource_event *e_alloc, *e_dealloc;
};
@@ -1342,9 +1345,7 @@ static void iso_resource_work(struct work_struct *work)
skip = todo == ISO_RES_REALLOC &&
r->params.generation == generation;
}
- free = todo == ISO_RES_DEALLOC ||
- todo == ISO_RES_ALLOC_ONCE ||
- todo == ISO_RES_DEALLOC_ONCE;
+ free = todo == ISO_RES_DEALLOC;
r->params.generation = generation;
}
@@ -1356,8 +1357,7 @@ static void iso_resource_work(struct work_struct *work)
fw_iso_resource_manage(client->device->card, generation,
r->params.channels, &channel, &bandwidth,
todo == ISO_RES_ALLOC ||
- todo == ISO_RES_REALLOC ||
- todo == ISO_RES_ALLOC_ONCE);
+ todo == ISO_RES_REALLOC);
/*
* Is this generation outdated already? As long as this resource sticks
* in the xarray, it will be scheduled again for a newer generation or at
@@ -1390,7 +1390,7 @@ static void iso_resource_work(struct work_struct *work)
if (todo == ISO_RES_REALLOC && success)
goto out;
- if (todo == ISO_RES_ALLOC || todo == ISO_RES_ALLOC_ONCE) {
+ if (todo == ISO_RES_ALLOC) {
e = r->e_alloc;
r->e_alloc = NULL;
} else {
@@ -1425,8 +1425,7 @@ static void release_iso_resource(struct client *client,
schedule_iso_resource(r, 0);
}
-static int init_iso_resource(struct client *client,
- struct fw_cdev_allocate_iso_resource *request, int todo)
+static int init_iso_resource(struct client *client, struct fw_cdev_allocate_iso_resource *request)
{
struct iso_resource_event *e1, *e2;
struct iso_resource *r;
@@ -1446,7 +1445,7 @@ static int init_iso_resource(struct client *client,
INIT_DELAYED_WORK(&r->work, iso_resource_work);
r->client = client;
- r->todo = todo;
+ r->todo = ISO_RES_ALLOC;
r->e_alloc = e1;
r->e_dealloc = e2;
@@ -1455,15 +1454,10 @@ static int init_iso_resource(struct client *client,
e2->iso_resource.closure = request->closure;
e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
- if (todo == ISO_RES_ALLOC) {
- r->resource.release = release_iso_resource;
- ret = add_client_resource(client, &r->resource, GFP_KERNEL);
- if (ret < 0)
- goto fail;
- } else {
- r->resource.release = NULL;
- r->resource.handle = -1;
- }
+ r->resource.release = release_iso_resource;
+ ret = add_client_resource(client, &r->resource, GFP_KERNEL);
+ if (ret < 0)
+ goto fail;
schedule_iso_resource(r, 0);
request->handle = r->resource.handle;
@@ -1480,8 +1474,7 @@ static int init_iso_resource(struct client *client,
static int ioctl_allocate_iso_resource(struct client *client,
union ioctl_arg *arg)
{
- return init_iso_resource(client,
- &arg->allocate_iso_resource, ISO_RES_ALLOC);
+ return init_iso_resource(client, &arg->allocate_iso_resource);
}
static int ioctl_deallocate_iso_resource(struct client *client,
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6/7] firewire: core: append _auto suffix for non-once iso resource operations
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
` (4 preceding siblings ...)
2026-04-29 9:34 ` [PATCH 5/7] firewire: core: code cleanup to remove old implementations for " Takashi Sakamoto
@ 2026-04-29 9:34 ` Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 7/7] firewire: core: code cleanup for iso resource auto creation Takashi Sakamoto
2026-04-30 13:05 ` [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
The functions for iso_resource once operations are carefully split from
another type of operation.
This commit adds _auto suffix to functions for the another type so that
it is easily to distinguish them.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-cdev.c | 75 ++++++++++++++++++------------------
1 file changed, 37 insertions(+), 38 deletions(-)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index f81a8aa4bcbc..b3ce34d777c3 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -134,15 +134,15 @@ struct iso_resource_params {
s32 bandwidth;
};
-struct iso_resource {
+struct iso_resource_auto {
struct client_resource resource;
struct client *client;
/* Schedule work and access todo only with client->lock held. */
struct delayed_work work;
enum {
- ISO_RES_ALLOC,
- ISO_RES_REALLOC,
- ISO_RES_DEALLOC,
+ ISO_RES_AUTO_ALLOC,
+ ISO_RES_AUTO_REALLOC,
+ ISO_RES_AUTO_DEALLOC,
} todo;
struct iso_resource_params params;
struct iso_resource_event *e_alloc, *e_dealloc;
@@ -175,16 +175,16 @@ static struct descriptor_resource *to_descriptor_resource(struct client_resource
return container_of(resource, struct descriptor_resource, resource);
}
-static struct iso_resource *to_iso_resource(struct client_resource *resource)
+static struct iso_resource_auto *to_iso_resource_auto(struct client_resource *resource)
{
- return container_of(resource, struct iso_resource, resource);
+ return container_of(resource, struct iso_resource_auto, resource);
}
-static void release_iso_resource(struct client *, struct client_resource *);
+static void release_iso_resource_auto(struct client *, struct client_resource *);
-static int is_iso_resource(const struct client_resource *resource)
+static int is_iso_resource_auto(const struct client_resource *resource)
{
- return resource->release == release_iso_resource;
+ return resource->release == release_iso_resource_auto;
}
static void release_transaction(struct client *client,
@@ -195,7 +195,7 @@ static int is_outbound_transaction_resource(const struct client_resource *resour
return resource->release == release_transaction;
}
-static void schedule_iso_resource(struct iso_resource *r, unsigned long delay)
+static void schedule_iso_resource_auto(struct iso_resource_auto *r, unsigned long delay)
{
client_get(r->client);
if (!queue_delayed_work(fw_workqueue, &r->work, delay))
@@ -443,8 +443,8 @@ static void queue_bus_reset_event(struct client *client)
guard(spinlock_irq)(&client->lock);
xa_for_each(&client->resource_xa, index, resource) {
- if (is_iso_resource(resource))
- schedule_iso_resource(to_iso_resource(resource), 0);
+ if (is_iso_resource_auto(resource))
+ schedule_iso_resource_auto(to_iso_resource_auto(resource), 0);
}
}
@@ -1323,10 +1323,10 @@ static int fill_iso_resource_params(struct iso_resource_params *params,
return 0;
}
-static void iso_resource_work(struct work_struct *work)
+static void iso_resource_auto_work(struct work_struct *work)
{
struct iso_resource_event *e;
- struct iso_resource *r = from_work(r, work, work.work);
+ struct iso_resource_auto *r = from_work(r, work, work.work);
struct client *client = r->client;
unsigned long index = r->resource.handle;
int generation, channel, bandwidth, todo;
@@ -1336,16 +1336,16 @@ static void iso_resource_work(struct work_struct *work)
generation = client->device->generation;
todo = r->todo;
// Allow 1000ms grace period for other reallocations.
- if (todo == ISO_RES_ALLOC &&
+ if (todo == ISO_RES_AUTO_ALLOC &&
time_is_after_jiffies64(client->device->card->reset_jiffies + secs_to_jiffies(1))) {
- schedule_iso_resource(r, msecs_to_jiffies(333));
+ schedule_iso_resource_auto(r, msecs_to_jiffies(333));
skip = true;
} else {
// We could be called twice within the same generation.
- skip = todo == ISO_RES_REALLOC &&
+ skip = todo == ISO_RES_AUTO_REALLOC &&
r->params.generation == generation;
}
- free = todo == ISO_RES_DEALLOC;
+ free = todo == ISO_RES_AUTO_DEALLOC;
r->params.generation = generation;
}
@@ -1356,15 +1356,15 @@ static void iso_resource_work(struct work_struct *work)
fw_iso_resource_manage(client->device->card, generation,
r->params.channels, &channel, &bandwidth,
- todo == ISO_RES_ALLOC ||
- todo == ISO_RES_REALLOC);
+ todo == ISO_RES_AUTO_ALLOC ||
+ todo == ISO_RES_AUTO_REALLOC);
/*
* Is this generation outdated already? As long as this resource sticks
* in the xarray, it will be scheduled again for a newer generation or at
* shutdown.
*/
if (channel == -EAGAIN &&
- (todo == ISO_RES_ALLOC || todo == ISO_RES_REALLOC))
+ (todo == ISO_RES_AUTO_ALLOC || todo == ISO_RES_AUTO_REALLOC))
goto out;
success = channel >= 0 || bandwidth > 0;
@@ -1372,11 +1372,11 @@ static void iso_resource_work(struct work_struct *work)
scoped_guard(spinlock_irq, &client->lock) {
// Transit from allocation to reallocation, except if the client
// requested deallocation in the meantime.
- if (r->todo == ISO_RES_ALLOC)
- r->todo = ISO_RES_REALLOC;
+ if (r->todo == ISO_RES_AUTO_ALLOC)
+ r->todo = ISO_RES_AUTO_REALLOC;
// Allocation or reallocation failure? Pull this resource out of the
// xarray and prepare for deletion, unless the client is shutting down.
- if (r->todo == ISO_RES_REALLOC && !success &&
+ if (r->todo == ISO_RES_AUTO_REALLOC && !success &&
!client->in_shutdown &&
xa_erase(&client->resource_xa, index)) {
client_put(client);
@@ -1384,13 +1384,13 @@ static void iso_resource_work(struct work_struct *work)
}
}
- if (todo == ISO_RES_ALLOC && channel >= 0)
+ if (todo == ISO_RES_AUTO_ALLOC && channel >= 0)
r->params.channels = 1ULL << channel;
- if (todo == ISO_RES_REALLOC && success)
+ if (todo == ISO_RES_AUTO_REALLOC && success)
goto out;
- if (todo == ISO_RES_ALLOC) {
+ if (todo == ISO_RES_AUTO_ALLOC) {
e = r->e_alloc;
r->e_alloc = NULL;
} else {
@@ -1414,21 +1414,20 @@ static void iso_resource_work(struct work_struct *work)
client_put(client);
}
-static void release_iso_resource(struct client *client,
- struct client_resource *resource)
+static void release_iso_resource_auto(struct client *client, struct client_resource *resource)
{
- struct iso_resource *r = to_iso_resource(resource);
+ struct iso_resource_auto *r = to_iso_resource_auto(resource);
guard(spinlock_irq)(&client->lock);
- r->todo = ISO_RES_DEALLOC;
- schedule_iso_resource(r, 0);
+ r->todo = ISO_RES_AUTO_DEALLOC;
+ schedule_iso_resource_auto(r, 0);
}
static int init_iso_resource(struct client *client, struct fw_cdev_allocate_iso_resource *request)
{
struct iso_resource_event *e1, *e2;
- struct iso_resource *r;
+ struct iso_resource_auto *r;
int ret;
r = kmalloc_obj(*r);
@@ -1443,9 +1442,9 @@ static int init_iso_resource(struct client *client, struct fw_cdev_allocate_iso_
if (ret < 0)
goto fail;
- INIT_DELAYED_WORK(&r->work, iso_resource_work);
+ INIT_DELAYED_WORK(&r->work, iso_resource_auto_work);
r->client = client;
- r->todo = ISO_RES_ALLOC;
+ r->todo = ISO_RES_AUTO_ALLOC;
r->e_alloc = e1;
r->e_dealloc = e2;
@@ -1454,11 +1453,11 @@ static int init_iso_resource(struct client *client, struct fw_cdev_allocate_iso_
e2->iso_resource.closure = request->closure;
e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
- r->resource.release = release_iso_resource;
+ r->resource.release = release_iso_resource_auto;
ret = add_client_resource(client, &r->resource, GFP_KERNEL);
if (ret < 0)
goto fail;
- schedule_iso_resource(r, 0);
+ schedule_iso_resource_auto(r, 0);
request->handle = r->resource.handle;
@@ -1481,7 +1480,7 @@ static int ioctl_deallocate_iso_resource(struct client *client,
union ioctl_arg *arg)
{
return release_client_resource(client,
- arg->deallocate.handle, release_iso_resource, NULL);
+ arg->deallocate.handle, release_iso_resource_auto, NULL);
}
#define UNAVAILABLE_HANDLE -1
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 7/7] firewire: core: code cleanup for iso resource auto creation
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
` (5 preceding siblings ...)
2026-04-29 9:34 ` [PATCH 6/7] firewire: core: append _auto suffix for non-once iso resource operations Takashi Sakamoto
@ 2026-04-29 9:34 ` Takashi Sakamoto
2026-04-30 13:05 ` [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-29 9:34 UTC (permalink / raw)
To: linux1394-devel; +Cc: shuangpeng.kernel, dingiso.kernel, linux-kernel
The init_iso_resource function is only called by
ioctl_allocate_iso_resource(), thus no need to be unique.
This commit unifies them with minor code refactoring.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
drivers/firewire/core-cdev.c | 53 ++++++++++++++----------------------
1 file changed, 20 insertions(+), 33 deletions(-)
diff --git a/drivers/firewire/core-cdev.c b/drivers/firewire/core-cdev.c
index b3ce34d777c3..bcfb20b770df 100644
--- a/drivers/firewire/core-cdev.c
+++ b/drivers/firewire/core-cdev.c
@@ -1424,23 +1424,20 @@ static void release_iso_resource_auto(struct client *client, struct client_resou
schedule_iso_resource_auto(r, 0);
}
-static int init_iso_resource(struct client *client, struct fw_cdev_allocate_iso_resource *request)
+static int ioctl_allocate_iso_resource(struct client *client, union ioctl_arg *arg)
{
- struct iso_resource_event *e1, *e2;
- struct iso_resource_auto *r;
- int ret;
+ struct fw_cdev_allocate_iso_resource *request = &arg->allocate_iso_resource;
+ struct iso_resource_event *e1 __free(kfree) = kmalloc_obj(*e1);
+ struct iso_resource_event *e2 __free(kfree) = kmalloc_obj(*e2);
+ struct iso_resource_auto *r __free(kfree) = kmalloc_obj(*r);
+ int err;
- r = kmalloc_obj(*r);
- e1 = kmalloc_obj(*e1);
- e2 = kmalloc_obj(*e2);
- if (r == NULL || e1 == NULL || e2 == NULL) {
- ret = -ENOMEM;
- goto fail;
- }
+ if (!r || !e1 || !e2)
+ return -ENOMEM;
- ret = fill_iso_resource_params(&r->params, request);
- if (ret < 0)
- goto fail;
+ err = fill_iso_resource_params(&r->params, request);
+ if (err < 0)
+ return err;
INIT_DELAYED_WORK(&r->work, iso_resource_auto_work);
r->client = client;
@@ -1449,31 +1446,21 @@ static int init_iso_resource(struct client *client, struct fw_cdev_allocate_iso_
r->e_dealloc = e2;
e1->iso_resource.closure = request->closure;
- e1->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
+ e1->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_ALLOCATED;
e2->iso_resource.closure = request->closure;
- e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
+ e2->iso_resource.type = FW_CDEV_EVENT_ISO_RESOURCE_DEALLOCATED;
r->resource.release = release_iso_resource_auto;
- ret = add_client_resource(client, &r->resource, GFP_KERNEL);
- if (ret < 0)
- goto fail;
- schedule_iso_resource_auto(r, 0);
-
+ err = add_client_resource(client, &r->resource, GFP_KERNEL);
+ if (err < 0)
+ return err;
request->handle = r->resource.handle;
- return 0;
- fail:
- kfree(r);
- kfree(e1);
- kfree(e2);
-
- return ret;
-}
+ retain_and_null_ptr(e1);
+ retain_and_null_ptr(e2);
+ schedule_iso_resource_auto(no_free_ptr(r), 0);
-static int ioctl_allocate_iso_resource(struct client *client,
- union ioctl_arg *arg)
-{
- return init_iso_resource(client, &arg->allocate_iso_resource);
+ return 0;
}
static int ioctl_deallocate_iso_resource(struct client *client,
--
2.53.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/7] firewire: core: separate iso_resource paths
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
` (6 preceding siblings ...)
2026-04-29 9:34 ` [PATCH 7/7] firewire: core: code cleanup for iso resource auto creation Takashi Sakamoto
@ 2026-04-30 13:05 ` Takashi Sakamoto
7 siblings, 0 replies; 9+ messages in thread
From: Takashi Sakamoto @ 2026-04-30 13:05 UTC (permalink / raw)
To: linux1394-devel; +Cc: dingiso.kernel, linux-kernel, shuangpeng.kernel
On Wed, Apr 29, 2026 at 06:34:41PM +0900, Takashi Sakamoto wrote:
> Hi,
>
> (Repost since lkml was excluded.)
>
> Dingisoul has reported that a case where the reference count of a
> client structure is leaked when handling iso_resource in cdev layer[1].
> Fixing the bug immediately s difficult due to the complexity of
> per-client resource lifetime.
>
> As a first step toward addressing this issue, this patchset refactors the
> existing code for isochronous resource operation. Userspace application
> can allocate and deallocate isochronous resources on IEEE 1394 bus in two
> ways:
> * FW_CDEV_IOC_[DE]ALLOCATE_ISO_RESOURCE
> * FW_CDEV_IOC_[DE]ALLOCATE_ISO_RESOURCE_ONCE
>
> With the former, the application delegates the maintenance of the
> allocated isochronous resources to kernel and obtain a handle for the
> client resource. With the latter, the application should maintain
> isochronous resources every time receiving bus reset event, without
> relying on a handle.
>
> Currently, both operations are handled by the same code, although they
> differ in terms of client resource management.
>
> This patchset separates these two paths. As a result, it becomes clear
> that the reported issue only affects client resource allocated via the
> former method. While the actual bug fix is deferred, this refactoring
> lays the groundwork for it.
>
> [1] https://sourceforge.net/p/linux1394/mailman/linux1394-devel/thread/20260404110936.GA282614%40sakamocchi.jp/#msg59317811
>
> Takashi Sakamoto (7):
> firewire: core: code refactoring for early return at client resource
> allocation
> firewire: core: code refactoring to queue work item for iso_resource
> firewire: core: code refactoring for helper function to fill
> iso_resource parameters
> firewire: core: split functions for iso_resource once operation
> firewire: core: code cleanup to remove old implementations for once
> operation
> firewire: core: append _auto suffix for non-once iso resource
> operations
> firewire: core: code cleanup for iso resource auto creation
>
> drivers/firewire/core-cdev.c | 285 +++++++++++++++++++++--------------
> 1 file changed, 176 insertions(+), 109 deletions(-)
Applied to for-next branch.
Regards
Takashi Sakamoto
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-04-30 13:05 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-29 9:34 [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 1/7] firewire: core: code refactoring for early return at client resource allocation Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 2/7] firewire: core: code refactoring to queue work item for iso_resource Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 3/7] firewire: core: code refactoring for helper function to fill iso_resource parameters Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 4/7] firewire: core: split functions for iso_resource once operation Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 5/7] firewire: core: code cleanup to remove old implementations for " Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 6/7] firewire: core: append _auto suffix for non-once iso resource operations Takashi Sakamoto
2026-04-29 9:34 ` [PATCH 7/7] firewire: core: code cleanup for iso resource auto creation Takashi Sakamoto
2026-04-30 13:05 ` [PATCH 0/7] firewire: core: separate iso_resource paths Takashi Sakamoto
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox