[RFC] MMC: Request for comments attempt at dealing with removeable suspend/resume.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <andreiw@xxxxxxxxxxxx>
---
 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux