Merge tag 'mmc-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Jul 2021 16:51:38 +0000 (09:51 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 22 Jul 2021 16:51:38 +0000 (09:51 -0700)
Pull MMC fixes from Ulf Hansson:

 - Use kref to fix KASAN splats triggered during card removal

 - Don't allocate IDA for OF aliases

* tag 'mmc-v5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: core: Don't allocate IDA for OF aliases
  mmc: core: Use kref in place of struct mmc_blk_data::usage

drivers/mmc/core/block.c
drivers/mmc/core/host.c

index 9890a15..ce8aed5 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/errno.h>
 #include <linux/hdreg.h>
 #include <linux/kdev_t.h>
+#include <linux/kref.h>
 #include <linux/blkdev.h>
 #include <linux/cdev.h>
 #include <linux/mutex.h>
@@ -111,7 +112,7 @@ struct mmc_blk_data {
 #define MMC_BLK_CMD23  (1 << 0)        /* Can do SET_BLOCK_COUNT for multiblock */
 #define MMC_BLK_REL_WR (1 << 1)        /* MMC Reliable write support */
 
-       unsigned int    usage;
+       struct kref     kref;
        unsigned int    read_only;
        unsigned int    part_type;
        unsigned int    reset_done;
@@ -181,10 +182,8 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
 
        mutex_lock(&open_lock);
        md = disk->private_data;
-       if (md && md->usage == 0)
+       if (md && !kref_get_unless_zero(&md->kref))
                md = NULL;
-       if (md)
-               md->usage++;
        mutex_unlock(&open_lock);
 
        return md;
@@ -196,18 +195,25 @@ static inline int mmc_get_devidx(struct gendisk *disk)
        return devidx;
 }
 
-static void mmc_blk_put(struct mmc_blk_data *md)
+static void mmc_blk_kref_release(struct kref *ref)
 {
-       mutex_lock(&open_lock);
-       md->usage--;
-       if (md->usage == 0) {
-               int devidx = mmc_get_devidx(md->disk);
+       struct mmc_blk_data *md = container_of(ref, struct mmc_blk_data, kref);
+       int devidx;
 
-               ida_simple_remove(&mmc_blk_ida, devidx);
-               put_disk(md->disk);
-               kfree(md);
-       }
+       devidx = mmc_get_devidx(md->disk);
+       ida_simple_remove(&mmc_blk_ida, devidx);
+
+       mutex_lock(&open_lock);
+       md->disk->private_data = NULL;
        mutex_unlock(&open_lock);
+
+       put_disk(md->disk);
+       kfree(md);
+}
+
+static void mmc_blk_put(struct mmc_blk_data *md)
+{
+       kref_put(&md->kref, mmc_blk_kref_release);
 }
 
 static ssize_t power_ro_lock_show(struct device *dev,
@@ -2327,7 +2333,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
 
        INIT_LIST_HEAD(&md->part);
        INIT_LIST_HEAD(&md->rpmbs);
-       md->usage = 1;
+       kref_init(&md->kref);
+
        md->queue.blkdata = md;
 
        md->disk->major = MMC_BLOCK_MAJOR;
index eda4a18..0475d96 100644 (file)
@@ -75,7 +75,8 @@ static void mmc_host_classdev_release(struct device *dev)
 {
        struct mmc_host *host = cls_dev_to_mmc_host(dev);
        wakeup_source_unregister(host->ws);
-       ida_simple_remove(&mmc_host_ida, host->index);
+       if (of_alias_get_id(host->parent->of_node, "mmc") < 0)
+               ida_simple_remove(&mmc_host_ida, host->index);
        kfree(host);
 }
 
@@ -502,7 +503,7 @@ static int mmc_first_nonreserved_index(void)
  */
 struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 {
-       int err;
+       int index;
        struct mmc_host *host;
        int alias_id, min_idx, max_idx;
 
@@ -515,20 +516,19 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
 
        alias_id = of_alias_get_id(dev->of_node, "mmc");
        if (alias_id >= 0) {
-               min_idx = alias_id;
-               max_idx = alias_id + 1;
+               index = alias_id;
        } else {
                min_idx = mmc_first_nonreserved_index();
                max_idx = 0;
-       }
 
-       err = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL);
-       if (err < 0) {
-               kfree(host);
-               return NULL;
+               index = ida_simple_get(&mmc_host_ida, min_idx, max_idx, GFP_KERNEL);
+               if (index < 0) {
+                       kfree(host);
+                       return NULL;
+               }
        }
 
-       host->index = err;
+       host->index = index;
 
        dev_set_name(&host->class_dev, "mmc%d", host->index);
        host->ws = wakeup_source_register(NULL, dev_name(&host->class_dev));