diff options
| -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)  		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: { 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 {  	__REQ_FLUSH,		/* request for cache flush */  	__REQ_IO_STAT,		/* account I/O stat */  	__REQ_MIXED_MERGE,	/* merge of different types, fail separately */ +	__REQ_SECURE,		/* secure discard (used with __REQ_DISCARD) */  	__REQ_NR_BITS,		/* stops here */  }; @@ -190,5 +191,6 @@ enum rq_flag_bits {  #define REQ_FLUSH		(1 << __REQ_FLUSH)  #define REQ_IO_STAT		(1 << __REQ_IO_STAT)  #define REQ_MIXED_MERGE		(1 << __REQ_MIXED_MERGE) +#define REQ_SECURE		(1 << __REQ_SECURE)  #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  #define QUEUE_FLAG_DISCARD     16	/* supports DISCARD */  #define QUEUE_FLAG_NOXMERGES   17	/* No extended merges */  #define QUEUE_FLAG_ADD_RANDOM  18	/* Contributes to random pool */ +#define QUEUE_FLAG_SECDISCARD  19	/* supports SECDISCARD */  #define QUEUE_FLAG_DEFAULT	((1 << QUEUE_FLAG_IO_STAT) |		\  				 (1 << QUEUE_FLAG_CLUSTER) |		\ @@ -524,6 +525,8 @@ enum {  #define blk_queue_stackable(q)	\  	test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags)  #define blk_queue_discard(q)	test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags) +#define blk_queue_secdiscard(q)	(blk_queue_discard(q) && \ +	test_bit(QUEUE_FLAG_SECDISCARD, &(q)->queue_flags))  #define blk_noretry_request(rq) \  	((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,  }  enum{  	BLKDEV_WAIT,	/* wait for completion */ -	BLKDEV_BARRIER,	/*issue request with barrier */ +	BLKDEV_BARRIER,	/* issue request with barrier */ +	BLKDEV_SECURE,	/* secure discard */  };  #define BLKDEV_IFL_WAIT		(1 << BLKDEV_WAIT)  #define BLKDEV_IFL_BARRIER	(1 << BLKDEV_BARRIER) +#define BLKDEV_IFL_SECURE	(1 << BLKDEV_SECURE)  extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *,  			unsigned long);  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 {   */  #define DISCARD_NOBARRIER	(WRITE | REQ_DISCARD)  #define DISCARD_BARRIER		(WRITE | REQ_DISCARD | REQ_HARDBARRIER) +#define DISCARD_SECURE		(DISCARD_NOBARRIER | REQ_SECURE)  #define SEL_IN		1  #define SEL_OUT		2 @@ -317,6 +318,7 @@ struct inodes_stat_t {  #define BLKALIGNOFF _IO(0x12,122)  #define BLKPBSZGET _IO(0x12,123)  #define BLKDISCARDZEROES _IO(0x12,124) +#define BLKSECDISCARD _IO(0x12,125)  #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */  #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,  	if (rq->cmd_flags & REQ_DISCARD)  		rw |= REQ_DISCARD; +	if (rq->cmd_flags & REQ_SECURE) +		rw |= REQ_SECURE; +  	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {  		what |= BLK_TC_ACT(BLK_TC_PC);  		__blk_add_trace(bt, 0, blk_rq_bytes(rq), rw, @@ -1816,6 +1819,8 @@ void blk_fill_rwbs(char *rwbs, u32 rw, int bytes)  		rwbs[i++] = 'S';  	if (rw & REQ_META)  		rwbs[i++] = 'M'; +	if (rw & REQ_SECURE) +		rwbs[i++] = 'E';  	rwbs[i] = '\0';  } @@ -1828,6 +1833,9 @@ void blk_fill_rwbs_rq(char *rwbs, struct request *rq)  	if (rq->cmd_flags & REQ_DISCARD)  		rw |= REQ_DISCARD; +	if (rq->cmd_flags & REQ_SECURE) +		rw |= REQ_SECURE; +  	bytes = blk_rq_bytes(rq);  	blk_fill_rwbs(rwbs, rw, bytes); | 
