zvol: cleanup error handling and passthrough

This is trying to get all the uses and non-uses of SET_ERROR correct
(being: only call it if we're the originator of an error _within ZFS_),
and correctly negating errors going to/from the kernel. And/or both.

Sponsored-by: Klara, Inc.
Sponsored-by: Railway Corporation
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #17605
This commit is contained in:
Rob Norris 2025-08-09 10:04:01 +10:00 committed by GitHub
parent 90a1e13df2
commit 2fd145b578
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 42 additions and 40 deletions

View File

@ -84,8 +84,9 @@ static unsigned int zvol_blk_mq_blocks_per_thread = 8;
static inline void static inline void
zvol_end_io(struct bio *bio, struct request *rq, int error) zvol_end_io(struct bio *bio, struct request *rq, int error)
{ {
ASSERT3U(error, >=, 0);
if (bio) { if (bio) {
bio->bi_status = errno_to_bi_status(-error); bio->bi_status = errno_to_bi_status(error);
bio_endio(bio); bio_endio(bio);
} else { } else {
blk_mq_end_request(rq, errno_to_bi_status(error)); blk_mq_end_request(rq, errno_to_bi_status(error));
@ -288,7 +289,7 @@ zvol_write(zv_request_t *zvr)
blk_generic_end_io_acct(q, disk, WRITE, bio, start_time); blk_generic_end_io_acct(q, disk, WRITE, bio, start_time);
} }
zvol_end_io(bio, rq, -error); zvol_end_io(bio, rq, error);
} }
static void static void
@ -377,7 +378,7 @@ unlock:
start_time); start_time);
} }
zvol_end_io(bio, rq, -error); zvol_end_io(bio, rq, error);
} }
static void static void
@ -455,7 +456,7 @@ zvol_read(zv_request_t *zvr)
blk_generic_end_io_acct(q, disk, READ, bio, start_time); blk_generic_end_io_acct(q, disk, READ, bio, start_time);
} }
zvol_end_io(bio, rq, -error); zvol_end_io(bio, rq, error);
} }
static void static void
@ -486,7 +487,7 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq,
int rw = io_data_dir(bio, rq); int rw = io_data_dir(bio, rq);
if (unlikely(zv->zv_flags & ZVOL_REMOVING)) { if (unlikely(zv->zv_flags & ZVOL_REMOVING)) {
zvol_end_io(bio, rq, -SET_ERROR(ENXIO)); zvol_end_io(bio, rq, SET_ERROR(ENXIO));
goto out; goto out;
} }
@ -505,7 +506,7 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq,
(long long unsigned)offset, (long long unsigned)offset,
(long unsigned)size); (long unsigned)size);
zvol_end_io(bio, rq, -SET_ERROR(EIO)); zvol_end_io(bio, rq, SET_ERROR(EIO));
goto out; goto out;
} }
@ -527,7 +528,7 @@ zvol_request_impl(zvol_state_t *zv, struct bio *bio, struct request *rq,
if (rw == WRITE) { if (rw == WRITE) {
if (unlikely(zv->zv_flags & ZVOL_RDONLY)) { if (unlikely(zv->zv_flags & ZVOL_RDONLY)) {
zvol_end_io(bio, rq, -SET_ERROR(EROFS)); zvol_end_io(bio, rq, SET_ERROR(EROFS));
goto out; goto out;
} }
@ -892,16 +893,18 @@ zvol_ioctl(struct block_device *bdev, fmode_t mode,
case BLKZNAME: case BLKZNAME:
mutex_enter(&zv->zv_state_lock); mutex_enter(&zv->zv_state_lock);
error = copy_to_user((void *)arg, zv->zv_name, MAXNAMELEN); error = -copy_to_user((void *)arg, zv->zv_name, MAXNAMELEN);
mutex_exit(&zv->zv_state_lock); mutex_exit(&zv->zv_state_lock);
if (error)
error = SET_ERROR(error);
break; break;
default: default:
error = -ENOTTY; error = SET_ERROR(ENOTTY);
break; break;
} }
return (SET_ERROR(error)); return (-error);
} }
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
@ -1480,7 +1483,9 @@ __zvol_os_add_disk(struct gendisk *disk)
{ {
int error = 0; int error = 0;
#ifdef HAVE_ADD_DISK_RET #ifdef HAVE_ADD_DISK_RET
error = add_disk(disk); error = -add_disk(disk);
if (error)
error = SET_ERROR(error);
#else #else
add_disk(disk); add_disk(disk);
#endif #endif
@ -1765,10 +1770,10 @@ zvol_init(void)
return (error); return (error);
} }
error = register_blkdev(zvol_major, ZVOL_DRIVER); error = -register_blkdev(zvol_major, ZVOL_DRIVER);
if (error) { if (error) {
printk(KERN_INFO "ZFS: register_blkdev() failed %d\n", error); printk(KERN_INFO "ZFS: register_blkdev() failed %d\n", error);
return (error); return (SET_ERROR(error));
} }
if (zvol_blk_mq_queue_depth == 0) { if (zvol_blk_mq_queue_depth == 0) {

View File

@ -253,7 +253,7 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &val); error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &val);
if (error) if (error)
return (SET_ERROR(error)); return (error);
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLSIZE, val); dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_VOLSIZE, val);
doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP); doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP);
@ -266,7 +266,7 @@ zvol_get_stats(objset_t *os, nvlist_t *nv)
kmem_free(doi, sizeof (dmu_object_info_t)); kmem_free(doi, sizeof (dmu_object_info_t));
return (SET_ERROR(error)); return (error);
} }
/* /*
@ -304,7 +304,7 @@ zvol_update_volsize(uint64_t volsize, objset_t *os)
error = dmu_tx_assign(tx, DMU_TX_WAIT); error = dmu_tx_assign(tx, DMU_TX_WAIT);
if (error) { if (error) {
dmu_tx_abort(tx); dmu_tx_abort(tx);
return (SET_ERROR(error)); return (error);
} }
txg = dmu_tx_get_txg(tx); txg = dmu_tx_get_txg(tx);
@ -336,7 +336,7 @@ zvol_set_volsize(const char *name, uint64_t volsize)
error = dsl_prop_get_integer(name, error = dsl_prop_get_integer(name,
zfs_prop_to_name(ZFS_PROP_READONLY), &readonly, NULL); zfs_prop_to_name(ZFS_PROP_READONLY), &readonly, NULL);
if (error != 0) if (error != 0)
return (SET_ERROR(error)); return (error);
if (readonly) if (readonly)
return (SET_ERROR(EROFS)); return (SET_ERROR(EROFS));
@ -352,7 +352,7 @@ zvol_set_volsize(const char *name, uint64_t volsize)
FTAG, &os)) != 0) { FTAG, &os)) != 0) {
if (zv != NULL) if (zv != NULL)
mutex_exit(&zv->zv_state_lock); mutex_exit(&zv->zv_state_lock);
return (SET_ERROR(error)); return (error);
} }
owned = B_TRUE; owned = B_TRUE;
if (zv != NULL) if (zv != NULL)
@ -389,7 +389,7 @@ out:
if (error == 0 && zv != NULL) if (error == 0 && zv != NULL)
zvol_os_update_volsize(zv, volsize); zvol_os_update_volsize(zv, volsize);
return (SET_ERROR(error)); return (error);
} }
/* /*
@ -400,7 +400,7 @@ zvol_set_volthreading(const char *name, boolean_t value)
{ {
zvol_state_t *zv = zvol_find_by_name(name, RW_NONE); zvol_state_t *zv = zvol_find_by_name(name, RW_NONE);
if (zv == NULL) if (zv == NULL)
return (ENOENT); return (SET_ERROR(ENOENT));
zv->zv_threading = value; zv->zv_threading = value;
mutex_exit(&zv->zv_state_lock); mutex_exit(&zv->zv_state_lock);
return (0); return (0);
@ -619,7 +619,7 @@ zvol_clone_range(zvol_state_t *zv_src, uint64_t inoff, zvol_state_t *zv_dst,
dmu_tx_t *tx; dmu_tx_t *tx;
blkptr_t *bps; blkptr_t *bps;
size_t maxblocks; size_t maxblocks;
int error = EINVAL; int error = 0;
rw_enter(&zv_dst->zv_suspend_lock, RW_READER); rw_enter(&zv_dst->zv_suspend_lock, RW_READER);
if (zv_dst->zv_zilog == NULL) { if (zv_dst->zv_zilog == NULL) {
@ -645,23 +645,22 @@ zvol_clone_range(zvol_state_t *zv_src, uint64_t inoff, zvol_state_t *zv_dst,
*/ */
if (!spa_feature_is_enabled(dmu_objset_spa(outos), if (!spa_feature_is_enabled(dmu_objset_spa(outos),
SPA_FEATURE_BLOCK_CLONING)) { SPA_FEATURE_BLOCK_CLONING)) {
error = EOPNOTSUPP; error = SET_ERROR(EOPNOTSUPP);
goto out; goto out;
} }
if (dmu_objset_spa(inos) != dmu_objset_spa(outos)) { if (dmu_objset_spa(inos) != dmu_objset_spa(outos)) {
error = EXDEV; error = SET_ERROR(EXDEV);
goto out; goto out;
} }
if (inos->os_encrypted != outos->os_encrypted) { if (inos->os_encrypted != outos->os_encrypted) {
error = EXDEV; error = SET_ERROR(EXDEV);
goto out; goto out;
} }
if (zv_src->zv_volblocksize != zv_dst->zv_volblocksize) { if (zv_src->zv_volblocksize != zv_dst->zv_volblocksize) {
error = EINVAL; error = SET_ERROR(EINVAL);
goto out; goto out;
} }
if (inoff >= zv_src->zv_volsize || outoff >= zv_dst->zv_volsize) { if (inoff >= zv_src->zv_volsize || outoff >= zv_dst->zv_volsize) {
error = 0;
goto out; goto out;
} }
@ -672,17 +671,15 @@ zvol_clone_range(zvol_state_t *zv_src, uint64_t inoff, zvol_state_t *zv_dst,
len = zv_src->zv_volsize - inoff; len = zv_src->zv_volsize - inoff;
if (len > zv_dst->zv_volsize - outoff) if (len > zv_dst->zv_volsize - outoff)
len = zv_dst->zv_volsize - outoff; len = zv_dst->zv_volsize - outoff;
if (len == 0) { if (len == 0)
error = 0;
goto out; goto out;
}
/* /*
* No overlapping if we are cloning within the same file * No overlapping if we are cloning within the same file
*/ */
if (zv_src == zv_dst) { if (zv_src == zv_dst) {
if (inoff < outoff + len && outoff < inoff + len) { if (inoff < outoff + len && outoff < inoff + len) {
error = EINVAL; error = SET_ERROR(EINVAL);
goto out; goto out;
} }
} }
@ -692,7 +689,7 @@ zvol_clone_range(zvol_state_t *zv_src, uint64_t inoff, zvol_state_t *zv_dst,
*/ */
if ((inoff % zv_src->zv_volblocksize) != 0 || if ((inoff % zv_src->zv_volblocksize) != 0 ||
(outoff % zv_dst->zv_volblocksize) != 0) { (outoff % zv_dst->zv_volblocksize) != 0) {
error = EINVAL; error = SET_ERROR(EINVAL);
goto out; goto out;
} }
@ -700,7 +697,7 @@ zvol_clone_range(zvol_state_t *zv_src, uint64_t inoff, zvol_state_t *zv_dst,
* Length must be multiple of block size * Length must be multiple of block size
*/ */
if ((len % zv_src->zv_volblocksize) != 0) { if ((len % zv_src->zv_volblocksize) != 0) {
error = EINVAL; error = SET_ERROR(EINVAL);
goto out; goto out;
} }
@ -778,7 +775,7 @@ out:
if (zv_src != zv_dst) if (zv_src != zv_dst)
rw_exit(&zv_src->zv_suspend_lock); rw_exit(&zv_src->zv_suspend_lock);
rw_exit(&zv_dst->zv_suspend_lock); rw_exit(&zv_dst->zv_suspend_lock);
return (SET_ERROR(error)); return (error);
} }
/* /*
@ -1027,7 +1024,7 @@ zvol_get_data(void *arg, uint64_t arg2, lr_write_t *lr, char *buf,
zvol_get_done(zgd, error); zvol_get_done(zgd, error);
return (SET_ERROR(error)); return (error);
} }
/* /*
@ -1072,15 +1069,15 @@ zvol_setup_zv(zvol_state_t *zv)
error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL); error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
if (error) if (error)
return (SET_ERROR(error)); return (error);
error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize); error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
if (error) if (error)
return (SET_ERROR(error)); return (error);
error = dnode_hold(os, ZVOL_OBJ, zv, &zv->zv_dn); error = dnode_hold(os, ZVOL_OBJ, zv, &zv->zv_dn);
if (error) if (error)
return (SET_ERROR(error)); return (error);
zvol_os_set_capacity(zv, volsize >> 9); zvol_os_set_capacity(zv, volsize >> 9);
zv->zv_volsize = volsize; zv->zv_volsize = volsize;
@ -1199,7 +1196,7 @@ zvol_resume(zvol_state_t *zv)
if (zv->zv_flags & ZVOL_REMOVING) if (zv->zv_flags & ZVOL_REMOVING)
cv_broadcast(&zv->zv_removing_cv); cv_broadcast(&zv->zv_removing_cv);
return (SET_ERROR(error)); return (error);
} }
int int
@ -1215,7 +1212,7 @@ zvol_first_open(zvol_state_t *zv, boolean_t readonly)
boolean_t ro = (readonly || (strchr(zv->zv_name, '@') != NULL)); boolean_t ro = (readonly || (strchr(zv->zv_name, '@') != NULL));
error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, ro, B_TRUE, zv, &os); error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, ro, B_TRUE, zv, &os);
if (error) if (error)
return (SET_ERROR(error)); return (error);
zv->zv_objset = os; zv->zv_objset = os;
@ -1725,7 +1722,7 @@ zvol_remove_minor_impl(const char *name)
if (zv == NULL) { if (zv == NULL) {
rw_exit(&zvol_state_lock); rw_exit(&zvol_state_lock);
return (ENOENT); return (SET_ERROR(ENOENT));
} }
ASSERT(MUTEX_HELD(&zv->zv_state_lock)); ASSERT(MUTEX_HELD(&zv->zv_state_lock));