Is there any value to doing something like this in order to be able to 
suspend/resume
with a (manually, or rootfs) mounted filesystem on mmcblk?

Thoughts?

Signed-off-by: Andrei Warkentin <[email protected]>
---
 drivers/mmc/card/block.c |   76 +++++++++++++++++++++++++++++++++++++++++----
 drivers/mmc/core/core.c  |    3 +-
 2 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index ee8f7a9..19eb5b6 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -53,6 +53,9 @@ MODULE_ALIAS("mmc:block");
      ((card)->ext_csd.rel_sectors)))
 
 static DEFINE_MUTEX(block_mutex);
+static DEFINE_MUTEX(orphan_mutex);
+
+struct list_head orphans = LIST_HEAD_INIT(orphans);
 
 /*
  * The defaults come from config options but can be overriden by module
@@ -77,6 +80,7 @@ struct mmc_blk_data {
        struct gendisk  *disk;
        struct mmc_queue queue;
        struct list_head part;
+       struct list_head orphan;
 
        unsigned int    usage;
        unsigned int    read_only;
@@ -88,6 +92,7 @@ struct mmc_blk_data {
         * track of the current selected device partition.
         */
        unsigned int    part_curr;
+       u32             raw_cid[4];
        struct device_attribute force_ro;
 };
 
@@ -126,10 +131,12 @@ static void mmc_blk_put(struct mmc_blk_data *md)
        mutex_lock(&open_lock);
        md->usage--;
        if (md->usage == 0) {
-               int devidx = mmc_get_devidx(md->disk);
-               blk_cleanup_queue(md->queue.queue);
+               mutex_lock(&orphan_mutex);
+               list_del(&md->orphan);
+               mutex_unlock(&orphan_mutex);
 
-               __clear_bit(devidx, dev_use);
+               blk_cleanup_queue(md->queue.queue);
+               __clear_bit(mmc_get_devidx(md->disk), dev_use);
 
                put_disk(md->disk);
                kfree(md);
@@ -718,6 +725,49 @@ static inline int mmc_blk_readonly(struct mmc_card *card)
               !(card->csd.cmdclass & CCC_BLOCK_WRITE);
 }
 
+static inline struct mmc_blk_data *mmc_lookup_orphan(struct mmc_card *card,
+                                                    struct device *parent,
+                                                    unsigned int part_type,
+                                                    sector_t size)
+{
+       int ret;
+       struct list_head *pos, *q;
+       struct mmc_blk_data *md;
+       bool found = false;
+
+       mutex_lock(&orphan_mutex);
+       list_for_each_safe(pos, q, &orphans) {
+               md = list_entry(pos, struct mmc_blk_data, orphan);
+               if (!memcmp(md->raw_cid, card->raw_cid, sizeof(md->raw_cid)) &&
+                   md->part_type == part_type) {
+                       list_del(pos);
+                       found = true;
+                       mmc_blk_get(md->disk);
+                       break;
+               }
+       }
+       mutex_unlock(&orphan_mutex);
+
+       if (!found)
+               return NULL;
+
+       ret = mmc_init_queue(&md->queue, card, &md->lock);
+       if (ret)
+               return NULL;
+
+       INIT_LIST_HEAD(&md->part);
+       md->disk->driverfs_dev = parent;
+       md->queue.issue_fn = mmc_blk_issue_rq;
+       md->queue.data = md;
+       md->disk->queue = md->queue.queue;
+       if (REL_WRITES_SUPPORTED(card))
+               blk_queue_flush(md->queue.queue, REQ_FLUSH | REQ_FUA);
+       blk_queue_logical_block_size(md->queue.queue, 512);
+       set_capacity(md->disk, size);
+       printk("set cap to %x\n", (unsigned int) get_capacity(md->disk));
+       return md;
+}
+
 static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
                                              struct device *parent,
                                              sector_t size,
@@ -752,7 +802,9 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct 
mmc_card *card,
 
        spin_lock_init(&md->lock);
        INIT_LIST_HEAD(&md->part);
+       INIT_LIST_HEAD(&md->orphan);
        md->usage = 1;
+       memcpy(md->raw_cid, card->raw_cid, sizeof(card->raw_cid));
 
        ret = mmc_init_queue(&md->queue, card, &md->lock);
        if (ret)
@@ -822,7 +874,9 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card 
*card)
                size = card->csd.capacity << (card->csd.read_blkbits - 9);
        }
 
-       md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
+       md = mmc_lookup_orphan(card, &card->dev, 0, size);
+       if (!md)
+               md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL);
        return md;
 }
 
@@ -836,8 +890,10 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
        char cap_str[10];
        struct mmc_blk_data *part_md;
 
-       part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, 
default_ro,
-                                   subname);
+       part_md = mmc_lookup_orphan(card, disk_to_dev(md->disk), part_type, 
size);
+       if (!part_md)
+               part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size,
+                                           default_ro, subname);
        if (IS_ERR(part_md))
                return PTR_ERR(part_md);
        part_md->part_type = part_type;
@@ -906,6 +962,10 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
 
                /* Then flush out any already in there */
                mmc_cleanup_queue(&md->queue);
+
+               mutex_lock(&orphan_mutex);
+               list_add(&md->orphan, &orphans);
+               mutex_unlock(&orphan_mutex);
                mmc_blk_put(md);
        }
 }
@@ -933,8 +993,10 @@ static int mmc_add_disk(struct mmc_blk_data *md)
        md->force_ro.attr.name = "force_ro";
        md->force_ro.attr.mode = S_IRUGO | S_IWUSR;
        ret = device_create_file(disk_to_dev(md->disk), &md->force_ro);
-       if (ret)
+       if (ret) {
                del_gendisk(md->disk);
+               return ret;
+       }
 
        return ret;
 }
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 85ef72c..87c4af7 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1823,11 +1823,10 @@ int mmc_pm_notify(struct notifier_block *notify_block,
                if (!host->bus_ops || host->bus_ops->suspend)
                        break;
 
-               mmc_claim_host(host);
-
                if (host->bus_ops->remove)
                        host->bus_ops->remove(host);
 
+               mmc_claim_host(host);
                mmc_detach_bus(host);
                mmc_release_host(host);
                host->pm_flags = 0;
-- 
1.7.0.4

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to