aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2009-12-03 03:24:48 -0500
committerJens Axboe <jens.axboe@oracle.com>2009-12-03 03:24:48 -0500
commit98262f2762f0067375f83824d81ea929e37e6bfe (patch)
treea26618d5c305eed975501c80cb02bc0f1b6e4524
parent464191c65b85a8ec68a6e1a6293af625287c807e (diff)
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>
-rw-r--r--block/blk-settings.c2
-rw-r--r--block/blk-sysfs.c11
-rw-r--r--block/compat_ioctl.c2
-rw-r--r--block/ioctl.c2
-rw-r--r--include/linux/blkdev.h14
-rw-r--r--include/linux/fs.h1
6 files changed, 32 insertions, 0 deletions
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 1ebc1fdb9144..dd1f1e0e196f 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -101,6 +101,7 @@ void blk_set_default_limits(struct queue_limits *lim)
101 lim->discard_granularity = 0; 101 lim->discard_granularity = 0;
102 lim->discard_alignment = 0; 102 lim->discard_alignment = 0;
103 lim->discard_misaligned = 0; 103 lim->discard_misaligned = 0;
104 lim->discard_zeroes_data = -1;
104 lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; 105 lim->logical_block_size = lim->physical_block_size = lim->io_min = 512;
105 lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT); 106 lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT);
106 lim->alignment_offset = 0; 107 lim->alignment_offset = 0;
@@ -544,6 +545,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
544 545
545 t->io_min = max(t->io_min, b->io_min); 546 t->io_min = max(t->io_min, b->io_min);
546 t->no_cluster |= b->no_cluster; 547 t->no_cluster |= b->no_cluster;
548 t->discard_zeroes_data &= b->discard_zeroes_data;
547 549
548 /* Bottom device offset aligned? */ 550 /* Bottom device offset aligned? */
549 if (offset && 551 if (offset &&
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 3147145edc15..8606c9543fdd 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -136,6 +136,11 @@ static ssize_t queue_discard_max_show(struct request_queue *q, char *page)
136 return queue_var_show(q->limits.max_discard_sectors << 9, page); 136 return queue_var_show(q->limits.max_discard_sectors << 9, page);
137} 137}
138 138
139static 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
139static ssize_t 144static ssize_t
140queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) 145queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
141{ 146{
@@ -313,6 +318,11 @@ static struct queue_sysfs_entry queue_discard_max_entry = {
313 .show = queue_discard_max_show, 318 .show = queue_discard_max_show,
314}; 319};
315 320
321static 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
316static struct queue_sysfs_entry queue_nonrot_entry = { 326static struct queue_sysfs_entry queue_nonrot_entry = {
317 .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR }, 327 .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR },
318 .show = queue_nonrot_show, 328 .show = queue_nonrot_show,
@@ -350,6 +360,7 @@ static struct attribute *default_attrs[] = {
350 &queue_io_opt_entry.attr, 360 &queue_io_opt_entry.attr,
351 &queue_discard_granularity_entry.attr, 361 &queue_discard_granularity_entry.attr,
352 &queue_discard_max_entry.attr, 362 &queue_discard_max_entry.attr,
363 &queue_discard_zeroes_data_entry.attr,
353 &queue_nonrot_entry.attr, 364 &queue_nonrot_entry.attr,
354 &queue_nomerges_entry.attr, 365 &queue_nomerges_entry.attr,
355 &queue_rq_affinity_entry.attr, 366 &queue_rq_affinity_entry.attr,
diff --git a/block/compat_ioctl.c b/block/compat_ioctl.c
index 9bd086c1a4d5..4eb8e9ea4af5 100644
--- a/block/compat_ioctl.c
+++ b/block/compat_ioctl.c
@@ -747,6 +747,8 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
747 return compat_put_uint(arg, bdev_io_opt(bdev)); 747 return compat_put_uint(arg, bdev_io_opt(bdev));
748 case BLKALIGNOFF: 748 case BLKALIGNOFF:
749 return compat_put_int(arg, bdev_alignment_offset(bdev)); 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 case BLKFLSBUF: 752 case BLKFLSBUF:
751 case BLKROSET: 753 case BLKROSET:
752 case BLKDISCARD: 754 case BLKDISCARD:
diff --git a/block/ioctl.c b/block/ioctl.c
index 1f4d1de12b09..be48ea51faee 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -280,6 +280,8 @@ int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
280 return put_uint(arg, bdev_io_opt(bdev)); 280 return put_uint(arg, bdev_io_opt(bdev));
281 case BLKALIGNOFF: 281 case BLKALIGNOFF:
282 return put_int(arg, bdev_alignment_offset(bdev)); 282 return put_int(arg, bdev_alignment_offset(bdev));
283 case BLKDISCARDZEROES:
284 return put_uint(arg, bdev_discard_zeroes_data(bdev));
283 case BLKSECTGET: 285 case BLKSECTGET:
284 return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev))); 286 return put_ushort(arg, queue_max_sectors(bdev_get_queue(bdev)));
285 case BLKRASET: 287 case BLKRASET:
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index e727f6c44c44..784a919aa0d0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -322,6 +322,7 @@ struct queue_limits {
322 unsigned char misaligned; 322 unsigned char misaligned;
323 unsigned char discard_misaligned; 323 unsigned char discard_misaligned;
324 unsigned char no_cluster; 324 unsigned char no_cluster;
325 signed char discard_zeroes_data;
325}; 326};
326 327
327struct request_queue 328struct request_queue
@@ -1150,6 +1151,19 @@ static inline int queue_sector_discard_alignment(struct request_queue *q,
1150 & (q->limits.discard_granularity - 1); 1151 & (q->limits.discard_granularity - 1);
1151} 1152}
1152 1153
1154static 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
1162static inline unsigned int bdev_discard_zeroes_data(struct block_device *bdev)
1163{
1164 return queue_discard_zeroes_data(bdev_get_queue(bdev));
1165}
1166
1153static inline int queue_dma_alignment(struct request_queue *q) 1167static inline int queue_dma_alignment(struct request_queue *q)
1154{ 1168{
1155 return q ? q->dma_alignment : 511; 1169 return q ? q->dma_alignment : 511;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 79cea8051736..891f7d642e5c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -304,6 +304,7 @@ struct inodes_stat_t {
304#define BLKIOOPT _IO(0x12,121) 304#define BLKIOOPT _IO(0x12,121)
305#define BLKALIGNOFF _IO(0x12,122) 305#define BLKALIGNOFF _IO(0x12,122)
306#define BLKPBSZGET _IO(0x12,123) 306#define BLKPBSZGET _IO(0x12,123)
307#define BLKDISCARDZEROES _IO(0x12,124)
307 308
308#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */ 309#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
309#define FIBMAP _IO(0x00,1) /* bmap access */ 310#define FIBMAP _IO(0x00,1) /* bmap access */