summaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@nokia.com>2010-08-11 14:17:49 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-12 08:43:30 -0700
commit8d57a98ccd0b4489003473979da8f5a1363ba7a3 (patch)
tree2982997ce66bb6a92c020b7189966c3097095fd7 /block
parent93caf8e69eac763f6a20cf253ace8e7fc1ab7953 (diff)
downloadlinux-8d57a98ccd0b4489003473979da8f5a1363ba7a3.tar.gz
linux-8d57a98ccd0b4489003473979da8f5a1363ba7a3.tar.bz2
linux-8d57a98ccd0b4489003473979da8f5a1363ba7a3.zip
block: add secure discard
Secure discard is the same as discard except that all copies of the discarded sectors (perhaps created by garbage collection) must also be erased. Signed-off-by: Adrian Hunter <adrian.hunter@nokia.com> Acked-by: Jens Axboe <axboe@kernel.dk> Cc: Kyungmin Park <kmpark@infradead.org> Cc: Madhusudhan Chikkature <madhu.cr@ti.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Ben Gardiner <bengardiner@nanometrics.ca> Cc: <linux-mmc@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'block')
-rw-r--r--block/blk-core.c5
-rw-r--r--block/blk-lib.c6
-rw-r--r--block/compat_ioctl.c1
-rw-r--r--block/elevator.c6
-rw-r--r--block/ioctl.c15
5 files changed, 27 insertions, 6 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index 7da630e25ae7..ee1a1e7e63cc 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1514,7 +1514,10 @@ static inline void __generic_make_request(struct bio *bio)
if (bio_check_eod(bio, nr_sectors))
goto end_io;
- if ((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+ if ((bio->bi_rw & REQ_DISCARD) &&
+ (!blk_queue_discard(q) ||
+ ((bio->bi_rw & REQ_SECURE) &&
+ !blk_queue_secdiscard(q)))) {
err = -EOPNOTSUPP;
goto end_io;
}
diff --git a/block/blk-lib.c b/block/blk-lib.c
index c1fc55a83ba1..c392029a104e 100644
--- a/block/blk-lib.c
+++ b/block/blk-lib.c
@@ -62,6 +62,12 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
max_discard_sectors &= ~(disc_sects - 1);
}
+ if (flags & BLKDEV_IFL_SECURE) {
+ if (!blk_queue_secdiscard(q))
+ return -EOPNOTSUPP;
+ type |= DISCARD_SECURE;
+ }
+
while (nr_sects && !ret) {
bio = bio_alloc(gfp_mask, 1);
if (!bio) {
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index d53085637731..119f07b74dc0 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -703,6 +703,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
case BLKFLSBUF:
case BLKROSET:
case BLKDISCARD:
+ case BLKSECDISCARD:
/*
* the ones below are implemented in blkdev_locked_ioctl,
* but we call blkdev_ioctl, which gets the lock for us
diff --git a/block/elevator.c b/block/elevator.c
index 816a7c8d6394..ec585c9554d3 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -83,6 +83,12 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio)
return 0;
/*
+ * Don't merge discard requests and secure discard requests
+ */
+ if ((bio->bi_rw & REQ_SECURE) != (rq->bio->bi_rw & REQ_SECURE))
+ return 0;
+
+ /*
* different data direction or already started, don't merge
*/
if (bio_data_dir(bio) != rq_data_dir(rq))
diff --git a/block/ioctl.c b/block/ioctl.c
index 09fd7f1ef23a..d8052f0dabd3 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -114,8 +114,10 @@ static int blkdev_reread_part(struct block_device *bdev)
}
static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
- uint64_t len)
+ uint64_t len, int secure)
{
+ unsigned long flags = BLKDEV_IFL_WAIT;
+
if (start & 511)
return -EINVAL;
if (len & 511)
@@ -125,8 +127,9 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start,
if (start + len > (bdev->bd_inode->i_size >> 9))
return -EINVAL;
- return blkdev_issue_discard(bdev, start, len, GFP_KERNEL,
- BLKDEV_IFL_WAIT);
+ if (secure)
+ flags |= BLKDEV_IFL_SECURE;
+ return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags);
}
static int put_ushort(unsigned long arg, unsigned short val)
@@ -213,7 +216,8 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
set_device_ro(bdev, n);
return 0;
- case BLKDISCARD: {
+ case BLKDISCARD:
+ case BLKSECDISCARD: {
uint64_t range[2];
if (!(mode & FMODE_WRITE))
@@ -222,7 +226,8 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
if (copy_from_user(range, (void __user *)arg, sizeof(range)))
return -EFAULT;
- return blk_ioctl_discard(bdev, range[0], range[1]);
+ return blk_ioctl_discard(bdev, range[0], range[1],
+ cmd == BLKSECDISCARD);
}
case HDIO_GETGEO: {