Skip to content

Commit

Permalink
block: decouple REQ_OP_SECURE_ERASE from REQ_OP_DISCARD
Browse files Browse the repository at this point in the history
Secure erase is a very different operation from discard in that it is
a data integrity operation vs hint.  Fully split the limits and helper
infrastructure to make the separation more clear.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Acked-by: Christoph Böhmwalder <christoph.boehmwalder@linbit.com> [drbd]
Acked-by: Ryusuke Konishi <konishi.ryusuke@gmail.com> [nifs2]
Acked-by: Jaegeuk Kim <jaegeuk@kernel.org> [f2fs]
Acked-by: Coly Li <colyli@suse.de> [bcache]
Acked-by: David Sterba <dsterba@suse.com> [btrfs]
Acked-by: Chao Yu <chao@kernel.org>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Link: https://lore.kernel.org/r/20220415045258.199825-27-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
  • Loading branch information
Christoph Hellwig authored and axboe committed Apr 18, 2022
1 parent 7b47ef5 commit 44abff2
Show file tree
Hide file tree
Showing 33 changed files with 168 additions and 99 deletions.
2 changes: 1 addition & 1 deletion block/blk-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -824,7 +824,7 @@ void submit_bio_noacct(struct bio *bio)
goto not_supported;
break;
case REQ_OP_SECURE_ERASE:
if (!blk_queue_secure_erase(q))
if (!bdev_max_secure_erase_sectors(bdev))
goto not_supported;
break;
case REQ_OP_ZONE_APPEND:
Expand Down
64 changes: 45 additions & 19 deletions block/blk-lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,15 @@ static sector_t bio_discard_limit(struct block_device *bdev, sector_t sector)
}

int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask, int flags,
struct bio **biop)
sector_t nr_sects, gfp_t gfp_mask, struct bio **biop)
{
struct request_queue *q = bdev_get_queue(bdev);
struct bio *bio = *biop;
unsigned int op;
sector_t bs_mask;

if (bdev_read_only(bdev))
return -EPERM;

if (flags & BLKDEV_DISCARD_SECURE) {
if (!blk_queue_secure_erase(q))
return -EOPNOTSUPP;
op = REQ_OP_SECURE_ERASE;
} else {
if (!bdev_max_discard_sectors(bdev))
return -EOPNOTSUPP;
op = REQ_OP_DISCARD;
}
if (!bdev_max_discard_sectors(bdev))
return -EOPNOTSUPP;

/* In case the discard granularity isn't set by buggy device driver */
if (WARN_ON_ONCE(!bdev_discard_granularity(bdev))) {
Expand All @@ -77,7 +66,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t req_sects =
min(nr_sects, bio_discard_limit(bdev, sector));

bio = blk_next_bio(bio, bdev, 0, op, gfp_mask);
bio = blk_next_bio(bio, bdev, 0, REQ_OP_DISCARD, gfp_mask);
bio->bi_iter.bi_sector = sector;
bio->bi_iter.bi_size = req_sects << 9;
sector += req_sects;
Expand All @@ -103,21 +92,19 @@ EXPORT_SYMBOL(__blkdev_issue_discard);
* @sector: start sector
* @nr_sects: number of sectors to discard
* @gfp_mask: memory allocation flags (for bio_alloc)
* @flags: BLKDEV_DISCARD_* flags to control behaviour
*
* Description:
* Issue a discard request for the sectors in question.
*/
int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask, unsigned long flags)
sector_t nr_sects, gfp_t gfp_mask)
{
struct bio *bio = NULL;
struct blk_plug plug;
int ret;

blk_start_plug(&plug);
ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, flags,
&bio);
ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, &bio);
if (!ret && bio) {
ret = submit_bio_wait(bio);
if (ret == -EOPNOTSUPP)
Expand Down Expand Up @@ -314,3 +301,42 @@ int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
return ret;
}
EXPORT_SYMBOL(blkdev_issue_zeroout);

int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp)
{
sector_t bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1;
unsigned int max_sectors = bdev_max_secure_erase_sectors(bdev);
struct bio *bio = NULL;
struct blk_plug plug;
int ret = 0;

if (max_sectors == 0)
return -EOPNOTSUPP;
if ((sector | nr_sects) & bs_mask)
return -EINVAL;
if (bdev_read_only(bdev))
return -EPERM;

blk_start_plug(&plug);
for (;;) {
unsigned int len = min_t(sector_t, nr_sects, max_sectors);

bio = blk_next_bio(bio, bdev, 0, REQ_OP_SECURE_ERASE, gfp);
bio->bi_iter.bi_sector = sector;
bio->bi_iter.bi_size = len;

sector += len << SECTOR_SHIFT;
nr_sects -= len << SECTOR_SHIFT;
if (!nr_sects) {
ret = submit_bio_wait(bio);
bio_put(bio);
break;
}
cond_resched();
}
blk_finish_plug(&plug);

return ret;
}
EXPORT_SYMBOL(blkdev_issue_secure_erase);
1 change: 0 additions & 1 deletion block/blk-mq-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ static const char *const blk_queue_flag_name[] = {
QUEUE_FLAG_NAME(IO_STAT),
QUEUE_FLAG_NAME(NOXMERGES),
QUEUE_FLAG_NAME(ADD_RANDOM),
QUEUE_FLAG_NAME(SECERASE),
QUEUE_FLAG_NAME(SAME_FORCE),
QUEUE_FLAG_NAME(DEAD),
QUEUE_FLAG_NAME(INIT_DONE),
Expand Down
16 changes: 15 additions & 1 deletion block/blk-settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ void blk_set_default_limits(struct queue_limits *lim)
lim->max_zone_append_sectors = 0;
lim->max_discard_sectors = 0;
lim->max_hw_discard_sectors = 0;
lim->max_secure_erase_sectors = 0;
lim->discard_granularity = 0;
lim->discard_alignment = 0;
lim->discard_misaligned = 0;
Expand Down Expand Up @@ -176,6 +177,18 @@ void blk_queue_max_discard_sectors(struct request_queue *q,
}
EXPORT_SYMBOL(blk_queue_max_discard_sectors);

/**
* blk_queue_max_secure_erase_sectors - set max sectors for a secure erase
* @q: the request queue for the device
* @max_sectors: maximum number of sectors to secure_erase
**/
void blk_queue_max_secure_erase_sectors(struct request_queue *q,
unsigned int max_sectors)
{
q->limits.max_secure_erase_sectors = max_sectors;
}
EXPORT_SYMBOL(blk_queue_max_secure_erase_sectors);

/**
* blk_queue_max_write_zeroes_sectors - set max sectors for a single
* write zeroes
Expand Down Expand Up @@ -661,7 +674,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) %
t->discard_granularity;
}

t->max_secure_erase_sectors = min_not_zero(t->max_secure_erase_sectors,
b->max_secure_erase_sectors);
t->zone_write_granularity = max(t->zone_write_granularity,
b->zone_write_granularity);
t->zoned = max(t->zoned, b->zoned);
Expand Down
2 changes: 1 addition & 1 deletion block/fops.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
break;
case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE | FALLOC_FL_NO_HIDE_STALE:
error = blkdev_issue_discard(bdev, start >> SECTOR_SHIFT,
len >> SECTOR_SHIFT, GFP_KERNEL, 0);
len >> SECTOR_SHIFT, GFP_KERNEL);
break;
default:
error = -EOPNOTSUPP;
Expand Down
43 changes: 35 additions & 8 deletions block/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ static int compat_blkpg_ioctl(struct block_device *bdev,
#endif

static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
unsigned long arg, unsigned long flags)
unsigned long arg)
{
uint64_t range[2];
uint64_t start, len;
Expand Down Expand Up @@ -114,15 +114,43 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
err = truncate_bdev_range(bdev, mode, start, start + len - 1);
if (err)
goto fail;

err = blkdev_issue_discard(bdev, start >> 9, len >> 9,
GFP_KERNEL, flags);

err = blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL);
fail:
filemap_invalidate_unlock(inode->i_mapping);
return err;
}

static int blk_ioctl_secure_erase(struct block_device *bdev, fmode_t mode,
void __user *argp)
{
uint64_t start, len;
uint64_t range[2];
int err;

if (!(mode & FMODE_WRITE))
return -EBADF;
if (!bdev_max_secure_erase_sectors(bdev))
return -EOPNOTSUPP;
if (copy_from_user(range, argp, sizeof(range)))
return -EFAULT;

start = range[0];
len = range[1];
if ((start & 511) || (len & 511))
return -EINVAL;
if (start + len > bdev_nr_bytes(bdev))
return -EINVAL;

filemap_invalidate_lock(bdev->bd_inode->i_mapping);
err = truncate_bdev_range(bdev, mode, start, start + len - 1);
if (!err)
err = blkdev_issue_secure_erase(bdev, start >> 9, len >> 9,
GFP_KERNEL);
filemap_invalidate_unlock(bdev->bd_inode->i_mapping);
return err;
}


static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
unsigned long arg)
{
Expand Down Expand Up @@ -450,10 +478,9 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
case BLKROSET:
return blkdev_roset(bdev, mode, cmd, arg);
case BLKDISCARD:
return blk_ioctl_discard(bdev, mode, arg, 0);
return blk_ioctl_discard(bdev, mode, arg);
case BLKSECDISCARD:
return blk_ioctl_discard(bdev, mode, arg,
BLKDEV_DISCARD_SECURE);
return blk_ioctl_secure_erase(bdev, mode, argp);
case BLKZEROOUT:
return blk_ioctl_zeroout(bdev, mode, arg);
case BLKGETDISKSEQ:
Expand Down
5 changes: 3 additions & 2 deletions drivers/block/drbd/drbd_receiver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1547,7 +1547,8 @@ int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, u
start = tmp;
}
while (nr_sectors >= max_discard_sectors) {
err |= blkdev_issue_discard(bdev, start, max_discard_sectors, GFP_NOIO, 0);
err |= blkdev_issue_discard(bdev, start, max_discard_sectors,
GFP_NOIO);
nr_sectors -= max_discard_sectors;
start += max_discard_sectors;
}
Expand All @@ -1559,7 +1560,7 @@ int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, u
nr = nr_sectors;
nr -= (unsigned int)nr % granularity;
if (nr) {
err |= blkdev_issue_discard(bdev, start, nr, GFP_NOIO, 0);
err |= blkdev_issue_discard(bdev, start, nr, GFP_NOIO);
nr_sectors -= nr;
start += nr;
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/block/rnbd/rnbd-clt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1365,8 +1365,8 @@ static void setup_request_queue(struct rnbd_clt_dev *dev)
dev->queue->limits.discard_granularity = dev->discard_granularity;
dev->queue->limits.discard_alignment = dev->discard_alignment;
if (dev->secure_discard)
blk_queue_flag_set(QUEUE_FLAG_SECERASE, dev->queue);

blk_queue_max_secure_erase_sectors(dev->queue,
dev->max_discard_sectors);
blk_queue_flag_set(QUEUE_FLAG_SAME_COMP, dev->queue);
blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, dev->queue);
blk_queue_max_segments(dev->queue, dev->max_segments);
Expand Down
2 changes: 1 addition & 1 deletion drivers/block/rnbd/rnbd-srv-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ static inline int rnbd_dev_get_max_hw_sects(const struct rnbd_dev *dev)

static inline int rnbd_dev_get_secure_discard(const struct rnbd_dev *dev)
{
return blk_queue_secure_erase(bdev_get_queue(dev->bdev));
return bdev_max_secure_erase_sectors(dev->bdev);
}

static inline int rnbd_dev_get_max_discard_sects(const struct rnbd_dev *dev)
Expand Down
15 changes: 8 additions & 7 deletions drivers/block/xen-blkback/blkback.c
Original file line number Diff line number Diff line change
Expand Up @@ -970,7 +970,6 @@ static int dispatch_discard_io(struct xen_blkif_ring *ring,
int status = BLKIF_RSP_OKAY;
struct xen_blkif *blkif = ring->blkif;
struct block_device *bdev = blkif->vbd.bdev;
unsigned long secure;
struct phys_req preq;

xen_blkif_get(blkif);
Expand All @@ -987,13 +986,15 @@ static int dispatch_discard_io(struct xen_blkif_ring *ring,
}
ring->st_ds_req++;

secure = (blkif->vbd.discard_secure &&
(req->u.discard.flag & BLKIF_DISCARD_SECURE)) ?
BLKDEV_DISCARD_SECURE : 0;
if (blkif->vbd.discard_secure &&
(req->u.discard.flag & BLKIF_DISCARD_SECURE))
err = blkdev_issue_secure_erase(bdev,
req->u.discard.sector_number,
req->u.discard.nr_sectors, GFP_KERNEL);
else
err = blkdev_issue_discard(bdev, req->u.discard.sector_number,
req->u.discard.nr_sectors, GFP_KERNEL);

err = blkdev_issue_discard(bdev, req->u.discard.sector_number,
req->u.discard.nr_sectors,
GFP_KERNEL, secure);
fail_response:
if (err == -EOPNOTSUPP) {
pr_debug("discard op failed, not supported\n");
Expand Down
5 changes: 1 addition & 4 deletions drivers/block/xen-blkback/xenbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,6 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
{
struct xen_vbd *vbd;
struct block_device *bdev;
struct request_queue *q;

vbd = &blkif->vbd;
vbd->handle = handle;
Expand Down Expand Up @@ -516,11 +515,9 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
vbd->type |= VDISK_REMOVABLE;

q = bdev_get_queue(bdev);
if (bdev_write_cache(bdev))
vbd->flush_support = true;

if (q && blk_queue_secure_erase(q))
if (bdev_max_secure_erase_sectors(bdev))
vbd->discard_secure = true;

vbd->feature_gnt_persistent = feature_persistent;
Expand Down
5 changes: 3 additions & 2 deletions drivers/block/xen-blkfront.c
Original file line number Diff line number Diff line change
Expand Up @@ -949,7 +949,8 @@ static void blkif_set_queue_limits(struct blkfront_info *info)
info->physical_sector_size;
rq->limits.discard_alignment = info->discard_alignment;
if (info->feature_secdiscard)
blk_queue_flag_set(QUEUE_FLAG_SECERASE, rq);
blk_queue_max_secure_erase_sectors(rq,
get_capacity(gd));
}

/* Hard sector size and max sectors impersonate the equiv. hardware. */
Expand Down Expand Up @@ -1606,7 +1607,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
info->feature_discard = 0;
info->feature_secdiscard = 0;
blk_queue_max_discard_sectors(rq, 0);
blk_queue_flag_clear(QUEUE_FLAG_SECERASE, rq);
blk_queue_max_secure_erase_sectors(rq, 0);
}
break;
case BLKIF_OP_FLUSH_DISKCACHE:
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/bcache/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ static int bch_allocator_thread(void *arg)
mutex_unlock(&ca->set->bucket_lock);
blkdev_issue_discard(ca->bdev,
bucket_to_sector(ca->set, bucket),
ca->sb.bucket_size, GFP_KERNEL, 0);
ca->sb.bucket_size, GFP_KERNEL);
mutex_lock(&ca->set->bucket_lock);
}

Expand Down
8 changes: 3 additions & 5 deletions drivers/md/dm-table.c
Original file line number Diff line number Diff line change
Expand Up @@ -1920,9 +1920,7 @@ static int device_not_secure_erase_capable(struct dm_target *ti,
struct dm_dev *dev, sector_t start,
sector_t len, void *data)
{
struct request_queue *q = bdev_get_queue(dev->bdev);

return !blk_queue_secure_erase(q);
return !bdev_max_secure_erase_sectors(dev->bdev);
}

static bool dm_table_supports_secure_erase(struct dm_table *t)
Expand Down Expand Up @@ -1975,8 +1973,8 @@ int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
q->limits.discard_misaligned = 0;
}

if (dm_table_supports_secure_erase(t))
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q);
if (!dm_table_supports_secure_erase(t))
q->limits.max_secure_erase_sectors = 0;

if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_WC))) {
wc = true;
Expand Down
4 changes: 2 additions & 2 deletions drivers/md/dm-thin.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,8 @@ static int issue_discard(struct discard_op *op, dm_block_t data_b, dm_block_t da
sector_t s = block_to_sectors(tc->pool, data_b);
sector_t len = block_to_sectors(tc->pool, data_e - data_b);

return __blkdev_issue_discard(tc->pool_dev->bdev, s, len,
GFP_NOWAIT, 0, &op->bio);
return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOWAIT,
&op->bio);
}

static void end_discard(struct discard_op *op, int r)
Expand Down
2 changes: 1 addition & 1 deletion drivers/md/md.c
Original file line number Diff line number Diff line change
Expand Up @@ -8584,7 +8584,7 @@ void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
{
struct bio *discard_bio = NULL;

if (__blkdev_issue_discard(rdev->bdev, start, size, GFP_NOIO, 0,
if (__blkdev_issue_discard(rdev->bdev, start, size, GFP_NOIO,
&discard_bio) || !discard_bio)
return;

Expand Down
Loading

0 comments on commit 44abff2

Please sign in to comment.