aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Hunter <adrian.hunter@nokia.com>2010-08-11 17:17:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-12 11:43:30 -0400
commit8d57a98ccd0b4489003473979da8f5a1363ba7a3 (patch)
tree2982997ce66bb6a92c020b7189966c3097095fd7
parent93caf8e69eac763f6a20cf253ace8e7fc1ab7953 (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.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
-rw-r--r--include/linux/blk_types.h2
-rw-r--r--include/linux/blkdev.h7
-rw-r--r--include/linux/fs.h2
-rw-r--r--kernel/trace/blktrace.c8
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
116static int blk_ioctl_discard(struct block_device *bdev, uint64_t start, 116static 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
132static int put_ushort(unsigned long arg, unsigned short val) 135static 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}
919enum{ 922enum{
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)
925extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *, 930extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *,
926 unsigned long); 931 unsigned long);
927extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, 932extern 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);