diff options
| author | Adrian Hunter <adrian.hunter@nokia.com> | 2010-08-11 17:17:49 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-12 11:43:30 -0400 |
| commit | 8d57a98ccd0b4489003473979da8f5a1363ba7a3 (patch) | |
| tree | 2982997ce66bb6a92c020b7189966c3097095fd7 | |
| parent | 93caf8e69eac763f6a20cf253ace8e7fc1ab7953 (diff) | |
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>
| -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 | ||||
| -rw-r--r-- | include/linux/blk_types.h | 2 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 7 | ||||
| -rw-r--r-- | include/linux/fs.h | 2 | ||||
| -rw-r--r-- | kernel/trace/blktrace.c | 8 |
9 files changed, 45 insertions, 7 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) | |||
| 1514 | if (bio_check_eod(bio, nr_sectors)) | 1514 | if (bio_check_eod(bio, nr_sectors)) |
| 1515 | goto end_io; | 1515 | goto end_io; |
| 1516 | 1516 | ||
| 1517 | if ((bio->bi_rw & REQ_DISCARD) && !blk_queue_discard(q)) { | 1517 | if ((bio->bi_rw & REQ_DISCARD) && |
| 1518 | (!blk_queue_discard(q) || | ||
| 1519 | ((bio->bi_rw & REQ_SECURE) && | ||
| 1520 | !blk_queue_secdiscard(q)))) { | ||
| 1518 | err = -EOPNOTSUPP; | 1521 | err = -EOPNOTSUPP; |
| 1519 | goto end_io; | 1522 | goto end_io; |
| 1520 | } | 1523 | } |
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, | |||
| 62 | max_discard_sectors &= ~(disc_sects - 1); | 62 | max_discard_sectors &= ~(disc_sects - 1); |
| 63 | } | 63 | } |
| 64 | 64 | ||
| 65 | if (flags & BLKDEV_IFL_SECURE) { | ||
| 66 | if (!blk_queue_secdiscard(q)) | ||
| 67 | return -EOPNOTSUPP; | ||
| 68 | type |= DISCARD_SECURE; | ||
| 69 | } | ||
| 70 | |||
| 65 | while (nr_sects && !ret) { | 71 | while (nr_sects && !ret) { |
| 66 | bio = bio_alloc(gfp_mask, 1); | 72 | bio = bio_alloc(gfp_mask, 1); |
| 67 | if (!bio) { | 73 | 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) | |||
| 703 | case BLKFLSBUF: | 703 | case BLKFLSBUF: |
| 704 | case BLKROSET: | 704 | case BLKROSET: |
| 705 | case BLKDISCARD: | 705 | case BLKDISCARD: |
| 706 | case BLKSECDISCARD: | ||
| 706 | /* | 707 | /* |
| 707 | * the ones below are implemented in blkdev_locked_ioctl, | 708 | * the ones below are implemented in blkdev_locked_ioctl, |
| 708 | * but we call blkdev_ioctl, which gets the lock for us | 709 | * 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) | |||
| 83 | return 0; | 83 | return 0; |
| 84 | 84 | ||
| 85 | /* | 85 | /* |
| 86 | * Don't merge discard requests and secure discard requests | ||
| 87 | */ | ||
| 88 | if ((bio->bi_rw & REQ_SECURE) != (rq->bio->bi_rw & REQ_SECURE)) | ||
| 89 | return 0; | ||
| 90 | |||
| 91 | /* | ||
| 86 | * different data direction or already started, don't merge | 92 | * different data direction or already started, don't merge |
| 87 | */ | 93 | */ |
| 88 | if (bio_data_dir(bio) != rq_data_dir(rq)) | 94 | 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) | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, | 116 | static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, |
| 117 | uint64_t len) | 117 | uint64_t len, int secure) |
| 118 | { | 118 | { |
| 119 | unsigned long flags = BLKDEV_IFL_WAIT; | ||
| 120 | |||
| 119 | if (start & 511) | 121 | if (start & 511) |
| 120 | return -EINVAL; | 122 | return -EINVAL; |
| 121 | if (len & 511) | 123 | if (len & 511) |
| @@ -125,8 +127,9 @@ static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, | |||
| 125 | 127 | ||
| 126 | if (start + len > (bdev->bd_inode->i_size >> 9)) | 128 | if (start + len > (bdev->bd_inode->i_size >> 9)) |
| 127 | return -EINVAL; | 129 | return -EINVAL; |
| 128 | return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, | 130 | if (secure) |
| 129 | BLKDEV_IFL_WAIT); | 131 | flags |= BLKDEV_IFL_SECURE; |
| 132 | return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags); | ||
| 130 | } | 133 | } |
| 131 | 134 | ||
| 132 | static int put_ushort(unsigned long arg, unsigned short val) | 135 | 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, | |||
| 213 | set_device_ro(bdev, n); | 216 | set_device_ro(bdev, n); |
| 214 | return 0; | 217 | return 0; |
| 215 | 218 | ||
| 216 | case BLKDISCARD: { | 219 | case BLKDISCARD: |
| 220 | case BLKSECDISCARD: { | ||
| 217 | uint64_t range[2]; | 221 | uint64_t range[2]; |
| 218 | 222 | ||
| 219 | if (!(mode & FMODE_WRITE)) | 223 | if (!(mode & FMODE_WRITE)) |
| @@ -222,7 +226,8 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, | |||
| 222 | if (copy_from_user(range, (void __user *)arg, sizeof(range))) | 226 | if (copy_from_user(range, (void __user *)arg, sizeof(range))) |
| 223 | return -EFAULT; | 227 | return -EFAULT; |
| 224 | 228 | ||
| 225 | return blk_ioctl_discard(bdev, range[0], range[1]); | 229 | return blk_ioctl_discard(bdev, range[0], range[1], |
| 230 | cmd == BLKSECDISCARD); | ||
| 226 | } | 231 | } |
| 227 | 232 | ||
| 228 | case HDIO_GETGEO: { | 233 | case HDIO_GETGEO: { |
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 53691774d34e..ca83a97c9715 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h | |||
| @@ -150,6 +150,7 @@ enum rq_flag_bits { | |||
| 150 | __REQ_FLUSH, /* request for cache flush */ | 150 | __REQ_FLUSH, /* request for cache flush */ |
| 151 | __REQ_IO_STAT, /* account I/O stat */ | 151 | __REQ_IO_STAT, /* account I/O stat */ |
| 152 | __REQ_MIXED_MERGE, /* merge of different types, fail separately */ | 152 | __REQ_MIXED_MERGE, /* merge of different types, fail separately */ |
| 153 | __REQ_SECURE, /* secure discard (used with __REQ_DISCARD) */ | ||
| 153 | __REQ_NR_BITS, /* stops here */ | 154 | __REQ_NR_BITS, /* stops here */ |
| 154 | }; | 155 | }; |
| 155 | 156 | ||
| @@ -190,5 +191,6 @@ enum rq_flag_bits { | |||
| 190 | #define REQ_FLUSH (1 << __REQ_FLUSH) | 191 | #define REQ_FLUSH (1 << __REQ_FLUSH) |
| 191 | #define REQ_IO_STAT (1 << __REQ_IO_STAT) | 192 | #define REQ_IO_STAT (1 << __REQ_IO_STAT) |
| 192 | #define REQ_MIXED_MERGE (1 << __REQ_MIXED_MERGE) | 193 | #define REQ_MIXED_MERGE (1 << __REQ_MIXED_MERGE) |
| 194 | #define REQ_SECURE (1 << __REQ_SECURE) | ||
| 193 | 195 | ||
| 194 | #endif /* __LINUX_BLK_TYPES_H */ | 196 | #endif /* __LINUX_BLK_TYPES_H */ |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 89c855c5655c..2c54906f678f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
| @@ -389,6 +389,7 @@ struct request_queue | |||
| 389 | #define QUEUE_FLAG_DISCARD 16 /* supports DISCARD */ | 389 | #define QUEUE_FLAG_DISCARD 16 /* supports DISCARD */ |
| 390 | #define QUEUE_FLAG_NOXMERGES 17 /* No extended merges */ | 390 | #define QUEUE_FLAG_NOXMERGES 17 /* No extended merges */ |
| 391 | #define QUEUE_FLAG_ADD_RANDOM 18 /* Contributes to random pool */ | 391 | #define QUEUE_FLAG_ADD_RANDOM 18 /* Contributes to random pool */ |
| 392 | #define QUEUE_FLAG_SECDISCARD 19 /* supports SECDISCARD */ | ||
| 392 | 393 | ||
| 393 | #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ | 394 | #define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ |
| 394 | (1 << QUEUE_FLAG_CLUSTER) | \ | 395 | (1 << QUEUE_FLAG_CLUSTER) | \ |
| @@ -524,6 +525,8 @@ enum { | |||
| 524 | #define blk_queue_stackable(q) \ | 525 | #define blk_queue_stackable(q) \ |
| 525 | test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags) | 526 | test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags) |
| 526 | #define blk_queue_discard(q) test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags) | 527 | #define blk_queue_discard(q) test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags) |
| 528 | #define blk_queue_secdiscard(q) (blk_queue_discard(q) && \ | ||
| 529 | test_bit(QUEUE_FLAG_SECDISCARD, &(q)->queue_flags)) | ||
| 527 | 530 | ||
| 528 | #define blk_noretry_request(rq) \ | 531 | #define blk_noretry_request(rq) \ |
| 529 | ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ | 532 | ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ |
| @@ -918,10 +921,12 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, | |||
| 918 | } | 921 | } |
| 919 | enum{ | 922 | enum{ |
| 920 | BLKDEV_WAIT, /* wait for completion */ | 923 | BLKDEV_WAIT, /* wait for completion */ |
| 921 | BLKDEV_BARRIER, /*issue request with barrier */ | 924 | BLKDEV_BARRIER, /* issue request with barrier */ |
| 925 | BLKDEV_SECURE, /* secure discard */ | ||
| 922 | }; | 926 | }; |
| 923 | #define BLKDEV_IFL_WAIT (1 << BLKDEV_WAIT) | 927 | #define BLKDEV_IFL_WAIT (1 << BLKDEV_WAIT) |
| 924 | #define BLKDEV_IFL_BARRIER (1 << BLKDEV_BARRIER) | 928 | #define BLKDEV_IFL_BARRIER (1 << BLKDEV_BARRIER) |
| 929 | #define BLKDEV_IFL_SECURE (1 << BLKDEV_SECURE) | ||
| 925 | extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *, | 930 | extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *, |
| 926 | unsigned long); | 931 | unsigned long); |
| 927 | extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, | 932 | extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 267d02630517..7a0625e26a39 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -174,6 +174,7 @@ struct inodes_stat_t { | |||
| 174 | */ | 174 | */ |
| 175 | #define DISCARD_NOBARRIER (WRITE | REQ_DISCARD) | 175 | #define DISCARD_NOBARRIER (WRITE | REQ_DISCARD) |
| 176 | #define DISCARD_BARRIER (WRITE | REQ_DISCARD | REQ_HARDBARRIER) | 176 | #define DISCARD_BARRIER (WRITE | REQ_DISCARD | REQ_HARDBARRIER) |
| 177 | #define DISCARD_SECURE (DISCARD_NOBARRIER | REQ_SECURE) | ||
| 177 | 178 | ||
| 178 | #define SEL_IN 1 | 179 | #define SEL_IN 1 |
| 179 | #define SEL_OUT 2 | 180 | #define SEL_OUT 2 |
| @@ -317,6 +318,7 @@ struct inodes_stat_t { | |||
| 317 | #define BLKALIGNOFF _IO(0x12,122) | 318 | #define BLKALIGNOFF _IO(0x12,122) |
| 318 | #define BLKPBSZGET _IO(0x12,123) | 319 | #define BLKPBSZGET _IO(0x12,123) |
| 319 | #define BLKDISCARDZEROES _IO(0x12,124) | 320 | #define BLKDISCARDZEROES _IO(0x12,124) |
| 321 | #define BLKSECDISCARD _IO(0x12,125) | ||
| 320 | 322 | ||
| 321 | #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ | 323 | #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ |
| 322 | #define FIBMAP _IO(0x00,1) /* bmap access */ | 324 | #define FIBMAP _IO(0x00,1) /* bmap access */ |
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index 82499a5bdcb7..959f8d6c8cc1 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c | |||
| @@ -710,6 +710,9 @@ static void blk_add_trace_rq(struct request_queue *q, struct request *rq, | |||
| 710 | if (rq->cmd_flags & REQ_DISCARD) | 710 | if (rq->cmd_flags & REQ_DISCARD) |
| 711 | rw |= REQ_DISCARD; | 711 | rw |= REQ_DISCARD; |
| 712 | 712 | ||
| 713 | if (rq->cmd_flags & REQ_SECURE) | ||
| 714 | rw |= REQ_SECURE; | ||
| 715 | |||
| 713 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { | 716 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { |
| 714 | what |= BLK_TC_ACT(BLK_TC_PC); | 717 | what |= BLK_TC_ACT(BLK_TC_PC); |
| 715 | __blk_add_trace(bt, 0, blk_rq_bytes(rq), rw, | 718 | __blk_add_trace(bt, 0, blk_rq_bytes(rq), rw, |
| @@ -1816,6 +1819,8 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes) | |||
| 1816 | rwbs[i++] = 'S'; | 1819 | rwbs[i++] = 'S'; |
| 1817 | if (rw & REQ_META) | 1820 | if (rw & REQ_META) |
| 1818 | rwbs[i++] = 'M'; | 1821 | rwbs[i++] = 'M'; |
| 1822 | if (rw & REQ_SECURE) | ||
| 1823 | rwbs[i++] = 'E'; | ||
| 1819 | 1824 | ||
| 1820 | rwbs[i] = '\0'; | 1825 | rwbs[i] = '\0'; |
| 1821 | } | 1826 | } |
| @@ -1828,6 +1833,9 @@ void blk_fill_rwbs_rq(char *rwbs, struct request *rq) | |||
| 1828 | if (rq->cmd_flags & REQ_DISCARD) | 1833 | if (rq->cmd_flags & REQ_DISCARD) |
| 1829 | rw |= REQ_DISCARD; | 1834 | rw |= REQ_DISCARD; |
| 1830 | 1835 | ||
| 1836 | if (rq->cmd_flags & REQ_SECURE) | ||
| 1837 | rw |= REQ_SECURE; | ||
| 1838 | |||
| 1831 | bytes = blk_rq_bytes(rq); | 1839 | bytes = blk_rq_bytes(rq); |
| 1832 | 1840 | ||
| 1833 | blk_fill_rwbs(rwbs, rw, bytes); | 1841 | blk_fill_rwbs(rwbs, rw, bytes); |
