From: Adrian Hunter <adrian.hunter@nokia.com>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: Jens Axboe <axboe@kernel.dk>,
"linux-mmc@vger.kernel.org" <linux-mmc@vger.kernel.org>,
LKML <linux-kernel@vger.kernel.org>
Subject: [PATCH 3/4] mmc_block: Add BLKDISCARD, BLKSECDISCARD and BLKDISCARDZEROES support
Date: Fri, 04 Jun 2010 00:13:25 +0300 [thread overview]
Message-ID: <4C081AF5.50306@nokia.com> (raw)
>From 15f8b6cda53848ced93a20554584dc860baab8b7 Mon Sep 17 00:00:00 2001
From: Adrian Hunter <adrian.hunter@nokia.com>
Date: Thu, 3 Jun 2010 10:47:12 +0300
Subject: [PATCH 3/4] mmc_block: Add BLKDISCARD, BLKSECDISCARD and BLKDISCARDZEROES support
Add implementations for ioctls BLKDISCARD and BLKSECDISCARD, and
flag the I/O queue if the SD/MMC card zeroes erased sectors.
N.B. SD/MMC cards set erased sectors either to ones or zeroes.
Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com>
---
drivers/mmc/card/block.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/mmc/card/queue.c | 2 +
2 files changed, 154 insertions(+), 0 deletions(-)
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index cb9fbc8..67f59bc 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -31,6 +31,7 @@
#include <linux/mutex.h>
#include <linux/scatterlist.h>
#include <linux/string_helpers.h>
+#include <linux/delay.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -138,9 +139,160 @@ mmc_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
+static int mmc_blk_check_eod(struct block_device *bdev, unsigned int from,
+ unsigned int nr)
+{
+ unsigned int maxsector;
+
+ if (!nr)
+ return 0;
+
+ maxsector = bdev->bd_inode->i_size >> 9;
+ if (maxsector && (maxsector < nr || maxsector - nr < from))
+ return 1;
+
+ return 0;
+}
+
+static void mmc_blk_erase_throttle(struct mmc_blk_data *md)
+{
+ struct mmc_card *card = md->queue.card;
+ struct request_queue *q = md->queue.queue;
+ int i, ok;
+
+ for (i = 0; i < 40; i++) {
+ spin_lock_irq(q->queue_lock);
+ ok = elv_queue_empty(q);
+ spin_unlock_irq(q->queue_lock);
+ if (ok)
+ break;
+ mmc_release_host(card->host);
+ msleep(50);
+ mmc_claim_host(card->host);
+ }
+}
+
+static int mmc_blk_erase(struct mmc_blk_data *md, unsigned int from,
+ unsigned int nr)
+{
+ struct mmc_card *card = md->queue.card;
+ unsigned int n, arg;
+ int err;
+
+ if (!mmc_can_erase(card))
+ return -EOPNOTSUPP;
+
+ if (mmc_can_trim(card))
+ arg = MMC_TRIM_ARG;
+ else
+ arg = MMC_ERASE_ARG;
+
+ mmc_claim_host(card->host);
+ n = card->max_erase - (from % card->max_erase);
+ do {
+ /*
+ * Do not allow the BLKDISCARD ioctl to have priority over
+ * scheduled I/O.
+ */
+ mmc_blk_erase_throttle(md);
+ if (n > nr)
+ n = nr;
+ err = mmc_erase(card, from, n, arg);
+ if (err)
+ break;
+ from += n;
+ nr -= n;
+ n = card->max_erase;
+ } while (nr);
+ mmc_release_host(card->host);
+
+ return err;
+}
+
+static int mmc_blk_secure_erase(struct mmc_blk_data *md, unsigned int from,
+ unsigned int nr)
+{
+ struct mmc_card *card = md->queue.card;
+ unsigned int arg;
+ int err;
+
+ if (!mmc_can_secure_erase_trim(card))
+ return -EOPNOTSUPP;
+
+ if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
+ arg = MMC_SECURE_TRIM1_ARG;
+ else
+ arg = MMC_SECURE_ERASE_ARG;
+
+ mmc_claim_host(card->host);
+ /*
+ * Secure erase can be very inefficient when used with any size
+ * significantly smaller than the size of the whole card, so do not
+ * break up the original request, but still wait for scheduled I/O
+ * in case the user is trying to securely erase one partition in
+ * small pieces while still using another partition on the same card.
+ */
+ mmc_blk_erase_throttle(md);
+ err = mmc_erase(card, from, nr, arg);
+ if (!err && arg == MMC_SECURE_TRIM1_ARG)
+ err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG);
+ mmc_release_host(card->host);
+
+ return err;
+}
+
+static int mmc_blk_ioctl_discard(struct block_device *bdev, uint64_t start,
+ uint64_t len, int secure)
+{
+ struct mmc_blk_data *md = bdev->bd_disk->private_data;
+ unsigned int from, nr;
+
+ if ((start & 511) || (len & 511))
+ return -EINVAL;
+
+ start >>= 9;
+ len >>= 9;
+
+ if (start > UINT_MAX || len > UINT_MAX)
+ return -EINVAL;
+
+ from = start;
+ nr = len;
+
+ if (mmc_blk_check_eod(bdev, from, nr))
+ return -EINVAL;
+
+ if (bdev != bdev->bd_contains)
+ from += bdev->bd_part->start_sect;
+
+ if (secure)
+ return mmc_blk_secure_erase(md, from, nr);
+ else
+ return mmc_blk_erase(md, from, nr);
+}
+
+static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned cmd, unsigned long arg)
+{
+ uint64_t range[2];
+ int secure = 0;
+
+ switch (cmd) {
+ case BLKSECDISCARD:
+ secure = 1;
+ case BLKDISCARD:
+ if (copy_from_user(range, (void __user *)arg, sizeof(range)))
+ return -EFAULT;
+
+ return mmc_blk_ioctl_discard(bdev, range[0], range[1], secure);
+ }
+ return -ENOTTY;
+}
+
static const struct block_device_operations mmc_bdops = {
.open = mmc_blk_open,
.release = mmc_blk_release,
+ .ioctl = mmc_blk_ioctl,
.getgeo = mmc_blk_getgeo,
.owner = THIS_MODULE,
};
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index d6ded24..9b760d7 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -130,6 +130,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
blk_queue_prep_rq(mq->queue, mmc_prep_request);
blk_queue_ordered(mq->queue, QUEUE_ORDERED_DRAIN, NULL);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
+ if (card->erased_byte == 0)
+ mq->queue->limits.discard_zeroes_data = 1;
#ifdef CONFIG_MMC_BLOCK_BOUNCE
if (host->max_hw_segs == 1) {
--
1.6.3.3
reply other threads:[~2010-06-03 21:14 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C081AF5.50306@nokia.com \
--to=adrian.hunter@nokia.com \
--cc=akpm@linux-foundation.org \
--cc=axboe@kernel.dk \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mmc@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.