Skip to content

Commit 10252ba

Browse files
bebarinostorulf
authored andcommitted
mmc: core: Don't allocate IDA for OF aliases
There's a chance that the IDA allocated in mmc_alloc_host() is not freed for some time because it's freed as part of a class' release function (see mmc_host_classdev_release() where the IDA is freed). If another thread is holding a reference to the class, then only once all balancing device_put() calls (in turn calling kobject_put()) have been made will the IDA be released and usable again. Normally this isn't a problem because the kobject is released before anything else that may want to use the same number tries to again, but with CONFIG_DEBUG_KOBJECT_RELEASE=y and OF aliases it becomes pretty easy to try to allocate an alias from the IDA twice while the first time it was allocated is still pending a call to ida_simple_remove(). It's also possible to trigger it by using CONFIG_DEBUG_KOBJECT_RELEASE and probe defering a driver at boot that calls mmc_alloc_host() before trying to get resources that may defer likes clks or regulators. Instead of allocating from the IDA in this scenario, let's just skip it if we know this is an OF alias. The number is already "claimed" and devices that aren't using OF aliases won't try to use the claimed numbers anyway (see mmc_first_nonreserved_index()). This should avoid any issues with mmc_alloc_host() returning failures from the ida_simple_get() in the case that we're using an OF alias. Cc: Matthias Schiffer <matthias.schiffer@ew.tq-group.com> Cc: Sujit Kautkar <sujitka@chromium.org> Reported-by: Zubin Mithra <zsm@chromium.org> Fixes: fa2d0aa ("mmc: core: Allow setting slot index via device tree alias") Signed-off-by: Stephen Boyd <swboyd@chromium.org> Link: https://lore.kernel.org/r/20210623075002.1746924-3-swboyd@chromium.org Cc: stable@vger.kernel.org Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
1 parent edb2557 commit 10252ba

File tree

1 file changed

+10
-10
lines changed

1 file changed

+10
-10
lines changed

drivers/mmc/core/host.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ static void mmc_host_classdev_release(struct device *dev)
7575
{
7676
struct mmc_host *host = cls_dev_to_mmc_host(dev);
7777
wakeup_source_unregister(host->ws);
78-
ida_simple_remove(&mmc_host_ida, host->index);
78+
if (of_alias_get_id(host->parent->of_node, "mmc") < 0)
79+
ida_simple_remove(&mmc_host_ida, host->index);
7980
kfree(host);
8081
}
8182

@@ -502,7 +503,7 @@ static int mmc_first_nonreserved_index(void)
502503
*/
503504
struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
504505
{
505-
int err;
506+
int index;
506507
struct mmc_host *host;
507508
int alias_id, min_idx, max_idx;
508509

@@ -515,20 +516,19 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
515516

516517
alias_id = of_alias_get_id(dev->of_node, "mmc");
517518
if (alias_id >= 0) {
518-
min_idx = alias_id;
519-
max_idx = alias_id + 1;
519+
index = alias_id;
520520
} else {
521521
min_idx = mmc_first_nonreserved_index();
522522
max_idx = 0;
523-
}
524523

525-
err = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL);
526-
if (err < 0) {
527-
kfree(host);
528-
return NULL;
524+
index = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL);
525+
if (index < 0) {
526+
kfree(host);
527+
return NULL;
528+
}
529529
}
530530

531-
host->index = err;
531+
host->index = index;
532532

533533
dev_set_name(&host->class_dev, "mmc%d", host->index);
534534
host->ws = wakeup_source_register(NULL, dev_name(&host->class_dev));

0 commit comments

Comments
 (0)