Commit 98262f2762f0067375f83824d81ea929e37e6bfe

Authored by Martin K. Petersen
Committed by Jens Axboe
1 parent 464191c65b

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 &&
... ... @@ -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:
... ... @@ -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)
... ... @@ -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 */