block: decouple REQ_OP_SECURE_ERASE from REQ_OP_DISCARD

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>
This commit is contained in:
Christoph Hellwig 2022-04-15 06:52:57 +02:00 committed by Jens Axboe
parent 7b47ef52d0
commit 44abff2c0b
33 changed files with 168 additions and 99 deletions

View File

@ -824,7 +824,7 @@ void submit_bio_noacct(struct bio *bio)
goto not_supported; goto not_supported;
break; break;
case REQ_OP_SECURE_ERASE: case REQ_OP_SECURE_ERASE:
if (!blk_queue_secure_erase(q)) if (!bdev_max_secure_erase_sectors(bdev))
goto not_supported; goto not_supported;
break; break;
case REQ_OP_ZONE_APPEND: case REQ_OP_ZONE_APPEND:

View File

@ -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, int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask, int flags, sector_t nr_sects, gfp_t gfp_mask, struct bio **biop)
struct bio **biop)
{ {
struct request_queue *q = bdev_get_queue(bdev);
struct bio *bio = *biop; struct bio *bio = *biop;
unsigned int op;
sector_t bs_mask; sector_t bs_mask;
if (bdev_read_only(bdev)) if (bdev_read_only(bdev))
return -EPERM; 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)) if (!bdev_max_discard_sectors(bdev))
return -EOPNOTSUPP; return -EOPNOTSUPP;
op = REQ_OP_DISCARD;
}
/* In case the discard granularity isn't set by buggy device driver */ /* In case the discard granularity isn't set by buggy device driver */
if (WARN_ON_ONCE(!bdev_discard_granularity(bdev))) { if (WARN_ON_ONCE(!bdev_discard_granularity(bdev))) {
@ -77,7 +66,7 @@ int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t req_sects = sector_t req_sects =
min(nr_sects, bio_discard_limit(bdev, sector)); 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_sector = sector;
bio->bi_iter.bi_size = req_sects << 9; bio->bi_iter.bi_size = req_sects << 9;
sector += req_sects; sector += req_sects;
@ -103,21 +92,19 @@ EXPORT_SYMBOL(__blkdev_issue_discard);
* @sector: start sector * @sector: start sector
* @nr_sects: number of sectors to discard * @nr_sects: number of sectors to discard
* @gfp_mask: memory allocation flags (for bio_alloc) * @gfp_mask: memory allocation flags (for bio_alloc)
* @flags: BLKDEV_DISCARD_* flags to control behaviour
* *
* Description: * Description:
* Issue a discard request for the sectors in question. * Issue a discard request for the sectors in question.
*/ */
int blkdev_issue_discard(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, unsigned long flags) sector_t nr_sects, gfp_t gfp_mask)
{ {
struct bio *bio = NULL; struct bio *bio = NULL;
struct blk_plug plug; struct blk_plug plug;
int ret; int ret;
blk_start_plug(&plug); blk_start_plug(&plug);
ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, flags, ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, &bio);
&bio);
if (!ret && bio) { if (!ret && bio) {
ret = submit_bio_wait(bio); ret = submit_bio_wait(bio);
if (ret == -EOPNOTSUPP) if (ret == -EOPNOTSUPP)
@ -314,3 +301,42 @@ retry:
return ret; return ret;
} }
EXPORT_SYMBOL(blkdev_issue_zeroout); 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);

View File

@ -115,7 +115,6 @@ static const char *const blk_queue_flag_name[] = {
QUEUE_FLAG_NAME(IO_STAT), QUEUE_FLAG_NAME(IO_STAT),
QUEUE_FLAG_NAME(NOXMERGES), QUEUE_FLAG_NAME(NOXMERGES),
QUEUE_FLAG_NAME(ADD_RANDOM), QUEUE_FLAG_NAME(ADD_RANDOM),
QUEUE_FLAG_NAME(SECERASE),
QUEUE_FLAG_NAME(SAME_FORCE), QUEUE_FLAG_NAME(SAME_FORCE),
QUEUE_FLAG_NAME(DEAD), QUEUE_FLAG_NAME(DEAD),
QUEUE_FLAG_NAME(INIT_DONE), QUEUE_FLAG_NAME(INIT_DONE),

View File

@ -46,6 +46,7 @@ void blk_set_default_limits(struct queue_limits *lim)
lim->max_zone_append_sectors = 0; lim->max_zone_append_sectors = 0;
lim->max_discard_sectors = 0; lim->max_discard_sectors = 0;
lim->max_hw_discard_sectors = 0; lim->max_hw_discard_sectors = 0;
lim->max_secure_erase_sectors = 0;
lim->discard_granularity = 0; lim->discard_granularity = 0;
lim->discard_alignment = 0; lim->discard_alignment = 0;
lim->discard_misaligned = 0; lim->discard_misaligned = 0;
@ -176,6 +177,18 @@ void blk_queue_max_discard_sectors(struct request_queue *q,
} }
EXPORT_SYMBOL(blk_queue_max_discard_sectors); 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 * blk_queue_max_write_zeroes_sectors - set max sectors for a single
* write zeroes * write zeroes
@ -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_alignment = lcm_not_zero(t->discard_alignment, alignment) %
t->discard_granularity; 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, t->zone_write_granularity = max(t->zone_write_granularity,
b->zone_write_granularity); b->zone_write_granularity);
t->zoned = max(t->zoned, b->zoned); t->zoned = max(t->zoned, b->zoned);

View File

@ -677,7 +677,7 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
break; break;
case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE | FALLOC_FL_NO_HIDE_STALE: case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE | FALLOC_FL_NO_HIDE_STALE:
error = blkdev_issue_discard(bdev, start >> SECTOR_SHIFT, error = blkdev_issue_discard(bdev, start >> SECTOR_SHIFT,
len >> SECTOR_SHIFT, GFP_KERNEL, 0); len >> SECTOR_SHIFT, GFP_KERNEL);
break; break;
default: default:
error = -EOPNOTSUPP; error = -EOPNOTSUPP;

View File

@ -83,7 +83,7 @@ static int compat_blkpg_ioctl(struct block_device *bdev,
#endif #endif
static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, 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 range[2];
uint64_t start, len; uint64_t start, len;
@ -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); err = truncate_bdev_range(bdev, mode, start, start + len - 1);
if (err) if (err)
goto fail; goto fail;
err = blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL);
err = blkdev_issue_discard(bdev, start >> 9, len >> 9,
GFP_KERNEL, flags);
fail: fail:
filemap_invalidate_unlock(inode->i_mapping); filemap_invalidate_unlock(inode->i_mapping);
return err; 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, static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
unsigned long arg) unsigned long arg)
{ {
@ -450,10 +478,9 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
case BLKROSET: case BLKROSET:
return blkdev_roset(bdev, mode, cmd, arg); return blkdev_roset(bdev, mode, cmd, arg);
case BLKDISCARD: case BLKDISCARD:
return blk_ioctl_discard(bdev, mode, arg, 0); return blk_ioctl_discard(bdev, mode, arg);
case BLKSECDISCARD: case BLKSECDISCARD:
return blk_ioctl_discard(bdev, mode, arg, return blk_ioctl_secure_erase(bdev, mode, argp);
BLKDEV_DISCARD_SECURE);
case BLKZEROOUT: case BLKZEROOUT:
return blk_ioctl_zeroout(bdev, mode, arg); return blk_ioctl_zeroout(bdev, mode, arg);
case BLKGETDISKSEQ: case BLKGETDISKSEQ:

View File

@ -1547,7 +1547,8 @@ int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, u
start = tmp; start = tmp;
} }
while (nr_sectors >= max_discard_sectors) { 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; nr_sectors -= max_discard_sectors;
start += max_discard_sectors; start += max_discard_sectors;
} }
@ -1559,7 +1560,7 @@ int drbd_issue_discard_or_zero_out(struct drbd_device *device, sector_t start, u
nr = nr_sectors; nr = nr_sectors;
nr -= (unsigned int)nr % granularity; nr -= (unsigned int)nr % granularity;
if (nr) { if (nr) {
err |= blkdev_issue_discard(bdev, start, nr, GFP_NOIO, 0); err |= blkdev_issue_discard(bdev, start, nr, GFP_NOIO);
nr_sectors -= nr; nr_sectors -= nr;
start += nr; start += nr;
} }

View File

@ -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_granularity = dev->discard_granularity;
dev->queue->limits.discard_alignment = dev->discard_alignment; dev->queue->limits.discard_alignment = dev->discard_alignment;
if (dev->secure_discard) 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_COMP, dev->queue);
blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, dev->queue); blk_queue_flag_set(QUEUE_FLAG_SAME_FORCE, dev->queue);
blk_queue_max_segments(dev->queue, dev->max_segments); blk_queue_max_segments(dev->queue, dev->max_segments);

View File

@ -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) 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) static inline int rnbd_dev_get_max_discard_sects(const struct rnbd_dev *dev)

View File

@ -970,7 +970,6 @@ static int dispatch_discard_io(struct xen_blkif_ring *ring,
int status = BLKIF_RSP_OKAY; int status = BLKIF_RSP_OKAY;
struct xen_blkif *blkif = ring->blkif; struct xen_blkif *blkif = ring->blkif;
struct block_device *bdev = blkif->vbd.bdev; struct block_device *bdev = blkif->vbd.bdev;
unsigned long secure;
struct phys_req preq; struct phys_req preq;
xen_blkif_get(blkif); xen_blkif_get(blkif);
@ -987,13 +986,15 @@ static int dispatch_discard_io(struct xen_blkif_ring *ring,
} }
ring->st_ds_req++; ring->st_ds_req++;
secure = (blkif->vbd.discard_secure && if (blkif->vbd.discard_secure &&
(req->u.discard.flag & BLKIF_DISCARD_SECURE)) ? (req->u.discard.flag & BLKIF_DISCARD_SECURE))
BLKDEV_DISCARD_SECURE : 0; 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, err = blkdev_issue_discard(bdev, req->u.discard.sector_number,
req->u.discard.nr_sectors, req->u.discard.nr_sectors, GFP_KERNEL);
GFP_KERNEL, secure);
fail_response: fail_response:
if (err == -EOPNOTSUPP) { if (err == -EOPNOTSUPP) {
pr_debug("discard op failed, not supported\n"); pr_debug("discard op failed, not supported\n");

View File

@ -484,7 +484,6 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
{ {
struct xen_vbd *vbd; struct xen_vbd *vbd;
struct block_device *bdev; struct block_device *bdev;
struct request_queue *q;
vbd = &blkif->vbd; vbd = &blkif->vbd;
vbd->handle = handle; vbd->handle = handle;
@ -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) if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
vbd->type |= VDISK_REMOVABLE; vbd->type |= VDISK_REMOVABLE;
q = bdev_get_queue(bdev);
if (bdev_write_cache(bdev)) if (bdev_write_cache(bdev))
vbd->flush_support = true; vbd->flush_support = true;
if (bdev_max_secure_erase_sectors(bdev))
if (q && blk_queue_secure_erase(q))
vbd->discard_secure = true; vbd->discard_secure = true;
vbd->feature_gnt_persistent = feature_persistent; vbd->feature_gnt_persistent = feature_persistent;

View File

@ -949,7 +949,8 @@ static void blkif_set_queue_limits(struct blkfront_info *info)
info->physical_sector_size; info->physical_sector_size;
rq->limits.discard_alignment = info->discard_alignment; rq->limits.discard_alignment = info->discard_alignment;
if (info->feature_secdiscard) 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. */ /* Hard sector size and max sectors impersonate the equiv. hardware. */
@ -1606,7 +1607,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
info->feature_discard = 0; info->feature_discard = 0;
info->feature_secdiscard = 0; info->feature_secdiscard = 0;
blk_queue_max_discard_sectors(rq, 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; break;
case BLKIF_OP_FLUSH_DISKCACHE: case BLKIF_OP_FLUSH_DISKCACHE:

View File

@ -336,7 +336,7 @@ static int bch_allocator_thread(void *arg)
mutex_unlock(&ca->set->bucket_lock); mutex_unlock(&ca->set->bucket_lock);
blkdev_issue_discard(ca->bdev, blkdev_issue_discard(ca->bdev,
bucket_to_sector(ca->set, bucket), 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); mutex_lock(&ca->set->bucket_lock);
} }

View File

@ -1920,9 +1920,7 @@ static int device_not_secure_erase_capable(struct dm_target *ti,
struct dm_dev *dev, sector_t start, struct dm_dev *dev, sector_t start,
sector_t len, void *data) sector_t len, void *data)
{ {
struct request_queue *q = bdev_get_queue(dev->bdev); return !bdev_max_secure_erase_sectors(dev->bdev);
return !blk_queue_secure_erase(q);
} }
static bool dm_table_supports_secure_erase(struct dm_table *t) static bool dm_table_supports_secure_erase(struct dm_table *t)
@ -1975,8 +1973,8 @@ int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
q->limits.discard_misaligned = 0; q->limits.discard_misaligned = 0;
} }
if (dm_table_supports_secure_erase(t)) if (!dm_table_supports_secure_erase(t))
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); q->limits.max_secure_erase_sectors = 0;
if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_WC))) { if (dm_table_supports_flush(t, (1UL << QUEUE_FLAG_WC))) {
wc = true; wc = true;

View File

@ -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 s = block_to_sectors(tc->pool, data_b);
sector_t len = block_to_sectors(tc->pool, data_e - data_b); sector_t len = block_to_sectors(tc->pool, data_e - data_b);
return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, return __blkdev_issue_discard(tc->pool_dev->bdev, s, len, GFP_NOWAIT,
GFP_NOWAIT, 0, &op->bio); &op->bio);
} }
static void end_discard(struct discard_op *op, int r) static void end_discard(struct discard_op *op, int r)

View File

@ -8584,7 +8584,7 @@ void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
{ {
struct bio *discard_bio = NULL; 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) &discard_bio) || !discard_bio)
return; return;

View File

@ -1344,14 +1344,14 @@ static void r5l_write_super_and_discard_space(struct r5l_log *log,
if (log->last_checkpoint < end) { if (log->last_checkpoint < end) {
blkdev_issue_discard(bdev, blkdev_issue_discard(bdev,
log->last_checkpoint + log->rdev->data_offset, log->last_checkpoint + log->rdev->data_offset,
end - log->last_checkpoint, GFP_NOIO, 0); end - log->last_checkpoint, GFP_NOIO);
} else { } else {
blkdev_issue_discard(bdev, blkdev_issue_discard(bdev,
log->last_checkpoint + log->rdev->data_offset, log->last_checkpoint + log->rdev->data_offset,
log->device_size - log->last_checkpoint, log->device_size - log->last_checkpoint,
GFP_NOIO, 0); GFP_NOIO);
blkdev_issue_discard(bdev, log->rdev->data_offset, end, blkdev_issue_discard(bdev, log->rdev->data_offset, end,
GFP_NOIO, 0); GFP_NOIO);
} }
} }

View File

@ -189,7 +189,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
if (card->pref_erase > max_discard) if (card->pref_erase > max_discard)
q->limits.discard_granularity = SECTOR_SIZE; q->limits.discard_granularity = SECTOR_SIZE;
if (mmc_can_secure_erase_trim(card)) if (mmc_can_secure_erase_trim(card))
blk_queue_flag_set(QUEUE_FLAG_SECERASE, q); blk_queue_max_secure_erase_sectors(q, max_discard);
} }
static unsigned short mmc_get_max_segments(struct mmc_host *host) static unsigned short mmc_get_max_segments(struct mmc_host *host)

View File

@ -360,7 +360,7 @@ static u16 nvmet_bdev_discard_range(struct nvmet_req *req,
ret = __blkdev_issue_discard(ns->bdev, ret = __blkdev_issue_discard(ns->bdev,
nvmet_lba_to_sect(ns, range->slba), nvmet_lba_to_sect(ns, range->slba),
le32_to_cpu(range->nlb) << (ns->blksize_shift - 9), le32_to_cpu(range->nlb) << (ns->blksize_shift - 9),
GFP_KERNEL, 0, bio); GFP_KERNEL, bio);
if (ret && ret != -EOPNOTSUPP) { if (ret && ret != -EOPNOTSUPP) {
req->error_slba = le64_to_cpu(range->slba); req->error_slba = le64_to_cpu(range->slba);
return errno_to_nvme_status(req, ret); return errno_to_nvme_status(req, ret);

View File

@ -558,7 +558,7 @@ fd_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
ret = blkdev_issue_discard(bdev, ret = blkdev_issue_discard(bdev,
target_to_linux_sector(dev, lba), target_to_linux_sector(dev, lba),
target_to_linux_sector(dev, nolb), target_to_linux_sector(dev, nolb),
GFP_KERNEL, 0); GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n", pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n",
ret); ret);

View File

@ -434,7 +434,7 @@ iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb)
ret = blkdev_issue_discard(bdev, ret = blkdev_issue_discard(bdev,
target_to_linux_sector(dev, lba), target_to_linux_sector(dev, lba),
target_to_linux_sector(dev, nolb), target_to_linux_sector(dev, nolb),
GFP_KERNEL, 0); GFP_KERNEL);
if (ret < 0) { if (ret < 0) {
pr_err("blkdev_issue_discard() failed: %d\n", ret); pr_err("blkdev_issue_discard() failed: %d\n", ret);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;

View File

@ -1239,7 +1239,7 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
if (size) { if (size) {
ret = blkdev_issue_discard(bdev, start >> 9, size >> 9, ret = blkdev_issue_discard(bdev, start >> 9, size >> 9,
GFP_NOFS, 0); GFP_NOFS);
if (!ret) if (!ret)
*discarded_bytes += size; *discarded_bytes += size;
else if (ret != -EOPNOTSUPP) else if (ret != -EOPNOTSUPP)
@ -1256,7 +1256,7 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
if (bytes_left) { if (bytes_left) {
ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9, ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9,
GFP_NOFS, 0); GFP_NOFS);
if (!ret) if (!ret)
*discarded_bytes += bytes_left; *discarded_bytes += bytes_left;
} }

View File

@ -3629,7 +3629,7 @@ static inline int ext4_issue_discard(struct super_block *sb,
return __blkdev_issue_discard(sb->s_bdev, return __blkdev_issue_discard(sb->s_bdev,
(sector_t)discard_block << (sb->s_blocksize_bits - 9), (sector_t)discard_block << (sb->s_blocksize_bits - 9),
(sector_t)count << (sb->s_blocksize_bits - 9), (sector_t)count << (sb->s_blocksize_bits - 9),
GFP_NOFS, 0, biop); GFP_NOFS, biop);
} else } else
return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0); return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0);
} }

View File

@ -3685,18 +3685,18 @@ out:
static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode, static int f2fs_secure_erase(struct block_device *bdev, struct inode *inode,
pgoff_t off, block_t block, block_t len, u32 flags) pgoff_t off, block_t block, block_t len, u32 flags)
{ {
struct request_queue *q = bdev_get_queue(bdev);
sector_t sector = SECTOR_FROM_BLOCK(block); sector_t sector = SECTOR_FROM_BLOCK(block);
sector_t nr_sects = SECTOR_FROM_BLOCK(len); sector_t nr_sects = SECTOR_FROM_BLOCK(len);
int ret = 0; int ret = 0;
if (!q) if (flags & F2FS_TRIM_FILE_DISCARD) {
return -ENXIO; if (bdev_max_secure_erase_sectors(bdev))
ret = blkdev_issue_secure_erase(bdev, sector, nr_sects,
if (flags & F2FS_TRIM_FILE_DISCARD) GFP_NOFS);
ret = blkdev_issue_discard(bdev, sector, nr_sects, GFP_NOFS, else
blk_queue_secure_erase(q) ? ret = blkdev_issue_discard(bdev, sector, nr_sects,
BLKDEV_DISCARD_SECURE : 0); GFP_NOFS);
}
if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) { if (!ret && (flags & F2FS_TRIM_FILE_ZEROOUT)) {
if (IS_ENCRYPTED(inode)) if (IS_ENCRYPTED(inode))

View File

@ -1244,7 +1244,7 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi,
err = __blkdev_issue_discard(bdev, err = __blkdev_issue_discard(bdev,
SECTOR_FROM_BLOCK(start), SECTOR_FROM_BLOCK(start),
SECTOR_FROM_BLOCK(len), SECTOR_FROM_BLOCK(len),
GFP_NOFS, 0, &bio); GFP_NOFS, &bio);
submit: submit:
if (err) { if (err) {
spin_lock_irqsave(&dc->lock, flags); spin_lock_irqsave(&dc->lock, flags);

View File

@ -1825,7 +1825,7 @@ static int __jbd2_journal_erase(journal_t *journal, unsigned int flags)
err = blkdev_issue_discard(journal->j_dev, err = blkdev_issue_discard(journal->j_dev,
byte_start >> SECTOR_SHIFT, byte_start >> SECTOR_SHIFT,
byte_count >> SECTOR_SHIFT, byte_count >> SECTOR_SHIFT,
GFP_NOFS, 0); GFP_NOFS);
} else if (flags & JBD2_JOURNAL_FLUSH_ZEROOUT) { } else if (flags & JBD2_JOURNAL_FLUSH_ZEROOUT) {
err = blkdev_issue_zeroout(journal->j_dev, err = blkdev_issue_zeroout(journal->j_dev,
byte_start >> SECTOR_SHIFT, byte_start >> SECTOR_SHIFT,

View File

@ -1100,7 +1100,7 @@ int nilfs_sufile_trim_fs(struct inode *sufile, struct fstrim_range *range)
ret = blkdev_issue_discard(nilfs->ns_bdev, ret = blkdev_issue_discard(nilfs->ns_bdev,
start * sects_per_block, start * sects_per_block,
nblocks * sects_per_block, nblocks * sects_per_block,
GFP_NOFS, 0); GFP_NOFS);
if (ret < 0) { if (ret < 0) {
put_bh(su_bh); put_bh(su_bh);
goto out_sem; goto out_sem;
@ -1134,7 +1134,7 @@ int nilfs_sufile_trim_fs(struct inode *sufile, struct fstrim_range *range)
ret = blkdev_issue_discard(nilfs->ns_bdev, ret = blkdev_issue_discard(nilfs->ns_bdev,
start * sects_per_block, start * sects_per_block,
nblocks * sects_per_block, nblocks * sects_per_block,
GFP_NOFS, 0); GFP_NOFS);
if (!ret) if (!ret)
ndiscarded += nblocks; ndiscarded += nblocks;
} }

View File

@ -672,7 +672,7 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump,
ret = blkdev_issue_discard(nilfs->ns_bdev, ret = blkdev_issue_discard(nilfs->ns_bdev,
start * sects_per_block, start * sects_per_block,
nblocks * sects_per_block, nblocks * sects_per_block,
GFP_NOFS, 0); GFP_NOFS);
if (ret < 0) if (ret < 0)
return ret; return ret;
nblocks = 0; nblocks = 0;
@ -682,7 +682,7 @@ int nilfs_discard_segments(struct the_nilfs *nilfs, __u64 *segnump,
ret = blkdev_issue_discard(nilfs->ns_bdev, ret = blkdev_issue_discard(nilfs->ns_bdev,
start * sects_per_block, start * sects_per_block,
nblocks * sects_per_block, nblocks * sects_per_block,
GFP_NOFS, 0); GFP_NOFS);
return ret; return ret;
} }

View File

@ -1333,7 +1333,7 @@ int ntfs_discard(struct ntfs_sb_info *sbi, CLST lcn, CLST len)
return 0; return 0;
err = blkdev_issue_discard(sb->s_bdev, start >> 9, (end - start) >> 9, err = blkdev_issue_discard(sb->s_bdev, start >> 9, (end - start) >> 9,
GFP_NOFS, 0); GFP_NOFS);
if (err == -EOPNOTSUPP) if (err == -EOPNOTSUPP)
sbi->flags |= NTFS_FLAGS_NODISCARD; sbi->flags |= NTFS_FLAGS_NODISCARD;

View File

@ -114,7 +114,7 @@ xfs_trim_extents(
} }
trace_xfs_discard_extent(mp, agno, fbno, flen); trace_xfs_discard_extent(mp, agno, fbno, flen);
error = blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS, 0); error = blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS);
if (error) if (error)
goto out_del_cursor; goto out_del_cursor;
*blocks_trimmed += flen; *blocks_trimmed += flen;

View File

@ -605,7 +605,7 @@ xlog_discard_busy_extents(
error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev, error = __blkdev_issue_discard(mp->m_ddev_targp->bt_bdev,
XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno), XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno),
XFS_FSB_TO_BB(mp, busyp->length), XFS_FSB_TO_BB(mp, busyp->length),
GFP_NOFS, 0, &bio); GFP_NOFS, &bio);
if (error && error != -EOPNOTSUPP) { if (error && error != -EOPNOTSUPP) {
xfs_info(mp, xfs_info(mp,
"discard failed for extent [0x%llx,%u], error %d", "discard failed for extent [0x%llx,%u], error %d",

View File

@ -248,6 +248,7 @@ struct queue_limits {
unsigned int io_opt; unsigned int io_opt;
unsigned int max_discard_sectors; unsigned int max_discard_sectors;
unsigned int max_hw_discard_sectors; unsigned int max_hw_discard_sectors;
unsigned int max_secure_erase_sectors;
unsigned int max_write_zeroes_sectors; unsigned int max_write_zeroes_sectors;
unsigned int max_zone_append_sectors; unsigned int max_zone_append_sectors;
unsigned int discard_granularity; unsigned int discard_granularity;
@ -542,7 +543,6 @@ struct request_queue {
#define QUEUE_FLAG_IO_STAT 7 /* do disk/partitions IO accounting */ #define QUEUE_FLAG_IO_STAT 7 /* do disk/partitions IO accounting */
#define QUEUE_FLAG_NOXMERGES 9 /* No extended merges */ #define QUEUE_FLAG_NOXMERGES 9 /* No extended merges */
#define QUEUE_FLAG_ADD_RANDOM 10 /* Contributes to random pool */ #define QUEUE_FLAG_ADD_RANDOM 10 /* Contributes to random pool */
#define QUEUE_FLAG_SECERASE 11 /* supports secure erase */
#define QUEUE_FLAG_SAME_FORCE 12 /* force complete on same CPU */ #define QUEUE_FLAG_SAME_FORCE 12 /* force complete on same CPU */
#define QUEUE_FLAG_DEAD 13 /* queue tear-down finished */ #define QUEUE_FLAG_DEAD 13 /* queue tear-down finished */
#define QUEUE_FLAG_INIT_DONE 14 /* queue is initialized */ #define QUEUE_FLAG_INIT_DONE 14 /* queue is initialized */
@ -583,8 +583,6 @@ bool blk_queue_flag_test_and_set(unsigned int flag, struct request_queue *q);
#define blk_queue_add_random(q) test_bit(QUEUE_FLAG_ADD_RANDOM, &(q)->queue_flags) #define blk_queue_add_random(q) test_bit(QUEUE_FLAG_ADD_RANDOM, &(q)->queue_flags)
#define blk_queue_zone_resetall(q) \ #define blk_queue_zone_resetall(q) \
test_bit(QUEUE_FLAG_ZONE_RESETALL, &(q)->queue_flags) test_bit(QUEUE_FLAG_ZONE_RESETALL, &(q)->queue_flags)
#define blk_queue_secure_erase(q) \
(test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags))
#define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) #define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags)
#define blk_queue_pci_p2pdma(q) \ #define blk_queue_pci_p2pdma(q) \
test_bit(QUEUE_FLAG_PCI_P2PDMA, &(q)->queue_flags) test_bit(QUEUE_FLAG_PCI_P2PDMA, &(q)->queue_flags)
@ -947,6 +945,8 @@ extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int);
extern void blk_queue_max_segments(struct request_queue *, unsigned short); extern void blk_queue_max_segments(struct request_queue *, unsigned short);
extern void blk_queue_max_discard_segments(struct request_queue *, extern void blk_queue_max_discard_segments(struct request_queue *,
unsigned short); unsigned short);
void blk_queue_max_secure_erase_sectors(struct request_queue *q,
unsigned int max_sectors);
extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); extern void blk_queue_max_segment_size(struct request_queue *, unsigned int);
extern void blk_queue_max_discard_sectors(struct request_queue *q, extern void blk_queue_max_discard_sectors(struct request_queue *q,
unsigned int max_discard_sectors); unsigned int max_discard_sectors);
@ -1087,13 +1087,12 @@ static inline long nr_blockdev_pages(void)
extern void blk_io_schedule(void); extern void blk_io_schedule(void);
#define BLKDEV_DISCARD_SECURE (1 << 0) /* issue a secure erase */ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask);
extern int blkdev_issue_discard(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, unsigned long flags); sector_t nr_sects, gfp_t gfp_mask, struct bio **biop);
extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, int blkdev_issue_secure_erase(struct block_device *bdev, sector_t sector,
sector_t nr_sects, gfp_t gfp_mask, int flags, sector_t nr_sects, gfp_t gfp);
struct bio **biop);
#define BLKDEV_ZERO_NOUNMAP (1 << 0) /* do not free blocks */ #define BLKDEV_ZERO_NOUNMAP (1 << 0) /* do not free blocks */
#define BLKDEV_ZERO_NOFALLBACK (1 << 1) /* don't write explicit zeroes */ #define BLKDEV_ZERO_NOFALLBACK (1 << 1) /* don't write explicit zeroes */
@ -1112,7 +1111,7 @@ static inline int sb_issue_discard(struct super_block *sb, sector_t block,
SECTOR_SHIFT), SECTOR_SHIFT),
nr_blocks << (sb->s_blocksize_bits - nr_blocks << (sb->s_blocksize_bits -
SECTOR_SHIFT), SECTOR_SHIFT),
gfp_mask, flags); gfp_mask);
} }
static inline int sb_issue_zeroout(struct super_block *sb, sector_t block, static inline int sb_issue_zeroout(struct super_block *sb, sector_t block,
sector_t nr_blocks, gfp_t gfp_mask) sector_t nr_blocks, gfp_t gfp_mask)
@ -1262,6 +1261,12 @@ static inline unsigned int bdev_discard_granularity(struct block_device *bdev)
return bdev_get_queue(bdev)->limits.discard_granularity; return bdev_get_queue(bdev)->limits.discard_granularity;
} }
static inline unsigned int
bdev_max_secure_erase_sectors(struct block_device *bdev)
{
return bdev_get_queue(bdev)->limits.max_secure_erase_sectors;
}
static inline unsigned int bdev_write_zeroes_sectors(struct block_device *bdev) static inline unsigned int bdev_write_zeroes_sectors(struct block_device *bdev)
{ {
struct request_queue *q = bdev_get_queue(bdev); struct request_queue *q = bdev_get_queue(bdev);

View File

@ -179,7 +179,7 @@ static int discard_swap(struct swap_info_struct *si)
nr_blocks = ((sector_t)se->nr_pages - 1) << (PAGE_SHIFT - 9); nr_blocks = ((sector_t)se->nr_pages - 1) << (PAGE_SHIFT - 9);
if (nr_blocks) { if (nr_blocks) {
err = blkdev_issue_discard(si->bdev, start_block, err = blkdev_issue_discard(si->bdev, start_block,
nr_blocks, GFP_KERNEL, 0); nr_blocks, GFP_KERNEL);
if (err) if (err)
return err; return err;
cond_resched(); cond_resched();
@ -190,7 +190,7 @@ static int discard_swap(struct swap_info_struct *si)
nr_blocks = (sector_t)se->nr_pages << (PAGE_SHIFT - 9); nr_blocks = (sector_t)se->nr_pages << (PAGE_SHIFT - 9);
err = blkdev_issue_discard(si->bdev, start_block, err = blkdev_issue_discard(si->bdev, start_block,
nr_blocks, GFP_KERNEL, 0); nr_blocks, GFP_KERNEL);
if (err) if (err)
break; break;
@ -254,7 +254,7 @@ static void discard_swap_cluster(struct swap_info_struct *si,
start_block <<= PAGE_SHIFT - 9; start_block <<= PAGE_SHIFT - 9;
nr_blocks <<= PAGE_SHIFT - 9; nr_blocks <<= PAGE_SHIFT - 9;
if (blkdev_issue_discard(si->bdev, start_block, if (blkdev_issue_discard(si->bdev, start_block,
nr_blocks, GFP_NOIO, 0)) nr_blocks, GFP_NOIO))
break; break;
se = next_se(se); se = next_se(se);