block-7.1-20260424

-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmnrh6gQHGF4Ym9lQGtl
 cm5lbC5kawAKCRD301j7KXHgpkE+D/4h1caXVwyXjeBQ+UQ0hXqRkPHgCym+NxAx
 W/ezIs2/Yldbe31x5YZqtYXfV+0SyZhd6ugDbRpOahol8+7wpa4E4wZNYfoxKKqF
 +q9SysEDRCAOOGkCtNvxpALIzmmmXEswrqwJOmge2J+vdNsZwFq8APMiGS0kEo3x
 nJrzOdxnpMHVY68yCB+LtRjggyptoJNMT14lIeFg1uXLAUK7CAg8Ax3qSzuAcW1m
 zWTkGUudrVtVWNEjKdR4kvPWtrkbNb8PY6ybKxJo+4z1XMrOkVlbIAEX6o6dOIqy
 hk5WKWNQIU82oxUi+FondGgq2yRHwuRY4fiDAz+eQ+SO6EcaUxQWqJgAD3gcNyRl
 C2ywNRFT3EZhYHSr8ec+kuNX3Bot5YvRP2BdFpQpmKLhGGs1JwV9pjsYiLr1bXOy
 fI6Wo1CsEnHM7I4rBFaji7W9ZhOXo/6IlehfDO2vf6iAAaWo1aDnJ4gOxNMcIYx3
 hCGWWiug1RadsPXKe9wIjGjR9ahUl48Ucs06fgN2kMjtPb09QsB66yUF7jJS9mvk
 Mdn9EltVqLIoyTt5vS/hUk/hO7VPzYaD/pL0yun4I9h7vi9hEyd/rXm3BIvuLQgJ
 7u7c00ozgZyNVbubUa3lOxJLW7L/ukxHsCOJQW+FW/uJUvqxC3g5LGYaxe9r6uE0
 KB1uNV7sKg==
 =0AP+
 -----END PGP SIGNATURE-----

Merge tag 'block-7.1-20260424' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull block fixes from Jens Axboe:

 - Series for zloop, fixing a variety of issues

 - t10-pi code cleanup

 - Fix for a merge window regression with the bio memory allocation mask

 - Fix for a merge window regression in ublk, caused by an issue with
   the maple tree iteration code at teardown

 - ublk self tests additions

 - Zoned device pgmap fixes

 - Various little cleanups and fixes

* tag 'block-7.1-20260424' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (21 commits)
  Revert "floppy: fix reference leak on platform_device_register() failure"
  ublk: avoid unpinning pages under maple tree spinlock
  ublk: refactor common helper ublk_shmem_remove_ranges()
  ublk: fix maple tree lockdep warning in ublk_buf_cleanup
  selftests: ublk: add ublk auto integrity test
  selftests: ublk: enable test_integrity_02.sh on fio 3.42
  selftests: ublk: remove unused argument to _cleanup
  block: only restrict bio allocation gfp mask asked to block
  block/blk-throttle: Add WQ_PERCPU to alloc_workqueue users
  block: Add WQ_PERCPU to alloc_workqueue users
  block: relax pgmap check in bio_add_page for compatible zone device pages
  block: add pgmap check to biovec_phys_mergeable
  floppy: fix reference leak on platform_device_register() failure
  ublk: use unchecked copy helpers for bio page data
  t10-pi: reduce ref tag code duplication
  zloop: remove irq-safe locking
  zloop: factor out zloop_mark_{full,empty} helpers
  zloop: set RQF_QUIET when completing requests on deleted devices
  zloop: improve the unaligned write pointer warning
  zloop: use vfs_truncate
  ...
This commit is contained in:
Linus Torvalds 2026-04-24 15:06:55 -07:00
commit f3e3dbcea1
61 changed files with 347 additions and 187 deletions

View File

@ -125,7 +125,7 @@ static int __init blk_integrity_auto_init(void)
* Make it highpri CPU intensive wq with max concurrency of 1.
*/
kintegrityd_wq = alloc_workqueue("kintegrityd", WQ_MEM_RECLAIM |
WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1);
WQ_HIGHPRI | WQ_CPU_INTENSIVE | WQ_PERCPU, 1);
if (!kintegrityd_wq)
panic("Failed to create kintegrityd\n");
return 0;

View File

@ -231,10 +231,10 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
if (bip->bip_vcnt > 0) {
struct bio_vec *bv = &bip->bip_vec[bip->bip_vcnt - 1];
if (!zone_device_pages_have_same_pgmap(bv->bv_page, page))
if (!zone_device_pages_compatible(bv->bv_page, page))
return 0;
if (bvec_try_merge_hw_page(q, bv, page, len, offset)) {
if (zone_device_pages_have_same_pgmap(bv->bv_page, page) &&
bvec_try_merge_hw_page(q, bv, page, len, offset)) {
bip->bip_iter.bi_size += len;
return len;
}

View File

@ -544,7 +544,8 @@ struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
if (WARN_ON_ONCE(!mempool_initialized(&bs->bvec_pool) && nr_vecs > 0))
return NULL;
gfp = try_alloc_gfp(gfp);
if (saved_gfp & __GFP_DIRECT_RECLAIM)
gfp = try_alloc_gfp(gfp);
if (bs->cache && nr_vecs <= BIO_INLINE_VECS) {
/*
* Set REQ_ALLOC_CACHE even if no cached bio is available to
@ -1048,10 +1049,10 @@ int bio_add_page(struct bio *bio, struct page *page,
if (bio->bi_vcnt > 0) {
struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
if (!zone_device_pages_have_same_pgmap(bv->bv_page, page))
if (!zone_device_pages_compatible(bv->bv_page, page))
return 0;
if (bvec_try_merge_page(bv, page, len, offset)) {
if (zone_device_pages_have_same_pgmap(bv->bv_page, page) &&
bvec_try_merge_page(bv, page, len, offset)) {
bio->bi_iter.bi_size += len;
return len;
}
@ -1958,7 +1959,7 @@ int bioset_init(struct bio_set *bs,
if (flags & BIOSET_NEED_RESCUER) {
bs->rescue_workqueue = alloc_workqueue("bioset",
WQ_MEM_RECLAIM, 0);
WQ_MEM_RECLAIM | WQ_PERCPU, 0);
if (!bs->rescue_workqueue)
goto bad;
}

View File

@ -1282,7 +1282,7 @@ int __init blk_dev_init(void)
/* used for unplugging and affects IO latency/throughput - HIGHPRI */
kblockd_workqueue = alloc_workqueue("kblockd",
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_PERCPU, 0);
if (!kblockd_workqueue)
panic("Failed to create kblockd\n");

View File

@ -1839,7 +1839,7 @@ void blk_throtl_exit(struct gendisk *disk)
static int __init throtl_init(void)
{
kthrotld_workqueue = alloc_workqueue("kthrotld", WQ_MEM_RECLAIM, 0);
kthrotld_workqueue = alloc_workqueue("kthrotld", WQ_MEM_RECLAIM | WQ_PERCPU, 0);
if (!kthrotld_workqueue)
panic("Failed to create kthrotld\n");

View File

@ -127,6 +127,8 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
if (addr1 + vec1->bv_len != addr2)
return false;
if (!zone_device_pages_have_same_pgmap(vec1->bv_page, vec2->bv_page))
return false;
if (xen_domain() && !xen_biovec_phys_mergeable(vec1, vec2->bv_page))
return false;
if ((addr1 | mask) != ((addr2 + vec2->bv_len - 1) | mask))
@ -134,6 +136,25 @@ static inline bool biovec_phys_mergeable(struct request_queue *q,
return true;
}
/*
* Check if two pages from potentially different zone device pgmaps can
* coexist as separate bvec entries in the same bio.
*
* The block DMA iterator (blk_dma_map_iter_start) caches the P2PDMA mapping
* state from the first segment and applies it to all subsequent segments, so
* P2PDMA pages from different pgmaps must not be mixed in the same bio.
*
* Other zone device types (FS_DAX, GENERIC) use the same dma_map_phys() path
* as normal RAM. PRIVATE and COHERENT pages never appear in bios.
*/
static inline bool zone_device_pages_compatible(const struct page *a,
const struct page *b)
{
if (is_pci_p2pdma_page(a) || is_pci_p2pdma_page(b))
return zone_device_pages_have_same_pgmap(a, b);
return true;
}
static inline bool __bvec_gap_to_prev(const struct queue_limits *lim,
struct bio_vec *bprv, unsigned int offset)
{

View File

@ -1319,10 +1319,18 @@ static bool ublk_copy_user_bvec(const struct bio_vec *bv, unsigned *offset,
len = bv->bv_len - *offset;
bv_buf = kmap_local_page(bv->bv_page) + bv->bv_offset + *offset;
/*
* Bio pages may originate from slab caches without a usercopy region
* (e.g. jbd2 frozen metadata buffers). This is the same data that
* the loop driver writes to its backing file no exposure risk.
* The bvec length is always trusted, so the size check in
* check_copy_size() is not needed either. Use the unchecked
* helpers to avoid false positives on slab pages.
*/
if (dir == ITER_DEST)
copied = copy_to_iter(bv_buf, len, uiter);
copied = _copy_to_iter(bv_buf, len, uiter);
else
copied = copy_from_iter(bv_buf, len, uiter);
copied = _copy_from_iter(bv_buf, len, uiter);
kunmap_local(bv_buf);
@ -5413,39 +5421,88 @@ static int ublk_ctrl_reg_buf(struct ublk_device *ub,
return ret;
}
static int __ublk_ctrl_unreg_buf(struct ublk_device *ub, int buf_index)
static void ublk_unpin_range_pages(unsigned long base_pfn,
unsigned long nr_pages)
{
#define UBLK_UNPIN_BATCH 32
struct page *pages[UBLK_UNPIN_BATCH];
unsigned long off;
for (off = 0; off < nr_pages; ) {
unsigned int batch = min_t(unsigned long,
nr_pages - off, UBLK_UNPIN_BATCH);
unsigned int j;
for (j = 0; j < batch; j++)
pages[j] = pfn_to_page(base_pfn + off + j);
unpin_user_pages(pages, batch);
off += batch;
}
}
/*
* Inner loop: erase up to UBLK_REMOVE_BATCH matching ranges under
* mas_lock, collecting them into an xarray. Then drop the lock and
* unpin pages + free ranges outside spinlock context.
*
* Returns true if the tree walk completed, false if more ranges remain.
* Xarray key is the base PFN, value encodes nr_pages via xa_mk_value().
*/
#define UBLK_REMOVE_BATCH 64
static bool __ublk_shmem_remove_ranges(struct ublk_device *ub,
int buf_index, int *ret)
{
MA_STATE(mas, &ub->buf_tree, 0, ULONG_MAX);
struct ublk_buf_range *range;
struct page *pages[32];
int ret = -ENOENT;
struct xarray to_unpin;
unsigned long idx;
unsigned int count = 0;
bool done = false;
void *entry;
xa_init(&to_unpin);
mas_lock(&mas);
mas_for_each(&mas, range, ULONG_MAX) {
unsigned long base, nr, off;
unsigned long nr;
if (range->buf_index != buf_index)
if (buf_index >= 0 && range->buf_index != buf_index)
continue;
ret = 0;
base = mas.index;
nr = mas.last - base + 1;
*ret = 0;
nr = mas.last - mas.index + 1;
if (xa_err(xa_store(&to_unpin, mas.index,
xa_mk_value(nr), GFP_ATOMIC)))
goto unlock;
mas_erase(&mas);
for (off = 0; off < nr; ) {
unsigned int batch = min_t(unsigned long,
nr - off, 32);
unsigned int j;
for (j = 0; j < batch; j++)
pages[j] = pfn_to_page(base + off + j);
unpin_user_pages(pages, batch);
off += batch;
}
kfree(range);
if (++count >= UBLK_REMOVE_BATCH)
goto unlock;
}
done = true;
unlock:
mas_unlock(&mas);
xa_for_each(&to_unpin, idx, entry)
ublk_unpin_range_pages(idx, xa_to_value(entry));
xa_destroy(&to_unpin);
return done;
}
/*
* Remove ranges from the maple tree matching buf_index, unpin pages
* and free range structs. If buf_index < 0, remove all ranges.
* Processes ranges in batches to avoid holding the maple tree spinlock
* across potentially expensive page unpinning.
*/
static int ublk_shmem_remove_ranges(struct ublk_device *ub, int buf_index)
{
int ret = -ENOENT;
while (!__ublk_shmem_remove_ranges(ub, buf_index, &ret))
cond_resched();
return ret;
}
@ -5464,7 +5521,7 @@ static int ublk_ctrl_unreg_buf(struct ublk_device *ub,
memflags = ublk_lock_buf_tree(ub);
ret = __ublk_ctrl_unreg_buf(ub, index);
ret = ublk_shmem_remove_ranges(ub, index);
if (!ret)
ida_free(&ub->buf_ida, index);
@ -5474,27 +5531,7 @@ static int ublk_ctrl_unreg_buf(struct ublk_device *ub,
static void ublk_buf_cleanup(struct ublk_device *ub)
{
MA_STATE(mas, &ub->buf_tree, 0, ULONG_MAX);
struct ublk_buf_range *range;
struct page *pages[32];
mas_for_each(&mas, range, ULONG_MAX) {
unsigned long base = mas.index;
unsigned long nr = mas.last - base + 1;
unsigned long off;
for (off = 0; off < nr; ) {
unsigned int batch = min_t(unsigned long,
nr - off, 32);
unsigned int j;
for (j = 0; j < batch; j++)
pages[j] = pfn_to_page(base + off + j);
unpin_user_pages(pages, batch);
off += batch;
}
kfree(range);
}
ublk_shmem_remove_ranges(ub, -1);
mtree_destroy(&ub->buf_tree);
ida_destroy(&ub->buf_ida);
}

View File

@ -288,12 +288,29 @@ static bool zloop_do_open_zone(struct zloop_device *zlo,
}
}
static void zloop_mark_full(struct zloop_device *zlo, struct zloop_zone *zone)
{
lockdep_assert_held(&zone->wp_lock);
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_FULL;
zone->wp = ULLONG_MAX;
}
static void zloop_mark_empty(struct zloop_device *zlo, struct zloop_zone *zone)
{
lockdep_assert_held(&zone->wp_lock);
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_EMPTY;
zone->wp = zone->start;
}
static int zloop_update_seq_zone(struct zloop_device *zlo, unsigned int zone_no)
{
struct zloop_zone *zone = &zlo->zones[zone_no];
struct kstat stat;
sector_t file_sectors;
unsigned long flags;
int ret;
lockdep_assert_held(&zone->lock);
@ -313,28 +330,24 @@ static int zloop_update_seq_zone(struct zloop_device *zlo, unsigned int zone_no)
return -EINVAL;
}
if (file_sectors & ((zlo->block_size >> SECTOR_SHIFT) - 1)) {
pr_err("Zone %u file size not aligned to block size %u\n",
zone_no, zlo->block_size);
if (!IS_ALIGNED(stat.size, zlo->block_size)) {
pr_err("Zone %u file size (%llu) not aligned to block size %u\n",
zone_no, stat.size, zlo->block_size);
return -EINVAL;
}
spin_lock_irqsave(&zone->wp_lock, flags);
spin_lock(&zone->wp_lock);
if (!file_sectors) {
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_EMPTY;
zone->wp = zone->start;
zloop_mark_empty(zlo, zone);
} else if (file_sectors == zlo->zone_capacity) {
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_FULL;
zone->wp = ULLONG_MAX;
zloop_mark_full(zlo, zone);
} else {
if (zone->cond != BLK_ZONE_COND_IMP_OPEN &&
zone->cond != BLK_ZONE_COND_EXP_OPEN)
zone->cond = BLK_ZONE_COND_CLOSED;
zone->wp = zone->start + file_sectors;
}
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
return 0;
}
@ -367,7 +380,6 @@ static int zloop_open_zone(struct zloop_device *zlo, unsigned int zone_no)
static int zloop_close_zone(struct zloop_device *zlo, unsigned int zone_no)
{
struct zloop_zone *zone = &zlo->zones[zone_no];
unsigned long flags;
int ret = 0;
if (test_bit(ZLOOP_ZONE_CONV, &zone->flags))
@ -386,13 +398,13 @@ static int zloop_close_zone(struct zloop_device *zlo, unsigned int zone_no)
break;
case BLK_ZONE_COND_IMP_OPEN:
case BLK_ZONE_COND_EXP_OPEN:
spin_lock_irqsave(&zone->wp_lock, flags);
spin_lock(&zone->wp_lock);
zloop_lru_remove_open_zone(zlo, zone);
if (zone->wp == zone->start)
zone->cond = BLK_ZONE_COND_EMPTY;
else
zone->cond = BLK_ZONE_COND_CLOSED;
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
break;
case BLK_ZONE_COND_EMPTY:
case BLK_ZONE_COND_FULL:
@ -410,7 +422,6 @@ static int zloop_close_zone(struct zloop_device *zlo, unsigned int zone_no)
static int zloop_reset_zone(struct zloop_device *zlo, unsigned int zone_no)
{
struct zloop_zone *zone = &zlo->zones[zone_no];
unsigned long flags;
int ret = 0;
if (test_bit(ZLOOP_ZONE_CONV, &zone->flags))
@ -428,12 +439,10 @@ static int zloop_reset_zone(struct zloop_device *zlo, unsigned int zone_no)
goto unlock;
}
spin_lock_irqsave(&zone->wp_lock, flags);
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_EMPTY;
zone->wp = zone->start;
spin_lock(&zone->wp_lock);
zloop_mark_empty(zlo, zone);
clear_bit(ZLOOP_ZONE_SEQ_ERROR, &zone->flags);
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
unlock:
mutex_unlock(&zone->lock);
@ -458,7 +467,6 @@ static int zloop_reset_all_zones(struct zloop_device *zlo)
static int zloop_finish_zone(struct zloop_device *zlo, unsigned int zone_no)
{
struct zloop_zone *zone = &zlo->zones[zone_no];
unsigned long flags;
int ret = 0;
if (test_bit(ZLOOP_ZONE_CONV, &zone->flags))
@ -476,12 +484,10 @@ static int zloop_finish_zone(struct zloop_device *zlo, unsigned int zone_no)
goto unlock;
}
spin_lock_irqsave(&zone->wp_lock, flags);
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_FULL;
zone->wp = ULLONG_MAX;
spin_lock(&zone->wp_lock);
zloop_mark_full(zlo, zone);
clear_bit(ZLOOP_ZONE_SEQ_ERROR, &zone->flags);
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
unlock:
mutex_unlock(&zone->lock);
@ -571,10 +577,9 @@ static int zloop_seq_write_prep(struct zloop_cmd *cmd)
bool is_append = req_op(rq) == REQ_OP_ZONE_APPEND;
struct zloop_zone *zone = &zlo->zones[zone_no];
sector_t zone_end = zone->start + zlo->zone_capacity;
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&zone->wp_lock, flags);
spin_lock(&zone->wp_lock);
/*
* Zone append operations always go at the current write pointer, but
@ -616,14 +621,11 @@ static int zloop_seq_write_prep(struct zloop_cmd *cmd)
*/
if (!is_append || !zlo->ordered_zone_append) {
zone->wp += nr_sectors;
if (zone->wp == zone_end) {
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_FULL;
zone->wp = ULLONG_MAX;
}
if (zone->wp == zone_end)
zloop_mark_full(zlo, zone);
}
out_unlock:
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
return ret;
}
@ -861,25 +863,21 @@ static bool zloop_set_zone_append_sector(struct request *rq)
struct zloop_zone *zone = &zlo->zones[zone_no];
sector_t zone_end = zone->start + zlo->zone_capacity;
sector_t nr_sectors = blk_rq_sectors(rq);
unsigned long flags;
spin_lock_irqsave(&zone->wp_lock, flags);
spin_lock(&zone->wp_lock);
if (zone->cond == BLK_ZONE_COND_FULL ||
zone->wp + nr_sectors > zone_end) {
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
return false;
}
rq->__sector = zone->wp;
zone->wp += blk_rq_sectors(rq);
if (zone->wp >= zone_end) {
zloop_lru_remove_open_zone(zlo, zone);
zone->cond = BLK_ZONE_COND_FULL;
zone->wp = ULLONG_MAX;
}
if (zone->wp >= zone_end)
zloop_mark_full(zlo, zone);
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
return true;
}
@ -891,8 +889,10 @@ static blk_status_t zloop_queue_rq(struct blk_mq_hw_ctx *hctx,
struct zloop_cmd *cmd = blk_mq_rq_to_pdu(rq);
struct zloop_device *zlo = rq->q->queuedata;
if (data_race(READ_ONCE(zlo->state)) == Zlo_deleting)
if (data_race(READ_ONCE(zlo->state)) == Zlo_deleting) {
rq->rq_flags |= RQF_QUIET;
return BLK_STS_IOERR;
}
/*
* If we need to strongly order zone append operations, set the request
@ -938,7 +938,6 @@ static int zloop_report_zones(struct gendisk *disk, sector_t sector,
struct zloop_device *zlo = disk->private_data;
struct blk_zone blkz = {};
unsigned int first, i;
unsigned long flags;
int ret;
first = disk_zone_no(disk, sector);
@ -962,9 +961,9 @@ static int zloop_report_zones(struct gendisk *disk, sector_t sector,
blkz.start = zone->start;
blkz.len = zlo->zone_size;
spin_lock_irqsave(&zone->wp_lock, flags);
spin_lock(&zone->wp_lock);
blkz.wp = zone->wp;
spin_unlock_irqrestore(&zone->wp_lock, flags);
spin_unlock(&zone->wp_lock);
blkz.cond = zone->cond;
if (test_bit(ZLOOP_ZONE_CONV, &zone->flags)) {
blkz.type = BLK_ZONE_TYPE_CONVENTIONAL;
@ -1363,20 +1362,6 @@ static int zloop_ctl_add(struct zloop_options *opts)
return ret;
}
static void zloop_truncate(struct file *file, loff_t pos)
{
struct mnt_idmap *idmap = file_mnt_idmap(file);
struct dentry *dentry = file_dentry(file);
struct iattr newattrs;
newattrs.ia_size = pos;
newattrs.ia_valid = ATTR_SIZE;
inode_lock(dentry->d_inode);
notify_change(idmap, dentry, &newattrs, NULL);
inode_unlock(dentry->d_inode);
}
static void zloop_forget_cache(struct zloop_device *zlo)
{
unsigned int i;
@ -1401,8 +1386,18 @@ static void zloop_forget_cache(struct zloop_device *zlo)
zlo->disk->part0, ret);
continue;
}
if (old_wp < zone->wp)
zloop_truncate(file, old_wp);
if (old_wp > zone->wp)
continue;
/*
* This should not happen, if we recored a full zone, it can't
* be active.
*/
if (WARN_ON_ONCE(old_wp == ULLONG_MAX))
continue;
vfs_truncate(&file->f_path,
(old_wp - zone->start) << SECTOR_SHIFT);
}
}

View File

@ -4,6 +4,7 @@
#include <linux/types.h>
#include <linux/blk-mq.h>
#include <linux/wordpart.h>
/*
* A T10 PI-capable target device can be formatted with different
@ -25,6 +26,16 @@ enum t10_dif_type {
T10_PI_TYPE3_PROTECTION = 0x3,
};
static inline u64 full_pi_ref_tag(const struct request *rq)
{
unsigned int shift = ilog2(queue_logical_block_size(rq->q));
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
rq->q->limits.integrity.interval_exp)
shift = rq->q->limits.integrity.interval_exp;
return blk_rq_pos(rq) >> (shift - SECTOR_SHIFT);
}
/*
* T10 Protection Information tuple.
*/
@ -39,12 +50,7 @@ struct t10_pi_tuple {
static inline u32 t10_pi_ref_tag(struct request *rq)
{
unsigned int shift = ilog2(queue_logical_block_size(rq->q));
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
rq->q->limits.integrity.interval_exp)
shift = rq->q->limits.integrity.interval_exp;
return blk_rq_pos(rq) >> (shift - SECTOR_SHIFT) & 0xffffffff;
return lower_32_bits(full_pi_ref_tag(rq));
}
struct crc64_pi_tuple {
@ -64,12 +70,7 @@ static inline u64 lower_48_bits(u64 n)
static inline u64 ext_pi_ref_tag(struct request *rq)
{
unsigned int shift = ilog2(queue_logical_block_size(rq->q));
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
rq->q->limits.integrity.interval_exp)
shift = rq->q->limits.integrity.interval_exp;
return lower_48_bits(blk_rq_pos(rq) >> (shift - SECTOR_SHIFT));
return lower_48_bits(full_pi_ref_tag(rq));
}
#endif

View File

@ -37,6 +37,7 @@ TEST_PROGS += test_loop_07.sh
TEST_PROGS += test_integrity_01.sh
TEST_PROGS += test_integrity_02.sh
TEST_PROGS += test_integrity_03.sh
TEST_PROGS += test_recover_01.sh
TEST_PROGS += test_recover_02.sh

View File

@ -18,7 +18,7 @@ dev_id=$(_add_ublk_dev -t loop -q 2 -b "${UBLK_BACKFILES[0]}")
_check_add_dev $TID $?
if ! _mkfs_mount_test /dev/ublkb"${dev_id}"; then
_cleanup_test "generic"
_cleanup_test
_show_result $TID 255
fi
@ -27,5 +27,5 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "generic"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -25,5 +25,5 @@ fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrit
--iodepth=32 --size=100M --numjobs=4 > /dev/null 2>&1
ERR_CODE=$?
_cleanup_test "generic"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -25,5 +25,5 @@ fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrit
--iodepth=32 --size=100M --numjobs=4 > /dev/null 2>&1
ERR_CODE=$?
_cleanup_test "generic"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -29,7 +29,7 @@ for _ in $(seq 100); do
done
if ! kill -0 "$btrace_pid" 2>/dev/null; then
_cleanup_test "null"
_cleanup_test
exit "$UBLK_SKIP_CODE"
fi
@ -51,5 +51,5 @@ if grep -q "^out_of_order:" "$UBLK_TMP"; then
grep "^out_of_order:" "$UBLK_TMP"
ERR_CODE=255
fi
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -23,5 +23,5 @@ fi
if [ "$max_segment_size" != "32768" ]; then
ERR_CODE=255
fi
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -36,5 +36,5 @@ if [ $ELAPSED -ge 5 ]; then
ERR_CODE=255
fi
_cleanup_test "fault_inject"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -23,5 +23,5 @@ if [ "$ERR_CODE" -eq 0 ]; then
ERR_CODE=$?
fi
_cleanup_test "generic"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -18,7 +18,7 @@ dev_id=$(_add_ublk_dev -t loop -q 2 --auto_zc "${UBLK_BACKFILES[0]}")
_check_add_dev $TID $?
if ! _mkfs_mount_test /dev/ublkb"${dev_id}"; then
_cleanup_test "generic"
_cleanup_test
_show_result $TID 255
fi
@ -27,5 +27,5 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "generic"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -22,6 +22,6 @@ _check_add_dev $TID $?
fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1
ERR_CODE=$?
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -25,5 +25,5 @@ if [ "$new_size" != "$size" ]; then
ERR_CODE=255
fi
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -25,7 +25,7 @@ btrace_pid=$!
sleep 2
if ! kill -0 "$btrace_pid" > /dev/null 2>&1; then
_cleanup_test "null"
_cleanup_test
exit "$UBLK_SKIP_CODE"
fi
@ -54,5 +54,5 @@ if [[ $NR_THREADS_THAT_HANDLED_IO -ne $NTHREADS ]]; then
ERR_CODE=255
fi
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -15,5 +15,5 @@ if ${UBLK_PROG} features | grep -q unknown; then
ERR_CODE=255
fi
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -9,7 +9,7 @@ _prep_test "null" "stop --safe command"
# Check if SAFE_STOP_DEV feature is supported
if ! _have_feature "SAFE_STOP_DEV"; then
_cleanup_test "null"
_cleanup_test
exit "$UBLK_SKIP_CODE"
fi
@ -52,5 +52,5 @@ wait $dd_pid 2>/dev/null
_ublk_del_dev "${dev_id}"
udevadm settle
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -31,5 +31,5 @@ fi
# time out here
_ublk_del_dev "${dev_id}"
_cleanup_test "fault_inject"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -7,9 +7,10 @@ if ! _have_program fio; then
exit $UBLK_SKIP_CODE
fi
min_fio_version=fio-3.42
fio_version=$(fio --version)
if [[ "$fio_version" =~ fio-[0-9]+\.[0-9]+$ ]]; then
echo "Requires development fio version with https://github.com/axboe/fio/pull/1992"
if ! sort --version-sort --check=quiet <(printf "%s\n%s\n" "$min_fio_version" "$fio_version"); then
echo "Requires fio version with https://github.com/axboe/fio/pull/1992"
exit $UBLK_SKIP_CODE
fi

View File

@ -0,0 +1,103 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
if ! _have_program fio; then
exit $UBLK_SKIP_CODE
fi
_test_fill_and_verify() {
fio --name fill --rw randwrite $fio_args > /dev/null
if [ $? != 0 ]; then
echo "fio fill failed"
ERR_CODE=255
return 1
fi
fio --name verify --rw randread $fio_args > /dev/null
if [ $? != 0 ]; then
echo "fio verify failed"
ERR_CODE=255
return 1
fi
}
_test_corrupted_reftag() {
local dd_reftag_args="bs=1 seek=58 count=6 oflag=dsync conv=notrunc status=none"
# Overwrite 6-byte reftag at offset 48 + 10 = 58
dd if=/dev/urandom "of=${UBLK_BACKFILES[1]}" $dd_reftag_args
if [ $? != 0 ]; then
echo "dd corrupted_reftag failed"
ERR_CODE=255
return 1
fi
if fio --name corrupted_reftag --rw randread $fio_args > /dev/null 2> "$fio_err"; then
echo "fio corrupted_reftag unexpectedly succeeded"
ERR_CODE=255
return 1
fi
if ! grep -q "$expected_err" "$fio_err"; then
echo "fio corrupted_reftag message not found: $expected_err"
ERR_CODE=255
return 1
fi
# Reset to 0
dd if=/dev/zero "of=${UBLK_BACKFILES[1]}" $dd_reftag_args
if [ $? != 0 ]; then
echo "dd restore corrupted_reftag failed"
ERR_CODE=255
return 1
fi
}
_test_corrupted_data() {
local dd_data_args="bs=512 count=1 oflag=direct,dsync conv=notrunc status=none"
dd if=/dev/zero "of=${UBLK_BACKFILES[0]}" $dd_data_args
if [ $? != 0 ]; then
echo "dd corrupted_data failed"
ERR_CODE=255
return 1
fi
if fio --name corrupted_data --rw randread $fio_args > /dev/null 2> "$fio_err"; then
echo "fio corrupted_data unexpectedly succeeded"
ERR_CODE=255
return 1
fi
if ! grep -q "$expected_err" "$fio_err"; then
echo "fio corrupted_data message not found: $expected_err"
ERR_CODE=255
return 1
fi
}
_prep_test "loop" "end-to-end auto integrity"
_create_backfile 0 256M
_create_backfile 1 32M # 256M * (64 integrity bytes / 512 data bytes)
integrity_params="--integrity_capable --integrity_reftag
--metadata_size 64 --pi_offset 48 --csum_type nvme"
dev_id=$(_add_ublk_dev -t loop -u $integrity_params "${UBLK_BACKFILES[@]}")
_check_add_dev "$TID" $?
fio_args="--ioengine libaio --direct 1 --bsrange 512-1M --iodepth 32
--filename /dev/ublkb$dev_id"
fio_err=$(mktemp "${UBLK_TEST_DIR}"/fio_err_XXXXX)
ERR_CODE=0
expected_err="Invalid or incomplete multibyte or wide character: read offset=0"
_test_fill_and_verify && \
_test_corrupted_reftag && \
_test_corrupted_data
rm -f "$fio_err"
_cleanup_test
_show_result "$TID" $ERR_CODE

View File

@ -20,6 +20,6 @@ _check_add_dev $TID $?
_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M
ERR_CODE=$?
_cleanup_test "loop"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -14,6 +14,6 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "loop"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -19,6 +19,6 @@ _check_add_dev $TID $?
_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M
ERR_CODE=$?
_cleanup_test "loop"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -15,6 +15,6 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "loop"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -20,6 +20,6 @@ _check_add_dev $TID $?
_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M
ERR_CODE=$?
_cleanup_test "loop"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -19,6 +19,6 @@ _check_add_dev $TID $?
_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M
ERR_CODE=$?
_cleanup_test "loop"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -15,6 +15,6 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "loop"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -18,6 +18,6 @@ _check_add_dev $TID $?
fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1
ERR_CODE=$?
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -18,6 +18,6 @@ _check_add_dev $TID $?
fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1
ERR_CODE=$?
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -18,6 +18,6 @@ _check_add_dev $TID $?
fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1
ERR_CODE=$?
_cleanup_test "null"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -82,7 +82,7 @@ fi
_prep_test "generic" "test UBLK_F_NO_AUTO_PART_SCAN"
if ! _have_feature "UBLK_F_NO_AUTO_PART_SCAN"; then
_cleanup_test "generic"
_cleanup_test
exit "$UBLK_SKIP_CODE"
fi
@ -100,5 +100,5 @@ format_backing_file "${UBLK_BACKFILES[0]}"
[ "$ERR_CODE" -eq 0 ] && test_no_auto_part_scan "${UBLK_BACKFILES[0]}"
[ $? -ne 0 ] && ERR_CODE=255
_cleanup_test "generic"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -63,5 +63,5 @@ _test_partition_scan_no_hang "no" "DEAD"
# Test 2: With recovery support - should transition to QUIESCED
_test_partition_scan_no_hang "yes" "QUIESCED"
_cleanup_test "partition_scan"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -40,5 +40,5 @@ ublk_run_recover_test -t loop -q 2 -r 1 -i 1 "${UBLK_BACKFILES[0]}" &
ublk_run_recover_test -t stripe -q 2 -r 1 -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
wait
_cleanup_test "recover"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -44,5 +44,5 @@ ublk_run_recover_test -t loop -q 2 -r 1 -z -i 1 "${UBLK_BACKFILES[0]}" &
ublk_run_recover_test -t stripe -q 2 -r 1 -z -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
wait
_cleanup_test "recover"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -39,5 +39,5 @@ ublk_run_quiesce_recover -t loop -q 2 -r 1 -i 1 "${UBLK_BACKFILES[0]}" &
ublk_run_quiesce_recover -t stripe -q 2 -r 1 -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
wait
_cleanup_test "quiesce"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -35,5 +35,5 @@ ublk_run_recover_test -t loop -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[0]}" &
ublk_run_recover_test -t stripe -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
wait
_cleanup_test "recover"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -67,6 +67,6 @@ umount "$HTLB_MNT"
rmdir "$HTLB_MNT"
echo "$OLD_NR_HP" > /proc/sys/vm/nr_hugepages
_cleanup_test "shmem_zc"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -63,6 +63,6 @@ umount "$HTLB_MNT"
rmdir "$HTLB_MNT"
echo "$OLD_NR_HP" > /proc/sys/vm/nr_hugepages
_cleanup_test "shmem_zc"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -64,6 +64,6 @@ umount "$HTLB_MNT"
rmdir "$HTLB_MNT"
echo "$OLD_NR_HP" > /proc/sys/vm/nr_hugepages
_cleanup_test "shmem_zc"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -67,6 +67,6 @@ umount "$HTLB_MNT"
rmdir "$HTLB_MNT"
echo "$OLD_NR_HP" > /proc/sys/vm/nr_hugepages
_cleanup_test "shmem_zc"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -29,5 +29,5 @@ ublk_io_and_remove 256M -t loop -q 4 "${UBLK_BACKFILES[0]}" &
ublk_io_and_remove 256M -t stripe -q 4 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
wait
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -31,5 +31,5 @@ for nr_queue in 1 4; do
wait
done
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -49,5 +49,5 @@ if _have_feature "PER_IO_DAEMON"; then
wait
fi
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -48,5 +48,5 @@ if _have_feature "PER_IO_DAEMON"; then
wait
fi
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -79,5 +79,5 @@ if _have_feature "PER_IO_DAEMON"; then
fi
wait
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -34,5 +34,5 @@ ublk_io_and_remove 256M -t loop -q 4 -u --nthreads 8 --per_io_tasks "${UBLK_BACK
ublk_io_and_remove 256M -t stripe -q 4 -u --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
wait
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -34,5 +34,5 @@ ublk_io_and_kill_daemon 256M -t loop -q 4 -u --nthreads 8 --per_io_tasks "${UBLK
ublk_io_and_kill_daemon 256M -t stripe -q 4 -u --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
wait
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -40,5 +40,5 @@ ublk_io_and_remove 256M -t stripe -q 4 --auto_zc -b "${UBLK_BACKFILES[1]}" "${UB
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback -b &
wait
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -39,5 +39,5 @@ ublk_io_and_kill_daemon 256M -t stripe -q 4 -b "${UBLK_BACKFILES[1]}" "${UBLK_BA
ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback -b &
wait
_cleanup_test "stress"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -21,5 +21,5 @@ _check_add_dev $TID $?
_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=512M
ERR_CODE=$?
_cleanup_test "stripe"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -16,5 +16,5 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "stripe"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -21,5 +21,5 @@ _check_add_dev $TID $?
_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=512M
ERR_CODE=$?
_cleanup_test "stripe"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -16,5 +16,5 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "stripe"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -21,5 +21,5 @@ _check_add_dev $TID $?
_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=512M
ERR_CODE=$?
_cleanup_test "stripe"
_cleanup_test
_show_result $TID $ERR_CODE

View File

@ -16,5 +16,5 @@ _check_add_dev $TID $?
_mkfs_mount_test /dev/ublkb"${dev_id}"
ERR_CODE=$?
_cleanup_test "stripe"
_cleanup_test
_show_result $TID $ERR_CODE