diff options
author | Adrian Hunter <adrian.hunter@nokia.com> | 2010-08-11 14:17:49 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-12 08:43:30 -0700 |
commit | 8d57a98ccd0b4489003473979da8f5a1363ba7a3 (patch) | |
tree | 2982997ce66bb6a92c020b7189966c3097095fd7 /block | |
parent | 93caf8e69eac763f6a20cf253ace8e7fc1ab7953 (diff) | |
download | lwn-8d57a98ccd0b4489003473979da8f5a1363ba7a3.tar.gz lwn-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.c | 5 | ||||
-rw-r--r-- | block/blk-lib.c | 6 | ||||
-rw-r--r-- | block/compat_ioctl.c | 1 | ||||
-rw-r--r-- | block/elevator.c | 6 | ||||
-rw-r--r-- | block/ioctl.c | 15 |
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: { |