Commit 98262f2762f0067375f83824d81ea929e37e6bfe
Committed by
Jens Axboe
1 parent
464191c65b
Exists in
master
and in
7 other branches
block: Allow devices to indicate whether discarded blocks are zeroed
The discard ioctl is used by mkfs utilities to clear a block device prior to putting metadata down. However, not all devices return zeroed blocks after a discard. Some drives return stale data, potentially containing old superblocks. It is therefore important to know whether discarded blocks are properly zeroed. Both ATA and SCSI drives have configuration bits that indicate whether zeroes are returned after a discard operation. Implement a block level interface that allows this information to be bubbled up the stack and queried via a new block device ioctl. Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Showing 6 changed files with 32 additions and 0 deletions Side-by-side Diff
block/blk-settings.c
... | ... | @@ -101,6 +101,7 @@ |
101 | 101 | lim->discard_granularity = 0; |
102 | 102 | lim->discard_alignment = 0; |
103 | 103 | lim->discard_misaligned = 0; |
104 | + lim->discard_zeroes_data = -1; | |
104 | 105 | lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; |
105 | 106 | lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT); |
106 | 107 | lim->alignment_offset = 0; |
... | ... | @@ -544,6 +545,7 @@ |
544 | 545 | |
545 | 546 | t->io_min = max(t->io_min, b->io_min); |
546 | 547 | t->no_cluster |= b->no_cluster; |
548 | + t->discard_zeroes_data &= b->discard_zeroes_data; | |
547 | 549 | |
548 | 550 | /* Bottom device offset aligned? */ |
549 | 551 | if (offset && |
block/blk-sysfs.c
... | ... | @@ -136,6 +136,11 @@ |
136 | 136 | return queue_var_show(q->limits.max_discard_sectors << 9, page); |
137 | 137 | } |
138 | 138 | |
139 | +static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page) | |
140 | +{ | |
141 | + return queue_var_show(queue_discard_zeroes_data(q), page); | |
142 | +} | |
143 | + | |
139 | 144 | static ssize_t |
140 | 145 | queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) |
141 | 146 | { |
... | ... | @@ -313,6 +318,11 @@ |
313 | 318 | .show = queue_discard_max_show, |
314 | 319 | }; |
315 | 320 | |
321 | +static struct queue_sysfs_entry queue_discard_zeroes_data_entry = { | |
322 | + .attr = {.name = "discard_zeroes_data", .mode = S_IRUGO }, | |
323 | + .show = queue_discard_zeroes_data_show, | |
324 | +}; | |
325 | + | |
316 | 326 | static struct queue_sysfs_entry queue_nonrot_entry = { |
317 | 327 | .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR }, |
318 | 328 | .show = queue_nonrot_show, |
... | ... | @@ -350,6 +360,7 @@ |
350 | 360 | &queue_io_opt_entry.attr, |
351 | 361 | &queue_discard_granularity_entry.attr, |
352 | 362 | &queue_discard_max_entry.attr, |
363 | + &queue_discard_zeroes_data_entry.attr, | |
353 | 364 | &queue_nonrot_entry.attr, |
354 | 365 | &queue_nomerges_entry.attr, |
355 | 366 | &queue_rq_affinity_entry.attr, |
block/compat_ioctl.c
... | ... | @@ -747,6 +747,8 @@ |
747 | 747 | return compat_put_uint(arg, bdev_io_opt(bdev)); |
748 | 748 | case BLKALIGNOFF: |
749 | 749 | return compat_put_int(arg, bdev_alignment_offset(bdev)); |
750 | + case BLKDISCARDZEROES: | |
751 | + return compat_put_uint(arg, bdev_discard_zeroes_data(bdev)); | |
750 | 752 | case BLKFLSBUF: |
751 | 753 | case BLKROSET: |
752 | 754 | case BLKDISCARD: |
block/ioctl.c
... | ... | @@ -280,6 +280,8 @@ |
280 | 280 | return put_uint(arg, bdev_io_opt(bdev)); |
281 | 281 | case BLKALIGNOFF: |
282 | 282 | return put_int(arg, bdev_alignment_offset(bdev)); |
283 | + case BLKDISCARDZEROES: | |
284 | + return put_uint(arg, bdev_discard_zeroes_data(bdev)); | |
283 | 285 | case BLKSECTGET: |
284 | 286 | return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev))); |
285 | 287 | case BLKRASET: |
include/linux/blkdev.h
... | ... | @@ -322,6 +322,7 @@ |
322 | 322 | unsigned char misaligned; |
323 | 323 | unsigned char discard_misaligned; |
324 | 324 | unsigned char no_cluster; |
325 | + signed char discard_zeroes_data; | |
325 | 326 | }; |
326 | 327 | |
327 | 328 | struct request_queue |
... | ... | @@ -1148,6 +1149,19 @@ |
1148 | 1149 | { |
1149 | 1150 | return ((sector << 9) - q->limits.discard_alignment) |
1150 | 1151 | & (q->limits.discard_granularity - 1); |
1152 | +} | |
1153 | + | |
1154 | +static inline unsigned int queue_discard_zeroes_data(struct request_queue *q) | |
1155 | +{ | |
1156 | + if (q->limits.discard_zeroes_data == 1) | |
1157 | + return 1; | |
1158 | + | |
1159 | + return 0; | |
1160 | +} | |
1161 | + | |
1162 | +static inline unsigned int bdev_discard_zeroes_data(struct block_device *bdev) | |
1163 | +{ | |
1164 | + return queue_discard_zeroes_data(bdev_get_queue(bdev)); | |
1151 | 1165 | } |
1152 | 1166 | |
1153 | 1167 | static inline int queue_dma_alignment(struct request_queue *q) |
include/linux/fs.h
... | ... | @@ -304,6 +304,7 @@ |
304 | 304 | #define BLKIOOPT _IO(0x12,121) |
305 | 305 | #define BLKALIGNOFF _IO(0x12,122) |
306 | 306 | #define BLKPBSZGET _IO(0x12,123) |
307 | +#define BLKDISCARDZEROES _IO(0x12,124) | |
307 | 308 | |
308 | 309 | #define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ |
309 | 310 | #define FIBMAP _IO(0x00,1) /* bmap access */ |