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); |