On Thu, Jan 08, 2026 at 02:10PM -0800, 'Bart Van Assche' via kasan-dev wrote:
> On 12/19/25 8:39 AM, Marco Elver wrote:
> > diff --git a/include/linux/mutex.h b/include/linux/mutex.h
> > index bf535f0118bb..89977c215cbd 100644
> > --- a/include/linux/mutex.h
> > +++ b/include/linux/mutex.h
> > @@ -62,6 +62,7 @@ do {
> > \
> > static struct lock_class_key __key; \
> > \
> > __mutex_init((mutex), #mutex, &__key); \
> > + __assume_ctx_lock(mutex); \
> > } while (0)
>
> The above type of change probably will have to be reverted. If I enable
> context analysis for the entire kernel tree, drivers/base/devcoredump.c
> doesn't build. The following error is reported:
>
> drivers/base/devcoredump.c:406:2: error: acquiring mutex '_res->mutex' that
> is already held [-Werror,-Wthread-safety-analysis]
> 406 | mutex_lock(&devcd->mutex);
> | ^
>
> dev_coredumpm_timeout() calls mutex_init() and mutex_lock() from the same
> function. The above type of change breaks compilation of all code
> that initializes and locks a synchronization object from the same
> function. My understanding of dev_coredumpm_timeout() is that there is a
> good reason for calling both mutex_init() and mutex_lock() from that
> function. Possible solutions are disabling context analysis for that
> function or removing __assume_ctx_lock() again from mutex_init(). Does
> anyone want to share their opinion about this?
Probably the most idiomatic option is to just factor out construction.
Clearly separating complex object construction from use also helps
readability regardless, esp. where concurrency is involved. We could
document such advice somewhere.
For the above case, this seems cleanest and also clearer to me:
diff --git a/drivers/base/devcoredump.c b/drivers/base/devcoredump.c
index 55bdc7f5e59d..56ac8aa41608 100644
--- a/drivers/base/devcoredump.c
+++ b/drivers/base/devcoredump.c
@@ -339,6 +339,40 @@ void dev_coredump_put(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_coredump_put);
+static struct devcd_entry *
+dev_coredumpm_init(struct device *dev, struct module *owner, void *data,
+ size_t datalen, gfp_t gfp,
+ ssize_t (*read)(char *buffer, loff_t offset, size_t count,
+ void *data, size_t datalen),
+ void (*free)(void *data))
+{
+ static atomic_t devcd_count = ATOMIC_INIT(0);
+ struct devcd_entry *devcd;
+
+ devcd = kzalloc(sizeof(*devcd), gfp);
+ if (!devcd)
+ return NULL;
+
+ devcd->owner = owner;
+ devcd->data = data;
+ devcd->datalen = datalen;
+ devcd->read = read;
+ devcd->free = free;
+ devcd->failing_dev = get_device(dev);
+ devcd->deleted = false;
+
+ mutex_init(&devcd->mutex);
+ device_initialize(&devcd->devcd_dev);
+
+ dev_set_name(&devcd->devcd_dev, "devcd%d",
+ atomic_inc_return(&devcd_count));
+ devcd->devcd_dev.class = &devcd_class;
+
+ dev_set_uevent_suppress(&devcd->devcd_dev, true);
+
+ return devcd;
+}
+
/**
* dev_coredumpm_timeout - create device coredump with read/free methods with a
* custom timeout.
@@ -364,7 +398,6 @@ void dev_coredumpm_timeout(struct device *dev, struct
module *owner,
void (*free)(void *data),
unsigned long timeout)
{
- static atomic_t devcd_count = ATOMIC_INIT(0);
struct devcd_entry *devcd;
struct device *existing;
@@ -381,27 +414,10 @@ void dev_coredumpm_timeout(struct device *dev, struct
module *owner,
if (!try_module_get(owner))
goto free;
- devcd = kzalloc(sizeof(*devcd), gfp);
+ devcd = dev_coredumpm_init(dev, owner, data, datalen, gfp, read, free);
if (!devcd)
goto put_module;
- devcd->owner = owner;
- devcd->data = data;
- devcd->datalen = datalen;
- devcd->read = read;
- devcd->free = free;
- devcd->failing_dev = get_device(dev);
- devcd->deleted = false;
-
- mutex_init(&devcd->mutex);
- device_initialize(&devcd->devcd_dev);
-
- dev_set_name(&devcd->devcd_dev, "devcd%d",
- atomic_inc_return(&devcd_count));
- devcd->devcd_dev.class = &devcd_class;
-
- dev_set_uevent_suppress(&devcd->devcd_dev, true);
-
/* devcd->mutex prevents devcd_del() completing until init finishes */
mutex_lock(&devcd->mutex);
devcd->init_completed = false;