From 67e716329b905b1f2951739297c7aebacb6a6b2c Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Tue, 28 Oct 2025 18:41:36 +0200 Subject: [PATCH 01/91] ZTS: autotrim_config.ksh is missing pool type functional/trim tests do create pools of different types to test trim, autotrim_config.ksh is missing the type from zpool create command line while we are looping over different pool types. Sponsored-by: Edgecast Cloud LLC. Signed-off-by: Toomas Soome Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Closes #17874 --- tests/zfs-tests/tests/functional/trim/autotrim_config.ksh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/zfs-tests/tests/functional/trim/autotrim_config.ksh b/tests/zfs-tests/tests/functional/trim/autotrim_config.ksh index 8d4340e47bf9..a8deedfb8c3c 100755 --- a/tests/zfs-tests/tests/functional/trim/autotrim_config.ksh +++ b/tests/zfs-tests/tests/functional/trim/autotrim_config.ksh @@ -88,7 +88,7 @@ for type in "" "mirror" "raidz2" "draid"; do fi log_must truncate -s $((4 * MINVDEVSIZE)) $VDEVS - log_must zpool create -f $TESTPOOL $VDEVS + log_must zpool create -f $TESTPOOL $type $VDEVS log_must zpool set autotrim=on $TESTPOOL typeset availspace=$(get_prop available $TESTPOOL) From 3caf66c25b94e4eaef143c7932225ae83e5448e1 Mon Sep 17 00:00:00 2001 From: Quartz Date: Wed, 29 Oct 2025 03:49:05 +0800 Subject: [PATCH 02/91] man: Update zpool-event subclass names and document new types Reviewed-by: Brian Behlendorf Signed-off-by: Quartz Closes #17868 --- man/man8/zpool-events.8 | 73 +++++++++++++++++++++++++++++++---------- 1 file changed, 55 insertions(+), 18 deletions(-) diff --git a/man/man8/zpool-events.8 b/man/man8/zpool-events.8 index 36a9864dc73b..3753139bdfe7 100644 --- a/man/man8/zpool-events.8 +++ b/man/man8/zpool-events.8 @@ -113,17 +113,19 @@ See for more details on the .Sy zfs_vdev_direct_write_verify module parameter. -.It Sy config +.It Sy config_sync Issued every time a vdev change have been done to the pool. .It Sy zpool Issued when a pool cannot be imported. -.It Sy zpool.destroy +.It Sy pool_create +Issued when a pool is created. +.It Sy pool_destroy Issued when a pool is destroyed. -.It Sy zpool.export +.It Sy pool_export Issued when a pool is exported. -.It Sy zpool.import +.It Sy pool_import Issued when a pool is imported. -.It Sy zpool.reguid +.It Sy pool_reguid Issued when a REGUID (new unique identifier for the pool have been regenerated) have been detected. .It Sy vdev.unknown @@ -150,21 +152,31 @@ event. Issued when the label is OK but invalid. .It Sy vdev.bad_ashift Issued when the ashift alignment requirement has increased. -.It Sy vdev.remove +.It Sy vdev_remove Issued when a vdev is detached from a mirror (or a spare detached from a vdev where it have been used to replace a failed drive - only works if the original drive have been re-added). -.It Sy vdev.clear +.It Sy vdev_remove_aux +Issued when an auxiliary vdev is removed. +.It Sy vdev_remove_dev +Issued when a specific device is removed from a vdev. +.It Sy vdev_clear Issued when clearing device errors in a pool. Such as running .Nm zpool Cm clear on a device in the pool. -.It Sy vdev.check +.It Sy vdev_check Issued when a check to see if a given vdev could be opened is started. -.It Sy vdev.spare +.It Sy vdev_spare Issued when a spare have kicked in to replace a failed device. -.It Sy vdev.autoexpand +.It Sy vdev_autoexpand Issued when a vdev can be automatically expanded. +.It Sy vdev_add +Issued when a vdev is added to a pool. +.It Sy vdev_attach +Issued when a vdev is attached to a mirror or raidz vdev type. +.It Sy vdev_online +Issued when an offline vdev is brought online .It Sy io_failure Issued when there is an I/O failure in a vdev in the pool. .It Sy probe_failure @@ -175,21 +187,46 @@ have removed the device). .It Sy log_replay Issued when the intent log cannot be replayed. The can occur in the case of a missing or damaged log device. -.It Sy resilver.start +.It Sy resilver_start Issued when a resilver is started. -.It Sy resilver.finish +.It Sy resilver_finish Issued when the running resilver have finished. -.It Sy scrub.start +.It Sy scrub_start Issued when a scrub is started on a pool. -.It Sy scrub.finish +.It Sy scrub_finish Issued when a pool has finished scrubbing. -.It Sy scrub.abort +.It Sy scrub_abort Issued when a scrub is aborted on a pool. -.It Sy scrub.resume +.It Sy scrub_resume Issued when a scrub is resumed on a pool. -.It Sy scrub.paused +.It Sy scrub_paused Issued when a scrub is paused on a pool. -.It Sy bootfs.vdev.attach +.It Sy errorscrub_start +Issued when a errorscrub is started on a pool. +.It Sy errorscrub_finish +Issued when a pool has finished errorscrubbing. +.It Sy errorscrub_abort +Issued when a errorscrub is aborted on a pool. +.It Sy errorscrub_resume +Issued when a errorscrub is resumed on a pool. +.It Sy errorscrub_paused +Issued when a errorscrub is paused on a pool. +.It Sy trim_start +Issued when a trim is started on a pool. +.It Sy trim_finish +Issued when a pool has finished trimbing. +.It Sy trim_cancel +Issued when a trim is canceled on a pool. +.It Sy trim_resume +Issued when a trim is resumed on a pool. +.It Sy trim_suspend +Issued when a trim is suspend on a pool. +.It Sy authentication +Issued when there is a decryption / authentication error. +.It Sy config_cache_write +Issued when the config cache file cannot be written. +.It Sy bootfs_vdev_attach +Issued when a vdev is attached to a root pool with the bootfs property set. .It Sy sitout Issued when a .Sy RAIDZ From dcada084b95e994f3bd6452148e51959f2933862 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Wed, 29 Oct 2025 14:17:51 -0400 Subject: [PATCH 03/91] Pass flags to more DMU write/hold functions Over the time many of DMU functions got flags argument to control prefetch, caching, etc. Few functions though left without it, even though closer look shown that many of them do not require prefetch due to their access pattern. This patch adds the flags argument to dmu_write(), dmu_buf_hold_array() and dmu_buf_hold_array_by_bonus(), passing DMU_READ_NO_PREFETCH where applicable. I am going to also pass DMU_UNCACHEDIO to some of them later. Reviewed-by: Brian Behlendorf Reviewed-by: Rob Norris Signed-off-by: Alexander Motin Closes #17872 --- cmd/ztest.c | 15 ++++++++++----- include/sys/dmu.h | 6 +++--- module/os/freebsd/zfs/dmu_os.c | 5 +++-- module/os/freebsd/zfs/zfs_acl.c | 3 ++- module/os/freebsd/zfs/zfs_vnops_os.c | 3 ++- module/os/linux/zfs/zfs_acl.c | 3 ++- module/os/linux/zfs/zfs_vnops_os.c | 3 ++- module/zfs/bpobj.c | 7 ++++--- module/zfs/bptree.c | 9 ++++++--- module/zfs/brt.c | 2 +- module/zfs/dmu.c | 22 +++++++++++----------- module/zfs/dmu_redact.c | 6 ++++-- module/zfs/metaslab.c | 8 +++++--- module/zfs/spa.c | 3 ++- module/zfs/spa_checkpoint.c | 2 +- module/zfs/spa_history.c | 5 +++-- module/zfs/space_map.c | 2 +- module/zfs/vdev_indirect_births.c | 2 +- module/zfs/vdev_indirect_mapping.c | 5 +++-- module/zfs/zfs_fuid.c | 2 +- module/zfs/zvol.c | 3 ++- 21 files changed, 69 insertions(+), 47 deletions(-) diff --git a/cmd/ztest.c b/cmd/ztest.c index 89752dcb0f0f..7d590e5e06da 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -2306,7 +2306,8 @@ ztest_replay_write(void *arg1, void *arg2, boolean_t byteswap) } if (abuf == NULL) { - dmu_write(os, lr->lr_foid, offset, length, data, tx); + dmu_write(os, lr->lr_foid, offset, length, data, tx, + DMU_READ_PREFETCH); } else { memcpy(abuf->b_data, data, length); VERIFY0(dmu_assign_arcbuf_by_dbuf(db, offset, abuf, tx, 0)); @@ -5243,7 +5244,8 @@ ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id) * We've verified all the old bufwads, and made new ones. * Now write them out. */ - dmu_write(os, packobj, packoff, packsize, packbuf, tx); + dmu_write(os, packobj, packoff, packsize, packbuf, tx, + DMU_READ_PREFETCH); if (freeit) { if (ztest_opts.zo_verbose >= 7) { @@ -5258,7 +5260,8 @@ ztest_dmu_read_write(ztest_ds_t *zd, uint64_t id) " txg %"PRIx64"\n", bigoff, bigsize, txg); } - dmu_write(os, bigobj, bigoff, bigsize, bigbuf, tx); + dmu_write(os, bigobj, bigoff, bigsize, bigbuf, tx, + DMU_READ_PREFETCH); } dmu_tx_commit(tx); @@ -5513,7 +5516,8 @@ ztest_dmu_read_write_zcopy(ztest_ds_t *zd, uint64_t id) * We've verified all the old bufwads, and made new ones. * Now write them out. */ - dmu_write(os, packobj, packoff, packsize, packbuf, tx); + dmu_write(os, packobj, packoff, packsize, packbuf, tx, + DMU_READ_PREFETCH); if (ztest_opts.zo_verbose >= 7) { (void) printf("writing offset %"PRIx64" size %"PRIx64"" " txg %"PRIx64"\n", @@ -6119,7 +6123,8 @@ ztest_dmu_commit_callbacks(ztest_ds_t *zd, uint64_t id) "future leak: got %"PRIu64", open txg is %"PRIu64"", old_txg, txg); - dmu_write(os, od->od_object, 0, sizeof (uint64_t), &txg, tx); + dmu_write(os, od->od_object, 0, sizeof (uint64_t), &txg, tx, + DMU_READ_PREFETCH); (void) mutex_enter(&zcl.zcl_callbacks_lock); diff --git a/include/sys/dmu.h b/include/sys/dmu.h index aa5035862def..a33e16a065b1 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -625,7 +625,7 @@ int dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset, const void *tag, dmu_buf_t **, dmu_flags_t flags); int dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset, uint64_t length, int read, const void *tag, int *numbufsp, - dmu_buf_t ***dbpp); + dmu_buf_t ***dbpp, dmu_flags_t flags); int dmu_buf_hold_noread(objset_t *os, uint64_t object, uint64_t offset, const void *tag, dmu_buf_t **dbp); int dmu_buf_hold_by_dnode(dnode_t *dn, uint64_t offset, @@ -668,7 +668,7 @@ uint64_t dmu_buf_user_refcount(dmu_buf_t *db); */ int dmu_buf_hold_array_by_bonus(dmu_buf_t *db, uint64_t offset, uint64_t length, boolean_t read, const void *tag, - int *numbufsp, dmu_buf_t ***dbpp); + int *numbufsp, dmu_buf_t ***dbpp, dmu_flags_t flags); void dmu_buf_rele_array(dmu_buf_t **, int numbufs, const void *tag); typedef void dmu_buf_evict_func_t(void *user_ptr); @@ -924,7 +924,7 @@ int dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, int dmu_read_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, void *buf, dmu_flags_t flags); void dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, - const void *buf, dmu_tx_t *tx); + const void *buf, dmu_tx_t *tx, dmu_flags_t flags); int dmu_write_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, const void *buf, dmu_tx_t *tx, dmu_flags_t flags); void dmu_prealloc(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, diff --git a/module/os/freebsd/zfs/dmu_os.c b/module/os/freebsd/zfs/dmu_os.c index 26cc7981bfcd..1990ec677d37 100644 --- a/module/os/freebsd/zfs/dmu_os.c +++ b/module/os/freebsd/zfs/dmu_os.c @@ -76,7 +76,7 @@ dmu_write_pages(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, return (0); err = dmu_buf_hold_array(os, object, offset, size, - FALSE, FTAG, &numbufs, &dbp); + FALSE, FTAG, &numbufs, &dbp, DMU_READ_PREFETCH); if (err) return (err); @@ -147,7 +147,8 @@ dmu_read_pages(objset_t *os, uint64_t object, vm_page_t *ma, int count, ASSERT3S(last_size, <=, PAGE_SIZE); err = dmu_buf_hold_array(os, object, IDX_TO_OFF(ma[0]->pindex), - IDX_TO_OFF(count - 1) + last_size, TRUE, FTAG, &numbufs, &dbp); + IDX_TO_OFF(count - 1) + last_size, TRUE, FTAG, &numbufs, &dbp, + DMU_READ_PREFETCH); if (err != 0) return (err); diff --git a/module/os/freebsd/zfs/zfs_acl.c b/module/os/freebsd/zfs/zfs_acl.c index cb5787269db2..c98ccd756405 100644 --- a/module/os/freebsd/zfs/zfs_acl.c +++ b/module/os/freebsd/zfs/zfs_acl.c @@ -1262,7 +1262,8 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) if (aclnode->z_ace_count == 0) continue; dmu_write(zfsvfs->z_os, aoid, off, - aclnode->z_size, aclnode->z_acldata, tx); + aclnode->z_size, aclnode->z_acldata, tx, + DMU_READ_NO_PREFETCH); off += aclnode->z_size; } } else { diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index 25fbb77acba3..5bd3e6bf2f15 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -4481,7 +4481,8 @@ zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags, for (i = 0; wlen > 0; woff += tocopy, wlen -= tocopy, i++) { tocopy = MIN(PAGE_SIZE, wlen); va = zfs_map_page(ma[i], &sf); - dmu_write(zfsvfs->z_os, zp->z_id, woff, tocopy, va, tx); + dmu_write(zfsvfs->z_os, zp->z_id, woff, tocopy, va, tx, + DMU_READ_PREFETCH); zfs_unmap_page(sf); } } else { diff --git a/module/os/linux/zfs/zfs_acl.c b/module/os/linux/zfs/zfs_acl.c index 934d74a112fd..4c929a4642b1 100644 --- a/module/os/linux/zfs/zfs_acl.c +++ b/module/os/linux/zfs/zfs_acl.c @@ -1447,7 +1447,8 @@ zfs_aclset_common(znode_t *zp, zfs_acl_t *aclp, cred_t *cr, dmu_tx_t *tx) if (aclnode->z_ace_count == 0) continue; dmu_write(zfsvfs->z_os, aoid, off, - aclnode->z_size, aclnode->z_acldata, tx); + aclnode->z_size, aclnode->z_acldata, tx, + DMU_READ_NO_PREFETCH); off += aclnode->z_size; } } else { diff --git a/module/os/linux/zfs/zfs_vnops_os.c b/module/os/linux/zfs/zfs_vnops_os.c index e845ad69ad78..02465adf36d5 100644 --- a/module/os/linux/zfs/zfs_vnops_os.c +++ b/module/os/linux/zfs/zfs_vnops_os.c @@ -3892,7 +3892,8 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc, va = kmap(pp); ASSERT3U(pglen, <=, PAGE_SIZE); - dmu_write(zfsvfs->z_os, zp->z_id, pgoff, pglen, va, tx); + dmu_write(zfsvfs->z_os, zp->z_id, pgoff, pglen, va, tx, + DMU_READ_PREFETCH); kunmap(pp); SA_ADD_BULK_ATTR(bulk, cnt, SA_ZPL_MTIME(zfsvfs), NULL, &mtime, 16); diff --git a/module/zfs/bpobj.c b/module/zfs/bpobj.c index ea9fbd036c6e..afcb2374f824 100644 --- a/module/zfs/bpobj.c +++ b/module/zfs/bpobj.c @@ -752,7 +752,8 @@ bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx) } dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj), - numsubsub * sizeof (subobj), subdb->db_data, tx); + numsubsub * sizeof (subobj), subdb->db_data, tx, + DMU_READ_NO_PREFETCH); dmu_buf_rele(subdb, FTAG); bpo->bpo_phys->bpo_num_subobjs += numsubsub; @@ -777,7 +778,7 @@ bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx) dmu_write(bpo->bpo_os, bpo->bpo_object, bpo->bpo_phys->bpo_num_blkptrs * sizeof (blkptr_t), numbps * sizeof (blkptr_t), - bps->db_data, tx); + bps->db_data, tx, DMU_READ_NO_PREFETCH); dmu_buf_rele(bps, FTAG); bpo->bpo_phys->bpo_num_blkptrs += numbps; @@ -794,7 +795,7 @@ bpobj_enqueue_subobj(bpobj_t *bpo, uint64_t subobj, dmu_tx_t *tx) dmu_write(bpo->bpo_os, bpo->bpo_phys->bpo_subobjs, bpo->bpo_phys->bpo_num_subobjs * sizeof (subobj), - sizeof (subobj), &subobj, tx); + sizeof (subobj), &subobj, tx, DMU_READ_NO_PREFETCH); bpo->bpo_phys->bpo_num_subobjs++; } diff --git a/module/zfs/bptree.c b/module/zfs/bptree.c index a98bba3eb259..1274278e8e91 100644 --- a/module/zfs/bptree.c +++ b/module/zfs/bptree.c @@ -137,7 +137,8 @@ bptree_add(objset_t *os, uint64_t obj, blkptr_t *bp, uint64_t birth_txg, bte = kmem_zalloc(sizeof (*bte), KM_SLEEP); bte->be_birth_txg = birth_txg; bte->be_bp = *bp; - dmu_write(os, obj, bt->bt_end * sizeof (*bte), sizeof (*bte), bte, tx); + dmu_write(os, obj, bt->bt_end * sizeof (*bte), sizeof (*bte), bte, tx, + DMU_READ_NO_PREFETCH); kmem_free(bte, sizeof (*bte)); dmu_buf_will_dirty(db, tx); @@ -247,7 +248,8 @@ bptree_iterate(objset_t *os, uint64_t obj, boolean_t free, bptree_itor_t func, ZB_DESTROYED_OBJSET); ASSERT0(bte.be_zb.zb_level); dmu_write(os, obj, i * sizeof (bte), - sizeof (bte), &bte, tx); + sizeof (bte), &bte, tx, + DMU_READ_NO_PREFETCH); if (err == EIO || err == ECKSUM || err == ENXIO) { /* @@ -269,7 +271,8 @@ bptree_iterate(objset_t *os, uint64_t obj, boolean_t free, bptree_itor_t func, */ bte.be_birth_txg = UINT64_MAX; dmu_write(os, obj, i * sizeof (bte), - sizeof (bte), &bte, tx); + sizeof (bte), &bte, tx, + DMU_READ_NO_PREFETCH); } if (!ioerr) { diff --git a/module/zfs/brt.c b/module/zfs/brt.c index 40664354aa73..6655b7bca7fb 100644 --- a/module/zfs/brt.c +++ b/module/zfs/brt.c @@ -809,7 +809,7 @@ brt_vdev_sync(spa_t *spa, brt_vdev_t *brtvd, dmu_tx_t *tx) */ dmu_write(spa->spa_meta_objset, brtvd->bv_mos_brtvdev, 0, brtvd->bv_size * sizeof (brtvd->bv_entcount[0]), - brtvd->bv_entcount, tx); + brtvd->bv_entcount, tx, DMU_READ_NO_PREFETCH); uint64_t nblocks = BRT_RANGESIZE_TO_NBLOCKS(brtvd->bv_size); memset(brtvd->bv_bitmap, 0, BT_SIZEOFMAP(nblocks)); brtvd->bv_entcount_dirty = FALSE; diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index a7a5c89bdafb..249f878a1e22 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -635,7 +635,7 @@ dmu_buf_hold_array_by_dnode(dnode_t *dn, uint64_t offset, uint64_t length, int dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset, uint64_t length, int read, const void *tag, int *numbufsp, - dmu_buf_t ***dbpp) + dmu_buf_t ***dbpp, dmu_flags_t flags) { dnode_t *dn; int err; @@ -645,7 +645,7 @@ dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset, return (err); err = dmu_buf_hold_array_by_dnode(dn, offset, length, read, tag, - numbufsp, dbpp, DMU_READ_PREFETCH); + numbufsp, dbpp, flags); dnode_rele(dn, FTAG); @@ -655,14 +655,14 @@ dmu_buf_hold_array(objset_t *os, uint64_t object, uint64_t offset, int dmu_buf_hold_array_by_bonus(dmu_buf_t *db_fake, uint64_t offset, uint64_t length, boolean_t read, const void *tag, int *numbufsp, - dmu_buf_t ***dbpp) + dmu_buf_t ***dbpp, dmu_flags_t flags) { dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake; int err; DB_DNODE_ENTER(db); err = dmu_buf_hold_array_by_dnode(DB_DNODE(db), offset, length, read, - tag, numbufsp, dbpp, DMU_READ_PREFETCH); + tag, numbufsp, dbpp, flags); DB_DNODE_EXIT(db); return (err); @@ -1293,7 +1293,7 @@ dmu_write_impl(dmu_buf_t **dbp, int numbufs, uint64_t offset, uint64_t size, void dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, - const void *buf, dmu_tx_t *tx) + const void *buf, dmu_tx_t *tx, dmu_flags_t flags) { dmu_buf_t **dbp; int numbufs; @@ -1302,8 +1302,8 @@ dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, return; VERIFY0(dmu_buf_hold_array(os, object, offset, size, - FALSE, FTAG, &numbufs, &dbp)); - dmu_write_impl(dbp, numbufs, offset, size, buf, tx, DMU_READ_PREFETCH); + FALSE, FTAG, &numbufs, &dbp, flags)); + dmu_write_impl(dbp, numbufs, offset, size, buf, tx, flags); dmu_buf_rele_array(dbp, numbufs, FTAG); } @@ -1346,7 +1346,7 @@ dmu_prealloc(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, return; VERIFY0(dmu_buf_hold_array(os, object, offset, size, - FALSE, FTAG, &numbufs, &dbp)); + FALSE, FTAG, &numbufs, &dbp, DMU_READ_PREFETCH)); for (i = 0; i < numbufs; i++) { dmu_buf_t *db = dbp[i]; @@ -1383,7 +1383,7 @@ dmu_redact(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, dmu_buf_t **dbp; VERIFY0(dmu_buf_hold_array(os, object, offset, size, FALSE, FTAG, - &numbufs, &dbp)); + &numbufs, &dbp, DMU_READ_PREFETCH)); for (i = 0; i < numbufs; i++) dmu_buf_redact(dbp[i], tx); dmu_buf_rele_array(dbp, numbufs, FTAG); @@ -2592,7 +2592,7 @@ dmu_read_l0_bps(objset_t *os, uint64_t object, uint64_t offset, uint64_t length, int error, numbufs; error = dmu_buf_hold_array(os, object, offset, length, FALSE, FTAG, - &numbufs, &dbp); + &numbufs, &dbp, DMU_READ_PREFETCH); if (error != 0) { if (error == ESRCH) { error = SET_ERROR(ENXIO); @@ -2693,7 +2693,7 @@ dmu_brt_clone(objset_t *os, uint64_t object, uint64_t offset, uint64_t length, spa = os->os_spa; VERIFY0(dmu_buf_hold_array(os, object, offset, length, FALSE, FTAG, - &numbufs, &dbp)); + &numbufs, &dbp, DMU_READ_PREFETCH)); ASSERT3U(nbps, ==, numbufs); /* diff --git a/module/zfs/dmu_redact.c b/module/zfs/dmu_redact.c index 5a22ed71a5fe..c087be4c811d 100644 --- a/module/zfs/dmu_redact.c +++ b/module/zfs/dmu_redact.c @@ -544,7 +544,8 @@ redaction_list_update_sync(void *arg, dmu_tx_t *tx) if (index == bufsize) { dmu_write(mos, rl->rl_object, rl->rl_phys->rlp_num_entries * sizeof (*buf), - bufsize * sizeof (*buf), buf, tx); + bufsize * sizeof (*buf), buf, tx, + DMU_READ_NO_PREFETCH); rl->rl_phys->rlp_num_entries += bufsize; index = 0; } @@ -552,7 +553,8 @@ redaction_list_update_sync(void *arg, dmu_tx_t *tx) } if (index > 0) { dmu_write(mos, rl->rl_object, rl->rl_phys->rlp_num_entries * - sizeof (*buf), index * sizeof (*buf), buf, tx); + sizeof (*buf), index * sizeof (*buf), buf, tx, + DMU_READ_NO_PREFETCH); rl->rl_phys->rlp_num_entries += index; } kmem_free(buf, bufsize * sizeof (*buf)); diff --git a/module/zfs/metaslab.c b/module/zfs/metaslab.c index 9f4399af56bd..3f649ffb44e4 100644 --- a/module/zfs/metaslab.c +++ b/module/zfs/metaslab.c @@ -3966,7 +3966,8 @@ metaslab_condense(metaslab_t *msp, dmu_tx_t *tx) object = space_map_object(msp->ms_sm); dmu_write(spa->spa_meta_objset, msp->ms_group->mg_vd->vdev_ms_array, sizeof (uint64_t) * - msp->ms_id, sizeof (uint64_t), &object, tx); + msp->ms_id, sizeof (uint64_t), &object, tx, + DMU_READ_NO_PREFETCH); } /* @@ -4292,7 +4293,8 @@ metaslab_sync(metaslab_t *msp, uint64_t txg) VERIFY3U(new_object, !=, 0); dmu_write(mos, vd->vdev_ms_array, sizeof (uint64_t) * - msp->ms_id, sizeof (uint64_t), &new_object, tx); + msp->ms_id, sizeof (uint64_t), &new_object, tx, + DMU_READ_NO_PREFETCH); VERIFY0(space_map_open(&msp->ms_sm, mos, new_object, msp->ms_start, msp->ms_size, vd->vdev_ashift)); @@ -6328,7 +6330,7 @@ metaslab_update_ondisk_flush_data(metaslab_t *ms, dmu_tx_t *tx) } dmu_write(spa_meta_objset(spa), object, entry_offset, entry_size, - &entry, tx); + &entry, tx, DMU_READ_NO_PREFETCH); } void diff --git a/module/zfs/spa.c b/module/zfs/spa.c index b3bb46da263b..8821757a8f09 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -9601,7 +9601,8 @@ spa_sync_nvlist(spa_t *spa, uint64_t obj, nvlist_t *nv, dmu_tx_t *tx) KM_SLEEP)); memset(packed + nvsize, 0, bufsize - nvsize); - dmu_write(spa->spa_meta_objset, obj, 0, bufsize, packed, tx); + dmu_write(spa->spa_meta_objset, obj, 0, bufsize, packed, tx, + DMU_READ_NO_PREFETCH); vmem_free(packed, bufsize); diff --git a/module/zfs/spa_checkpoint.c b/module/zfs/spa_checkpoint.c index e07756c46748..a42aa62e6599 100644 --- a/module/zfs/spa_checkpoint.c +++ b/module/zfs/spa_checkpoint.c @@ -427,7 +427,7 @@ spa_checkpoint_discard_thread(void *arg, zthr_t *zthr) */ int error = dmu_buf_hold_array_by_bonus( checkpoint_sm->sm_dbuf, offset, size, - B_TRUE, FTAG, &numbufs, &dbp); + B_TRUE, FTAG, &numbufs, &dbp, DMU_READ_PREFETCH); if (error != 0) { zfs_panic_recover("zfs: error %d was returned " "while prefetching checkpoint space map " diff --git a/module/zfs/spa_history.c b/module/zfs/spa_history.c index 60ab07944d72..b9d0c9656726 100644 --- a/module/zfs/spa_history.c +++ b/module/zfs/spa_history.c @@ -169,13 +169,14 @@ spa_history_write(spa_t *spa, void *buf, uint64_t len, spa_history_phys_t *shpp, phys_eof = spa_history_log_to_phys(shpp->sh_eof, shpp); firstwrite = MIN(len, shpp->sh_phys_max_off - phys_eof); shpp->sh_eof += len; - dmu_write(mos, spa->spa_history, phys_eof, firstwrite, buf, tx); + dmu_write(mos, spa->spa_history, phys_eof, firstwrite, buf, tx, + DMU_READ_NO_PREFETCH); len -= firstwrite; if (len > 0) { /* write out the rest at the beginning of physical file */ dmu_write(mos, spa->spa_history, shpp->sh_pool_create_len, - len, (char *)buf + firstwrite, tx); + len, (char *)buf + firstwrite, tx, DMU_READ_NO_PREFETCH); } return (0); diff --git a/module/zfs/space_map.c b/module/zfs/space_map.c index 5f24963f2291..f20c49ebb6de 100644 --- a/module/zfs/space_map.c +++ b/module/zfs/space_map.c @@ -537,7 +537,7 @@ space_map_write_intro_debug(space_map_t *sm, maptype_t maptype, dmu_tx_t *tx) SM_DEBUG_TXG_ENCODE(dmu_tx_get_txg(tx)); dmu_write(sm->sm_os, space_map_object(sm), sm->sm_phys->smp_length, - sizeof (dentry), &dentry, tx); + sizeof (dentry), &dentry, tx, DMU_READ_NO_PREFETCH); sm->sm_phys->smp_length += sizeof (dentry); } diff --git a/module/zfs/vdev_indirect_births.c b/module/zfs/vdev_indirect_births.c index c0127829c26c..ab7069f44b37 100644 --- a/module/zfs/vdev_indirect_births.c +++ b/module/zfs/vdev_indirect_births.c @@ -147,7 +147,7 @@ vdev_indirect_births_add_entry(vdev_indirect_births_t *vib, old_size = vdev_indirect_births_size_impl(vib); dmu_write(vib->vib_objset, vib->vib_object, old_size, sizeof (vibe), - &vibe, tx); + &vibe, tx, DMU_READ_NO_PREFETCH); vib->vib_phys->vib_count++; new_size = vdev_indirect_births_size_impl(vib); diff --git a/module/zfs/vdev_indirect_mapping.c b/module/zfs/vdev_indirect_mapping.c index 1515ddc1baa2..da90a8de016f 100644 --- a/module/zfs/vdev_indirect_mapping.c +++ b/module/zfs/vdev_indirect_mapping.c @@ -459,13 +459,14 @@ vdev_indirect_mapping_add_entries(vdev_indirect_mapping_t *vim, dmu_write(vim->vim_objset, vim->vim_object, vim->vim_phys->vimp_num_entries * sizeof (*mapbuf), i * sizeof (*mapbuf), - mapbuf, tx); + mapbuf, tx, DMU_READ_NO_PREFETCH); if (vim->vim_havecounts) { dmu_write(vim->vim_objset, vim->vim_phys->vimp_counts_object, vim->vim_phys->vimp_num_entries * sizeof (*countbuf), - i * sizeof (*countbuf), countbuf, tx); + i * sizeof (*countbuf), countbuf, tx, + DMU_READ_NO_PREFETCH); } vim->vim_phys->vimp_num_entries += i; } diff --git a/module/zfs/zfs_fuid.c b/module/zfs/zfs_fuid.c index 2af1efe82e62..7f786c00b93a 100644 --- a/module/zfs/zfs_fuid.c +++ b/module/zfs/zfs_fuid.c @@ -268,7 +268,7 @@ zfs_fuid_sync(zfsvfs_t *zfsvfs, dmu_tx_t *tx) nvlist_free(nvp); zfsvfs->z_fuid_size = nvsize; dmu_write(zfsvfs->z_os, zfsvfs->z_fuid_obj, 0, - zfsvfs->z_fuid_size, packed, tx); + zfsvfs->z_fuid_size, packed, tx, DMU_READ_NO_PREFETCH); kmem_free(packed, zfsvfs->z_fuid_size); VERIFY0(dmu_bonus_hold(zfsvfs->z_os, zfsvfs->z_fuid_obj, FTAG, &db)); dmu_buf_will_dirty(db, tx); diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 00f98168d3d8..63fd2335ad78 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -547,7 +547,8 @@ zvol_replay_write(void *arg1, void *arg2, boolean_t byteswap) if (error) { dmu_tx_abort(tx); } else { - dmu_write(os, ZVOL_OBJ, offset, length, data, tx); + dmu_write(os, ZVOL_OBJ, offset, length, data, tx, + DMU_READ_PREFETCH); (void) zil_replaying(zv->zv_zilog, tx); dmu_tx_commit(tx); } From f819b41c78a76bccb4a48d55f95ede46b1976661 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 30 Oct 2025 09:07:38 -0700 Subject: [PATCH 04/91] Retire ZoL patch scripts Remove the out of date helper scripts originally used to port Illumos commits to the ZoL repository. Due to layout changes made to this repository they're no longer entirely correct. Remove them to make it clear they're no longer being used or actively maintained. Reviewed-by: Rob Norris Reviewed-by: George Melikov Signed-off-by: Brian Behlendorf Closes #17880 --- scripts/Makefile.am | 4 +--- scripts/zfs2zol-patch.sed | 32 -------------------------------- scripts/zol2zfs-patch.sed | 20 -------------------- 3 files changed, 1 insertion(+), 55 deletions(-) delete mode 100755 scripts/zfs2zol-patch.sed delete mode 100755 scripts/zol2zfs-patch.sed diff --git a/scripts/Makefile.am b/scripts/Makefile.am index f623526307b4..bff5f8b78a85 100644 --- a/scripts/Makefile.am +++ b/scripts/Makefile.am @@ -28,9 +28,7 @@ endif dist_noinst_DATA += \ %D%/cstyle.pl \ - %D%/update_authors.pl \ - %D%/zfs2zol-patch.sed \ - %D%/zol2zfs-patch.sed + %D%/update_authors.pl SHELLCHECKSCRIPTS += $(dist_scripts_SCRIPTS) $(dist_noinst_SCRIPTS) diff --git a/scripts/zfs2zol-patch.sed b/scripts/zfs2zol-patch.sed deleted file mode 100755 index 2d744cd5de52..000000000000 --- a/scripts/zfs2zol-patch.sed +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sed -f - -s:usr/src/uts/common/fs/zfs/sys:include/sys:g -s:usr/src/uts/common/fs/zfs:module/zfs:g -s:usr/src/lib/libzpool:lib/libzpool:g -s:usr/src/cmd:cmd:g -s:usr/src/common/nvpair:module/nvpair:g -s:usr/src/lib/libzfs/common/libzfs.h:include/libzfs.h:g -s:usr/src/man/man1m/zfs.1m:man/man8/zfs.8:g -s:usr/src/uts/common/sys:include/sys:g -s:usr/src/lib/libzfs_core/common/libzfs_core.h:include/libzfs_core.h:g -s:usr/src/lib/libzfs/common:lib/libzfs:g -s:usr/src/lib/libzfs_core/common:lib/libzfs_core:g -s:lib/libzpool/common/sys:include/sys:g -s:lib/libzpool/common:lib/libzpool:g - -s:usr/src/test/zfs-tests/include:tests/zfs-tests/include:g -s:usr/src/test/zfs-tests/runfiles:tests/runfiles:g -s:usr/src/test/zfs-tests/tests/functional:tests/zfs-tests/tests/functional:g -s:usr/src/test/zfs-tests/tests/perf:tests/zfs-tests/tests/perf:g -s:usr/src/test/test-runner/cmd/run.py:tests/test-runner/cmd/test-runner.py:g -s:usr/src/common/zfs/\(.*\)\.c:module/zcommon/\1.c:g - -# crypto framework -s:usr/src/common/crypto:module/icp/algs:g -s:usr/src/uts/common/crypto/io:module/icp/io:g - -# Headers -s:usr/src/common/zfs/\(.*\)\.h:include/\1.h:g - -# Man pages -s:usr/src/man:man:g diff --git a/scripts/zol2zfs-patch.sed b/scripts/zol2zfs-patch.sed deleted file mode 100755 index 0ca4b6cd6b7e..000000000000 --- a/scripts/zol2zfs-patch.sed +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sed -f - -s:cmd:usr/src/cmd:g -s:include/libzfs.h:usr/src/lib/libzfs/common/libzfs.h:g -s:include/libzfs_core.h:usr/src/lib/libzfs_core/common/libzfs_core.h:g -s:include/sys:lib/libzpool/common/sys:g -s:include/sys:usr/src/uts/common/fs/zfs/sys:g -s:include/sys:usr/src/uts/common/sys:g -s:include/zfs_fletcher.h:usr/src/common/zfs/zfs_fletcher.h:g -s:include:usr/src/common/zfs:g -s:lib/libzfs:usr/src/lib/libzfs/common:g -s:lib/libzfs_core:usr/src/lib/libzfs_core/common:g -s:lib/libzpool:lib/libzpool/common:g -s:lib/libzpool:usr/src/lib/libzpool:g -s:man/man7/zpool-features.7:usr/src/man/man5/zpool-features.5:g -s:man/man8/zfs.8:usr/src/man/man1m/zfs.1m:g -s:module/nvpair:usr/src/common/nvpair:g -s:module/zcommon:usr/src/common/zfs/:g -s:module/zfs:usr/src/uts/common/fs/zfs:g -s:tests/zfs-tests:test/zfs-tests:g From 033dbdc98231bbd924ccf5df5efba32218f14070 Mon Sep 17 00:00:00 2001 From: Joseph Anthony Pasquale Holsten Date: Thu, 30 Oct 2025 16:26:56 -0700 Subject: [PATCH 05/91] autogen.sh: remove workaround for automake <1.14, needed for EL <=7 Ultimately this is a revert of 779ac93, which according to @nabijaczleweli is to paper over automake <1.14's lack of %reldir% support. As I understand it, EL8 is the lowest current build target. Reviewed-by: Rob Norris Reviewed-by: Brian Behlendorf Signed-off-by: Joseph Holsten Closes #17878 --- autogen.sh | 61 +----------------------------------------------------- 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/autogen.sh b/autogen.sh index 39eb82203d69..5cb152474698 100755 --- a/autogen.sh +++ b/autogen.sh @@ -1,62 +1,3 @@ #!/bin/sh -[ "${0%/*}" = "$0" ] || cd "${0%/*}" || exit -# %reldir%/%canon_reldir% (%D%/%C%) only appeared in automake 1.14, but RHEL/CentOS 7 has 1.13.4 -# This is an (overly) simplistic preprocessor that papers around this for the duration of the generation step, -# and can be removed once support for CentOS 7 is dropped -automake --version | awk '{print $NF; exit}' | ( - IFS=. read -r AM_MAJ AM_MIN _ - [ "$AM_MAJ" -gt 1 ] || [ "$AM_MIN" -ge 14 ] -) || { - process_root() { - root="$1"; shift - - grep -q '%[CD]%' "$root/Makefile.am" || return - find "$root" -name Makefile.am "$@" | while read -r dir; do - dir="${dir%/Makefile.am}" - grep -q '%[CD]%' "$dir/Makefile.am" || continue - - reldir="${dir#"$root"}" - reldir="${reldir#/}" - - canon_reldir="$(printf '%s' "$reldir" | tr -C 'a-zA-Z0-9@_' '_')" - - reldir_slash="$reldir/" - canon_reldir_slash="${canon_reldir}_" - [ -z "$reldir" ] && reldir_slash= - [ -z "$reldir" ] && canon_reldir_slash= - - echo "$dir/Makefile.am" >&3 - sed -i~ -e "s:%D%/:$reldir_slash:g" -e "s:%D%:$reldir:g" \ - -e "s:%C%_:$canon_reldir_slash:g" -e "s:%C%:$canon_reldir:g" "$dir/Makefile.am" - done 3>>"$substituted_files" - } - - rollback() { - while read -r f; do - mv "$f~" "$f" - done < "$substituted_files" - rm -f "$substituted_files" - } - - - echo "Automake <1.14; papering over missing %reldir%/%canon_reldir% support" >&2 - - substituted_files="$(mktemp)" - trap rollback EXIT - - roots="$(sed '/Makefile$/!d;/module/d;s:^\s*:./:;s:/Makefile::;/^\.$/d' configure.ac)" - - IFS=" -" - for root in $roots; do - root="${root#./}" - process_root "$root" - done - - set -f - # shellcheck disable=SC2086,SC2046 - process_root . $(printf '!\n-path\n%s/*\n' $roots) -} - -autoreconf -fiv && rm -rf autom4te.cache +autoreconf -fiv "$(dirname "$0")" && rm -rf "$(dirname "$0")"/autom4te.cache From ea125eeb5d5d5321c44568c79c1070040276513f Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sun, 26 Oct 2025 19:14:02 -0400 Subject: [PATCH 06/91] BRT: Round bv_entcount up to BRT_BLOCKSIZE Since we set bv_mos_brtvdev block size, and since we keep dirty bitmap at the same granularity, we should keep the allocations and writes done with. Otherwise it makes the last block write short, that will be odd once we implement writing of only dirty blocks, but also requires read-modify-write on DMU layer. Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Motin Closes #17875 --- module/zfs/brt.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/module/zfs/brt.c b/module/zfs/brt.c index 6655b7bca7fb..eb74ce96a1b8 100644 --- a/module/zfs/brt.c +++ b/module/zfs/brt.c @@ -508,8 +508,8 @@ brt_vdev_realloc(spa_t *spa, brt_vdev_t *brtvd) size = (vdev_get_min_asize(vd) - 1) / spa->spa_brt_rangesize + 1; spa_config_exit(spa, SCL_VDEV, FTAG); - entcount = vmem_zalloc(sizeof (entcount[0]) * size, KM_SLEEP); nblocks = BRT_RANGESIZE_TO_NBLOCKS(size); + entcount = vmem_zalloc(nblocks * BRT_BLOCKSIZE, KM_SLEEP); bitmap = kmem_zalloc(BT_SIZEOFMAP(nblocks), KM_SLEEP); if (!brtvd->bv_initiated) { @@ -530,9 +530,8 @@ brt_vdev_realloc(spa_t *spa, brt_vdev_t *brtvd) memcpy(entcount, brtvd->bv_entcount, sizeof (entcount[0]) * MIN(size, brtvd->bv_size)); - vmem_free(brtvd->bv_entcount, - sizeof (entcount[0]) * brtvd->bv_size); onblocks = BRT_RANGESIZE_TO_NBLOCKS(brtvd->bv_size); + vmem_free(brtvd->bv_entcount, onblocks * BRT_BLOCKSIZE); memcpy(bitmap, brtvd->bv_bitmap, MIN(BT_SIZEOFMAP(nblocks), BT_SIZEOFMAP(onblocks))); kmem_free(brtvd->bv_bitmap, BT_SIZEOFMAP(onblocks)); @@ -613,9 +612,9 @@ brt_vdev_dealloc(brt_vdev_t *brtvd) ASSERT(brtvd->bv_initiated); ASSERT0(avl_numnodes(&brtvd->bv_tree)); - vmem_free(brtvd->bv_entcount, sizeof (uint16_t) * brtvd->bv_size); - brtvd->bv_entcount = NULL; uint64_t nblocks = BRT_RANGESIZE_TO_NBLOCKS(brtvd->bv_size); + vmem_free(brtvd->bv_entcount, nblocks * BRT_BLOCKSIZE); + brtvd->bv_entcount = NULL; kmem_free(brtvd->bv_bitmap, BT_SIZEOFMAP(nblocks)); brtvd->bv_bitmap = NULL; @@ -807,10 +806,10 @@ brt_vdev_sync(spa_t *spa, brt_vdev_t *brtvd, dmu_tx_t *tx) /* * TODO: Walk brtvd->bv_bitmap and write only the dirty blocks. */ - dmu_write(spa->spa_meta_objset, brtvd->bv_mos_brtvdev, 0, - brtvd->bv_size * sizeof (brtvd->bv_entcount[0]), - brtvd->bv_entcount, tx, DMU_READ_NO_PREFETCH); uint64_t nblocks = BRT_RANGESIZE_TO_NBLOCKS(brtvd->bv_size); + dmu_write(spa->spa_meta_objset, brtvd->bv_mos_brtvdev, 0, + nblocks * BRT_BLOCKSIZE, brtvd->bv_entcount, tx, + DMU_READ_NO_PREFETCH); memset(brtvd->bv_bitmap, 0, BT_SIZEOFMAP(nblocks)); brtvd->bv_entcount_dirty = FALSE; } From ec268cdf97831d1306cd16da27df0e9e39abd412 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sun, 26 Oct 2025 19:41:48 -0400 Subject: [PATCH 07/91] Fix caching of DDT log and BRT Both DDT log and BRT counters we read on pool import and then only append or overwrite in full blocks. We don't need them in DMU or ARC caches. Fortunately we have DMU_UNCACHEDIO for this now. Even more we don't need BRT in non-evictable metadata DMU caches, since it will likely never fit there, while block the cache from its original users. Since DMU_OT_IS_METADATA_CACHED() has no way to differentiate the new metadata types, mark BRT with storage type of DMU_OT_DDT_ZAP. As side effect it will also put it on dedup device, but that should actually be right. Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Motin Closes #17875 --- include/sys/dmu.h | 2 +- module/zfs/brt.c | 6 ++++-- module/zfs/dbuf.c | 5 ++++- module/zfs/ddt_log.c | 7 ++++--- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/include/sys/dmu.h b/include/sys/dmu.h index a33e16a065b1..aae99d71ba7c 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -126,7 +126,7 @@ typedef enum dmu_object_byteswap { (ot) < DMU_OT_NUMTYPES) #define DMU_OT_IS_METADATA_CACHED(ot) (((ot) & DMU_OT_NEWTYPE) ? \ - B_TRUE : dmu_ot[(ot)].ot_dbuf_metadata_cache) + ((ot) & DMU_OT_METADATA) != 0 : dmu_ot[(ot)].ot_dbuf_metadata_cache) /* * MDB doesn't have dmu_ot; it defines these macros itself. diff --git a/module/zfs/brt.c b/module/zfs/brt.c index eb74ce96a1b8..9e389c8727b9 100644 --- a/module/zfs/brt.c +++ b/module/zfs/brt.c @@ -454,6 +454,7 @@ brt_vdev_create(spa_t *spa, brt_vdev_t *brtvd, dmu_tx_t *tx) VERIFY(mos_entries != 0); VERIFY0(dnode_hold(spa->spa_meta_objset, mos_entries, brtvd, &brtvd->bv_mos_entries_dnode)); + dnode_set_storage_type(brtvd->bv_mos_entries_dnode, DMU_OT_DDT_ZAP); rw_enter(&brtvd->bv_mos_entries_lock, RW_WRITER); brtvd->bv_mos_entries = mos_entries; rw_exit(&brtvd->bv_mos_entries_lock); @@ -580,13 +581,14 @@ brt_vdev_load(spa_t *spa, brt_vdev_t *brtvd) */ error = dmu_read(spa->spa_meta_objset, brtvd->bv_mos_brtvdev, 0, MIN(brtvd->bv_size, bvphys->bvp_size) * sizeof (uint16_t), - brtvd->bv_entcount, DMU_READ_NO_PREFETCH); + brtvd->bv_entcount, DMU_READ_NO_PREFETCH | DMU_UNCACHEDIO); if (error != 0) return (error); ASSERT(bvphys->bvp_mos_entries != 0); VERIFY0(dnode_hold(spa->spa_meta_objset, bvphys->bvp_mos_entries, brtvd, &brtvd->bv_mos_entries_dnode)); + dnode_set_storage_type(brtvd->bv_mos_entries_dnode, DMU_OT_DDT_ZAP); rw_enter(&brtvd->bv_mos_entries_lock, RW_WRITER); brtvd->bv_mos_entries = bvphys->bvp_mos_entries; rw_exit(&brtvd->bv_mos_entries_lock); @@ -809,7 +811,7 @@ brt_vdev_sync(spa_t *spa, brt_vdev_t *brtvd, dmu_tx_t *tx) uint64_t nblocks = BRT_RANGESIZE_TO_NBLOCKS(brtvd->bv_size); dmu_write(spa->spa_meta_objset, brtvd->bv_mos_brtvdev, 0, nblocks * BRT_BLOCKSIZE, brtvd->bv_entcount, tx, - DMU_READ_NO_PREFETCH); + DMU_READ_NO_PREFETCH | DMU_UNCACHEDIO); memset(brtvd->bv_bitmap, 0, BT_SIZEOFMAP(nblocks)); brtvd->bv_entcount_dirty = FALSE; } diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index fccc4c5b5b94..72c597609ade 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -446,7 +446,10 @@ static boolean_t dbuf_include_in_metadata_cache(dmu_buf_impl_t *db) { DB_DNODE_ENTER(db); - dmu_object_type_t type = DB_DNODE(db)->dn_type; + dnode_t *dn = DB_DNODE(db); + dmu_object_type_t type = dn->dn_storage_type; + if (type == DMU_OT_NONE) + type = dn->dn_type; DB_DNODE_EXIT(db); /* Check if this dbuf is one of the types we care about */ diff --git a/module/zfs/ddt_log.c b/module/zfs/ddt_log.c index c7a2426f3a77..3d42c51365a8 100644 --- a/module/zfs/ddt_log.c +++ b/module/zfs/ddt_log.c @@ -222,7 +222,7 @@ ddt_log_begin(ddt_t *ddt, size_t nentries, dmu_tx_t *tx, ddt_log_update_t *dlu) VERIFY0(dmu_buf_hold_array_by_dnode(dlu->dlu_dn, offset, length, B_FALSE, FTAG, &dlu->dlu_ndbp, &dlu->dlu_dbp, - DMU_READ_NO_PREFETCH)); + DMU_READ_NO_PREFETCH | DMU_UNCACHEDIO)); dlu->dlu_tx = tx; dlu->dlu_block = dlu->dlu_offset = 0; @@ -298,7 +298,8 @@ ddt_log_entry(ddt_t *ddt, ddt_lightweight_entry_t *ddlwe, ddt_log_update_t *dlu) * we will fill it, and zero it out. */ if (dlu->dlu_offset == 0) { - dmu_buf_will_fill(db, dlu->dlu_tx, B_FALSE); + dmu_buf_will_fill_flags(db, dlu->dlu_tx, B_FALSE, + DMU_UNCACHEDIO); memset(db->db_data, 0, db->db_size); } @@ -597,7 +598,7 @@ ddt_log_load_one(ddt_t *ddt, uint_t n) for (uint64_t offset = 0; offset < hdr.dlh_length; offset += dn->dn_datablksz) { err = dmu_buf_hold_by_dnode(dn, offset, FTAG, &db, - DMU_READ_PREFETCH); + DMU_READ_PREFETCH | DMU_UNCACHEDIO); if (err != 0) { dnode_rele(dn, FTAG); ddt_log_empty(ddt, ddl); From 6cfc3dba9c41f1250a2b0578ab5e3ff77e4f2855 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Thu, 30 Oct 2025 19:29:48 -0400 Subject: [PATCH 08/91] Cleanup ZIO_FLAG_IO_RETRY vs TRYHARD usage In cases where all issued ZIOs must succeed, and we can't do anything clever about the errors, we should just explicitly set ZIO_FLAG_TRYHARD and let OS to do all the reasonable retries. In other cases, where retries can be different from the original, for example, some ZIOs are allowed to fail due to redundancy, or we can disable aggregation on retrial to get at least some of the data, we can do first pass without TRYHARD, and only if needed retry with ZIO_FLAG_IO_RETRY (which implies TRYHARD semantics). Reviewed-by: Rob Norris Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Motin Closes #17877 --- module/os/freebsd/zfs/vdev_label_os.c | 8 ++----- module/zfs/vdev_label.c | 33 ++++++++++----------------- 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/module/os/freebsd/zfs/vdev_label_os.c b/module/os/freebsd/zfs/vdev_label_os.c index 11e93b800a54..9663f05cb354 100644 --- a/module/os/freebsd/zfs/vdev_label_os.c +++ b/module/os/freebsd/zfs/vdev_label_os.c @@ -42,7 +42,8 @@ vdev_label_write_pad2(vdev_t *vd, const char *buf, size_t size) spa_t *spa = vd->vdev_spa; zio_t *zio; abd_t *pad2; - int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL; + int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | + ZIO_FLAG_TRYHARD; int error; if (size > VDEV_PAD_SIZE) @@ -59,16 +60,11 @@ vdev_label_write_pad2(vdev_t *vd, const char *buf, size_t size) abd_copy_from_buf(pad2, buf, size); abd_zero_off(pad2, size, VDEV_PAD_SIZE - size); -retry: zio = zio_root(spa, NULL, NULL, flags); vdev_label_write(zio, vd, 0, pad2, offsetof(vdev_label_t, vl_be), VDEV_PAD_SIZE, NULL, NULL, flags); error = zio_wait(zio); - if (error != 0 && !(flags & ZIO_FLAG_TRYHARD)) { - flags |= ZIO_FLAG_TRYHARD; - goto retry; - } abd_free(pad2); return (error); diff --git a/module/zfs/vdev_label.c b/module/zfs/vdev_label.c index 0d4fdaa77ba0..7e222eac5edc 100644 --- a/module/zfs/vdev_label.c +++ b/module/zfs/vdev_label.c @@ -862,8 +862,8 @@ retry: } } - if (config == NULL && !(flags & ZIO_FLAG_TRYHARD)) { - flags |= ZIO_FLAG_TRYHARD; + if (config == NULL && !(flags & ZIO_FLAG_IO_RETRY)) { + flags |= ZIO_FLAG_IO_RETRY; goto retry; } @@ -1079,7 +1079,8 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason) size_t buflen; int error; uint64_t spare_guid = 0, l2cache_guid = 0; - int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL; + int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | + ZIO_FLAG_TRYHARD; boolean_t reason_spare = (reason == VDEV_LABEL_SPARE || (reason == VDEV_LABEL_REMOVE && vd->vdev_isspare)); boolean_t reason_l2cache = (reason == VDEV_LABEL_L2CACHE || (reason == @@ -1223,7 +1224,6 @@ vdev_label_init(vdev_t *vd, uint64_t crtxg, vdev_labeltype_t reason) /* * Write everything in parallel. */ -retry: zio = zio_root(spa, NULL, NULL, flags); for (int l = 0; l < VDEV_LABELS; l++) { @@ -1248,11 +1248,6 @@ retry: error = zio_wait(zio); - if (error != 0 && !(flags & ZIO_FLAG_TRYHARD)) { - flags |= ZIO_FLAG_TRYHARD; - goto retry; - } - nvlist_free(label); abd_free(bootenv); abd_free(ub_abd); @@ -1398,7 +1393,8 @@ vdev_label_write_bootenv(vdev_t *vd, nvlist_t *env) zio_t *zio; spa_t *spa = vd->vdev_spa; vdev_boot_envblock_t *bootenv; - int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL; + int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL | + ZIO_FLAG_TRYHARD; int error; size_t nvsize; char *nvbuf; @@ -1466,7 +1462,6 @@ vdev_label_write_bootenv(vdev_t *vd, nvlist_t *env) return (SET_ERROR(error)); } -retry: zio = zio_root(spa, NULL, NULL, flags); for (int l = 0; l < VDEV_LABELS; l++) { vdev_label_write(zio, vd, l, abd, @@ -1475,10 +1470,6 @@ retry: } error = zio_wait(zio); - if (error != 0 && !(flags & ZIO_FLAG_TRYHARD)) { - flags |= ZIO_FLAG_TRYHARD; - goto retry; - } abd_free(abd); return (error); @@ -2056,13 +2047,13 @@ retry: * Normally, we don't want to try too hard to write every label and * uberblock. If there is a flaky disk, we don't want the rest of the * sync process to block while we retry. But if we can't write a - * single label out, we should retry with ZIO_FLAG_TRYHARD before + * single label out, we should retry with ZIO_FLAG_IO_RETRY before * bailing out and declaring the pool faulted. */ if (error != 0) { - if ((flags & ZIO_FLAG_TRYHARD) != 0) + if ((flags & ZIO_FLAG_IO_RETRY) != 0) return (error); - flags |= ZIO_FLAG_TRYHARD; + flags |= ZIO_FLAG_IO_RETRY; } ASSERT(ub->ub_txg <= txg); @@ -2113,7 +2104,7 @@ retry: * are committed to stable storage before the uberblock update. */ if ((error = vdev_label_sync_list(spa, 0, txg, flags)) != 0) { - if ((flags & ZIO_FLAG_TRYHARD) != 0) { + if ((flags & ZIO_FLAG_IO_RETRY) != 0) { zfs_dbgmsg("vdev_label_sync_list() returned error %d " "for pool '%s' when syncing out the even labels " "of dirty vdevs", error, spa_name(spa)); @@ -2137,7 +2128,7 @@ retry: * to the new uberblocks. */ if ((error = vdev_uberblock_sync_list(svd, svdcount, ub, flags)) != 0) { - if ((flags & ZIO_FLAG_TRYHARD) != 0) { + if ((flags & ZIO_FLAG_IO_RETRY) != 0) { zfs_dbgmsg("vdev_uberblock_sync_list() returned error " "%d for pool '%s'", error, spa_name(spa)); } @@ -2158,7 +2149,7 @@ retry: * stable storage before the next transaction group begins. */ if ((error = vdev_label_sync_list(spa, 1, txg, flags)) != 0) { - if ((flags & ZIO_FLAG_TRYHARD) != 0) { + if ((flags & ZIO_FLAG_IO_RETRY) != 0) { zfs_dbgmsg("vdev_label_sync_list() returned error %d " "for pool '%s' when syncing out the odd labels of " "dirty vdevs", error, spa_name(spa)); From a90f816be6ae1badf1acfd6338c9d9f3ff2f4ea2 Mon Sep 17 00:00:00 2001 From: jamisiveshkumar Date: Tue, 4 Nov 2025 06:07:58 +0530 Subject: [PATCH 09/91] Fix capitalization typo in README.md Reviewed-by: Brian Behlendorf Reviewed-by: George Melikov Signed-off-by: Sivesh Kumar Closes #17889 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a90736bb56b7..a39b88fedd12 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This repository contains the code for running OpenZFS on Linux and FreeBSD. # Official Resources * [Documentation](https://openzfs.github.io/openzfs-docs/) - for using and developing this repo - * [ZoL Site](https://zfsonlinux.org) - Linux release info & links + * [ZoL site](https://zfsonlinux.org) - Linux release info & links * [Mailing lists](https://openzfs.github.io/openzfs-docs/Project%20and%20Community/Mailing%20Lists.html) * [OpenZFS site](https://openzfs.org/) - for conference videos and info on other platforms (illumos, OSX, Windows, etc) From d0294aa7587fe258d7cd88861bd0041e661cc696 Mon Sep 17 00:00:00 2001 From: Robert Evans Date: Tue, 4 Nov 2025 16:12:17 -0500 Subject: [PATCH 10/91] Update dnode_next_offset_level to accept blkid instead of offset Currently this function uses L0 offsets which: 1. is hard to read since it maps offsets to blkid and back each call 2. necessitates dnode_next_block to handle edge cases at limits 3. makes it hard to tell if the traversal can loop infinitely Instead, update this and dnode_next_offset to work in (blkid, index). This way the blkid manipulations are clear, and it's also clear that the traversal always terminates since blkid goes one direction. I've also considered updating dnode_next_offset to operate on blkid. Callers use both patterns, so maybe another PR can split the cases? While here tidy up dnode_next_offset_level comments. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Robert Evans Closes #17792 --- module/zfs/dnode.c | 156 ++++++++++++++++++++------------------------- 1 file changed, 68 insertions(+), 88 deletions(-) diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c index e88d394b5229..e0cc4a7e13e0 100644 --- a/module/zfs/dnode.c +++ b/module/zfs/dnode.c @@ -2496,26 +2496,27 @@ dnode_diduse_space(dnode_t *dn, int64_t delta) } /* - * Scans a block at the indicated "level" looking for a hole or data, - * depending on 'flags'. + * Scans the block at the indicated "level" looking for a hole or data, + * depending on 'flags' starting from array position given by *index. * - * If level > 0, then we are scanning an indirect block looking at its - * pointers. If level == 0, then we are looking at a block of dnodes. + * If lvl > 0, then we are scanning an indirect block looking at its + * pointers. If lvl == 0, then we are looking at a block of dnodes. * * If we don't find what we are looking for in the block, we return ESRCH. - * Otherwise, return with *offset pointing to the beginning (if searching - * forwards) or end (if searching backwards) of the range covered by the - * block pointer we matched on (or dnode). + * Otherwise, return with *index set to the matching array position. * - * The basic search algorithm used below by dnode_next_offset() is to - * use this function to search up the block tree (widen the search) until - * we find something (i.e., we don't return ESRCH) and then search back - * down the tree (narrow the search) until we reach our original search - * level. + * In both cases, *offset is updated to point at the matched BP/dnode or + * the next offset to search (unless at the limit of possible offsets). + * + * The basic search algorithm used below by dnode_next_offset() uses this + * function to perform a block-order tree traversal. We search up the block + * tree (widen the search) until we find something (i.e., we don't return + * ESRCH) and then search back down the tree (narrow the search) until we + * reach our original search level or backtrack up because nothing matches. */ static int -dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, - int lvl, uint64_t blkfill, uint64_t txg) +dnode_next_offset_level(dnode_t *dn, int flags, int lvl, uint64_t blkid, + int *index, uint64_t blkfill, uint64_t txg, uint64_t *offset) { dmu_buf_impl_t *db = NULL; void *data = NULL; @@ -2541,20 +2542,12 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, rrw_enter(&dmu_objset_ds(dn->dn_objset)->ds_bp_rwlock, RW_READER, FTAG); } else { - uint64_t blkid = dbuf_whichblock(dn, lvl, *offset); error = dbuf_hold_impl(dn, lvl, blkid, TRUE, FALSE, FTAG, &db); if (error) { if (error != ENOENT) return (error); if (hole) return (0); - /* - * This can only happen when we are searching up - * the block tree for data. We don't really need to - * adjust the offset, as we will just end up looking - * at the pointer to this block in its parent, and its - * going to be unallocated, so we will skip over it. - */ return (SET_ERROR(ESRCH)); } error = dbuf_read(db, NULL, @@ -2582,8 +2575,7 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, ASSERT(dn->dn_type == DMU_OT_DNODE); ASSERT(!(flags & DNODE_FIND_BACKWARDS)); - for (i = (*offset >> DNODE_SHIFT) & (blkfill - 1); - i < blkfill; i += dnp[i].dn_extra_slots + 1) { + for (i = *index; i < blkfill; i += dnp[i].dn_extra_slots + 1) { if ((dnp[i].dn_type == DMU_OT_NONE) == hole) break; } @@ -2591,11 +2583,11 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, if (i == blkfill) error = SET_ERROR(ESRCH); + *index = i; *offset = (*offset & ~(DNODE_BLOCK_SIZE - 1)) + (i << DNODE_SHIFT); } else { blkptr_t *bp = data; - uint64_t start = *offset; span = (lvl - 1) * epbs + dn->dn_datablkshift; minfill = 0; maxfill = blkfill << ((lvl - 1) * epbs); @@ -2605,40 +2597,27 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, else minfill++; - if (span >= 8 * sizeof (*offset)) { - /* This only happens on the highest indirection level */ - ASSERT3U((lvl - 1), ==, dn->dn_phys->dn_nlevels - 1); - *offset = 0; - } else { - *offset = *offset >> span; - } - - for (i = BF64_GET(*offset, 0, epbs); - i >= 0 && i < epb; i += inc) { + for (i = *index; i >= 0 && i < epb; i += inc) { if (BP_GET_FILL(&bp[i]) >= minfill && BP_GET_FILL(&bp[i]) <= maxfill && (hole || BP_GET_LOGICAL_BIRTH(&bp[i]) > txg)) break; - if (inc > 0 || *offset > 0) - *offset += inc; } - if (span >= 8 * sizeof (*offset)) { - *offset = start; - } else { - *offset = *offset << span; - } - - if (inc < 0) { - /* traversing backwards; position offset at the end */ - if (span < 8 * sizeof (*offset)) - *offset = MIN(*offset + (1ULL << span) - 1, - start); - } else if (*offset < start) { - *offset = start; - } if (i < 0 || i >= epb) error = SET_ERROR(ESRCH); + + *index = i; + if (span < 8 * sizeof (*offset)) { + uint64_t nblk = blkid << epbs; + if (i >= 0 || blkid != 0) + nblk += i; + if ((nblk >> (8 * sizeof (*offset) - span)) == 0) + *offset = (flags & DNODE_FIND_BACKWARDS) ? + /* backwards: position offset at the end */ + MIN(*offset, ((nblk + 1) << span) - 1) : + MAX(*offset, nblk << span); + } } if (db != NULL) { @@ -2655,32 +2634,6 @@ dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, return (error); } -/* - * Adjust *offset to the next (or previous) block byte offset at lvl. - * Returns FALSE if *offset would overflow or underflow. - */ -static boolean_t -dnode_next_block(dnode_t *dn, int flags, uint64_t *offset, int lvl) -{ - int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT; - int span = lvl * epbs + dn->dn_datablkshift; - uint64_t blkid, maxblkid; - - if (span >= 8 * sizeof (uint64_t)) - return (B_FALSE); - - blkid = *offset >> span; - maxblkid = 1ULL << (8 * sizeof (*offset) - span); - if (!(flags & DNODE_FIND_BACKWARDS) && blkid + 1 < maxblkid) - *offset = (blkid + 1) << span; - else if ((flags & DNODE_FIND_BACKWARDS) && blkid > 0) - *offset = (blkid << span) - 1; - else - return (B_FALSE); - - return (B_TRUE); -} - /* * Find the next hole, data, or sparse region at or after *offset. * The value 'blkfill' tells us how many items we expect to find @@ -2688,6 +2641,18 @@ dnode_next_block(dnode_t *dn, int flags, uint64_t *offset, int lvl) * DNODES_PER_BLOCK for the meta dnode, and some fraction of * DNODES_PER_BLOCK when searching for sparse regions thereof. * + * If minlvl == 0, this searches for dnodes or unallocated dnodes. + * If found, *offset points to the first offset of the matched dnode. + * Backwards search is not allowed for dnodes. + * + * If minlvl > 0, this searches for blocks at the given level. + * If found, *offset points to the first L0 offset of the block + * (or for backwards search, the last offset, inclusive). + * + * If not found, in both cases, *offset is set to the first (or last) + * offset of the unallocated indirect block where the search ended or + * the initial offset if no such block was encountered. + * * Examples: * * dnode_next_offset(dn, flags, offset, 1, 1, 0); @@ -2708,7 +2673,8 @@ int dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset, int minlvl, uint64_t blkfill, uint64_t txg) { - uint64_t matched = *offset; + uint64_t blkid; + int index, epbs; int lvl, maxlvl; int error = 0; @@ -2730,18 +2696,31 @@ dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset, goto out; } + epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT; maxlvl = dn->dn_phys->dn_nlevels; + if (minlvl > 0) { + uint64_t n = dbuf_whichblock(dn, minlvl - 1, *offset); + blkid = n >> epbs; + index = BF64_GET(n, 0, epbs); + } else { + blkid = dbuf_whichblock(dn, 0, *offset); + index = (*offset >> DNODE_SHIFT) & (blkfill - 1); + ASSERT3U(BF64_GET(*offset, 0, DNODE_SHIFT), ==, 0); + } + for (lvl = minlvl; lvl <= maxlvl; ) { error = dnode_next_offset_level(dn, - flags, offset, lvl, blkfill, txg); + flags, lvl, blkid, &index, blkfill, txg, offset); + if (error == 0 && lvl > minlvl) { + /* Continue search at matched block in lvl-1. */ + blkid = (blkid << epbs) + index; + index = 0; --lvl; - matched = *offset; - } else if (error == ESRCH && lvl < maxlvl && - dnode_next_block(dn, flags, &matched, lvl)) { + } else if (error == ESRCH && lvl < maxlvl) { /* - * Continue search at next/prev offset in lvl+1 block. + * Continue search at next/prev index in lvl+1 block. * * Usually we only search upwards at the start of the * search as higher level blocks point at a matching @@ -2752,13 +2731,14 @@ dnode_next_offset(dnode_t *dn, int flags, uint64_t *offset, * happens if we are still syncing out the tree, and * some BP's at higher levels are not updated yet. * - * We must adjust offset to avoid coming back to the - * same offset and getting stuck looping forever. This - * also deals with the case where offset is already at - * the beginning or end of the object. + * We must adjust index to avoid coming back to the + * same offset and getting stuck looping forever. The + * next loop goes up again if index is -1 or (1<> epbs; ++lvl; - *offset = matched; } else { break; } From 5d3380180266bbd83146c8445fbcb46d1dcf2b8c Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Tue, 4 Nov 2025 23:13:07 +0200 Subject: [PATCH 11/91] get_key_material_https: label 'kfdok' defined but not used The label 'kfdok' is only used with O_TMPFILE, we need to use the same #ifdef around this label. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Toomas Soome Closes #17894 --- lib/libzfs/libzfs_crypto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/libzfs/libzfs_crypto.c b/lib/libzfs/libzfs_crypto.c index b34a44c30eb4..f7cc1e84f804 100644 --- a/lib/libzfs/libzfs_crypto.c +++ b/lib/libzfs/libzfs_crypto.c @@ -613,7 +613,9 @@ get_key_material_https(libzfs_handle_t *hdl, const char *uri, (void) unlink(path); free(path); +#ifdef O_TMPFILE kfdok: +#endif if ((key = fdopen(kfd, "r+")) == NULL) { ret = errno; (void) close(kfd); From 7e7c3602562e49e86455de54d8648ad819f4af64 Mon Sep 17 00:00:00 2001 From: Tino Reichardt Date: Wed, 5 Nov 2025 18:56:17 +0100 Subject: [PATCH 12/91] CI: Update FreeBSD versions and ci-type handling Update FreeBSD versions: - add FreeBSD 15.0-STABLE - add FreeBSD 16.0-CURRENT So we use the latest versions of each line now: - Freebsd 14.3 (RELEASE) - FreeBSD 15.0 (STABLE) - FreeBSD 16.0 (CURRENT) In commits - you may specify which type of CI should run: - ZFS-CI-Type: quick - ZFS-CI-Type: linux - ZFS-CI-Type: freebsd - ZFS-CI-Type: full Reviewed-by: Alexx Saver Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Tino Reichardt Closes #17896 --- .github/workflows/scripts/generate-ci-type.py | 10 +++-- .github/workflows/scripts/qemu-2-start.sh | 22 ++++++----- .github/workflows/zfs-qemu-packages.yml | 2 +- .github/workflows/zfs-qemu.yml | 38 ++++++++++++------- 4 files changed, 45 insertions(+), 27 deletions(-) diff --git a/.github/workflows/scripts/generate-ci-type.py b/.github/workflows/scripts/generate-ci-type.py index 08021aabcb61..059d6ad3872b 100755 --- a/.github/workflows/scripts/generate-ci-type.py +++ b/.github/workflows/scripts/generate-ci-type.py @@ -7,7 +7,7 @@ Prints "quick" if (explicity required by user): - the *last* commit message contains 'ZFS-CI-Type: quick' or if (heuristics): - the files changed are not in the list of specified directories, and -- all commit messages do not contain 'ZFS-CI-Type: full' +- all commit messages do not contain 'ZFS-CI-Type: (full|linux|freebsd)' Otherwise prints "full". """ @@ -70,7 +70,7 @@ if __name__ == '__main__': for line in last_commit_message_raw.stdout.decode().splitlines(): if line.strip().lower() == 'zfs-ci-type: quick': - output_type('quick', f'explicitly requested by HEAD commit {head}') + output_type('quick', f'requested by HEAD commit {head}') # check all commit messages all_commit_message_raw = subprocess.run([ @@ -83,8 +83,12 @@ if __name__ == '__main__': for line in all_commit_message: if line.startswith('ZFS-CI-Commit:'): commit_ref = line.lstrip('ZFS-CI-Commit:').rstrip() + if line.strip().lower() == 'zfs-ci-type: freebsd': + output_type('freebsd', f'requested by commit {commit_ref}') + if line.strip().lower() == 'zfs-ci-type: linux': + output_type('linux', f'requested by commit {commit_ref}') if line.strip().lower() == 'zfs-ci-type: full': - output_type('full', f'explicitly requested by commit {commit_ref}') + output_type('full', f'requested by commit {commit_ref}') # check changed files changed_files_raw = subprocess.run([ diff --git a/.github/workflows/scripts/qemu-2-start.sh b/.github/workflows/scripts/qemu-2-start.sh index 422b3e9df388..5bdd84ca2435 100755 --- a/.github/workflows/scripts/qemu-2-start.sh +++ b/.github/workflows/scripts/qemu-2-start.sh @@ -47,16 +47,15 @@ case "$OS" in OSNAME="Archlinux" URL="https://geo.mirror.pkgbuild.com/images/latest/Arch-Linux-x86_64-cloudimg.qcow2" ;; - centos-stream10) - OSNAME="CentOS Stream 10" - # TODO: #16903 Overwrite OSv to stream9 for virt-install until it's added to osinfo - OSv="centos-stream9" - URL="https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-10-latest.x86_64.qcow2" - ;; centos-stream9) OSNAME="CentOS Stream 9" URL="https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2" ;; + centos-stream10) + OSNAME="CentOS Stream 10" + OSv="centos-stream9" + URL="https://cloud.centos.org/centos/10-stream/x86_64/images/CentOS-Stream-GenericCloud-10-latest.x86_64.qcow2" + ;; debian11) OSNAME="Debian 11" URL="https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2" @@ -83,6 +82,11 @@ case "$OS" in OSv="fedora-unknown" URL="https://download.fedoraproject.org/pub/fedora/linux/releases/42/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-42-1.1.x86_64.qcow2" ;; + fedora43) + OSNAME="Fedora 43" + OSv="fedora-unknown" + URL="https://download.fedoraproject.org/pub/fedora/linux/releases/43/Cloud/x86_64/images/Fedora-Cloud-Base-Generic-43-1.6.x86_64.qcow2" + ;; freebsd13-5r) FreeBSD="13.5-RELEASE" OSNAME="FreeBSD $FreeBSD" @@ -95,8 +99,8 @@ case "$OS" in FreeBSD="14.2-RELEASE" OSNAME="FreeBSD $FreeBSD" OSv="freebsd14.0" - KSRC="$FREEBSD_REL/../amd64/$FreeBSD/src.txz" URLxz="$FREEBSD_REL/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI.raw.xz" + KSRC="$FREEBSD_REL/../amd64/$FreeBSD/src.txz" ;; freebsd14-3r) FreeBSD="14.3-RELEASE" @@ -120,8 +124,8 @@ case "$OS" in URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz" KSRC="$FREEBSD_SNAP/../amd64/$FreeBSD/src.txz" ;; - freebsd15-0c) - FreeBSD="15.0-ALPHA4" + freebsd15-0s) + FreeBSD="15.0-STABLE" OSNAME="FreeBSD $FreeBSD" OSv="freebsd14.0" URLxz="$FREEBSD_SNAP/$FreeBSD/amd64/Latest/FreeBSD-$FreeBSD-amd64-BASIC-CI-ufs.raw.xz" diff --git a/.github/workflows/zfs-qemu-packages.yml b/.github/workflows/zfs-qemu-packages.yml index d8a95954fe1a..6367fb3a6ce2 100644 --- a/.github/workflows/zfs-qemu-packages.yml +++ b/.github/workflows/zfs-qemu-packages.yml @@ -52,7 +52,7 @@ jobs: strategy: fail-fast: false matrix: - os: ['almalinux8', 'almalinux9', 'almalinux10', 'fedora41', 'fedora42'] + os: ['almalinux8', 'almalinux9', 'almalinux10', 'fedora41', 'fedora42', 'fedora43'] runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/zfs-qemu.yml b/.github/workflows/zfs-qemu.yml index 3b164548f9be..dad7611cf1a9 100644 --- a/.github/workflows/zfs-qemu.yml +++ b/.github/workflows/zfs-qemu.yml @@ -29,24 +29,34 @@ jobs: - name: Generate OS config and CI type id: os run: | - FULL_OS='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian12", "debian13", "fedora41", "fedora42", "freebsd13-5r", "freebsd14-3s", "freebsd15-0c", "ubuntu22", "ubuntu24"]' - QUICK_OS='["almalinux8", "almalinux9", "almalinux10", "debian12", "fedora42", "freebsd14-3s", "ubuntu24"]' + ci_type="default" + # determine CI type when running on PR - ci_type="full" if ${{ github.event_name == 'pull_request' }}; then head=${{ github.event.pull_request.head.sha }} base=${{ github.event.pull_request.base.sha }} ci_type=$(python3 .github/workflows/scripts/generate-ci-type.py $head $base) fi - if [ "$ci_type" == "quick" ]; then - os_selection="$QUICK_OS" - else - os_selection="$FULL_OS" - fi + + case "$ci_type" in + quick) + os_selection='["almalinux8", "almalinux9", "almalinux10", "debian12", "fedora42", "freebsd15-0s", "ubuntu24"]' + ;; + linux) + os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian11", "debian12", "debian13", "fedora41", "fedora42", "fedora43", "ubuntu22", "ubuntu24"]' + ;; + freebsd) + os_selection='["freebsd13-5r", "freebsd14-2r", "freebsd14-3r", "freebsd13-5s", "freebsd14-3s", "freebsd15-0s", "freebsd16-0c"]' + ;; + *) + # default list + os_selection='["almalinux8", "almalinux9", "almalinux10", "centos-stream9", "centos-stream10", "debian12", "debian13", "fedora42", "fedora43", "freebsd14-3r", "freebsd15-0s", "freebsd16-0c", "ubuntu22", "ubuntu24"]' + ;; + esac if ${{ github.event.inputs.fedora_kernel_ver != '' }}; then - # They specified a custom kernel version for Fedora. Use only - # Fedora runners. + # They specified a custom kernel version for Fedora. + # Use only Fedora runners. os_json=$(echo ${os_selection} | jq -c '[.[] | select(startswith("fedora"))]') else # Normal case @@ -62,13 +72,13 @@ jobs: strategy: fail-fast: false matrix: - # rhl: almalinux8, almalinux9, centos-stream9, fedora4x + # rhl: almalinux8, almalinux9, centos-streamX, fedora4x # debian: debian12, debian13, ubuntu22, ubuntu24 # misc: archlinux, tumbleweed - # FreeBSD variants of 2025-06: + # FreeBSD variants of november 2025: # FreeBSD Release: freebsd13-5r, freebsd14-2r, freebsd14-3r - # FreeBSD Stable: freebsd13-5s, freebsd14-3s - # FreeBSD Current: freebsd15-0c, freebsd16-0c + # FreeBSD Stable: freebsd13-5s, freebsd14-3s, freebsd15-0s + # FreeBSD Current: freebsd16-0c os: ${{ fromJson(needs.test-config.outputs.test_os) }} runs-on: ubuntu-24.04 steps: From 8c225ff1b4c1f56320ab54deeab2534d037e95a6 Mon Sep 17 00:00:00 2001 From: Paul Dagnelie Date: Wed, 5 Nov 2025 11:40:22 -0800 Subject: [PATCH 13/91] Fix gang write late_arrival bug When a write comes in via dmu_sync_late_arrival, its txg is equal to the open TXG. If that write gangs, and we have not yet activated the new gang header feature, and the gang header we pick can store a larger gang header, we will try to schedule the upgrade for the open TXG + 1. In debug mode, this causes an assertion to trip. This PR sets the TXG for activating the feature to be the larger of either the current open TXG or the syncing TXG + 1. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Paul Dagnelie Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Closes #17824 --- module/zfs/zio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/zfs/zio.c b/module/zfs/zio.c index aeea58bedfe4..4f3ecdc35daf 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -3318,8 +3318,8 @@ zio_write_gang_block(zio_t *pio, metaslab_class_t *mc) } else if (any_failed && candidate > SPA_OLD_GANGBLOCKSIZE && spa_feature_is_enabled(spa, SPA_FEATURE_DYNAMIC_GANG_HEADER) && !spa_feature_is_active(spa, SPA_FEATURE_DYNAMIC_GANG_HEADER)) { - dmu_tx_t *tx = - dmu_tx_create_assigned(spa->spa_dsl_pool, txg + 1); + dmu_tx_t *tx = dmu_tx_create_assigned(spa->spa_dsl_pool, + MAX(txg, spa_syncing_txg(spa) + 1)); dsl_sync_task_nowait(spa->spa_dsl_pool, zio_update_feature, (void *)SPA_FEATURE_DYNAMIC_GANG_HEADER, tx); From f93506d1df8b34b7fc62c38b720b2b5aeed885aa Mon Sep 17 00:00:00 2001 From: Tony Hutter Date: Wed, 5 Nov 2025 16:22:03 -0800 Subject: [PATCH 14/91] Linux 6.17 compat: Fix broken projectquota on 6.17 We need to specifically use the FX_XFLAG_* macros in zpl_ioctl_*attr() codepaths, and the FS_*_FL macros in the zpl_ioctl_*flags() codepaths. The earlier code just assumes the FS_*_FL macros for both codepaths. The 6.17 kernel add a bitmask check in copy_fsxattr_from_user() that exposed this error via failing 'projectquota' ZTS tests. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Tony Hutter Closes #17884 Closes #17869 --- cmd/zfs/zfs_project.c | 36 ++++++++--- include/sys/zfs_project.h | 10 ++- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/os/linux/sys/vfs.h | 33 ++++++++++ module/os/freebsd/zfs/zfs_vnops_os.c | 6 +- module/os/linux/zfs/zpl_file.c | 93 ++++++++++++++++++++++----- 6 files changed, 146 insertions(+), 33 deletions(-) create mode 100644 lib/libspl/include/os/linux/sys/vfs.h diff --git a/cmd/zfs/zfs_project.c b/cmd/zfs/zfs_project.c index fbf5e6cbdc68..8925e6672bef 100644 --- a/cmd/zfs/zfs_project.c +++ b/cmd/zfs/zfs_project.c @@ -145,11 +145,11 @@ zfs_project_handle_one(const char *name, zfs_project_control_t *zpc) switch (zpc->zpc_op) { case ZFS_PROJECT_OP_LIST: (void) printf("%5u %c %s\n", fsx.fsx_projid, - (fsx.fsx_xflags & ZFS_PROJINHERIT_FL) ? 'P' : '-', name); + (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) ? 'P' : '-', name); goto out; case ZFS_PROJECT_OP_CHECK: if (fsx.fsx_projid == zpc->zpc_expected_projid && - fsx.fsx_xflags & ZFS_PROJINHERIT_FL) + fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) goto out; if (!zpc->zpc_newline) { @@ -164,29 +164,30 @@ zfs_project_handle_one(const char *name, zfs_project_control_t *zpc) "(%u/%u)\n", name, fsx.fsx_projid, (uint32_t)zpc->zpc_expected_projid); - if (!(fsx.fsx_xflags & ZFS_PROJINHERIT_FL)) + if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) (void) printf("%s - project inherit flag is not set\n", name); goto out; case ZFS_PROJECT_OP_CLEAR: - if (!(fsx.fsx_xflags & ZFS_PROJINHERIT_FL) && + if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) && (zpc->zpc_keep_projid || fsx.fsx_projid == ZFS_DEFAULT_PROJID)) goto out; - fsx.fsx_xflags &= ~ZFS_PROJINHERIT_FL; + fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT; if (!zpc->zpc_keep_projid) fsx.fsx_projid = ZFS_DEFAULT_PROJID; break; case ZFS_PROJECT_OP_SET: if (fsx.fsx_projid == zpc->zpc_expected_projid && - (!zpc->zpc_set_flag || fsx.fsx_xflags & ZFS_PROJINHERIT_FL)) + (!zpc->zpc_set_flag || + fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) goto out; fsx.fsx_projid = zpc->zpc_expected_projid; if (zpc->zpc_set_flag) - fsx.fsx_xflags |= ZFS_PROJINHERIT_FL; + fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT; break; default: ASSERT(0); @@ -194,11 +195,30 @@ zfs_project_handle_one(const char *name, zfs_project_control_t *zpc) } ret = ioctl(fd, ZFS_IOC_FSSETXATTR, &fsx); - if (ret) + if (ret) { (void) fprintf(stderr, gettext("failed to set xattr for %s: %s\n"), name, strerror(errno)); + if (errno == ENOTSUP) { + char *kver = zfs_version_kernel(); + /* + * Special case: a module/userspace version mismatch can + * return ENOTSUP due to us fixing the XFLAGs bits in + * #17884. In that case give a hint to the user that + * they should take action to make the versions match. + */ + if (strcmp(kver, ZFS_META_ALIAS) != 0) { + fprintf(stderr, + gettext("Warning: The zfs module version " + "(%s) and userspace\nversion (%s) do not " + "match up. This may be the\ncause of the " + "\"Operation not supported\" error.\n"), + kver, ZFS_META_ALIAS); + } + } + } + out: close(fd); return (ret); diff --git a/include/sys/zfs_project.h b/include/sys/zfs_project.h index 714c87a0d441..a368f49e14f5 100644 --- a/include/sys/zfs_project.h +++ b/include/sys/zfs_project.h @@ -35,18 +35,16 @@ #include -#ifdef FS_PROJINHERIT_FL -#define ZFS_PROJINHERIT_FL FS_PROJINHERIT_FL -#else -#define ZFS_PROJINHERIT_FL 0x20000000 -#endif - #ifdef FS_IOC_FSGETXATTR typedef struct fsxattr zfsxattr_t; #define ZFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR #define ZFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR #else +/* Non-Linux OS */ +#define FS_PROJINHERIT_FL 0x20000000 +#define FS_XFLAG_PROJINHERIT FS_PROJINHERIT_FL + struct zfsxattr { uint32_t fsx_xflags; /* xflags field value (get/set) */ uint32_t fsx_extsize; /* extsize field value (get/set) */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 21f0c70db9e7..746cb12bf637 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -78,6 +78,7 @@ libspl_sys_HEADERS += \ %D%/os/linux/sys/param.h \ %D%/os/linux/sys/stat.h \ %D%/os/linux/sys/sysmacros.h \ + %D%/os/linux/sys/vfs.h \ %D%/os/linux/sys/zfs_context_os.h libspl_ia32_HEADERS = \ diff --git a/lib/libspl/include/os/linux/sys/vfs.h b/lib/libspl/include/os/linux/sys/vfs.h new file mode 100644 index 000000000000..c7b567ff44a4 --- /dev/null +++ b/lib/libspl/include/os/linux/sys/vfs.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* Copyright 2025 by Lawrence Livermore National Security, LLC. */ + +/* This is the Linux userspace version of include/os/linux/spl/sys/vfs.h */ + +#ifndef _LIBSPL_SYS_VFS_H +#define _LIBSPL_SYS_VFS_H + +#include +#include + +#endif diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index 5bd3e6bf2f15..6dfabe0d69c2 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -278,7 +278,7 @@ zfs_ioctl_getxattr(vnode_t *vp, zfsxattr_t *fsx) memset(fsx, 0, sizeof (*fsx)); fsx->fsx_xflags = (zp->z_pflags & ZFS_PROJINHERIT) ? - ZFS_PROJINHERIT_FL : 0; + FS_PROJINHERIT_FL : 0; fsx->fsx_projid = zp->z_projid; return (0); @@ -290,7 +290,7 @@ zfs_ioctl_setflags(vnode_t *vp, uint32_t ioctl_flags, xvattr_t *xva) uint64_t zfs_flags = VTOZ(vp)->z_pflags; xoptattr_t *xoap; - if (ioctl_flags & ~(ZFS_PROJINHERIT_FL)) + if (ioctl_flags & ~(FS_PROJINHERIT_FL)) return (SET_ERROR(EOPNOTSUPP)); xva_init(xva); @@ -304,7 +304,7 @@ zfs_ioctl_setflags(vnode_t *vp, uint32_t ioctl_flags, xvattr_t *xva) } \ } while (0) - FLAG_CHANGE(ZFS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT, + FLAG_CHANGE(FS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT, xoap->xoa_projinherit); #undef FLAG_CHANGE diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index 02965ac8cbee..f7691c02d163 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -811,28 +811,44 @@ zpl_fadvise(struct file *filp, loff_t offset, loff_t len, int advice) return (error); } -#define ZFS_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | ZFS_PROJINHERIT_FL) -#define ZFS_FL_USER_MODIFIABLE (FS_FL_USER_MODIFIABLE | ZFS_PROJINHERIT_FL) +#define ZFS_FL_USER_VISIBLE (FS_FL_USER_VISIBLE | FS_PROJINHERIT_FL) +#define ZFS_FL_USER_MODIFIABLE (FS_FL_USER_MODIFIABLE | FS_PROJINHERIT_FL) + + +static struct { + uint64_t zfs_flag; + uint32_t fs_flag; + uint32_t xflag; +} flags_lookup[] = { + {ZFS_IMMUTABLE, FS_IMMUTABLE_FL, FS_XFLAG_IMMUTABLE}, + {ZFS_APPENDONLY, FS_APPEND_FL, FS_XFLAG_APPEND}, + {ZFS_NODUMP, FS_NODUMP_FL, FS_XFLAG_NODUMP}, + {ZFS_PROJINHERIT, FS_PROJINHERIT_FL, FS_XFLAG_PROJINHERIT} +}; static uint32_t __zpl_ioctl_getflags(struct inode *ip) { uint64_t zfs_flags = ITOZ(ip)->z_pflags; uint32_t ioctl_flags = 0; + for (int i = 0; i < ARRAY_SIZE(flags_lookup); i++) + if (zfs_flags & flags_lookup[i].zfs_flag) + ioctl_flags |= flags_lookup[i].fs_flag; - if (zfs_flags & ZFS_IMMUTABLE) - ioctl_flags |= FS_IMMUTABLE_FL; + return (ioctl_flags); +} - if (zfs_flags & ZFS_APPENDONLY) - ioctl_flags |= FS_APPEND_FL; +static uint32_t +__zpl_ioctl_getxflags(struct inode *ip) +{ + uint64_t zfs_flags = ITOZ(ip)->z_pflags; + uint32_t ioctl_flags = 0; - if (zfs_flags & ZFS_NODUMP) - ioctl_flags |= FS_NODUMP_FL; + for (int i = 0; i < ARRAY_SIZE(flags_lookup); i++) + if (zfs_flags & flags_lookup[i].zfs_flag) + ioctl_flags |= flags_lookup[i].xflag; - if (zfs_flags & ZFS_PROJINHERIT) - ioctl_flags |= ZFS_PROJINHERIT_FL; - - return (ioctl_flags & ZFS_FL_USER_VISIBLE); + return (ioctl_flags); } /* @@ -846,6 +862,7 @@ zpl_ioctl_getflags(struct file *filp, void __user *arg) int err; flags = __zpl_ioctl_getflags(file_inode(filp)); + flags = flags & ZFS_FL_USER_VISIBLE; err = copy_to_user(arg, &flags, sizeof (flags)); return (err); @@ -869,7 +886,7 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva) xoptattr_t *xoap; if (ioctl_flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL | - ZFS_PROJINHERIT_FL)) + FS_PROJINHERIT_FL)) return (-EOPNOTSUPP); if (ioctl_flags & ~ZFS_FL_USER_MODIFIABLE) @@ -900,7 +917,51 @@ __zpl_ioctl_setflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva) xoap->xoa_appendonly); FLAG_CHANGE(FS_NODUMP_FL, ZFS_NODUMP, XAT_NODUMP, xoap->xoa_nodump); - FLAG_CHANGE(ZFS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT, + FLAG_CHANGE(FS_PROJINHERIT_FL, ZFS_PROJINHERIT, XAT_PROJINHERIT, + xoap->xoa_projinherit); + +#undef FLAG_CHANGE + + return (0); +} + +static int +__zpl_ioctl_setxflags(struct inode *ip, uint32_t ioctl_flags, xvattr_t *xva) +{ + uint64_t zfs_flags = ITOZ(ip)->z_pflags; + xoptattr_t *xoap; + + if (ioctl_flags & ~(FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND | + FS_XFLAG_NODUMP | FS_XFLAG_PROJINHERIT)) + return (-EOPNOTSUPP); + + if ((fchange(ioctl_flags, zfs_flags, FS_XFLAG_IMMUTABLE, + ZFS_IMMUTABLE) || + fchange(ioctl_flags, zfs_flags, FS_XFLAG_APPEND, ZFS_APPENDONLY)) && + !capable(CAP_LINUX_IMMUTABLE)) + return (-EPERM); + + if (!zpl_inode_owner_or_capable(zfs_init_idmap, ip)) + return (-EACCES); + + xva_init(xva); + xoap = xva_getxoptattr(xva); + +#define FLAG_CHANGE(iflag, zflag, xflag, xfield) do { \ + if (((ioctl_flags & (iflag)) && !(zfs_flags & (zflag))) || \ + ((zfs_flags & (zflag)) && !(ioctl_flags & (iflag)))) { \ + XVA_SET_REQ(xva, (xflag)); \ + (xfield) = ((ioctl_flags & (iflag)) != 0); \ + } \ +} while (0) + + FLAG_CHANGE(FS_XFLAG_IMMUTABLE, ZFS_IMMUTABLE, XAT_IMMUTABLE, + xoap->xoa_immutable); + FLAG_CHANGE(FS_XFLAG_APPEND, ZFS_APPENDONLY, XAT_APPENDONLY, + xoap->xoa_appendonly); + FLAG_CHANGE(FS_XFLAG_NODUMP, ZFS_NODUMP, XAT_NODUMP, + xoap->xoa_nodump); + FLAG_CHANGE(FS_XFLAG_PROJINHERIT, ZFS_PROJINHERIT, XAT_PROJINHERIT, xoap->xoa_projinherit); #undef FLAG_CHANGE @@ -941,7 +1002,7 @@ zpl_ioctl_getxattr(struct file *filp, void __user *arg) struct inode *ip = file_inode(filp); int err; - fsx.fsx_xflags = __zpl_ioctl_getflags(ip); + fsx.fsx_xflags = __zpl_ioctl_getxflags(ip); fsx.fsx_projid = ITOZ(ip)->z_projid; err = copy_to_user(arg, &fsx, sizeof (fsx)); @@ -965,7 +1026,7 @@ zpl_ioctl_setxattr(struct file *filp, void __user *arg) if (!zpl_is_valid_projid(fsx.fsx_projid)) return (-EINVAL); - err = __zpl_ioctl_setflags(ip, fsx.fsx_xflags, &xva); + err = __zpl_ioctl_setxflags(ip, fsx.fsx_xflags, &xva); if (err) return (err); From 242fdb58e5984c39dc43b433b8c9b3fc0f241b05 Mon Sep 17 00:00:00 2001 From: Alexander Ziaee Date: Thu, 6 Nov 2025 16:53:24 -0500 Subject: [PATCH 15/91] zfs-jail.8: Add introductory sentence, refactor Add an introductory sentance explaining why the reader may want to use this command, and establishing the requirement that the jail must be running. Move other requirements from the description of the subcommands to follow this for flow and structure. Move the caveat that this is for FreeBSD down to a cannonical CAVEATS section, and crossreference Linux's equivelant functionality. Mention that this utility can not be used to delegate the root directory of the jail to that section also. Reported by: Jan Brankamp Reviewed-by: Brian Behlendorf Reviewed-by: Allan Jude Signed-off-by: Alexander Ziaee Closes #17883 --- man/man8/zfs-jail.8 | 79 ++++++++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 30 deletions(-) diff --git a/man/man8/zfs-jail.8 b/man/man8/zfs-jail.8 index 569f5f57eab4..8f94a1bd4d81 100644 --- a/man/man8/zfs-jail.8 +++ b/man/man8/zfs-jail.8 @@ -37,7 +37,7 @@ .\" Copyright 2018 Nexenta Systems, Inc. .\" Copyright 2019 Joyent, Inc. .\" -.Dd July 11, 2022 +.Dd November 4, 2025 .Dt ZFS-JAIL 8 .Os . @@ -53,9 +53,42 @@ .Ar filesystem . .Sh DESCRIPTION -.Bl -tag -width "" +The +.Nm +functionality can be used to assign a dataset onto a running +.Fx +system +.Xr jail 4 , +allowing +.Xr zfs 8 +management utilities to be run inside of the +.Xr jail 4 . +.Pp +To allow management of the dataset from within a jail, the +.Sy jailed +property should be set and the required +.Xr devfs.conf 5 +entries to expose +.Pa /dev/zfs +device within the jail must be present. +The +.Sy quota +property cannot be changed from within a jail. +.Pp +To use this functionality, the jail needs the +.Sy allow.mount +and +.Sy allow.mount.zfs +parameters set to +.Sy 1 +and the +.Sy enforce_statfs +parameter set to a value lower than +.Sy 2 . +.Pp +The subcommands are as follows: +.Bl -tag -width indent .It Xo -.Nm zfs .Cm jail .Ar jailid Ns | Ns Ar jailname .Ar filesystem @@ -69,16 +102,6 @@ or name From now on this file system tree can be managed from within a jail if the .Sy jailed property has been set. -To use this functionality, the jail needs the -.Sy allow.mount -and -.Sy allow.mount.zfs -parameters set to -.Sy 1 -and the -.Sy enforce_statfs -parameter set to a value lower than -.Sy 2 . .Pp You cannot attach a jailed dataset's children to another jail. You can also not attach the root file system @@ -86,29 +109,12 @@ of the jail or any dataset which needs to be mounted before the zfs rc script is run inside the jail, as it would be attached unmounted until it is mounted from the rc script inside the jail. .Pp -To allow management of the dataset from within a jail, the -.Sy jailed -property has to be set and the jail needs access to the -.Pa /dev/zfs -device. -The -.Sy quota -property cannot be changed from within a jail. -.Pp After a dataset is attached to a jail and the .Sy jailed property is set, a jailed file system cannot be mounted outside the jail, since the jail administrator might have set the mount point to an unacceptable value. -.Pp -See -.Xr jail 8 -for more information on managing jails. -Jails are a -.Fx -feature and are not relevant on other platforms. .It Xo -.Nm zfs .Cm unjail .Ar jailid Ns | Ns Ar jailname .Ar filesystem @@ -121,5 +127,18 @@ or name .Ar jailname . .El .Sh SEE ALSO +.Xr devfs.conf 5 , .Xr zfsprops 7 , .Xr jail 8 +.Sh CAVEATS +The root directory of jail can not be delegated to the jail with this +utility because the jail must be running with a valid root directory. +.Pp +Jails are a +.Fx +feature and are not relevant on other platforms. +See +.Xr jail 8 +for more information on managing jails, or +.Xr zfs-zone 8 +for the equivelant functionality on Linux. From 336c95372d5056c73095e60d6d315dac2ffe7d3c Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 8 Nov 2025 01:01:59 +1100 Subject: [PATCH 16/91] man: describe zfs-rewrite method and properties We've heard anecdotes that suggest some confusion/surprise/disappointment that a changed recordsize is not applied during rewrite. Until such time as we actually can do that, we can at least explicitly mention it at something that doesn't work. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Brian Behlendorf Reviewed-by: Alexander Motin Reviewed-by: Allan Jude Signed-off-by: Rob Norris Closes #17898 --- man/man8/zfs-rewrite.8 | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/man/man8/zfs-rewrite.8 b/man/man8/zfs-rewrite.8 index ca5340c7e5eb..ae0a1588293e 100644 --- a/man/man8/zfs-rewrite.8 +++ b/man/man8/zfs-rewrite.8 @@ -20,8 +20,9 @@ .\" CDDL HEADER END .\" .\" Copyright (c) 2025 iXsystems, Inc. +.\" Copyright (c) 2025, Klara, Inc. .\" -.Dd July 23, 2025 +.Dd November 5, 2025 .Dt ZFS-REWRITE 8 .Os . @@ -39,9 +40,10 @@ .Sh DESCRIPTION Rewrite blocks of specified .Ar file -as is without modification at a new location and possibly with new -properties, such as checksum, compression, dedup, copies, etc, +as is without modification at a new location and possibly with new properties, as if they were atomically read and written back. +.No See Sx NOTES . +for more information about property changes that may be applied during rewrite. .Bl -tag -width "-r" .It Fl P Perform physical rewrite, preserving logical birth time of blocks. @@ -64,6 +66,20 @@ Print names of all successfully rewritten files. Don't cross file system mount points when recursing. .El .Sh NOTES +Rewrite works by replacing an existing block with a new block of the same +logical size. +Changed dataset properties that operate on the data or metadata without +changing the logical size will be applied. +These include +.Sy checksum , +.Sy compression , +.Sy dedup +and +.Sy copies . +Changes to properties that affect the size of a logical block, like +.Sy recordsize , +will have no effect. +.Pp Rewrite of cloned blocks and blocks that are part of any snapshots, same as some property changes may increase pool space usage. Holes that were never written or were previously zero-compressed are From fe553581f0d6dc7fe158cde6ab585ef57ae046dd Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Fri, 7 Nov 2025 16:27:18 +0200 Subject: [PATCH 17/91] libzfs: ignoring unreachable code We have infinite loop and on certain condition, we exit this loop and thread with pthread_exit(). But also after this loop, we have a code to perform pthread_cleanup_pop() and return from the thread. The problem is that modern compilers are able to recognize that we actually never get to the statements after loop and therefore it is dead code there. I think, instead of pthread_exit(), it is better to break out of loop and let the last statements to work as intended. This is because we do need to keep pthread_cleanup_pop() anyhow. Of course, it is matter of taste if we want to use return or pthread_exit as very last statement in this function. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Reviewed-by: Igor Kozhukhov Signed-off-by: Toomas Soome Closes #17900 --- lib/libzfs/libzfs_sendrecv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 77134d197904..0e5cecc6cca9 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -1013,7 +1013,8 @@ send_progress_thread(void *arg) &blocks)) != 0) { if (err == EINTR || err == ENOENT) err = 0; - pthread_exit(((void *)(uintptr_t)err)); + /* Use break to reach pthread_cleanup_pop() below. */ + break; } (void) time(&t); @@ -1055,7 +1056,7 @@ send_progress_thread(void *arg) } } pthread_cleanup_pop(B_TRUE); - return (NULL); + pthread_exit(((void *)(uintptr_t)err)); } static boolean_t From 54876ee85ee72512fe6ac80de7e3eb05fa41d75a Mon Sep 17 00:00:00 2001 From: Adi-Goll <68113680+Adi-Goll@users.noreply.github.com> Date: Fri, 7 Nov 2025 09:55:03 -0800 Subject: [PATCH 18/91] Fix typo in vdev_raidz.c Change the spelling of "begining" on line 4875 to "beginning". Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Adi Gollamudi Closes #17905 --- module/zfs/vdev_raidz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/vdev_raidz.c b/module/zfs/vdev_raidz.c index 56b8e3b60b22..5fe70ec2b1d5 100644 --- a/module/zfs/vdev_raidz.c +++ b/module/zfs/vdev_raidz.c @@ -4872,7 +4872,7 @@ spa_raidz_expand_thread(void *arg, zthr_t *zthr) else vre->vre_offset = RRSS_GET_OFFSET(&spa->spa_ubsync); - /* Reflow the begining portion using the scratch area */ + /* Reflow the beginning portion using the scratch area */ if (vre->vre_offset == 0) { VERIFY0(dsl_sync_task(spa_name(spa), NULL, raidz_reflow_scratch_sync, From 962474d1a21a9e5ade60190d0cf02c6caccafff4 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Fri, 7 Nov 2025 10:01:12 -0800 Subject: [PATCH 19/91] zstd: disable intrinsics Disable the aarch64 NEON SIMD intrinsics for kernel builds. Safely using them in the kernel context requires saving/restoring the FPU registers which is not currently done. Additionally, remove the aarch64 optimized PREFETCH_L1 and PREFETCH_L2 instruction. Rely on the more portable compiler built ins. This lets us remove the problematic workaround in the aarch64_compat.h header which undefines the __aarch64__ macro. Reviewed-by: Rob Norris Reviewed-by: Tino Reichardt Signed-off-by: Brian Behlendorf Closes #17904 Closes #17852 --- module/Kbuild.in | 3 +- module/Makefile.bsd | 24 ---------------- module/zstd/include/aarch64_compat.h | 38 -------------------------- module/zstd/lib/common/compiler.h | 3 -- module/zstd/lib/common/zstd_internal.h | 9 ++++++ 5 files changed, 10 insertions(+), 67 deletions(-) delete mode 100644 module/zstd/include/aarch64_compat.h diff --git a/module/Kbuild.in b/module/Kbuild.in index 58a80dc4402c..95313c984178 100644 --- a/module/Kbuild.in +++ b/module/Kbuild.in @@ -293,10 +293,9 @@ ZSTD_UPSTREAM_OBJS := \ zfs-objs += $(addprefix zstd/,$(ZSTD_OBJS) $(ZSTD_UPSTREAM_OBJS)) -# Disable aarch64 neon SIMD instructions for kernel mode $(addprefix $(obj)/zstd/,$(ZSTD_OBJS) $(ZSTD_UPSTREAM_OBJS)) : ccflags-y += -I$(zstd_include) $(ZFS_ZSTD_FLAGS) $(addprefix $(obj)/zstd/,$(ZSTD_OBJS) $(ZSTD_UPSTREAM_OBJS)) : asflags-y += -I$(zstd_include) -$(addprefix $(obj)/zstd/,$(ZSTD_UPSTREAM_OBJS)) : ccflags-y += -include $(zstd_include)/aarch64_compat.h -include $(zstd_include)/zstd_compat_wrapper.h -Wp,-w +$(addprefix $(obj)/zstd/,$(ZSTD_UPSTREAM_OBJS)) : ccflags-y += -include $(zstd_include)/zstd_compat_wrapper.h -Wp,-w $(obj)/zstd/zfs_zstd.o : ccflags-y += -include $(zstd_include)/zstd_compat_wrapper.h diff --git a/module/Makefile.bsd b/module/Makefile.bsd index 3ba38c43f25b..c20fdc0c483b 100644 --- a/module/Makefile.bsd +++ b/module/Makefile.bsd @@ -521,30 +521,6 @@ CFLAGS.zstd_ldm.c= -U__BMI__ -fno-tree-vectorize ${NO_WBITWISE_INSTEAD_OF_LOGICA CFLAGS.zstd_opt.c= -U__BMI__ -fno-tree-vectorize ${NO_WBITWISE_INSTEAD_OF_LOGICAL} .if ${MACHINE_ARCH} == "aarch64" -__ZFS_ZSTD_AARCH64_FLAGS= -include ${SRCDIR}/zstd/include/aarch64_compat.h -CFLAGS.zstd.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.entropy_common.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.error_private.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.fse_compress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.fse_decompress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.hist.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.huf_compress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.huf_decompress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.pool.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.xxhash.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_common.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_compress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_compress_literals.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_compress_sequences.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_compress_superblock.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_ddict.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_decompress.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_decompress_block.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_double_fast.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_fast.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_lazy.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_ldm.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} -CFLAGS.zstd_opt.c+= ${__ZFS_ZSTD_AARCH64_FLAGS} sha256-armv8.o: sha256-armv8.S ${CC} -c ${CFLAGS:N-mgeneral-regs-only} ${WERROR} ${.IMPSRC} \ diff --git a/module/zstd/include/aarch64_compat.h b/module/zstd/include/aarch64_compat.h deleted file mode 100644 index 9500a832b81c..000000000000 --- a/module/zstd/include/aarch64_compat.h +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -/* - * BSD 3-Clause New License (https://spdx.org/licenses/BSD-3-Clause.html) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its - * contributors may be used to endorse or promote products derived from this - * software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Copyright (c) 2018-2020, Sebastian Gottschall - */ - -#ifdef _KERNEL -#undef __aarch64__ -#endif diff --git a/module/zstd/lib/common/compiler.h b/module/zstd/lib/common/compiler.h index d0f588e2ec3c..c8d65a201212 100644 --- a/module/zstd/lib/common/compiler.h +++ b/module/zstd/lib/common/compiler.h @@ -115,9 +115,6 @@ # include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) # define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) -# elif defined(__aarch64__) -# define PREFETCH_L1(ptr) __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))) -# define PREFETCH_L2(ptr) __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))) # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define PREFETCH_L1(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # define PREFETCH_L2(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) diff --git a/module/zstd/lib/common/zstd_internal.h b/module/zstd/lib/common/zstd_internal.h index 6b1fc44cf9f6..9650af77bcea 100644 --- a/module/zstd/lib/common/zstd_internal.h +++ b/module/zstd/lib/common/zstd_internal.h @@ -12,6 +12,15 @@ #ifndef ZSTD_CCOMMON_H_MODULE #define ZSTD_CCOMMON_H_MODULE +/* + * Disable the aarch64 NEON SIMD intrinsics for kernel builds. Safely + * using them in the kernel context requires saving/restoring the FPU + * registers which is not currently done. + */ +#ifdef _KERNEL +#define ZSTD_NO_INTRINSICS +#endif + /* this module contains definitions which must be identical * across compression, decompression and dictBuilder. * It also contains a few functions useful to at least 2 of them From e26b9fc871bd53d349ad02b41d464c16b41be7bf Mon Sep 17 00:00:00 2001 From: rmacklem <64620010+rmacklem@users.noreply.github.com> Date: Sat, 8 Nov 2025 10:20:23 -0800 Subject: [PATCH 20/91] FreeBSD: Add support for _PC_CASE_INSENSITIVE FreeBSD now has a pathconf name called _PC_CASE_INSENSITIVE used to check if a file system performs case insensitive name lookups. This patch adds support for this name. Reviewed-by: Alexander Motin Reviewed-by: Brian Behlendorf Signed-off-by: Rick Macklem Closes #17908 --- module/os/freebsd/zfs/zfs_vnops_os.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index 6dfabe0d69c2..b2b3473613ad 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -5760,7 +5760,7 @@ zfs_freebsd_pathconf(struct vop_pathconf_args *ap) { ulong_t val; int error; -#ifdef _PC_CLONE_BLKSIZE +#if defined(_PC_CLONE_BLKSIZE) || defined(_PC_CASE_INSENSITIVE) zfsvfs_t *zfsvfs; #endif @@ -5823,6 +5823,15 @@ zfs_freebsd_pathconf(struct vop_pathconf_args *ap) else *ap->a_retval = 0; return (0); +#endif +#ifdef _PC_CASE_INSENSITIVE + case _PC_CASE_INSENSITIVE: + zfsvfs = (zfsvfs_t *)ap->a_vp->v_mount->mnt_data; + if (zfsvfs->z_case == ZFS_CASE_INSENSITIVE) + *ap->a_retval = 1; + else + *ap->a_retval = 0; + return (0); #endif default: return (vop_stdpathconf(ap)); From baefe098eec7f8bc8d417552222d97c706820580 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Sat, 8 Nov 2025 14:41:53 -0500 Subject: [PATCH 21/91] ZIO: Set minimum number of free issue threads to 32 Free issue threads might block waiting for synchronous DDT, BRT or GANG header reads. So unlike other taskqs using ZTI_SCALE to scale with number of CPUs, here we also need some amount of threads to potentially saturate pool reads. I am not sure we always want the 96 threads we had before ZTI_SCALE introduction at #11966 on small systems, but lets make it at least 32. While here, make free taskqs configurable, similar to read and write ones. Reviewed-by: Brian Behlendorf Reviewed-by: Rob Norris Signed-off-by: Alexander Motin Closes #17903 --- include/os/freebsd/spl/sys/mod.h | 3 + man/man4/zfs.4 | 38 +++++++++++ module/zfs/spa.c | 104 +++++++++++++++++++++++++------ 3 files changed, 127 insertions(+), 18 deletions(-) diff --git a/include/os/freebsd/spl/sys/mod.h b/include/os/freebsd/spl/sys/mod.h index 4214189c32df..2aa66bbe19b7 100644 --- a/include/os/freebsd/spl/sys/mod.h +++ b/include/os/freebsd/spl/sys/mod.h @@ -104,6 +104,9 @@ #define spa_taskq_write_param_set_args(var) \ CTLTYPE_STRING, NULL, 0, spa_taskq_write_param, "A" +#define spa_taskq_free_param_set_args(var) \ + CTLTYPE_STRING, NULL, 0, spa_taskq_free_param, "A" + #define fletcher_4_param_set_args(var) \ CTLTYPE_STRING, NULL, 0, fletcher_4_param, "A" diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index 11bcbf430210..b01d9a8e57e5 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -2660,12 +2660,50 @@ Set value only applies to pools imported/created after that. Set the queue and thread configuration for the IO read queues. This is an advanced debugging parameter. Don't change this unless you understand what it does. +Each of the four values corresponds to the issue, issue high-priority, +interrupt, and interrupt high-priority queues. +Valid values are +.Sy fixed,N,M +(M queues with N threads each), +.Sy scale[,MIN] +(scale with CPUs, minimum MIN total threads), +.Sy sync , +and +.Sy null . Set values only apply to pools imported/created after that. . .It Sy zio_taskq_write Ns = Ns Sy sync null scale null Pq charp Set the queue and thread configuration for the IO write queues. This is an advanced debugging parameter. Don't change this unless you understand what it does. +Each of the four values corresponds to the issue, issue high-priority, +interrupt, and interrupt high-priority queues. +Valid values are +.Sy fixed,N,M +(M queues with N threads each), +.Sy scale[,MIN] +(scale with CPUs, minimum MIN total threads), +.Sy sync , +and +.Sy null . +Set values only apply to pools imported/created after that. +. +.It Sy zio_taskq_free Ns = Ns Sy scale,32 null null null Pq charp +Set the queue and thread configuration for the IO free queues. +This is an advanced debugging parameter. +Don't change this unless you understand what it does. +Each of the four values corresponds to the issue, issue high-priority, +interrupt, and interrupt high-priority queues. +Valid values are +.Sy fixed,N,M +(M queues with N threads each), +.Sy scale[,MIN] +(scale with CPUs, minimum MIN total threads), +.Sy sync , +and +.Sy null . +The default uses a minimum of 32 threads to improve parallelism for +DDT and BRT metadata operations during frees. Set values only apply to pools imported/created after that. . .It Sy zvol_inhibit_dev Ns = Ns Sy 0 Ns | Ns 1 Pq uint diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 8821757a8f09..a12740ff8acb 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -141,7 +141,7 @@ typedef enum zti_modes { #define ZTI_P(n, q) { ZTI_MODE_FIXED, (n), (q) } #define ZTI_PCT(n) { ZTI_MODE_ONLINE_PERCENT, (n), 1 } -#define ZTI_SCALE { ZTI_MODE_SCALE, 0, 1 } +#define ZTI_SCALE(min) { ZTI_MODE_SCALE, (min), 1 } #define ZTI_SYNC { ZTI_MODE_SYNC, 0, 1 } #define ZTI_NULL { ZTI_MODE_NULL, 0, 0 } @@ -180,13 +180,13 @@ static const char *const zio_taskq_types[ZIO_TASKQ_TYPES] = { static zio_taskq_info_t zio_taskqs[ZIO_TYPES][ZIO_TASKQ_TYPES] = { /* ISSUE ISSUE_HIGH INTR INTR_HIGH */ { ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, /* NULL */ - { ZTI_N(8), ZTI_NULL, ZTI_SCALE, ZTI_NULL }, /* READ */ + { ZTI_N(8), ZTI_NULL, ZTI_SCALE(0), ZTI_NULL }, /* READ */ #ifdef illumos - { ZTI_SYNC, ZTI_N(5), ZTI_SCALE, ZTI_N(5) }, /* WRITE */ + { ZTI_SYNC, ZTI_N(5), ZTI_SCALE(0), ZTI_N(5) }, /* WRITE */ #else - { ZTI_SYNC, ZTI_NULL, ZTI_SCALE, ZTI_NULL }, /* WRITE */ + { ZTI_SYNC, ZTI_NULL, ZTI_SCALE(0), ZTI_NULL }, /* WRITE */ #endif - { ZTI_SCALE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, /* FREE */ + { ZTI_SCALE(32), ZTI_NULL, ZTI_ONE, ZTI_NULL }, /* FREE */ { ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, /* CLAIM */ { ZTI_ONE, ZTI_NULL, ZTI_ONE, ZTI_NULL }, /* FLUSH */ { ZTI_N(4), ZTI_NULL, ZTI_ONE, ZTI_NULL }, /* TRIM */ @@ -1170,7 +1170,7 @@ spa_taskqs_init(spa_t *spa, zio_type_t t, zio_taskq_type_t q) uint_t value = ztip->zti_value; uint_t count = ztip->zti_count; spa_taskqs_t *tqs = &spa->spa_zio_taskq[t][q]; - uint_t cpus, flags = TASKQ_DYNAMIC; + uint_t cpus, threads, flags = TASKQ_DYNAMIC; switch (mode) { case ZTI_MODE_FIXED: @@ -1183,8 +1183,8 @@ spa_taskqs_init(spa_t *spa, zio_type_t t, zio_taskq_type_t q) * Create one wr_iss taskq for every 'zio_taskq_write_tpq' CPUs, * not to exceed the number of spa allocators, and align to it. */ - cpus = MAX(1, boot_ncpus * zio_taskq_batch_pct / 100); - count = MAX(1, cpus / MAX(1, zio_taskq_write_tpq)); + threads = MAX(1, boot_ncpus * zio_taskq_batch_pct / 100); + count = MAX(1, threads / MAX(1, zio_taskq_write_tpq)); count = MAX(count, (zio_taskq_batch_pct + 99) / 100); count = MIN(count, spa->spa_alloc_count); while (spa->spa_alloc_count % count != 0 && @@ -1201,14 +1201,14 @@ spa_taskqs_init(spa_t *spa, zio_type_t t, zio_taskq_type_t q) break; case ZTI_MODE_SCALE: - flags |= TASKQ_THREADS_CPU_PCT; /* * We want more taskqs to reduce lock contention, but we want * less for better request ordering and CPU utilization. */ - cpus = MAX(1, boot_ncpus * zio_taskq_batch_pct / 100); + threads = MAX(1, boot_ncpus * zio_taskq_batch_pct / 100); + threads = MAX(threads, value); if (zio_taskq_batch_tpq > 0) { - count = MAX(1, (cpus + zio_taskq_batch_tpq / 2) / + count = MAX(1, (threads + zio_taskq_batch_tpq / 2) / zio_taskq_batch_tpq); } else { /* @@ -1228,13 +1228,23 @@ spa_taskqs_init(spa_t *spa, zio_type_t t, zio_taskq_type_t q) * 128 10 8% 10 100 * 256 14 6% 15 210 */ - count = 1 + cpus / 6; + cpus = MIN(threads, boot_ncpus); + count = 1 + threads / 6; while (count * count > cpus) count--; } - /* Limit each taskq within 100% to not trigger assertion. */ - count = MAX(count, (zio_taskq_batch_pct + 99) / 100); - value = (zio_taskq_batch_pct + count / 2) / count; + + /* + * Try to represent the number of threads per taskq as percent + * of online CPUs to allow scaling with later online/offline. + * Fall back to absolute numbers if can't. + */ + value = (threads * 100 + boot_ncpus * count / 2) / + (boot_ncpus * count); + if (value < 5 || value > 100) + value = MAX(1, (threads + count / 2) / count); + else + flags |= TASKQ_THREADS_CPU_PCT; break; case ZTI_MODE_NULL: @@ -1433,8 +1443,30 @@ spa_taskq_param_set(zio_type_t t, char *cfg) break; } + /* + * SCALE is optionally parameterised by minimum number of + * threads. + */ case ZTI_MODE_SCALE: { - const zio_taskq_info_t zti = ZTI_SCALE; + unsigned long long mint = 0; + if (c != NULL && *c != '\0') { + /* Need a number */ + if (!(isdigit(*c))) + break; + tok = c; + + /* Take digits */ + err = ddi_strtoull(tok, &tok, 10, &mint); + /* Must succeed, and moved forward */ + if (err != 0 || tok == c || *tok != '\0') + break; + + /* Sanity check */ + if (mint >= 16384) + break; + } + + const zio_taskq_info_t zti = ZTI_SCALE(mint); row[q] = zti; break; } @@ -1501,6 +1533,9 @@ spa_taskq_param_get(zio_type_t t, char *buf, boolean_t add_newline) pos += sprintf(&buf[pos], "%s%s,%u,%u", sep, modes[zti->zti_mode], zti->zti_count, zti->zti_value); + else if (zti->zti_mode == ZTI_MODE_SCALE && zti->zti_value > 0) + pos += sprintf(&buf[pos], "%s%s,%u", sep, + modes[zti->zti_mode], zti->zti_value); else pos += sprintf(&buf[pos], "%s%s", sep, modes[zti->zti_mode]); @@ -1520,9 +1555,10 @@ spa_taskq_read_param_set(const char *val, zfs_kernel_param_t *kp) { char *cfg = kmem_strdup(val); int err = spa_taskq_param_set(ZIO_TYPE_READ, cfg); - kmem_free(cfg, strlen(val)+1); + kmem_strfree(cfg); return (-err); } + static int spa_taskq_read_param_get(char *buf, zfs_kernel_param_t *kp) { @@ -1534,14 +1570,30 @@ spa_taskq_write_param_set(const char *val, zfs_kernel_param_t *kp) { char *cfg = kmem_strdup(val); int err = spa_taskq_param_set(ZIO_TYPE_WRITE, cfg); - kmem_free(cfg, strlen(val)+1); + kmem_strfree(cfg); return (-err); } + static int spa_taskq_write_param_get(char *buf, zfs_kernel_param_t *kp) { return (spa_taskq_param_get(ZIO_TYPE_WRITE, buf, TRUE)); } + +static int +spa_taskq_free_param_set(const char *val, zfs_kernel_param_t *kp) +{ + char *cfg = kmem_strdup(val); + int err = spa_taskq_param_set(ZIO_TYPE_FREE, cfg); + kmem_strfree(cfg); + return (-err); +} + +static int +spa_taskq_free_param_get(char *buf, zfs_kernel_param_t *kp) +{ + return (spa_taskq_param_get(ZIO_TYPE_FREE, buf, TRUE)); +} #else /* * On FreeBSD load-time parameters can be set up before malloc() is available, @@ -1574,6 +1626,19 @@ spa_taskq_write_param(ZFS_MODULE_PARAM_ARGS) return (err); return (spa_taskq_param_set(ZIO_TYPE_WRITE, buf)); } + +static int +spa_taskq_free_param(ZFS_MODULE_PARAM_ARGS) +{ + char buf[SPA_TASKQ_PARAM_MAX]; + int err; + + (void) spa_taskq_param_get(ZIO_TYPE_FREE, buf, FALSE); + err = sysctl_handle_string(oidp, buf, sizeof (buf), req); + if (err || req->newptr == NULL) + return (err); + return (spa_taskq_param_set(ZIO_TYPE_FREE, buf)); +} #endif #endif /* _KERNEL */ @@ -11273,6 +11338,9 @@ ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs_zio, zio_, taskq_read, ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs_zio, zio_, taskq_write, spa_taskq_write_param_set, spa_taskq_write_param_get, ZMOD_RW, "Configure IO queues for write IO"); +ZFS_MODULE_VIRTUAL_PARAM_CALL(zfs_zio, zio_, taskq_free, + spa_taskq_free_param_set, spa_taskq_free_param_get, ZMOD_RW, + "Configure IO queues for free IO"); #endif ZFS_MODULE_PARAM(zfs_zio, zio_, taskq_write_tpq, UINT, ZMOD_RW, From 57b1b99d3115d68bccc1747560036373e33a3c59 Mon Sep 17 00:00:00 2001 From: Adi-Goll <68113680+Adi-Goll@users.noreply.github.com> Date: Mon, 10 Nov 2025 10:13:13 -0800 Subject: [PATCH 22/91] Update man page description of zpool rewind Update description of zpool import --rewind-to-checkpoint in man/man7/zpoolconcepts.7 to explain that rewinding automatically discards a checkpoint. Reviewed-by: Brian Behlendorf Signed-off-by: Adi Gollamudi Closes #12646 Closes #17918 --- man/man7/zpoolconcepts.7 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/man/man7/zpoolconcepts.7 b/man/man7/zpoolconcepts.7 index b9c8926d835d..21bd72351209 100644 --- a/man/man7/zpoolconcepts.7 +++ b/man/man7/zpoolconcepts.7 @@ -469,6 +469,11 @@ then rewind it during import: .Dl # Nm zpool Cm export Ar pool .Dl # Nm zpool Cm import Fl -rewind-to-checkpoint Ar pool .Pp +Note that rewinding to a checkpoint will +.Sy permanently discard it. +Once the pool has been successfully imported with the above rewind command, +you cannot rewind to the same checkpoint. +.Pp To discard the checkpoint from a pool: .Dl # Nm zpool Cm checkpoint Fl d Ar pool .Pp From 8aaed7dc4252bc73536bafab82b95acb7599f162 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 10 Nov 2025 16:58:39 -0500 Subject: [PATCH 23/91] BRT: Fix ranges to blocks conversion math BRT_RANGESIZE_TO_NBLOCKS() takes number of ranges as its argument. To get number of blocks we should multiply it by the entry size, not divide by it, as it was due to missing parentheses. Before #17875 this could cause small memory corruptions for vdevs bigger than 64TB, but the change made the bug more noticeable. Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Motin Closes #17886 Closes #17915 --- include/sys/brt_impl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sys/brt_impl.h b/include/sys/brt_impl.h index 1805d21b16b2..1843e6d988cd 100644 --- a/include/sys/brt_impl.h +++ b/include/sys/brt_impl.h @@ -65,7 +65,7 @@ _Static_assert(BRT_RANGESIZE / SPA_MINBLOCKSIZE <= UINT16_MAX, */ #define BRT_BLOCKSIZE (32 * 1024) #define BRT_RANGESIZE_TO_NBLOCKS(size) \ - (((size) - 1) / BRT_BLOCKSIZE / sizeof (uint16_t) + 1) + (((size) - 1) / (BRT_BLOCKSIZE / sizeof (uint16_t)) + 1) #define BRT_LITTLE_ENDIAN 0 #define BRT_BIG_ENDIAN 1 From 6e12f0bd77a00b9a069f4a32d48f9cd13bc80d38 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Tue, 11 Nov 2025 09:23:39 +1100 Subject: [PATCH 24/91] spa_misc: add an API for spa_namespace_lock This is useful as debugging support, as it lets namespace lock operations be traced directly. It will also be useful for future work to reduce the use of spa_namespace_lock, traditionally a source of difficult deadlocks. Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Reviewed-by: Brian Behlendorf Reviewed-by: Tony Hutter Signed-off-by: Rob Norris Closes #17906 --- cmd/zdb/zdb.c | 8 +- cmd/ztest.c | 24 ++-- include/sys/spa.h | 14 ++- lib/libzpool/kernel.c | 4 +- module/os/freebsd/zfs/spa_os.c | 10 +- module/os/freebsd/zfs/zfs_ioctl_os.c | 4 +- module/os/freebsd/zfs/zvol_os.c | 12 +- module/os/linux/zfs/zvol_os.c | 6 +- module/zfs/arc.c | 8 +- module/zfs/mmp.c | 4 +- module/zfs/spa.c | 174 +++++++++++++-------------- module/zfs/spa_config.c | 8 +- module/zfs/spa_misc.c | 110 ++++++++++++----- module/zfs/vdev_initialize.c | 8 +- module/zfs/vdev_rebuild.c | 4 +- module/zfs/vdev_removal.c | 20 +-- module/zfs/vdev_trim.c | 12 +- module/zfs/zfs_fm.c | 6 +- module/zfs/zfs_ioctl.c | 14 +-- module/zfs/zio_inject.c | 8 +- module/zfs/zvol.c | 6 +- 21 files changed, 260 insertions(+), 204 deletions(-) diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index 2560ad045db3..fa8e7fa691db 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -7899,11 +7899,11 @@ zdb_set_skip_mmp(char *target) * Disable the activity check to allow examination of * active pools. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if ((spa = spa_lookup(target)) != NULL) { spa->spa_import_flags |= ZFS_IMPORT_SKIP_MMP; } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } #define BOGUS_SUFFIX "_CHECKPOINTED_UNIVERSE" @@ -10022,13 +10022,13 @@ main(int argc, char **argv) * try opening the pool after clearing the * log state. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if ((spa = spa_lookup(target)) != NULL && spa->spa_log_state == SPA_LOG_MISSING) { spa->spa_log_state = SPA_LOG_CLEAR; error = 0; } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); if (!error) { error = spa_open_rewind(target, &spa, diff --git a/cmd/ztest.c b/cmd/ztest.c index 7d590e5e06da..89b1f68606ea 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -1228,10 +1228,10 @@ ztest_kill(ztest_shared_t *zs) * See comment above spa_write_cachefile(). */ if (raidz_expand_pause_point != RAIDZ_EXPAND_PAUSE_NONE) { - if (mutex_tryenter(&spa_namespace_lock)) { + if (spa_namespace_tryenter(FTAG)) { spa_write_cachefile(ztest_spa, B_FALSE, B_FALSE, B_FALSE); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); ztest_scratch_state->zs_raidz_scratch_verify_pause = raidz_expand_pause_point; @@ -1246,9 +1246,9 @@ ztest_kill(ztest_shared_t *zs) return; } } else { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_write_cachefile(ztest_spa, B_FALSE, B_FALSE, B_FALSE); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } (void) raise(SIGKILL); @@ -3689,10 +3689,10 @@ ztest_split_pool(ztest_ds_t *zd, uint64_t id) if (error == 0) { (void) printf("successful split - results:\n"); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); show_pool_stats(spa); show_pool_stats(spa_lookup("splitp")); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); ++zs->zs_splits; --zs->zs_mirrors; } @@ -3976,11 +3976,11 @@ raidz_scratch_verify(void) kernel_init(SPA_MODE_READ); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa = spa_lookup(ztest_opts.zo_pool); ASSERT(spa); spa->spa_import_flags |= ZFS_IMPORT_SKIP_MMP; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); VERIFY0(spa_open(ztest_opts.zo_pool, &spa, FTAG)); @@ -7427,11 +7427,11 @@ ztest_walk_pool_directory(const char *header) if (ztest_opts.zo_verbose >= 6) (void) puts(header); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((spa = spa_next(spa)) != NULL) if (ztest_opts.zo_verbose >= 6) (void) printf("\t%s\n", spa_name(spa)); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } static void @@ -8546,11 +8546,11 @@ ztest_run(ztest_shared_t *zs) /* * Verify that we can loop over all pools. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); for (spa = spa_next(NULL); spa != NULL; spa = spa_next(spa)) if (ztest_opts.zo_verbose > 3) (void) printf("spa_next: found %s\n", spa_name(spa)); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); /* * Verify that we can export the pool and reimport it under a diff --git a/include/sys/spa.h b/include/sys/spa.h index f172f2af6f07..2a4cc60c4aa8 100644 --- a/include/sys/spa.h +++ b/include/sys/spa.h @@ -29,7 +29,7 @@ * Copyright 2017 Joyent, Inc. * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, Allan Jude - * Copyright (c) 2019, Klara Inc. + * Copyright (c) 2019, 2025, Klara, Inc. * Copyright (c) 2019, Datto Inc. */ @@ -867,10 +867,14 @@ uint_t spa_acq_allocator(spa_t *spa); void spa_rel_allocator(spa_t *spa, uint_t allocator); void spa_select_allocator(zio_t *zio); -/* spa namespace global mutex */ -extern kmutex_t spa_namespace_lock; -extern avl_tree_t spa_namespace_avl; -extern kcondvar_t spa_namespace_cv; +/* spa namespace global lock */ +extern void spa_namespace_enter(const void *tag); +extern boolean_t spa_namespace_tryenter(const void *tag); +extern int spa_namespace_enter_interruptible(const void *tag); +extern void spa_namespace_exit(const void *tag); +extern boolean_t spa_namespace_held(void); +extern void spa_namespace_wait(void); +extern void spa_namespace_broadcast(void); /* * SPA configuration functions in spa_config.c diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 70eba5099119..452462a1700b 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -903,7 +903,7 @@ spa_config_load(void) * Iterate over all elements in the nvlist, creating a new spa_t for * each one with the specified configuration. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); nvpair = NULL; while ((nvpair = nvlist_next_nvpair(nvlist, nvpair)) != NULL) { if (nvpair_type(nvpair) != DATA_TYPE_NVLIST) @@ -915,7 +915,7 @@ spa_config_load(void) continue; (void) spa_add(nvpair_name(nvpair), child, NULL); } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); nvlist_free(nvlist); diff --git a/module/os/freebsd/zfs/spa_os.c b/module/os/freebsd/zfs/spa_os.c index 2d04ccf95fbf..d918b26521a7 100644 --- a/module/os/freebsd/zfs/spa_os.c +++ b/module/os/freebsd/zfs/spa_os.c @@ -193,7 +193,7 @@ spa_import_rootpool(const char *name, bool checkpointrewind) */ config = spa_generate_rootconf(name); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if (config != NULL) { pname = fnvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME); VERIFY0(strcmp(name, pname)); @@ -204,7 +204,7 @@ spa_import_rootpool(const char *name, bool checkpointrewind) * e.g., after reboot -r. */ if (spa->spa_state == POOL_STATE_ACTIVE) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); fnvlist_free(config); return (0); } @@ -226,7 +226,7 @@ spa_import_rootpool(const char *name, bool checkpointrewind) &spa->spa_ubsync.ub_version) != 0) spa->spa_ubsync.ub_version = SPA_VERSION_INITIAL; } else if ((spa = spa_lookup(name)) == NULL) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); fnvlist_free(config); cmn_err(CE_NOTE, "Cannot find the pool label for '%s'", name); @@ -249,7 +249,7 @@ spa_import_rootpool(const char *name, bool checkpointrewind) VDEV_ALLOC_ROOTPOOL); spa_config_exit(spa, SCL_ALL, FTAG); if (error) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); fnvlist_free(config); cmn_err(CE_NOTE, "Can not parse the config for pool '%s'", name); @@ -259,7 +259,7 @@ spa_import_rootpool(const char *name, bool checkpointrewind) spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER); vdev_free(rvd); spa_config_exit(spa, SCL_ALL, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); fnvlist_free(config); return (0); diff --git a/module/os/freebsd/zfs/zfs_ioctl_os.c b/module/os/freebsd/zfs/zfs_ioctl_os.c index dcdefae56639..29711fcf5d2c 100644 --- a/module/os/freebsd/zfs/zfs_ioctl_os.c +++ b/module/os/freebsd/zfs/zfs_ioctl_os.c @@ -108,11 +108,11 @@ zfs_ioc_nextboot(const char *unused, nvlist_t *innvl, nvlist_t *outnvl) "command", &command) != 0) return (EINVAL); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa = spa_by_guid(pool_guid, vdev_guid); if (spa != NULL) strcpy(name, spa_name(spa)); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); if (spa == NULL) return (ENOENT); diff --git a/module/os/freebsd/zfs/zvol_os.c b/module/os/freebsd/zfs/zvol_os.c index 0dd2ecd7fd8d..4efcea9419ed 100644 --- a/module/os/freebsd/zfs/zvol_os.c +++ b/module/os/freebsd/zfs/zvol_os.c @@ -282,8 +282,8 @@ retry: * Take spa_namespace_lock to prevent lock inversion when * zvols from one pool are opened as vdevs in another. */ - if (!mutex_owned(&spa_namespace_lock)) { - if (!mutex_tryenter(&spa_namespace_lock)) { + if (!spa_namespace_held()) { + if (!spa_namespace_tryenter(FTAG)) { mutex_exit(&zv->zv_state_lock); rw_exit(&zv->zv_suspend_lock); drop_suspend = B_FALSE; @@ -295,7 +295,7 @@ retry: } err = zvol_first_open(zv, !(flag & FWRITE)); if (drop_namespace) - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); if (err) goto out_locked; pp->mediasize = zv->zv_volsize; @@ -962,8 +962,8 @@ retry: * Take spa_namespace_lock to prevent lock inversion when * zvols from one pool are opened as vdevs in another. */ - if (!mutex_owned(&spa_namespace_lock)) { - if (!mutex_tryenter(&spa_namespace_lock)) { + if (!spa_namespace_held()) { + if (!spa_namespace_tryenter(FTAG)) { mutex_exit(&zv->zv_state_lock); rw_exit(&zv->zv_suspend_lock); drop_suspend = B_FALSE; @@ -975,7 +975,7 @@ retry: } err = zvol_first_open(zv, !(flags & FWRITE)); if (drop_namespace) - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); if (err) goto out_locked; } diff --git a/module/os/linux/zfs/zvol_os.c b/module/os/linux/zfs/zvol_os.c index fe939150b641..89f9bc555fcf 100644 --- a/module/os/linux/zfs/zvol_os.c +++ b/module/os/linux/zfs/zvol_os.c @@ -809,8 +809,8 @@ retry: * the kernel so the only option is to return the error for * the caller to handle it. */ - if (!mutex_owned(&spa_namespace_lock)) { - if (!mutex_tryenter(&spa_namespace_lock)) { + if (!spa_namespace_held()) { + if (!spa_namespace_tryenter(FTAG)) { mutex_exit(&zv->zv_state_lock); rw_exit(&zv->zv_suspend_lock); drop_suspend = B_FALSE; @@ -834,7 +834,7 @@ retry: error = -zvol_first_open(zv, !(blk_mode_is_open_write(flag))); if (drop_namespace) - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } if (error == 0) { diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 89abd20d1269..b864d9035974 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -8548,7 +8548,7 @@ l2arc_dev_get_next(void) * of cache devices (l2arc_dev_mtx). Once a device has been selected, * both locks will be dropped and a spa config lock held instead. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); mutex_enter(&l2arc_dev_mtx); /* if there are no vdevs, there is nothing to do */ @@ -8591,7 +8591,7 @@ out: */ if (next != NULL) spa_config_enter(next->l2ad_spa, SCL_L2ARC, next, RW_READER); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (next); } @@ -10231,7 +10231,7 @@ l2arc_stop(void) void l2arc_spa_rebuild_start(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); /* * Locate the spa's l2arc devices and kick off rebuild threads. @@ -10256,7 +10256,7 @@ l2arc_spa_rebuild_start(spa_t *spa) void l2arc_spa_rebuild_stop(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); for (int i = 0; i < spa->spa_l2cache.sav_count; i++) { diff --git a/module/zfs/mmp.c b/module/zfs/mmp.c index fd46127b6068..b8ba40ecdc9d 100644 --- a/module/zfs/mmp.c +++ b/module/zfs/mmp.c @@ -729,12 +729,12 @@ mmp_signal_all_threads(void) { spa_t *spa = NULL; - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((spa = spa_next(spa))) { if (spa->spa_state == POOL_STATE_ACTIVE) mmp_signal_thread(spa); } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } ZFS_MODULE_PARAM_CALL(zfs_multihost, zfs_multihost_, interval, diff --git a/module/zfs/spa.c b/module/zfs/spa.c index a12740ff8acb..34de3f1d9525 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -1082,7 +1082,7 @@ spa_change_guid(spa_t *spa, const uint64_t *guidp) int error; mutex_enter(&spa->spa_vdev_top_lock); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if (guidp != NULL) { guid = *guidp; @@ -1117,7 +1117,7 @@ spa_change_guid(spa_t *spa, const uint64_t *guidp) } out: - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); mutex_exit(&spa->spa_vdev_top_lock); return (error); @@ -2252,7 +2252,7 @@ spa_should_sync_time_logger_on_unload(spa_t *spa) static void spa_unload(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); ASSERT(spa_state(spa) != POOL_STATE_UNINITIALIZED); @@ -5325,7 +5325,7 @@ spa_ld_read_checkpoint_txg(spa_t *spa) int error = 0; ASSERT0(spa->spa_checkpoint_txg); - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_load_thread == curthread); error = zap_lookup(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, @@ -5352,7 +5352,7 @@ spa_ld_mos_init(spa_t *spa, spa_import_type_t type) { int error = 0; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); ASSERT(spa->spa_config_source != SPA_CONFIG_SRC_NONE); /* @@ -5428,7 +5428,7 @@ spa_ld_checkpoint_rewind(spa_t *spa) uberblock_t checkpoint; int error = 0; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); ASSERT(spa->spa_import_flags & ZFS_IMPORT_CHECKPOINT); error = zap_lookup(spa->spa_meta_objset, DMU_POOL_DIRECTORY_OBJECT, @@ -5575,7 +5575,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport) boolean_t update_config_cache = B_FALSE; hrtime_t load_start = gethrtime(); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); ASSERT(spa->spa_config_source != SPA_CONFIG_SRC_NONE); spa_load_note(spa, "LOADING"); @@ -5622,7 +5622,7 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport) * Drop the namespace lock for the rest of the function. */ spa->spa_load_thread = curthread; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); /* * Retrieve the checkpoint txg if the pool has a checkpoint. @@ -5861,9 +5861,9 @@ spa_load_impl(spa_t *spa, spa_import_type_t type, const char **ereport) spa_load_note(spa, "LOADED"); fail: - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa->spa_load_thread = NULL; - cv_broadcast(&spa_namespace_cv); + spa_namespace_broadcast(); return (error); @@ -6025,14 +6025,14 @@ spa_open_common(const char *pool, spa_t **spapp, const void *tag, * up calling spa_open() again. The real fix is to figure out how to * avoid dsl_dir_open() calling this in the first place. */ - if (MUTEX_NOT_HELD(&spa_namespace_lock)) { - mutex_enter(&spa_namespace_lock); + if (!spa_namespace_held()) { + spa_namespace_enter(FTAG); locked = B_TRUE; } if ((spa = spa_lookup(pool)) == NULL) { if (locked) - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (SET_ERROR(ENOENT)); } @@ -6069,7 +6069,7 @@ spa_open_common(const char *pool, spa_t **spapp, const void *tag, spa_write_cachefile(spa, B_TRUE, B_TRUE, B_FALSE); spa_remove(spa); if (locked) - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (SET_ERROR(ENOENT)); } @@ -6089,7 +6089,7 @@ spa_open_common(const char *pool, spa_t **spapp, const void *tag, spa_deactivate(spa); spa->spa_last_open_failed = error; if (locked) - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); *spapp = NULL; return (error); } @@ -6113,7 +6113,7 @@ spa_open_common(const char *pool, spa_t **spapp, const void *tag, spa->spa_last_open_failed = 0; spa->spa_last_ubsync_txg = 0; spa->spa_load_txg = 0; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } if (firstopen) @@ -6146,13 +6146,13 @@ spa_inject_addref(char *name) { spa_t *spa; - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if ((spa = spa_lookup(name)) == NULL) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (NULL); } spa->spa_inject_ref++; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (spa); } @@ -6160,9 +6160,9 @@ spa_inject_addref(char *name) void spa_inject_delref(spa_t *spa) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa->spa_inject_ref--; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } /* @@ -6406,14 +6406,14 @@ spa_get_stats(const char *name, nvlist_t **config, */ if (altroot) { if (spa == NULL) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa = spa_lookup(name); if (spa) spa_altroot(spa, altroot, buflen); else altroot[0] = '\0'; spa = NULL; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } else { spa_altroot(spa, altroot, buflen); } @@ -6633,9 +6633,9 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props, /* * If this pool already exists, return failure. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if (spa_lookup(poolname) != NULL) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (SET_ERROR(EEXIST)); } @@ -6653,7 +6653,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props, if (props && (error = spa_prop_validate(spa, props))) { spa_deactivate(spa); spa_remove(spa); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (error); } @@ -6686,14 +6686,14 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props, if (error != 0) { spa_deactivate(spa); spa_remove(spa); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (error); } } if (!has_allocclass && zfs_special_devs(nvroot, NULL)) { spa_deactivate(spa); spa_remove(spa); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (ENOTSUP); } @@ -6759,7 +6759,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props, spa_unload(spa); spa_deactivate(spa); spa_remove(spa); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (error); } @@ -6912,7 +6912,7 @@ spa_create(const char *pool, nvlist_t *nvroot, nvlist_t *props, spa_import_os(spa); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (0); } @@ -6937,9 +6937,9 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags) /* * If a pool with this name exists, return failure. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if (spa_lookup(pool) != NULL) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (SET_ERROR(EEXIST)); } @@ -6966,7 +6966,7 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags) spa_write_cachefile(spa, B_FALSE, B_TRUE, B_FALSE); spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_IMPORT); zfs_dbgmsg("spa_import: verbatim import of %s", pool); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (0); } @@ -7025,7 +7025,7 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags) spa_unload(spa); spa_deactivate(spa); spa_remove(spa); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (error); } @@ -7093,7 +7093,7 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags) spa_event_notify(spa, NULL, NULL, ESC_ZFS_POOL_IMPORT); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); zvol_create_minors(pool); @@ -7125,7 +7125,7 @@ spa_tryimport(nvlist_t *tryconfig) (void) snprintf(name, MAXPATHLEN, "%s-%llx-%s", TRYIMPORT_NAME, (u_longlong_t)(uintptr_t)curthread, poolname); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa = spa_add(name, tryconfig, NULL); spa_activate(spa, SPA_MODE_READ); kmem_free(name, MAXPATHLEN); @@ -7223,7 +7223,7 @@ spa_tryimport(nvlist_t *tryconfig) spa_unload(spa); spa_deactivate(spa); spa_remove(spa); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (config); } @@ -7251,15 +7251,15 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, if (!(spa_mode_global & SPA_MODE_WRITE)) return (SET_ERROR(EROFS)); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if ((spa = spa_lookup(pool)) == NULL) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (SET_ERROR(ENOENT)); } if (spa->spa_is_exporting) { /* the pool is being exported by another thread */ - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (SET_ERROR(ZFS_ERR_EXPORT_IN_PROGRESS)); } spa->spa_is_exporting = B_TRUE; @@ -7269,18 +7269,18 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, * and see if we can export. */ spa_open_ref(spa, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); spa_async_suspend(spa); if (spa->spa_zvol_taskq) { zvol_remove_minors(spa, spa_name(spa), B_TRUE); taskq_wait(spa->spa_zvol_taskq); } - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa->spa_export_thread = curthread; spa_close(spa, FTAG); if (spa->spa_state == POOL_STATE_UNINITIALIZED) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); goto export_spa; } @@ -7304,7 +7304,7 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, goto fail; } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); /* * At this point we no longer hold the spa_namespace_lock and * there were no references on the spa. Future spa_lookups will @@ -7323,7 +7323,7 @@ spa_export_common(const char *pool, int new_state, nvlist_t **oldconfig, if (!force && new_state == POOL_STATE_EXPORTED && spa_has_active_shared_spare(spa)) { error = SET_ERROR(EXDEV); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); goto fail; } @@ -7398,7 +7398,7 @@ export_spa: /* * Take the namespace lock for the actual spa_t removal */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if (new_state != POOL_STATE_UNINITIALIZED) { if (!hardforce) spa_write_cachefile(spa, B_TRUE, B_TRUE, B_FALSE); @@ -7416,8 +7416,8 @@ export_spa: /* * Wake up any waiters in spa_lookup() */ - cv_broadcast(&spa_namespace_cv); - mutex_exit(&spa_namespace_lock); + spa_namespace_broadcast(); + spa_namespace_exit(FTAG); return (0); fail: @@ -7428,8 +7428,8 @@ fail: /* * Wake up any waiters in spa_lookup() */ - cv_broadcast(&spa_namespace_cv); - mutex_exit(&spa_namespace_lock); + spa_namespace_broadcast(); + spa_namespace_exit(FTAG); return (error); } @@ -7639,10 +7639,10 @@ spa_vdev_add(spa_t *spa, nvlist_t *nvroot, boolean_t check_ashift) */ (void) spa_vdev_exit(spa, vd, txg, 0); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_config_update(spa, SPA_CONFIG_UPDATE_POOL); spa_event_notify(spa, NULL, NULL, ESC_ZFS_VDEV_ADD); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (0); } @@ -7759,7 +7759,7 @@ spa_vdev_attach(spa_t *spa, uint64_t guid, nvlist_t *nvroot, int replacing, oldvd = spa_lookup_by_guid(spa, guid, B_FALSE); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); if (spa_feature_is_active(spa, SPA_FEATURE_POOL_CHECKPOINT)) { error = (spa_has_checkpoint(spa)) ? ZFS_ERR_CHECKPOINT_EXISTS : ZFS_ERR_DISCARDING_CHECKPOINT; @@ -8143,7 +8143,7 @@ spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid, int replace_done) * as spa_vdev_resilver_done() calls this function everything * should be fine as the resilver will return right away. */ - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); if (spa_feature_is_active(spa, SPA_FEATURE_POOL_CHECKPOINT)) { error = (spa_has_checkpoint(spa)) ? ZFS_ERR_CHECKPOINT_EXISTS : ZFS_ERR_DISCARDING_CHECKPOINT; @@ -8347,28 +8347,28 @@ spa_vdev_detach(spa_t *spa, uint64_t guid, uint64_t pguid, int replace_done) if (unspare) { spa_t *altspa = NULL; - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((altspa = spa_next(altspa)) != NULL) { if (altspa->spa_state != POOL_STATE_ACTIVE || altspa == spa) continue; spa_open_ref(altspa, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); (void) spa_vdev_remove(altspa, unspare_guid, B_TRUE); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_close(altspa, FTAG); } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); /* search the rest of the vdevs for spares to remove */ spa_vdev_resilver_done(spa); } /* all done with the spa; OK to release */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_close(spa, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (error); } @@ -8377,7 +8377,7 @@ static int spa_vdev_initialize_impl(spa_t *spa, uint64_t guid, uint64_t cmd_type, list_t *vd_list) { - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER); @@ -8461,7 +8461,7 @@ spa_vdev_initialize(spa_t *spa, nvlist_t *nv, uint64_t cmd_type, * we can properly assess the vdev state before we commit to * the initializing operation. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); for (nvpair_t *pair = nvlist_next_nvpair(nv, NULL); pair != NULL; pair = nvlist_next_nvpair(nv, pair)) { @@ -8484,7 +8484,7 @@ spa_vdev_initialize(spa_t *spa, nvlist_t *nv, uint64_t cmd_type, /* Sync out the initializing state */ txg_wait_synced(spa->spa_dsl_pool, 0); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); list_destroy(&vd_list); @@ -8495,7 +8495,7 @@ static int spa_vdev_trim_impl(spa_t *spa, uint64_t guid, uint64_t cmd_type, uint64_t rate, boolean_t partial, boolean_t secure, list_t *vd_list) { - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); spa_config_enter(spa, SCL_CONFIG | SCL_STATE, FTAG, RW_READER); @@ -8582,7 +8582,7 @@ spa_vdev_trim(spa_t *spa, nvlist_t *nv, uint64_t cmd_type, uint64_t rate, * we can properly assess the vdev state before we commit to * the TRIM operation. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); for (nvpair_t *pair = nvlist_next_nvpair(nv, NULL); pair != NULL; pair = nvlist_next_nvpair(nv, pair)) { @@ -8605,7 +8605,7 @@ spa_vdev_trim(spa_t *spa, nvlist_t *nv, uint64_t cmd_type, uint64_t rate, /* Sync out the TRIM state */ txg_wait_synced(spa->spa_dsl_pool, 0); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); list_destroy(&vd_list); @@ -8633,7 +8633,7 @@ spa_vdev_split_mirror(spa_t *spa, const char *newname, nvlist_t *config, txg = spa_vdev_enter(spa); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); if (spa_feature_is_active(spa, SPA_FEATURE_POOL_CHECKPOINT)) { error = (spa_has_checkpoint(spa)) ? ZFS_ERR_CHECKPOINT_EXISTS : ZFS_ERR_DISCARDING_CHECKPOINT; @@ -9307,7 +9307,7 @@ spa_async_thread(void *arg) if (tasks & SPA_ASYNC_CONFIG_UPDATE) { uint64_t old_space, new_space; - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); old_space = metaslab_class_get_space(spa_normal_class(spa)); old_space += metaslab_class_get_space(spa_special_class(spa)); old_space += metaslab_class_get_space(spa_dedup_class(spa)); @@ -9325,7 +9325,7 @@ spa_async_thread(void *arg) spa_embedded_log_class(spa)); new_space += metaslab_class_get_space( spa_special_embedded_log_class(spa)); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); /* * If the pool grew as a result of the config update, @@ -9394,49 +9394,49 @@ spa_async_thread(void *arg) dsl_scan_restart_resilver(dp, 0); if (tasks & SPA_ASYNC_INITIALIZE_RESTART) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER); vdev_initialize_restart(spa->spa_root_vdev); spa_config_exit(spa, SCL_CONFIG, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } if (tasks & SPA_ASYNC_TRIM_RESTART) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER); vdev_trim_restart(spa->spa_root_vdev); spa_config_exit(spa, SCL_CONFIG, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } if (tasks & SPA_ASYNC_AUTOTRIM_RESTART) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER); vdev_autotrim_restart(spa); spa_config_exit(spa, SCL_CONFIG, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } /* * Kick off L2 cache whole device TRIM. */ if (tasks & SPA_ASYNC_L2CACHE_TRIM) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_config_enter(spa, SCL_CONFIG, FTAG, RW_READER); vdev_trim_l2arc(spa); spa_config_exit(spa, SCL_CONFIG, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } /* * Kick off L2 cache rebuilding. */ if (tasks & SPA_ASYNC_L2CACHE_REBUILD) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_config_enter(spa, SCL_L2ARC, FTAG, RW_READER); l2arc_spa_rebuild_start(spa); spa_config_exit(spa, SCL_L2ARC, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } /* @@ -10588,18 +10588,18 @@ void spa_sync_allpools(void) { spa_t *spa = NULL; - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((spa = spa_next(spa)) != NULL) { if (spa_state(spa) != POOL_STATE_ACTIVE || !spa_writeable(spa) || spa_suspended(spa)) continue; spa_open_ref(spa, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); txg_wait_synced(spa_get_dsl(spa), 0); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_close(spa, FTAG); } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } taskq_t * @@ -10746,7 +10746,7 @@ spa_evict_all(void) * Remove all cached state. All pools should be closed now, * so every spa in the AVL tree should be unreferenced. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((spa = spa_next(NULL)) != NULL) { /* * Stop async tasks. The async thread may need to detach @@ -10754,9 +10754,9 @@ spa_evict_all(void) * spa_namespace_lock, so we must drop it here. */ spa_open_ref(spa, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); spa_async_suspend(spa); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_close(spa, FTAG); if (spa->spa_state != POOL_STATE_UNINITIALIZED) { @@ -10765,7 +10765,7 @@ spa_evict_all(void) } spa_remove(spa); } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } vdev_t * diff --git a/module/zfs/spa_config.c b/module/zfs/spa_config.c index f615591e826b..31216e9a7ccc 100644 --- a/module/zfs/spa_config.c +++ b/module/zfs/spa_config.c @@ -161,7 +161,7 @@ spa_write_cachefile(spa_t *target, boolean_t removing, boolean_t postsysevent, boolean_t ccw_failure; int error = 0; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); if (!(spa_mode_global & SPA_MODE_WRITE)) return; @@ -287,7 +287,7 @@ spa_all_configs(uint64_t *generation, nvlist_t **pools) if (*generation == spa_config_generation) return (SET_ERROR(EEXIST)); - int error = mutex_enter_interruptible(&spa_namespace_lock); + int error = spa_namespace_enter_interruptible(FTAG); if (error) return (SET_ERROR(EINTR)); @@ -302,7 +302,7 @@ spa_all_configs(uint64_t *generation, nvlist_t **pools) } } *generation = spa_config_generation; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (0); } @@ -483,7 +483,7 @@ spa_config_update(spa_t *spa, int what) uint64_t txg; int c; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER); txg = spa_last_synced_txg(spa) + 1; diff --git a/module/zfs/spa_misc.c b/module/zfs/spa_misc.c index 0bead6d49666..bf22d2eb68e7 100644 --- a/module/zfs/spa_misc.c +++ b/module/zfs/spa_misc.c @@ -28,7 +28,7 @@ * Copyright (c) 2017 Datto Inc. * Copyright (c) 2017, Intel Corporation. * Copyright (c) 2019, loli10K . All rights reserved. - * Copyright (c) 2023, 2024, Klara Inc. + * Copyright (c) 2023, 2024, 2025, Klara, Inc. */ #include @@ -237,9 +237,10 @@ * locking is, always, based on spa_namespace_lock and spa_config_lock[]. */ -avl_tree_t spa_namespace_avl; -kmutex_t spa_namespace_lock; -kcondvar_t spa_namespace_cv; +static avl_tree_t spa_namespace_avl; +static kmutex_t spa_namespace_lock; +static kcondvar_t spa_namespace_cv; + static const int spa_max_replication_override = SPA_DVAS_PER_BP; static kmutex_t spa_spare_lock; @@ -608,6 +609,58 @@ spa_config_held(spa_t *spa, int locks, krw_t rw) * ========================================================================== */ +void +spa_namespace_enter(const void *tag) +{ + (void) tag; + ASSERT(!MUTEX_HELD(&spa_namespace_lock)); + mutex_enter(&spa_namespace_lock); +} + +boolean_t +spa_namespace_tryenter(const void *tag) +{ + (void) tag; + ASSERT(!MUTEX_HELD(&spa_namespace_lock)); + return (mutex_tryenter(&spa_namespace_lock)); +} + +int +spa_namespace_enter_interruptible(const void *tag) +{ + (void) tag; + ASSERT(!MUTEX_HELD(&spa_namespace_lock)); + return (mutex_enter_interruptible(&spa_namespace_lock)); +} + +void +spa_namespace_exit(const void *tag) +{ + (void) tag; + ASSERT(MUTEX_HELD(&spa_namespace_lock)); + mutex_exit(&spa_namespace_lock); +} + +boolean_t +spa_namespace_held(void) +{ + return (MUTEX_HELD(&spa_namespace_lock)); +} + +void +spa_namespace_wait(void) +{ + ASSERT(MUTEX_HELD(&spa_namespace_lock)); + cv_wait(&spa_namespace_cv, &spa_namespace_lock); +} + +void +spa_namespace_broadcast(void) +{ + ASSERT(MUTEX_HELD(&spa_namespace_lock)); + cv_broadcast(&spa_namespace_cv); +} + /* * Lookup the named spa_t in the AVL tree. The spa_namespace_lock must be held. * Returns NULL if no matching spa_t is found. @@ -620,7 +673,7 @@ spa_lookup(const char *name) avl_index_t where; char *cp; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); retry: (void) strlcpy(search.spa_name, name, sizeof (search.spa_name)); @@ -645,7 +698,7 @@ retry: spa->spa_load_thread != curthread) || (spa->spa_export_thread != NULL && spa->spa_export_thread != curthread)) { - cv_wait(&spa_namespace_cv, &spa_namespace_lock); + spa_namespace_wait(); goto retry; } @@ -697,7 +750,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot) spa_t *spa; spa_config_dirent_t *dp; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); spa = kmem_zalloc(sizeof (spa_t), KM_SLEEP); @@ -747,7 +800,7 @@ spa_add(const char *name, nvlist_t *config, const char *altroot) spa_config_lock_init(spa); spa_stats_init(spa); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); avl_add(&spa_namespace_avl, spa); /* @@ -837,7 +890,7 @@ spa_remove(spa_t *spa) { spa_config_dirent_t *dp; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); ASSERT(spa_state(spa) == POOL_STATE_UNINITIALIZED); ASSERT3U(zfs_refcount_count(&spa->spa_refcount), ==, 0); ASSERT0(spa->spa_waiters); @@ -916,7 +969,7 @@ spa_remove(spa_t *spa) spa_t * spa_next(spa_t *prev) { - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); if (prev) return (AVL_NEXT(&spa_namespace_avl, prev)); @@ -938,7 +991,7 @@ void spa_open_ref(spa_t *spa, const void *tag) { ASSERT(zfs_refcount_count(&spa->spa_refcount) >= spa->spa_minref || - MUTEX_HELD(&spa_namespace_lock) || + spa_namespace_held() || spa->spa_load_thread == curthread); (void) zfs_refcount_add(&spa->spa_refcount, tag); } @@ -951,7 +1004,7 @@ void spa_close(spa_t *spa, const void *tag) { ASSERT(zfs_refcount_count(&spa->spa_refcount) > spa->spa_minref || - MUTEX_HELD(&spa_namespace_lock) || + spa_namespace_held() || spa->spa_load_thread == curthread || spa->spa_export_thread == curthread); (void) zfs_refcount_remove(&spa->spa_refcount, tag); @@ -980,7 +1033,7 @@ spa_async_close(spa_t *spa, const void *tag) boolean_t spa_refcount_zero(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); return (zfs_refcount_count(&spa->spa_refcount) == spa->spa_minref); @@ -1227,7 +1280,7 @@ uint64_t spa_vdev_enter(spa_t *spa) { mutex_enter(&spa->spa_vdev_top_lock); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); ASSERT0(spa->spa_export_thread); @@ -1246,7 +1299,7 @@ uint64_t spa_vdev_detach_enter(spa_t *spa, uint64_t guid) { mutex_enter(&spa->spa_vdev_top_lock); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); ASSERT0(spa->spa_export_thread); @@ -1270,7 +1323,7 @@ spa_vdev_detach_enter(spa_t *spa, uint64_t guid) uint64_t spa_vdev_config_enter(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); spa_config_enter(spa, SCL_ALL, spa, RW_WRITER); @@ -1285,7 +1338,7 @@ void spa_vdev_config_exit(spa_t *spa, vdev_t *vd, uint64_t txg, int error, const char *tag) { - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); int config_changed = B_FALSE; @@ -1374,7 +1427,7 @@ spa_vdev_exit(spa_t *spa, vdev_t *vd, uint64_t txg, int error) vdev_rebuild_restart(spa); spa_vdev_config_exit(spa, vd, txg, error, FTAG); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); mutex_exit(&spa->spa_vdev_top_lock); return (error); @@ -1452,9 +1505,9 @@ spa_vdev_state_exit(spa_t *spa, vdev_t *vd, int error) * If the config changed, update the config cache. */ if (config_changed) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa_write_cachefile(spa, B_FALSE, B_TRUE, B_FALSE); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } return (error); @@ -1501,7 +1554,7 @@ spa_by_guid(uint64_t pool_guid, uint64_t device_guid) spa_t *spa; avl_tree_t *t = &spa_namespace_avl; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); for (spa = avl_first(t); spa != NULL; spa = AVL_NEXT(t, spa)) { if (spa->spa_state == POOL_STATE_UNINITIALIZED) @@ -1583,7 +1636,7 @@ spa_load_guid_exists(uint64_t guid) { avl_tree_t *t = &spa_namespace_avl; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); for (spa_t *spa = avl_first(t); spa != NULL; spa = AVL_NEXT(t, spa)) { if (spa_load_guid(spa) == guid) @@ -2200,10 +2253,10 @@ spa_set_deadman_ziotime(hrtime_t ns) spa_t *spa = NULL; if (spa_mode_global != SPA_MODE_UNINIT) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((spa = spa_next(spa)) != NULL) spa->spa_deadman_ziotime = ns; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } } @@ -2213,10 +2266,10 @@ spa_set_deadman_synctime(hrtime_t ns) spa_t *spa = NULL; if (spa_mode_global != SPA_MODE_UNINIT) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((spa = spa_next(spa)) != NULL) spa->spa_deadman_synctime = ns; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } } @@ -3048,10 +3101,10 @@ param_set_deadman_failmode_common(const char *val) return (SET_ERROR(EINVAL)); if (spa_mode_global != SPA_MODE_UNINIT) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); while ((spa = spa_next(spa)) != NULL) spa_set_deadman_failmode(spa, val); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } return (0); @@ -3135,7 +3188,6 @@ EXPORT_SYMBOL(spa_has_slogs); EXPORT_SYMBOL(spa_is_root); EXPORT_SYMBOL(spa_writeable); EXPORT_SYMBOL(spa_mode); -EXPORT_SYMBOL(spa_namespace_lock); EXPORT_SYMBOL(spa_trust_config); EXPORT_SYMBOL(spa_missing_tvds_allowed); EXPORT_SYMBOL(spa_set_missing_tvds); diff --git a/module/zfs/vdev_initialize.c b/module/zfs/vdev_initialize.c index 27188c46e561..d13da1e5a663 100644 --- a/module/zfs/vdev_initialize.c +++ b/module/zfs/vdev_initialize.c @@ -685,7 +685,7 @@ vdev_initialize_stop_wait(spa_t *spa, list_t *vd_list) (void) spa; vdev_t *vd; - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); while ((vd = list_remove_head(vd_list)) != NULL) { @@ -728,7 +728,7 @@ vdev_initialize_stop(vdev_t *vd, vdev_initializing_state_t tgt_state, if (vd_list == NULL) { vdev_initialize_stop_wait_impl(vd); } else { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || vd->vdev_spa->spa_export_thread == curthread); list_insert_tail(vd_list, vd); } @@ -761,7 +761,7 @@ vdev_initialize_stop_all(vdev_t *vd, vdev_initializing_state_t tgt_state) spa_t *spa = vd->vdev_spa; list_t vd_list; - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); list_create(&vd_list, sizeof (vdev_t), @@ -781,7 +781,7 @@ vdev_initialize_stop_all(vdev_t *vd, vdev_initializing_state_t tgt_state) void vdev_initialize_restart(vdev_t *vd) { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || vd->vdev_spa->spa_load_thread == curthread); ASSERT(!spa_config_held(vd->vdev_spa, SCL_ALL, RW_WRITER)); diff --git a/module/zfs/vdev_rebuild.c b/module/zfs/vdev_rebuild.c index 47b3b9921abe..30be1f851eb3 100644 --- a/module/zfs/vdev_rebuild.c +++ b/module/zfs/vdev_rebuild.c @@ -1079,7 +1079,7 @@ vdev_rebuild_restart_impl(vdev_t *vd) void vdev_rebuild_restart(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_load_thread == curthread); vdev_rebuild_restart_impl(spa->spa_root_vdev); @@ -1094,7 +1094,7 @@ vdev_rebuild_stop_wait(vdev_t *vd) { spa_t *spa = vd->vdev_spa; - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); if (vd == spa->spa_root_vdev) { diff --git a/module/zfs/vdev_removal.c b/module/zfs/vdev_removal.c index 8ea53e735a9c..89911e55bda8 100644 --- a/module/zfs/vdev_removal.c +++ b/module/zfs/vdev_removal.c @@ -309,12 +309,12 @@ spa_vdev_noalloc(spa_t *spa, uint64_t guid) uint64_t txg; int error = 0; - ASSERT(!MUTEX_HELD(&spa_namespace_lock)); + ASSERT(!spa_namespace_held()); ASSERT(spa_writeable(spa)); txg = spa_vdev_enter(spa); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); vd = spa_lookup_by_guid(spa, guid, B_FALSE); @@ -342,12 +342,12 @@ spa_vdev_alloc(spa_t *spa, uint64_t guid) uint64_t txg; int error = 0; - ASSERT(!MUTEX_HELD(&spa_namespace_lock)); + ASSERT(!spa_namespace_held()); ASSERT(spa_writeable(spa)); txg = spa_vdev_enter(spa); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); vd = spa_lookup_by_guid(spa, guid, B_FALSE); @@ -2085,7 +2085,7 @@ vdev_remove_make_hole_and_free(vdev_t *vd) spa_t *spa = vd->vdev_spa; vdev_t *rvd = spa->spa_root_vdev; - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL); vdev_free(vd); @@ -2113,7 +2113,7 @@ spa_vdev_remove_log(vdev_t *vd, uint64_t *txg) ASSERT(vd->vdev_islog); ASSERT(vd == vd->vdev_top); ASSERT0P(vd->vdev_log_mg); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); /* * Stop allocating from this vdev. @@ -2140,7 +2140,7 @@ spa_vdev_remove_log(vdev_t *vd, uint64_t *txg) * spa_namespace_lock held. Once this completes the device * should no longer have any blocks allocated on it. */ - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); if (vd->vdev_stat.vs_alloc != 0) error = spa_reset_logs(spa); @@ -2189,7 +2189,7 @@ spa_vdev_remove_log(vdev_t *vd, uint64_t *txg) sysevent_t *ev = spa_event_create(spa, vd, NULL, ESC_ZFS_VDEV_REMOVE_DEV); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL); /* The top ZAP should have been destroyed by vdev_remove_empty. */ @@ -2433,7 +2433,7 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare) uint64_t txg = 0; uint_t nspares, nl2cache; int error = 0, error_log; - boolean_t locked = MUTEX_HELD(&spa_namespace_lock); + boolean_t locked = spa_namespace_held(); sysevent_t *ev = NULL; const char *vd_type = NULL; char *vd_path = NULL; @@ -2443,7 +2443,7 @@ spa_vdev_remove(spa_t *spa, uint64_t guid, boolean_t unspare) if (!locked) txg = spa_vdev_enter(spa); - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); if (spa_feature_is_active(spa, SPA_FEATURE_POOL_CHECKPOINT)) { error = (spa_has_checkpoint(spa)) ? ZFS_ERR_CHECKPOINT_EXISTS : ZFS_ERR_DISCARDING_CHECKPOINT; diff --git a/module/zfs/vdev_trim.c b/module/zfs/vdev_trim.c index eee18b367909..a97f6650a81c 100644 --- a/module/zfs/vdev_trim.c +++ b/module/zfs/vdev_trim.c @@ -1045,7 +1045,7 @@ vdev_trim_stop_wait(spa_t *spa, list_t *vd_list) (void) spa; vdev_t *vd; - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); while ((vd = list_remove_head(vd_list)) != NULL) { @@ -1085,7 +1085,7 @@ vdev_trim_stop(vdev_t *vd, vdev_trim_state_t tgt_state, list_t *vd_list) if (vd_list == NULL) { vdev_trim_stop_wait_impl(vd); } else { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || vd->vdev_spa->spa_export_thread == curthread); list_insert_tail(vd_list, vd); } @@ -1122,7 +1122,7 @@ vdev_trim_stop_all(vdev_t *vd, vdev_trim_state_t tgt_state) list_t vd_list; vdev_t *vd_l2cache; - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_export_thread == curthread); list_create(&vd_list, sizeof (vdev_t), @@ -1156,7 +1156,7 @@ vdev_trim_stop_all(vdev_t *vd, vdev_trim_state_t tgt_state) void vdev_trim_restart(vdev_t *vd) { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || vd->vdev_spa->spa_load_thread == curthread); ASSERT(!spa_config_held(vd->vdev_spa, SCL_ALL, RW_WRITER)); @@ -1582,7 +1582,7 @@ vdev_autotrim_stop_all(spa_t *spa) void vdev_autotrim_restart(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock) || + ASSERT(spa_namespace_held() || spa->spa_load_thread == curthread); if (spa->spa_autotrim) vdev_autotrim(spa); @@ -1689,7 +1689,7 @@ vdev_trim_l2arc_thread(void *arg) void vdev_trim_l2arc(spa_t *spa) { - ASSERT(MUTEX_HELD(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); /* * Locate the spa's l2arc devices and kick off TRIM threads. diff --git a/module/zfs/zfs_fm.c b/module/zfs/zfs_fm.c index 221f24e381dc..96c722731aea 100644 --- a/module/zfs/zfs_fm.c +++ b/module/zfs/zfs_fm.c @@ -1580,10 +1580,10 @@ zfs_ereport_zvol_post(const char *subclass, const char *name, nvlist_t *aux; char *r; - boolean_t locked = mutex_owned(&spa_namespace_lock); - if (!locked) mutex_enter(&spa_namespace_lock); + boolean_t locked = spa_namespace_held(); + if (!locked) spa_namespace_enter(FTAG); spa_t *spa = spa_lookup(name); - if (!locked) mutex_exit(&spa_namespace_lock); + if (!locked) spa_namespace_exit(FTAG); if (spa == NULL) return; diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 5ca7c2320c4e..0ec6e1e23f5c 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -3122,12 +3122,12 @@ zfs_ioc_pool_set_props(zfs_cmd_t *zc) if (pair != NULL && strcmp(nvpair_name(pair), zpool_prop_to_name(ZPOOL_PROP_CACHEFILE)) == 0 && nvlist_next_nvpair(props, pair) == NULL) { - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if ((spa = spa_lookup(zc->zc_name)) != NULL) { spa_configfile_set(spa, props, B_FALSE); spa_write_cachefile(spa, B_FALSE, B_TRUE, B_FALSE); } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); if (spa != NULL) { nvlist_free(props); return (0); @@ -3176,14 +3176,14 @@ zfs_ioc_pool_get_props(const char *pool, nvlist_t *innvl, nvlist_t *outnvl) * get (such as altroot and cachefile), so attempt to get them * anyway. */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); if ((spa = spa_lookup(pool)) != NULL) { error = spa_prop_get(spa, outnvl); if (error == 0 && props != NULL) error = spa_prop_get_nvlist(spa, props, n_props, outnvl); } - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); } else { error = spa_prop_get(spa, outnvl); if (error == 0 && props != NULL) @@ -6121,10 +6121,10 @@ zfs_ioc_clear(zfs_cmd_t *zc) /* * On zpool clear we also fix up missing slogs */ - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); spa = spa_lookup(zc->zc_name); if (spa == NULL) { - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (SET_ERROR(EIO)); } if (spa_get_log_state(spa) == SPA_LOG_MISSING) { @@ -6132,7 +6132,7 @@ zfs_ioc_clear(zfs_cmd_t *zc) spa_set_log_state(spa, SPA_LOG_CLEAR); } spa->spa_last_open_failed = 0; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); if (zc->zc_cookie & ZPOOL_NO_REWIND) { error = spa_open(zc->zc_name, &spa, FTAG); diff --git a/module/zfs/zio_inject.c b/module/zfs/zio_inject.c index 287577018ed1..c3adfdab54ce 100644 --- a/module/zfs/zio_inject.c +++ b/module/zfs/zio_inject.c @@ -1008,9 +1008,9 @@ zio_inject_fault(char *name, int flags, int *id, zinject_record_t *record) if (zio_pool_handler_exists(name, record->zi_cmd)) return (SET_ERROR(EEXIST)); - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); boolean_t has_spa = spa_lookup(name) != NULL; - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); if (record->zi_cmd == ZINJECT_DELAY_IMPORT && has_spa) return (SET_ERROR(EEXIST)); @@ -1095,7 +1095,7 @@ zio_inject_list_next(int *id, char *name, size_t buflen, inject_handler_t *handler; int ret; - mutex_enter(&spa_namespace_lock); + spa_namespace_enter(FTAG); rw_enter(&inject_lock, RW_READER); for (handler = list_head(&inject_handlers); handler != NULL; @@ -1117,7 +1117,7 @@ zio_inject_list_next(int *id, char *name, size_t buflen, } rw_exit(&inject_lock); - mutex_exit(&spa_namespace_lock); + spa_namespace_exit(FTAG); return (ret); } diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 63fd2335ad78..407758641580 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -1233,7 +1233,7 @@ zvol_first_open(zvol_state_t *zv, boolean_t readonly) ASSERT(RW_READ_HELD(&zv->zv_suspend_lock)); ASSERT(MUTEX_HELD(&zv->zv_state_lock)); - ASSERT(mutex_owned(&spa_namespace_lock)); + ASSERT(spa_namespace_held()); boolean_t ro = (readonly || (strchr(zv->zv_name, '@') != NULL)); error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, ro, B_TRUE, zv, &os); @@ -1303,7 +1303,7 @@ zvol_create_snap_minor_cb(const char *dsname, void *arg) list_t *minors_list = j->list; const char *name = j->name; - ASSERT0(MUTEX_HELD(&spa_namespace_lock)); + ASSERT0(spa_namespace_held()); /* skip the designated dataset */ if (name && strcmp(dsname, name) == 0) @@ -1403,7 +1403,7 @@ zvol_create_minors_cb(const char *dsname, void *arg) int error; list_t *minors_list = arg; - ASSERT0(MUTEX_HELD(&spa_namespace_lock)); + ASSERT0(spa_namespace_held()); error = dsl_prop_get_integer(dsname, "snapdev", &snapdev, NULL); if (error) From 72b2a9571ac3d8e18c10baaf0370803a7abe1696 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 10 Nov 2025 17:26:15 -0500 Subject: [PATCH 25/91] ZAP: Remove dmu_object_info_from_dnode() call dmu_object_info_from_dnode() takes two locks and copies plenty of data that we don't need in zap_lockdir_impl(). Just read dn_type directly in this hot path. Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Motin Closes #17921 --- module/zfs/zap_micro.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/module/zfs/zap_micro.c b/module/zfs/zap_micro.c index ea4e3117a8b9..7e9e625a193e 100644 --- a/module/zfs/zap_micro.c +++ b/module/zfs/zap_micro.c @@ -625,12 +625,10 @@ zap_lockdir_impl(dnode_t *dn, dmu_buf_t *db, const void *tag, dmu_tx_t *tx, ASSERT0(db->db_offset); objset_t *os = dmu_buf_get_objset(db); uint64_t obj = db->db_object; - dmu_object_info_t doi; *zapp = NULL; - dmu_object_info_from_dnode(dn, &doi); - if (DMU_OT_BYTESWAP(doi.doi_type) != DMU_BSWAP_ZAP) + if (DMU_OT_BYTESWAP(dn->dn_type) != DMU_BSWAP_ZAP) return (SET_ERROR(EINVAL)); zap_t *zap = dmu_buf_get_user(db); From cc5cae5475e190e5f6cb0d8f81b5d047ae0704fb Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 10 Nov 2025 18:44:46 -0500 Subject: [PATCH 26/91] BRT: Increase block size from 4KB to 8KB According to my observations, BRT ZAPs are typically compressible 3:1 for data and 2:1 for indirects. With ashift=12, typical these days, it means increasing the block sizes to 8KB we may get most of possible compression, reducing on-disk and in-ARC BRT footprint in half by the cost of some compression/decompression overhead, but without real write inflation, only some dirty data increase. Increase to 32KB similar to DDT could further increase compression and storage efficiency, but at the cost of write inflation and much bigger dirty data increase, which we can not properly control now. So lets leave this for a time when BRT log gets implemented. Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Motin Closes #17916 --- man/man4/zfs.4 | 4 ++-- module/zfs/brt.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/man4/zfs.4 b/man/man4/zfs.4 index b01d9a8e57e5..60ec56b4d1f6 100644 --- a/man/man4/zfs.4 +++ b/man/man4/zfs.4 @@ -273,12 +273,12 @@ force this many of them to be gang blocks. .It Sy brt_zap_prefetch Ns = Ns Sy 1 Ns | Ns 0 Pq int Controls prefetching BRT records for blocks which are going to be cloned. . -.It Sy brt_zap_default_bs Ns = Ns Sy 12 Po 4 KiB Pc Pq int +.It Sy brt_zap_default_bs Ns = Ns Sy 13 Po 8 KiB Pc Pq int Default BRT ZAP data block size as a power of 2. Note that changing this after creating a BRT on the pool will not affect existing BRTs, only newly created ones. . -.It Sy brt_zap_default_ibs Ns = Ns Sy 12 Po 4 KiB Pc Pq int +.It Sy brt_zap_default_ibs Ns = Ns Sy 13 Po 8 KiB Pc Pq int Default BRT ZAP indirect block size as a power of 2. Note that changing this after creating a BRT on the pool will not affect existing BRTs, only newly created ones. diff --git a/module/zfs/brt.c b/module/zfs/brt.c index 9e389c8727b9..60f42116cfb8 100644 --- a/module/zfs/brt.c +++ b/module/zfs/brt.c @@ -260,8 +260,8 @@ static int brt_zap_prefetch = 1; #define BRT_DEBUG(...) do { } while (0) #endif -static int brt_zap_default_bs = 12; -static int brt_zap_default_ibs = 12; +static int brt_zap_default_bs = 13; +static int brt_zap_default_ibs = 13; static kstat_t *brt_ksp; From b4f073b5a67be56f89910e0ba5c8c7ffd6928588 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Mon, 10 Nov 2025 19:16:22 -0500 Subject: [PATCH 27/91] Add BRT support to zpool prefetch command Implement BRT (Block Reference Table) prefetch functionality similar to existing DDT prefetch. This allows preloading BRT metadata into ARC to improve performance for block cloning operations and frees of earlier cloned blocks. Make -t parameter optional. When omitted, prefetch all supported metadata types (both DDT and BRT now). Reviewed-by: Brian Behlendorf Signed-off-by: Alexander Motin Closes #17890 --- cmd/zpool/zpool_main.c | 34 ++++--- include/sys/brt.h | 1 + include/sys/fs/zfs.h | 3 +- lib/libzfs/libzfs_pool.c | 8 +- man/man8/zpool-prefetch.8 | 27 +++--- module/zfs/brt.c | 25 +++++ module/zfs/dmu.c | 5 +- module/zfs/zfs_ioctl.c | 27 ++++-- tests/runfiles/common.run | 2 +- tests/zfs-tests/tests/Makefile.am | 1 + .../zpool_prefetch/zpool_prefetch_001_pos.ksh | 12 ++- .../zpool_prefetch/zpool_prefetch_002_pos.ksh | 95 +++++++++++++++++++ 12 files changed, 198 insertions(+), 42 deletions(-) create mode 100755 tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_002_pos.ksh diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index a6658a9c2800..04908f14795c 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -494,8 +494,7 @@ get_usage(zpool_help_t idx) "[--json-int, --json-pool-key-guid]] ...\n" "\t [-T d|u] [pool] [interval [count]]\n")); case HELP_PREFETCH: - return (gettext("\tprefetch -t [] \n" - "\t -t ddt \n")); + return (gettext("\tprefetch [-t ] \n")); case HELP_OFFLINE: return (gettext("\toffline [--power]|[[-f][-t]] " " ...\n")); @@ -4200,7 +4199,7 @@ zpool_do_checkpoint(int argc, char **argv) #define CHECKPOINT_OPT 1024 /* - * zpool prefetch [] + * zpool prefetch [-t ] * * Prefetchs a particular type of data in the specified pool. */ @@ -4245,20 +4244,27 @@ zpool_do_prefetch(int argc, char **argv) poolname = argv[0]; - argc--; - argv++; - - if (strcmp(typestr, "ddt") == 0) { - type = ZPOOL_PREFETCH_DDT; - } else { - (void) fprintf(stderr, gettext("unsupported prefetch type\n")); - usage(B_FALSE); - } - if ((zhp = zpool_open(g_zfs, poolname)) == NULL) return (1); - err = zpool_prefetch(zhp, type); + if (typestr == NULL) { + /* Prefetch all types */ + err = zpool_prefetch(zhp, ZPOOL_PREFETCH_DDT); + if (err == 0) + err = zpool_prefetch(zhp, ZPOOL_PREFETCH_BRT); + } else { + if (strcmp(typestr, "ddt") == 0) { + type = ZPOOL_PREFETCH_DDT; + } else if (strcmp(typestr, "brt") == 0) { + type = ZPOOL_PREFETCH_BRT; + } else { + (void) fprintf(stderr, + gettext("unsupported prefetch type\n")); + zpool_close(zhp); + usage(B_FALSE); + } + err = zpool_prefetch(zhp, type); + } zpool_close(zhp); diff --git a/include/sys/brt.h b/include/sys/brt.h index d7c1814b084f..2a23a6a7f75d 100644 --- a/include/sys/brt.h +++ b/include/sys/brt.h @@ -56,6 +56,7 @@ extern void brt_create(spa_t *spa); extern int brt_load(spa_t *spa); extern void brt_unload(spa_t *spa); extern void brt_sync(spa_t *spa, uint64_t txg); +extern void brt_prefetch_all(spa_t *spa); #ifdef __cplusplus } diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index 662fd81c5ee1..aa7421261786 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -1713,7 +1713,8 @@ typedef enum { typedef enum { ZPOOL_PREFETCH_NONE = 0, - ZPOOL_PREFETCH_DDT + ZPOOL_PREFETCH_DDT, + ZPOOL_PREFETCH_BRT } zpool_prefetch_type_t; typedef enum { diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index ce154ae1a4cd..756d701e2d97 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -1745,9 +1745,13 @@ zpool_prefetch(zpool_handle_t *zhp, zpool_prefetch_type_t type) error = lzc_pool_prefetch(zhp->zpool_name, type); if (error != 0) { + const char *typename = "unknown"; + if (type == ZPOOL_PREFETCH_DDT) + typename = "ddt"; + else if (type == ZPOOL_PREFETCH_BRT) + typename = "brt"; (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, - "cannot prefetch %s in '%s'"), - type == ZPOOL_PREFETCH_DDT ? "ddt" : "", zhp->zpool_name); + "cannot prefetch %s in '%s'"), typename, zhp->zpool_name); (void) zpool_standard_error(hdl, error, msg); return (-1); } diff --git a/man/man8/zpool-prefetch.8 b/man/man8/zpool-prefetch.8 index a36ad52e681e..6f4c3b129040 100644 --- a/man/man8/zpool-prefetch.8 +++ b/man/man8/zpool-prefetch.8 @@ -28,20 +28,25 @@ . .Sh NAME .Nm zpool-prefetch -.Nd Loads specific types of data for the given pool +.Nd Prefetches pool metadata into ARC .Sh SYNOPSIS .Nm zpool .Cm prefetch -.Fl t Ar type +.Op Fl t Ar type .Ar pool .Sh DESCRIPTION -.Bl -tag -width Ds -.It Xo -.Nm zpool -.Cm prefetch -.Fl t Li ddt -.Ar pool -.Xc -Prefetch data of a specific type for the given pool; specifically the DDT, -which will improve write I/O performance when the DDT is resident in the ARC. +Massively prefetch metadata of a specific type for the given pool into the ARC +to reduce latency of some operations later. +If no type is specified, all types are prefetched. +.Pp +The following types are supported: +.Bl -tag -width "brt" +.It Sy brt +Prefetch the BRT (block reference table). +This may improve performance for block cloning operations, +and frees for earlier cloned blocks. +.It Sy ddt +Prefetch the DDT (deduplication table). +This may improve performance of writes when deduplication is enabled, +and frees for earlier deduplicated blocks. .El diff --git a/module/zfs/brt.c b/module/zfs/brt.c index 60f42116cfb8..08a6bd52ab31 100644 --- a/module/zfs/brt.c +++ b/module/zfs/brt.c @@ -1510,6 +1510,31 @@ brt_load(spa_t *spa) return (error); } +void +brt_prefetch_all(spa_t *spa) +{ + /* + * Load all BRT entries for each vdev. This is intended to perform + * a prefetch on all such blocks. For the same reason that brt_prefetch + * (called from brt_pending_add) isn't locked, this is also not locked. + */ + brt_rlock(spa); + for (uint64_t vdevid = 0; vdevid < spa->spa_brt_nvdevs; vdevid++) { + brt_vdev_t *brtvd = spa->spa_brt_vdevs[vdevid]; + brt_unlock(spa); + + rw_enter(&brtvd->bv_mos_entries_lock, RW_READER); + if (brtvd->bv_mos_entries != 0) { + (void) zap_prefetch_object(spa->spa_meta_objset, + brtvd->bv_mos_entries); + } + rw_exit(&brtvd->bv_mos_entries_lock); + + brt_rlock(spa); + } + brt_unlock(spa); +} + void brt_unload(spa_t *spa) { diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 249f878a1e22..5690f8afad00 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -850,12 +850,15 @@ dmu_prefetch_wait(objset_t *os, uint64_t object, uint64_t offset, uint64_t size) return (err); /* - * Chunk the requests (16 indirects worth) so that we can be interrupted + * Chunk the requests (16 indirects worth) so that we can be + * interrupted. Prefetch at least SPA_MAXBLOCKSIZE at a time + * to better utilize pools with smaller block sizes. */ uint64_t chunksize; if (dn->dn_indblkshift) { uint64_t nbps = bp_span_in_blocks(dn->dn_indblkshift, 1); chunksize = (nbps * 16) << dn->dn_datablkshift; + chunksize = MAX(chunksize, SPA_MAXBLOCKSIZE); } else { chunksize = dn->dn_datablksz; } diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c index 0ec6e1e23f5c..1b2392aeaa85 100644 --- a/module/zfs/zfs_ioctl.c +++ b/module/zfs/zfs_ioctl.c @@ -212,6 +212,8 @@ #include #include #include +#include +#include #include "zfs_namecheck.h" #include "zfs_prop.h" @@ -4276,13 +4278,11 @@ zfs_ioc_pool_prefetch(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) spa_t *spa; int32_t type; - /* - * Currently, only ZPOOL_PREFETCH_DDT is supported - */ - if (nvlist_lookup_int32(innvl, ZPOOL_PREFETCH_TYPE, &type) != 0 || - type != ZPOOL_PREFETCH_DDT) { + if (nvlist_lookup_int32(innvl, ZPOOL_PREFETCH_TYPE, &type) != 0) + return (EINVAL); + + if (type != ZPOOL_PREFETCH_DDT && type != ZPOOL_PREFETCH_BRT) return (EINVAL); - } error = spa_open(poolname, &spa, FTAG); if (error != 0) @@ -4290,10 +4290,17 @@ zfs_ioc_pool_prefetch(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl) hrtime_t start_time = gethrtime(); - ddt_prefetch_all(spa); - - zfs_dbgmsg("pool '%s': loaded ddt into ARC in %llu ms", spa->spa_name, - (u_longlong_t)NSEC2MSEC(gethrtime() - start_time)); + if (type == ZPOOL_PREFETCH_DDT) { + ddt_prefetch_all(spa); + zfs_dbgmsg("pool '%s': loaded ddt into ARC in %llu ms", + spa->spa_name, + (u_longlong_t)NSEC2MSEC(gethrtime() - start_time)); + } else { + brt_prefetch_all(spa); + zfs_dbgmsg("pool '%s': loaded brt into ARC in %llu ms", + spa->spa_name, + (u_longlong_t)NSEC2MSEC(gethrtime() - start_time)); + } spa_close(spa, FTAG); diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 9f531411fbe1..a69c6e3c8dd7 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -215,7 +215,7 @@ tests = ['zfs_create_001_pos', 'zfs_create_002_pos', 'zfs_create_003_pos', tags = ['functional', 'cli_root', 'zfs_create'] [tests/functional/cli_root/zpool_prefetch] -tests = ['zpool_prefetch_001_pos'] +tests = ['zpool_prefetch_001_pos', 'zpool_prefetch_002_pos'] tags = ['functional', 'cli_root', 'zpool_prefetch'] [tests/functional/cli_root/zfs_destroy] diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 678c01b58f94..23284234cdf7 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -1217,6 +1217,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/cli_root/zpool_prefetch/cleanup.ksh \ functional/cli_root/zpool_prefetch/setup.ksh \ functional/cli_root/zpool_prefetch/zpool_prefetch_001_pos.ksh \ + functional/cli_root/zpool_prefetch/zpool_prefetch_002_pos.ksh \ functional/cli_root/zpool_reguid/cleanup.ksh \ functional/cli_root/zpool_reguid/setup.ksh \ functional/cli_root/zpool_reguid/zpool_reguid_001_pos.ksh \ diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_001_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_001_pos.ksh index 8ef3a66ad0d9..fd446e46e96c 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_001_pos.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_001_pos.ksh @@ -42,6 +42,15 @@ verify_runnable "both" log_assert "'zpool prefetch -t ddt ' can successfully load the DDT for a pool." +DATASET=$TESTPOOL/ddt + +function cleanup +{ + datasetexists $DATASET && destroy_dataset $DATASET -f +} + +log_onexit cleanup + function getddtstats { typeset -n gds=$1 @@ -75,9 +84,8 @@ log_must zpool prefetch -t ddt $TESTPOOL # Build up the deduplicated dataset. This consists of creating enough files # to generate a reasonable size DDT for testing purposes. -DATASET=$TESTPOOL/ddt log_must zfs create -o compression=off -o dedup=on $DATASET -MNTPOINT=$(get_prop mountpoint $TESTPOOL/ddt) +MNTPOINT=$(get_prop mountpoint $DATASET) log_note "Generating dataset ..." typeset -i i=0 diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_002_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_002_pos.ksh new file mode 100755 index 000000000000..f34f8c36e592 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_prefetch/zpool_prefetch_002_pos.ksh @@ -0,0 +1,95 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright (c) 2025 by iXsystems, Inc. +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# 'zpool prefetch -t brt ' can successfully load a pool's BRT on demand. +# 'zpool prefetch ' without -t prefetches both DDT and BRT. +# +# STRATEGY: +# 1. Create a dataset with block cloning enabled. +# 2. Create files and clone them to populate the BRT. +# 3. Export and import the pool to flush caches. +# 4. Use zpool prefetch -t brt to load BRT. +# 5. Test zpool prefetch without -t to prefetch all types. +# + +verify_runnable "both" + +if ! command -v clonefile > /dev/null ; then + log_unsupported "clonefile program required to test block cloning" +fi + +log_assert "'zpool prefetch' can successfully load BRT and prefetch all types" + +DATASET=$TESTPOOL/brt + +function cleanup +{ + datasetexists $DATASET && destroy_dataset $DATASET -f +} + +log_onexit cleanup +log_must zfs create $DATASET +MNTPOINT=$(get_prop mountpoint $DATASET) + +log_note "Generating cloned blocks for BRT ..." + +# Create source file +log_must dd if=/dev/urandom of=$MNTPOINT/source bs=1M count=100 + +# Create clones using clonefile +typeset -i i=0 +while (( i < 50 )); do + log_must clonefile -f $MNTPOINT/source $MNTPOINT/clone.$i + ((i += 1)) +done + +sync_pool $TESTPOOL + +# Verify BRT has entries (non-zero saved space) +brt_saved=$(zpool get -Hp -o value bclone_saved $TESTPOOL) +log_note "BRT saved space: $brt_saved" +log_must test "$brt_saved" -gt "0" + +# Export/import to flush caches +log_must zpool export $TESTPOOL +log_must zpool import $TESTPOOL + +# Test BRT prefetch - verify command succeeds +# Note: BRT does not expose cache statistics like DDT, so we can only +# verify the prefetch command completes successfully +log_must zpool prefetch -t brt $TESTPOOL + +# Test prefetch without -t (should prefetch all types including BRT) +log_must zpool export $TESTPOOL +log_must zpool import $TESTPOOL +log_must zpool prefetch $TESTPOOL + +log_pass "'zpool prefetch' successfully loads BRT and all types" From 02fdd26e51fae981282e6a610086e134d2fe2950 Mon Sep 17 00:00:00 2001 From: Mariusz Zaborski Date: Tue, 11 Nov 2025 19:42:17 +0100 Subject: [PATCH 28/91] Add knob to disable slow io notifications Introduce a new vdev property `VDEV_PROP_SLOW_IO_REPORTING` that allows users to disable notifications for slow devices. This prevents ZED and/or ZFSD from degrading the pool due to slow I/O. Reviewed-by: Alexander Motin Reviewed-by: Tony Hutter Reviewed-by: Brian Behlendorf Signed-off-by: Mariusz Zaborski Closes 17477 --- include/sys/fs/zfs.h | 1 + include/sys/vdev_impl.h | 1 + lib/libzfs/libzfs.abi | 3 +- man/man7/vdevprops.7 | 8 +- module/zcommon/zpool_prop.c | 3 + module/zfs/vdev.c | 86 +++++++++++++------ module/zfs/zfs_fm.c | 3 + module/zfs/zio.c | 9 +- .../cli_root/zpool_get/vdev_get.cfg | 1 + .../tests/functional/events/zed_slow_io.ksh | 44 +++++++++- 10 files changed, 127 insertions(+), 32 deletions(-) diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index aa7421261786..830c8455bb1a 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -387,6 +387,7 @@ typedef enum { VDEV_PROP_SLOW_IOS, VDEV_PROP_SIT_OUT, VDEV_PROP_AUTOSIT, + VDEV_PROP_SLOW_IO_EVENTS, VDEV_NUM_PROPS } vdev_prop_t; diff --git a/include/sys/vdev_impl.h b/include/sys/vdev_impl.h index 5a8c2f846be2..afaa401343d9 100644 --- a/include/sys/vdev_impl.h +++ b/include/sys/vdev_impl.h @@ -470,6 +470,7 @@ struct vdev { uint64_t vdev_checksum_t; uint64_t vdev_io_n; uint64_t vdev_io_t; + boolean_t vdev_slow_io_events; uint64_t vdev_slow_io_n; uint64_t vdev_slow_io_t; }; diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index f988d27a286a..232265237f54 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -6026,7 +6026,8 @@ - + + diff --git a/man/man7/vdevprops.7 b/man/man7/vdevprops.7 index 0fb28d7db13c..b54abcd3ecc9 100644 --- a/man/man7/vdevprops.7 +++ b/man/man7/vdevprops.7 @@ -45,7 +45,7 @@ section, below. Every vdev has a set of properties that export statistics about the vdev as well as control various behaviors. Properties are not inherited from top-level vdevs, with the exception of -checksum_n, checksum_t, io_n, io_t, slow_io_n, and slow_io_t. +checksum_n, checksum_t, io_n, io_t, slow_io_events, slow_io_n, and slow_io_t. .Pp The values of numeric properties can be specified using human-readable suffixes .Po for example, @@ -149,6 +149,12 @@ For .Sy OpenZFS on FreeBSD defaults see .Xr zfsd 8 . +The +.It Sy slow_io_events +property controls whether slow I/O events are generated. +Even when disabled, slow I/Os will be included in the +.Nm zpool Cm status Fl s +output. .It Sy comment A text comment up to 8192 characters long .It Sy bootsize diff --git a/module/zcommon/zpool_prop.c b/module/zcommon/zpool_prop.c index 07819ba2be8b..4826237b23e8 100644 --- a/module/zcommon/zpool_prop.c +++ b/module/zcommon/zpool_prop.c @@ -481,6 +481,9 @@ vdev_prop_init(void) zprop_register_index(VDEV_PROP_FAILFAST, "failfast", B_TRUE, PROP_DEFAULT, ZFS_TYPE_VDEV, "on | off", "FAILFAST", boolean_table, sfeatures); + zprop_register_index(VDEV_PROP_SLOW_IO_EVENTS, "slow_io_events", + B_TRUE, PROP_DEFAULT, ZFS_TYPE_VDEV, "on | off", + "SLOW_IO_EVENTS", boolean_table, sfeatures); /* hidden properties */ zprop_register_hidden(VDEV_PROP_NAME, "name", PROP_TYPE_STRING, diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 654e034de9e1..2754769eb759 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -448,6 +448,23 @@ vdev_get_nparity(vdev_t *vd) return (nparity); } +static int +vdev_prop_get_objid(vdev_t *vd, uint64_t *objid) +{ + + if (vd->vdev_root_zap != 0) { + *objid = vd->vdev_root_zap; + } else if (vd->vdev_top_zap != 0) { + *objid = vd->vdev_top_zap; + } else if (vd->vdev_leaf_zap != 0) { + *objid = vd->vdev_leaf_zap; + } else { + return (EINVAL); + } + + return (0); +} + static int vdev_prop_get_int(vdev_t *vd, vdev_prop_t prop, uint64_t *value) { @@ -456,25 +473,29 @@ vdev_prop_get_int(vdev_t *vd, vdev_prop_t prop, uint64_t *value) uint64_t objid; int err; - if (vd->vdev_root_zap != 0) { - objid = vd->vdev_root_zap; - } else if (vd->vdev_top_zap != 0) { - objid = vd->vdev_top_zap; - } else if (vd->vdev_leaf_zap != 0) { - objid = vd->vdev_leaf_zap; - } else { + if (vdev_prop_get_objid(vd, &objid) != 0) return (EINVAL); - } err = zap_lookup(mos, objid, vdev_prop_to_name(prop), sizeof (uint64_t), 1, value); - if (err == ENOENT) *value = vdev_prop_default_numeric(prop); return (err); } +static int +vdev_prop_get_bool(vdev_t *vd, vdev_prop_t prop, boolean_t *bvalue) +{ + int err; + uint64_t ivalue; + + err = vdev_prop_get_int(vd, prop, &ivalue); + *bvalue = ivalue != 0; + + return (err); +} + /* * Get the number of data disks for a top-level vdev. */ @@ -737,8 +758,12 @@ vdev_alloc_common(spa_t *spa, uint_t id, uint64_t guid, vdev_ops_t *ops) */ vd->vdev_checksum_n = vdev_prop_default_numeric(VDEV_PROP_CHECKSUM_N); vd->vdev_checksum_t = vdev_prop_default_numeric(VDEV_PROP_CHECKSUM_T); + vd->vdev_io_n = vdev_prop_default_numeric(VDEV_PROP_IO_N); vd->vdev_io_t = vdev_prop_default_numeric(VDEV_PROP_IO_T); + + vd->vdev_slow_io_events = vdev_prop_default_numeric( + VDEV_PROP_SLOW_IO_EVENTS); vd->vdev_slow_io_n = vdev_prop_default_numeric(VDEV_PROP_SLOW_IO_N); vd->vdev_slow_io_t = vdev_prop_default_numeric(VDEV_PROP_SLOW_IO_T); @@ -3931,6 +3956,11 @@ vdev_load(vdev_t *vd) vdev_dbgmsg(vd, "vdev_load: zap_lookup(zap=%llu) " "failed [error=%d]", (u_longlong_t)zapobj, error); + error = vdev_prop_get_bool(vd, VDEV_PROP_SLOW_IO_EVENTS, + &vd->vdev_slow_io_events); + if (error && error != ENOENT) + vdev_dbgmsg(vd, "vdev_load: zap_lookup(zap=%llu) " + "failed [error=%d]", (u_longlong_t)zapobj, error); error = vdev_prop_get_int(vd, VDEV_PROP_SLOW_IO_N, &vd->vdev_slow_io_n); if (error && error != ENOENT) @@ -5980,15 +6010,8 @@ vdev_props_set_sync(void *arg, dmu_tx_t *tx) /* * Set vdev property values in the vdev props mos object. */ - if (vd->vdev_root_zap != 0) { - objid = vd->vdev_root_zap; - } else if (vd->vdev_top_zap != 0) { - objid = vd->vdev_top_zap; - } else if (vd->vdev_leaf_zap != 0) { - objid = vd->vdev_leaf_zap; - } else { + if (vdev_prop_get_objid(vd, &objid) != 0) panic("unexpected vdev type"); - } mutex_enter(&spa->spa_props_lock); @@ -6215,6 +6238,13 @@ vdev_prop_set(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) } vd->vdev_io_t = intval; break; + case VDEV_PROP_SLOW_IO_EVENTS: + if (nvpair_value_uint64(elem, &intval) != 0) { + error = EINVAL; + break; + } + vd->vdev_slow_io_events = intval != 0; + break; case VDEV_PROP_SLOW_IO_N: if (nvpair_value_uint64(elem, &intval) != 0) { error = EINVAL; @@ -6256,6 +6286,7 @@ vdev_prop_get(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) nvpair_t *elem = NULL; nvlist_t *nvprops = NULL; uint64_t intval = 0; + boolean_t boolval = 0; char *strval = NULL; const char *propname = NULL; vdev_prop_t prop; @@ -6269,15 +6300,8 @@ vdev_prop_get(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) nvlist_lookup_nvlist(innvl, ZPOOL_VDEV_PROPS_GET_PROPS, &nvprops); - if (vd->vdev_root_zap != 0) { - objid = vd->vdev_root_zap; - } else if (vd->vdev_top_zap != 0) { - objid = vd->vdev_top_zap; - } else if (vd->vdev_leaf_zap != 0) { - objid = vd->vdev_leaf_zap; - } else { + if (vdev_prop_get_objid(vd, &objid) != 0) return (SET_ERROR(EINVAL)); - } ASSERT(objid != 0); mutex_enter(&spa->spa_props_lock); @@ -6622,6 +6646,18 @@ vdev_prop_get(vdev_t *vd, nvlist_t *innvl, nvlist_t *outnvl) intval, src); break; + case VDEV_PROP_SLOW_IO_EVENTS: + err = vdev_prop_get_bool(vd, prop, &boolval); + if (err && err != ENOENT) + break; + + src = ZPROP_SRC_LOCAL; + if (boolval == vdev_prop_default_numeric(prop)) + src = ZPROP_SRC_DEFAULT; + + vdev_prop_add_list(outnvl, propname, NULL, + boolval, src); + break; case VDEV_PROP_CHECKSUM_N: case VDEV_PROP_CHECKSUM_T: case VDEV_PROP_IO_N: diff --git a/module/zfs/zfs_fm.c b/module/zfs/zfs_fm.c index 96c722731aea..4a0d41c24eed 100644 --- a/module/zfs/zfs_fm.c +++ b/module/zfs/zfs_fm.c @@ -223,6 +223,9 @@ vdev_prop_get_inherited(vdev_t *vd, vdev_prop_t prop) case VDEV_PROP_IO_T: propval = vd->vdev_io_t; break; + case VDEV_PROP_SLOW_IO_EVENTS: + propval = vd->vdev_slow_io_events; + break; case VDEV_PROP_SLOW_IO_N: propval = vd->vdev_slow_io_n; break; diff --git a/module/zfs/zio.c b/module/zfs/zio.c index 4f3ecdc35daf..74373f759cec 100644 --- a/module/zfs/zio.c +++ b/module/zfs/zio.c @@ -5569,9 +5569,12 @@ zio_done(zio_t *zio) zio->io_vd->vdev_stat.vs_slow_ios++; mutex_exit(&zio->io_vd->vdev_stat_lock); - (void) zfs_ereport_post(FM_EREPORT_ZFS_DELAY, - zio->io_spa, zio->io_vd, &zio->io_bookmark, - zio, 0); + if (zio->io_vd->vdev_slow_io_events) { + (void) zfs_ereport_post( + FM_EREPORT_ZFS_DELAY, + zio->io_spa, zio->io_vd, + &zio->io_bookmark, zio, 0); + } } } } diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg b/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg index ccb5e9c15809..6d9aa28681c7 100644 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_get/vdev_get.cfg @@ -71,6 +71,7 @@ typeset -a properties=( checksum_t io_n io_t + slow_io_events slow_io_n slow_io_t trim_support diff --git a/tests/zfs-tests/tests/functional/events/zed_slow_io.ksh b/tests/zfs-tests/tests/functional/events/zed_slow_io.ksh index 0c68530ee9ef..570c3b0c62b6 100755 --- a/tests/zfs-tests/tests/functional/events/zed_slow_io.ksh +++ b/tests/zfs-tests/tests/functional/events/zed_slow_io.ksh @@ -23,6 +23,7 @@ # # Copyright (c) 2023, Klara Inc. +# Copyright (c) 2025, Mariusz Zaborski # # DESCRIPTION: @@ -140,8 +141,8 @@ function slow_io_degrade { do_setup - zpool set slow_io_n=5 $TESTPOOL $VDEV - zpool set slow_io_t=60 $TESTPOOL $VDEV + log_must zpool set slow_io_n=5 $TESTPOOL $VDEV + log_must zpool set slow_io_t=60 $TESTPOOL $VDEV start_slow_io for i in {1..16}; do @@ -193,6 +194,44 @@ function slow_io_no_degrade do_clean } +# Change slow_io_n, slow_io_t to 5 events in 60 seconds +# fire more than 5 events. Disable slow io events. +# Should not degrade. +function slow_io_degrade_disabled +{ + do_setup + + log_must zpool set slow_io_n=5 $TESTPOOL $VDEV + log_must zpool set slow_io_t=60 $TESTPOOL $VDEV + log_must zpool set slow_io_events=off $TESTPOOL $VDEV + + start_slow_io + for i in {1..16}; do + dd if=${FILEPATH}$i of=/dev/null count=1 bs=512 2>/dev/null + sleep 0.5 + done + stop_slow_io + zpool sync + + # + # wait 60 seconds to confirm that zfs.delay was not generated. + # + typeset -i i=0 + typeset -i events=0 + while [[ $i -lt 60 ]]; do + events=$(zpool events | grep "ereport\.fs\.zfs.delay" | wc -l) + i=$((i+1)) + sleep 1 + done + log_note "$events delay events found" + + [ $events -eq "0" ] || \ + log_fail "expecting no delay events, found $events" + + log_mustnot wait_vdev_state $TESTPOOL $VDEV "DEGRADED" 45 + do_clean +} + log_assert "Test ZED slow io configurability" log_onexit cleanup @@ -202,5 +241,6 @@ log_must zed_start default_degrade slow_io_degrade slow_io_no_degrade +slow_io_degrade_disabled log_pass "Test ZED slow io configurability" From 24aaf3a3f9f990ca7bff7bf362d326e9356f648f Mon Sep 17 00:00:00 2001 From: Adi-Goll <68113680+Adi-Goll@users.noreply.github.com> Date: Tue, 11 Nov 2025 15:01:37 -0800 Subject: [PATCH 29/91] Reduce timeout to zero when running inside a container Detect container environments and set timeout to zero unless ZFS_MODULE_TIMEOUT is already set. This avoids an unnecessary ten second delay after running zfs/zpool commands in a container where /dev/zfs is unavailable. Reviewed-by: Brian Behlendorf Signed-off-by: Adi Gollamudi Closes #15165 Closes #17922 --- lib/libzfs/os/linux/libzfs_util_os.c | 37 ++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lib/libzfs/os/linux/libzfs_util_os.c b/lib/libzfs/os/linux/libzfs_util_os.c index 55dfdf3723bd..651d407b1884 100644 --- a/lib/libzfs/os/linux/libzfs_util_os.c +++ b/lib/libzfs/os/linux/libzfs_util_os.c @@ -78,6 +78,38 @@ libzfs_error_init(int error) } } +static int +in_container(void) +{ + char buffer[4096]; + ssize_t count; + int fd; + + if (access("/run/systemd/container", R_OK) == 0) + return (1); + + fd = open("/proc/1/cgroup", O_RDONLY); + if (fd == -1) + return (0); + + count = read(fd, buffer, sizeof (buffer) - 1); + close(fd); + + if (count <= 0) + return (0); + + buffer[count] = '\0'; + + if (strstr(buffer, "docker") || + strstr(buffer, "containerd") || + strstr(buffer, "kubepods") || + strstr(buffer, "lxc")) { + return (1); + } + + return (0); +} + /* * zfs(4) is loaded by udev if there's a fstype=zfs device present, * but if there isn't, load them automatically; @@ -104,6 +136,11 @@ libzfs_load_module(void) const char *timeout_str = getenv("ZFS_MODULE_TIMEOUT"); int seconds = 10; + + /* Set timeout to zero if inside of a container */ + if (in_container()) + seconds = 0; + if (timeout_str) seconds = MIN(strtol(timeout_str, NULL, 0), 600); struct itimerspec timeout = {.it_value.tv_sec = MAX(seconds, 0)}; From 80cfdbb19f0e0a9fac059c9155607e58f3904022 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Fri, 7 Nov 2025 16:05:09 -0800 Subject: [PATCH 30/91] Bump SONAME on libnvpair The nvlist_snprintf() function was added to the ABI of libnvpair. No other symbols were modified or removed. Bump the library-info SONAME current and age args to reflect this is a minor library version update. Reviewed-by: Rob Norris Signed-off-by: Brian Behlendorf Closes #17911 --- lib/libnvpair/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/libnvpair/Makefile.am b/lib/libnvpair/Makefile.am index 87b8d32aa175..0b3f964781b0 100644 --- a/lib/libnvpair/Makefile.am +++ b/lib/libnvpair/Makefile.am @@ -30,6 +30,6 @@ if !ASAN_ENABLED libnvpair_la_LDFLAGS += -Wl,-z,defs endif -libnvpair_la_LDFLAGS += -version-info 3:0:0 +libnvpair_la_LDFLAGS += -version-info 4:0:1 dist_noinst_DATA += %D%/libnvpair.abi %D%/libnvpair.suppr From e4fe41a79f3eba23a312de61176dc0584c41cbd5 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Mon, 10 Nov 2025 12:50:16 -0800 Subject: [PATCH 31/91] Bump SONAME of libzfs and libzpool The ABI of libzfs and libzpool have breaking changes since the last major release. Bump the SONAME for the upcoming 2.4 release branch to libzfs7 and libzpool7. Reviewed-by: Rob Norris Signed-off-by: Brian Behlendorf Closes #17911 --- config/deb.am | 8 ++-- contrib/debian/Makefile.am | 8 ++-- contrib/debian/clean | 4 +- contrib/debian/control | 26 +++++------ ...nzfs-libzfs6.docs => openzfs-libzfs7.docs} | 0 ....install.in => openzfs-libzfs7.install.in} | 0 ...-libzpool6.docs => openzfs-libzpool7.docs} | 0 ...nstall.in => openzfs-libzpool7.install.in} | 0 lib/libzfs/Makefile.am | 2 +- lib/libzpool/Makefile.am | 2 +- rpm/generic/zfs.spec.in | 44 ++++++++++--------- 11 files changed, 48 insertions(+), 46 deletions(-) rename contrib/debian/{openzfs-libzfs6.docs => openzfs-libzfs7.docs} (100%) rename contrib/debian/{openzfs-libzfs6.install.in => openzfs-libzfs7.install.in} (100%) rename contrib/debian/{openzfs-libzpool6.docs => openzfs-libzpool7.docs} (100%) rename contrib/debian/{openzfs-libzpool6.install.in => openzfs-libzpool7.install.in} (100%) diff --git a/config/deb.am b/config/deb.am index 9e58e1905b73..3e9a9379712e 100644 --- a/config/deb.am +++ b/config/deb.am @@ -58,9 +58,9 @@ deb-utils: deb-local rpm-utils-initramfs pkg1=$${name}-$${version}.$${arch}.rpm; \ pkg2=libnvpair3-$${version}.$${arch}.rpm; \ pkg3=libuutil3-$${version}.$${arch}.rpm; \ - pkg4=libzfs6-$${version}.$${arch}.rpm; \ - pkg5=libzpool6-$${version}.$${arch}.rpm; \ - pkg6=libzfs6-devel-$${version}.$${arch}.rpm; \ + pkg4=libzfs7-$${version}.$${arch}.rpm; \ + pkg5=libzpool7-$${version}.$${arch}.rpm; \ + pkg6=libzfs7-devel-$${version}.$${arch}.rpm; \ pkg7=$${name}-test-$${version}.$${arch}.rpm; \ pkg8=$${name}-dracut-$${version}.noarch.rpm; \ pkg9=$${name}-initramfs-$${version}.$${arch}.rpm; \ @@ -72,7 +72,7 @@ deb-utils: deb-local rpm-utils-initramfs path_prepend=`mktemp -d /tmp/intercept.XXXXXX`; \ echo "#!$(SHELL)" > $${path_prepend}/dh_shlibdeps; \ echo "`which dh_shlibdeps` -- \ - -xlibuutil3linux -xlibnvpair3linux -xlibzfs6linux -xlibzpool6linux" \ + -xlibuutil3linux -xlibnvpair3linux -xlibzfs7linux -xlibzpool7linux" \ >> $${path_prepend}/dh_shlibdeps; \ ## These -x arguments are passed to dpkg-shlibdeps, which exclude the ## Debianized packages from the auto-generated dependencies of the new debs, diff --git a/contrib/debian/Makefile.am b/contrib/debian/Makefile.am index 99d512312df6..3c219856005e 100644 --- a/contrib/debian/Makefile.am +++ b/contrib/debian/Makefile.am @@ -12,14 +12,14 @@ dist_noinst_DATA += %D%/openzfs-libpam-zfs.postinst dist_noinst_DATA += %D%/openzfs-libpam-zfs.prerm dist_noinst_DATA += %D%/openzfs-libuutil3.docs dist_noinst_DATA += %D%/openzfs-libuutil3.install.in -dist_noinst_DATA += %D%/openzfs-libzfs6.docs -dist_noinst_DATA += %D%/openzfs-libzfs6.install.in +dist_noinst_DATA += %D%/openzfs-libzfs7.docs +dist_noinst_DATA += %D%/openzfs-libzfs7.install.in dist_noinst_DATA += %D%/openzfs-libzfsbootenv1.docs dist_noinst_DATA += %D%/openzfs-libzfsbootenv1.install.in dist_noinst_DATA += %D%/openzfs-libzfs-dev.docs dist_noinst_DATA += %D%/openzfs-libzfs-dev.install.in -dist_noinst_DATA += %D%/openzfs-libzpool6.docs -dist_noinst_DATA += %D%/openzfs-libzpool6.install.in +dist_noinst_DATA += %D%/openzfs-libzpool7.docs +dist_noinst_DATA += %D%/openzfs-libzpool7.install.in dist_noinst_DATA += %D%/openzfs-python3-pyzfs.install dist_noinst_DATA += %D%/openzfs-zfs-dkms.config dist_noinst_DATA += %D%/openzfs-zfs-dkms.dkms diff --git a/contrib/debian/clean b/contrib/debian/clean index 4f52d01b8108..caabcd30c62a 100644 --- a/contrib/debian/clean +++ b/contrib/debian/clean @@ -6,6 +6,6 @@ contrib/pyzfs/libzfs_core/bindings/__pycache__/ contrib/pyzfs/pyzfs.egg-info/ debian/openzfs-libnvpair3.install debian/openzfs-libuutil3.install -debian/openzfs-libzfs6.install +debian/openzfs-libzfs7.install debian/openzfs-libzfs-dev.install -debian/openzfs-libzpool6.install +debian/openzfs-libzpool7.install diff --git a/contrib/debian/control b/contrib/debian/control index c5358dedc0fd..a886c2e86cc5 100644 --- a/contrib/debian/control +++ b/contrib/debian/control @@ -79,9 +79,9 @@ Architecture: linux-any Depends: libssl-dev | libssl1.0-dev, openzfs-libnvpair3 (= ${binary:Version}), openzfs-libuutil3 (= ${binary:Version}), - openzfs-libzfs6 (= ${binary:Version}), + openzfs-libzfs7 (= ${binary:Version}), openzfs-libzfsbootenv1 (= ${binary:Version}), - openzfs-libzpool6 (= ${binary:Version}), + openzfs-libzpool7 (= ${binary:Version}), ${misc:Depends} Replaces: libzfslinux-dev Conflicts: libzfslinux-dev @@ -91,18 +91,18 @@ Description: OpenZFS filesystem development files for Linux libraries of OpenZFS filesystem. . This package includes the development files of libnvpair3, libuutil3, - libzpool6 and libzfs6. + libzpool7 and libzfs7. -Package: openzfs-libzfs6 +Package: openzfs-libzfs7 Section: contrib/libs Architecture: linux-any Depends: ${misc:Depends}, ${shlibs:Depends} # The libcurl4 is loaded through dlopen("libcurl.so.4"). # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=988521 Recommends: libcurl4 -Breaks: libzfs2, libzfs4, libzfs4linux, libzfs6linux, openzfs-libzfs4 -Replaces: libzfs2, libzfs4, libzfs4linux, libzfs6linux, openzfs-libzfs4 -Conflicts: libzfs6linux +Breaks: libzfs2, libzfs4, libzfs4linux, libzfs6linux, libzfs7linux, openzfs-libzfs4, openzfs-libzfs6 +Replaces: libzfs2, libzfs4, libzfs4linux, libzfs6linux, libzfs7linux, openzfs-libzfs4, openzfs-libzfs6 +Conflicts: libzfs7linux Description: OpenZFS filesystem library for Linux - general support OpenZFS is a storage platform that encompasses the functionality of traditional filesystems and volume managers. It supports data checksums, @@ -124,13 +124,13 @@ Description: OpenZFS filesystem library for Linux - label info support . The zfsbootenv library provides support for modifying ZFS label information. -Package: openzfs-libzpool6 +Package: openzfs-libzpool7 Section: contrib/libs Architecture: linux-any Depends: ${misc:Depends}, ${shlibs:Depends} -Breaks: libzpool2, libzpool5, libzpool6linux -Replaces: libzpool2, libzpool5, libzpool6linux -Conflicts: libzpool6linux +Breaks: libzpool2, libzpool5, libzpool6linux, libzpool7linux +Replaces: libzpool2, libzpool5, libzpool6linux, libzpool7linux +Conflicts: libzpool7linux Description: OpenZFS pool library for Linux OpenZFS is a storage platform that encompasses the functionality of traditional filesystems and volume managers. It supports data checksums, @@ -247,8 +247,8 @@ Architecture: linux-any Pre-Depends: ${misc:Pre-Depends} Depends: openzfs-libnvpair3 (= ${binary:Version}), openzfs-libuutil3 (= ${binary:Version}), - openzfs-libzfs6 (= ${binary:Version}), - openzfs-libzpool6 (= ${binary:Version}), + openzfs-libzfs7 (= ${binary:Version}), + openzfs-libzpool7 (= ${binary:Version}), python3, ${misc:Depends}, ${shlibs:Depends} diff --git a/contrib/debian/openzfs-libzfs6.docs b/contrib/debian/openzfs-libzfs7.docs similarity index 100% rename from contrib/debian/openzfs-libzfs6.docs rename to contrib/debian/openzfs-libzfs7.docs diff --git a/contrib/debian/openzfs-libzfs6.install.in b/contrib/debian/openzfs-libzfs7.install.in similarity index 100% rename from contrib/debian/openzfs-libzfs6.install.in rename to contrib/debian/openzfs-libzfs7.install.in diff --git a/contrib/debian/openzfs-libzpool6.docs b/contrib/debian/openzfs-libzpool7.docs similarity index 100% rename from contrib/debian/openzfs-libzpool6.docs rename to contrib/debian/openzfs-libzpool7.docs diff --git a/contrib/debian/openzfs-libzpool6.install.in b/contrib/debian/openzfs-libzpool7.install.in similarity index 100% rename from contrib/debian/openzfs-libzpool6.install.in rename to contrib/debian/openzfs-libzpool7.install.in diff --git a/lib/libzfs/Makefile.am b/lib/libzfs/Makefile.am index 5f8963dccd1a..e2cbca47b9a3 100644 --- a/lib/libzfs/Makefile.am +++ b/lib/libzfs/Makefile.am @@ -70,7 +70,7 @@ if BUILD_FREEBSD libzfs_la_LIBADD += -lutil -lgeom endif -libzfs_la_LDFLAGS += -version-info 6:0:0 +libzfs_la_LDFLAGS += -version-info 7:0:0 pkgconfig_DATA += %D%/libzfs.pc diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index aeacc595b363..4658e025ea53 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -212,7 +212,7 @@ if BUILD_FREEBSD libzpool_la_LIBADD += -lgeom endif -libzpool_la_LDFLAGS += -version-info 6:0:0 +libzpool_la_LDFLAGS += -version-info 7:0:0 if TARGET_CPU_POWERPC module/zfs/libzpool_la-vdev_raidz_math_powerpc_altivec.$(OBJEXT) : CFLAGS += -maltivec diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in index 8986e29eb7fb..9ae479aeb96b 100644 --- a/rpm/generic/zfs.spec.in +++ b/rpm/generic/zfs.spec.in @@ -111,10 +111,10 @@ License: @ZFS_META_LICENSE@ URL: https://github.com/openzfs/zfs Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) -Requires: libzpool6%{?_isa} = %{version}-%{release} +Requires: libzpool7%{?_isa} = %{version}-%{release} Requires: libnvpair3%{?_isa} = %{version}-%{release} Requires: libuutil3%{?_isa} = %{version}-%{release} -Requires: libzfs6%{?_isa} = %{version}-%{release} +Requires: libzfs7%{?_isa} = %{version}-%{release} Requires: %{name}-kmod = %{version} Provides: %{name}-kmod-common = %{version}-%{release} Obsoletes: spl <= %{version} @@ -162,22 +162,23 @@ Requires: sysstat %description This package contains the core ZFS command line utilities. -%package -n libzpool6 +%package -n libzpool7 Summary: Native ZFS pool library for Linux Group: System Environment/Kernel Obsoletes: libzpool2 <= %{version} Obsoletes: libzpool4 <= %{version} Obsoletes: libzpool5 <= %{version} +Obsoletes: libzpool6 <= %{version} -%description -n libzpool6 +%description -n libzpool7 This package contains the zpool library, which provides support for managing zpools %if %{defined ldconfig_scriptlets} -%ldconfig_scriptlets -n libzpool6 +%ldconfig_scriptlets -n libzpool7 %else -%post -n libzpool6 -p /sbin/ldconfig -%postun -n libzpool6 -p /sbin/ldconfig +%post -n libzpool7 -p /sbin/ldconfig +%postun -n libzpool7 -p /sbin/ldconfig %endif %package -n libnvpair3 @@ -224,31 +225,32 @@ This library provides a variety of compatibility functions for OpenZFS: # The library version is encoded in the package name. When updating the # version information it is important to add an obsoletes line below for # the previous version of the package. -%package -n libzfs6 +%package -n libzfs7 Summary: Native ZFS filesystem library for Linux Group: System Environment/Kernel Obsoletes: libzfs2 <= %{version} Obsoletes: libzfs4 <= %{version} Obsoletes: libzfs5 <= %{version} +Obsoletes: libzfs6 <= %{version} -%description -n libzfs6 +%description -n libzfs7 This package provides support for managing ZFS filesystems %if %{defined ldconfig_scriptlets} -%ldconfig_scriptlets -n libzfs6 +%ldconfig_scriptlets -n libzfs7 %else -%post -n libzfs6 -p /sbin/ldconfig -%postun -n libzfs6 -p /sbin/ldconfig +%post -n libzfs7 -p /sbin/ldconfig +%postun -n libzfs7 -p /sbin/ldconfig %endif -%package -n libzfs6-devel +%package -n libzfs7-devel Summary: Development headers Group: System Environment/Kernel -Requires: libzfs6%{?_isa} = %{version}-%{release} -Requires: libzpool6%{?_isa} = %{version}-%{release} +Requires: libzfs7%{?_isa} = %{version}-%{release} +Requires: libzpool7%{?_isa} = %{version}-%{release} Requires: libnvpair3%{?_isa} = %{version}-%{release} Requires: libuutil3%{?_isa} = %{version}-%{release} -Provides: libzpool6-devel = %{version}-%{release} +Provides: libzpool7-devel = %{version}-%{release} Provides: libnvpair3-devel = %{version}-%{release} Provides: libuutil3-devel = %{version}-%{release} Obsoletes: zfs-devel <= %{version} @@ -256,7 +258,7 @@ Obsoletes: libzfs2-devel <= %{version} Obsoletes: libzfs4-devel <= %{version} Obsoletes: libzfs5-devel <= %{version} -%description -n libzfs6-devel +%description -n libzfs7-devel This package contains the header files needed for building additional applications against the ZFS libraries. @@ -305,7 +307,7 @@ Summary: Python %{python_version} wrapper for libzfs_core Group: Development/Languages/Python License: Apache-2.0 BuildArch: noarch -Requires: libzfs6 = %{version}-%{release} +Requires: libzfs7 = %{version}-%{release} Requires: libnvpair3 = %{version}-%{release} Requires: libffi Requires: python%{__python_pkg_version} @@ -548,7 +550,7 @@ systemctl --system daemon-reload >/dev/null || true %config(noreplace) %{_bashcompletiondir}/zfs %config(noreplace) %{_bashcompletiondir}/zpool -%files -n libzpool6 +%files -n libzpool7 %{_libdir}/libzpool.so.* %files -n libnvpair3 @@ -557,10 +559,10 @@ systemctl --system daemon-reload >/dev/null || true %files -n libuutil3 %{_libdir}/libuutil.so.* -%files -n libzfs6 +%files -n libzfs7 %{_libdir}/libzfs*.so.* -%files -n libzfs6-devel +%files -n libzfs7-devel %{_pkgconfigdir}/libzfs.pc %{_pkgconfigdir}/libzfsbootenv.pc %{_pkgconfigdir}/libzfs_core.pc From 64c4b6d17a46f233a99810e2fa18a1dcb3611aad Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 11 Nov 2025 17:11:54 -0800 Subject: [PATCH 32/91] libspl: hide zfs_tunable_* symbols The zfs_tunable_* functions are a public interface which are part of the internal libspl convenience library. They should be hidden to prevent an unnecessary ABI change in installed libraries which link against libspl (e.g. libzfs_core, libuutil). We do already leak long standing libspl symbols. This commit is solely intended to prevent leaking these new ones until this is properly sorted out. Reviewed-by: Rob Norris Signed-off-by: Brian Behlendorf Closes #17911 --- lib/libspl/include/sys/tunables.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/libspl/include/sys/tunables.h b/lib/libspl/include/sys/tunables.h index 5d9bb3d71a4a..c85400f6fd28 100644 --- a/lib/libspl/include/sys/tunables.h +++ b/lib/libspl/include/sys/tunables.h @@ -25,7 +25,7 @@ */ #ifndef _SYS_TUNABLES_H -#define _SYS_TUNABLES_H +#define _SYS_TUNABLES_H extern __attribute__((visibility("hidden"))) typedef enum { ZFS_TUNABLE_TYPE_INT, @@ -49,12 +49,14 @@ typedef struct zfs_tunable { const char *zt_desc; } zfs_tunable_t; -int zfs_tunable_set(const zfs_tunable_t *tunable, const char *val); -int zfs_tunable_get(const zfs_tunable_t *tunable, char *val, size_t valsz); +_SYS_TUNABLES_H int zfs_tunable_set(const zfs_tunable_t *tunable, + const char *val); +_SYS_TUNABLES_H int zfs_tunable_get(const zfs_tunable_t *tunable, char *val, + size_t valsz); -const zfs_tunable_t *zfs_tunable_lookup(const char *name); +_SYS_TUNABLES_H const zfs_tunable_t *zfs_tunable_lookup(const char *name); typedef int (*zfs_tunable_iter_t)(const zfs_tunable_t *tunable, void *arg); -void zfs_tunable_iter(zfs_tunable_iter_t cb, void *arg); +_SYS_TUNABLES_H void zfs_tunable_iter(zfs_tunable_iter_t cb, void *arg); #endif From cb6b249f8c9a72e71499e433ba8f66bce4259be3 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Tue, 11 Nov 2025 17:14:32 -0800 Subject: [PATCH 33/91] Update all ABI files Refresh all ABI files using the CI generated files to reflect the library interfaces to be published for the 2.4 release. Reviewed-by: Rob Norris Signed-off-by: Brian Behlendorf Closes #17911 --- lib/libuutil/libuutil.abi | 69 ------------------------- lib/libzfs/libzfs.abi | 80 +++-------------------------- lib/libzfs_core/libzfs_core.abi | 70 +------------------------ lib/libzfsbootenv/libzfsbootenv.abi | 2 +- 4 files changed, 8 insertions(+), 213 deletions(-) diff --git a/lib/libuutil/libuutil.abi b/lib/libuutil/libuutil.abi index 2a740afa07ca..52a00d9830b1 100644 --- a/lib/libuutil/libuutil.abi +++ b/lib/libuutil/libuutil.abi @@ -244,10 +244,6 @@ - - - - @@ -1310,52 +1306,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1368,31 +1324,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 232265237f54..9ce2ffa55df9 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -1,4 +1,4 @@ - + @@ -451,10 +451,6 @@ - - - - @@ -1497,50 +1493,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1553,31 +1509,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1808,10 +1739,6 @@ - - - - @@ -6251,6 +6178,7 @@ + @@ -7989,6 +7917,10 @@ + + + + diff --git a/lib/libzfs_core/libzfs_core.abi b/lib/libzfs_core/libzfs_core.abi index 263cad045f7a..7f3c8f2ff0d7 100644 --- a/lib/libzfs_core/libzfs_core.abi +++ b/lib/libzfs_core/libzfs_core.abi @@ -222,10 +222,6 @@ - - - - @@ -1256,52 +1252,12 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1319,31 +1275,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1709,6 +1640,7 @@ + diff --git a/lib/libzfsbootenv/libzfsbootenv.abi b/lib/libzfsbootenv/libzfsbootenv.abi index bf866b0fa61b..e2b492a0780d 100644 --- a/lib/libzfsbootenv/libzfsbootenv.abi +++ b/lib/libzfsbootenv/libzfsbootenv.abi @@ -1,6 +1,6 @@ - + From 5588f189a716b7cbf86af90e1f13bb95bf4f5791 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 6 Jul 2025 12:16:54 +1000 Subject: [PATCH 34/91] libspl: single zfs_context_os.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/include/Makefile.am | 5 ++- .../include/os/freebsd/sys/zfs_context_os.h | 35 ------------------- .../{os/linux => }/sys/zfs_context_os.h | 15 +++++--- 3 files changed, 12 insertions(+), 43 deletions(-) delete mode 100644 lib/libspl/include/os/freebsd/sys/zfs_context_os.h rename lib/libspl/include/{os/linux => }/sys/zfs_context_os.h (62%) diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 746cb12bf637..3a744def6dd7 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -65,6 +65,7 @@ libspl_sys_HEADERS = \ %D%/sys/uio.h \ %D%/sys/vnode.h \ %D%/sys/wmsum.h \ + %D%/sys/zfs_context_os.h \ %D%/sys/zone.h libspl_ia32dir = $(libspldir)/sys/ia32 @@ -79,7 +80,6 @@ libspl_sys_HEADERS += \ %D%/os/linux/sys/stat.h \ %D%/os/linux/sys/sysmacros.h \ %D%/os/linux/sys/vfs.h \ - %D%/os/linux/sys/zfs_context_os.h libspl_ia32_HEADERS = \ %D%/os/linux/sys/ia32/asm_linkage.h @@ -95,8 +95,7 @@ libspl_sys_HEADERS += \ %D%/os/freebsd/sys/param.h \ %D%/os/freebsd/sys/stat.h \ %D%/os/freebsd/sys/sysmacros.h \ - %D%/os/freebsd/sys/vfs.h \ - %D%/os/freebsd/sys/zfs_context_os.h + %D%/os/freebsd/sys/vfs.h libspl_ia32_HEADERS = \ %D%/os/freebsd/sys/ia32/asm_linkage.h diff --git a/lib/libspl/include/os/freebsd/sys/zfs_context_os.h b/lib/libspl/include/os/freebsd/sys/zfs_context_os.h deleted file mode 100644 index 1dd036d02ac6..000000000000 --- a/lib/libspl/include/os/freebsd/sys/zfs_context_os.h +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: BSD-2-Clause -/* - * Copyright (c) 2020 iXsystems, Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD$ - */ - -#ifndef ZFS_CONTEXT_OS_H_ -#define ZFS_CONTEXT_OS_H_ - -#define HAVE_LARGE_STACKS 1 - -#endif diff --git a/lib/libspl/include/os/linux/sys/zfs_context_os.h b/lib/libspl/include/sys/zfs_context_os.h similarity index 62% rename from lib/libspl/include/os/linux/sys/zfs_context_os.h rename to lib/libspl/include/sys/zfs_context_os.h index bbfb4d17e06d..4dcf386e3351 100644 --- a/lib/libspl/include/os/linux/sys/zfs_context_os.h +++ b/lib/libspl/include/sys/zfs_context_os.h @@ -3,9 +3,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or https://opensource.org/licenses/CDDL-1.0. @@ -20,9 +19,15 @@ * * CDDL HEADER END */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ -#ifndef ZFS_CONTEXT_OS_H -#define ZFS_CONTEXT_OS_H +#ifndef ZFS_CONTEXT_OS_H_ +#define ZFS_CONTEXT_OS_H_ #define HAVE_LARGE_STACKS 1 From f49b93e2c747e20992f31435ee863d6b49d3f35d Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 26 Oct 2025 14:47:11 +1100 Subject: [PATCH 35/91] libzpool: move zfs_context_os.h from libspl Keeping the spl/zfs module split, libzpool is the zfs module for userspace. Headers and functions specific to it belong there. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- config/Rules.am | 3 ++- lib/libspl/include/Makefile.am | 1 - lib/libzpool/Makefile.am | 2 ++ lib/libzpool/include/Makefile.am | 3 +++ lib/{libspl => libzpool}/include/sys/zfs_context_os.h | 0 5 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 lib/libzpool/include/Makefile.am rename lib/{libspl => libzpool}/include/sys/zfs_context_os.h (100%) diff --git a/config/Rules.am b/config/Rules.am index deffa352ea24..9c0714c82513 100644 --- a/config/Rules.am +++ b/config/Rules.am @@ -10,7 +10,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/include \ -I$(top_srcdir)/module/icp/include \ -I$(top_srcdir)/lib/libspl/include \ - -I$(top_srcdir)/lib/libspl/include/os/@ac_system_l@ + -I$(top_srcdir)/lib/libspl/include/os/@ac_system_l@ \ + -I$(top_srcdir)/lib/libzpool/include AM_LIBTOOLFLAGS = --silent diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 3a744def6dd7..be65bdb2216e 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -65,7 +65,6 @@ libspl_sys_HEADERS = \ %D%/sys/uio.h \ %D%/sys/vnode.h \ %D%/sys/wmsum.h \ - %D%/sys/zfs_context_os.h \ %D%/sys/zone.h libspl_ia32dir = $(libspldir)/sys/ia32 diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index 4658e025ea53..db8458885235 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -1,3 +1,5 @@ +include $(srcdir)/%D%/include/Makefile.am + libzpool_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) $(LIBRARY_CFLAGS) libzpool_la_CFLAGS += $(ZLIB_CFLAGS) diff --git a/lib/libzpool/include/Makefile.am b/lib/libzpool/include/Makefile.am new file mode 100644 index 000000000000..06fffdc75def --- /dev/null +++ b/lib/libzpool/include/Makefile.am @@ -0,0 +1,3 @@ +libzpool_sysdir = $(includedir)/libzpool/sys +libzpool_sys_HEADERS = \ + %D%/sys/zfs_context_os.h diff --git a/lib/libspl/include/sys/zfs_context_os.h b/lib/libzpool/include/sys/zfs_context_os.h similarity index 100% rename from lib/libspl/include/sys/zfs_context_os.h rename to lib/libzpool/include/sys/zfs_context_os.h From 37d5df62e01ef3a12e712b80bd47057136dfd634 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 26 Oct 2025 15:01:21 +1100 Subject: [PATCH 36/91] libzpool: move ZFS-specific headers from libspl Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/include/Makefile.am | 3 --- lib/libzpool/include/Makefile.am | 3 +++ lib/{libspl => libzpool}/include/sys/abd_impl_os.h | 0 lib/{libspl => libzpool}/include/sys/abd_os.h | 0 lib/{libspl => libzpool}/include/sys/trace_zfs.h | 0 scripts/spdxcheck.pl | 2 +- 6 files changed, 4 insertions(+), 4 deletions(-) rename lib/{libspl => libzpool}/include/sys/abd_impl_os.h (100%) rename lib/{libspl => libzpool}/include/sys/abd_os.h (100%) rename lib/{libspl => libzpool}/include/sys/trace_zfs.h (100%) diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index be65bdb2216e..4eb534d16ccc 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -24,8 +24,6 @@ libspl_rpc_HEADERS = \ libspl_sysdir = $(libspldir)/sys libspl_sys_HEADERS = \ - %D%/sys/abd_os.h \ - %D%/sys/abd_impl_os.h \ %D%/sys/acl.h \ %D%/sys/acl_impl.h \ %D%/sys/asm_linkage.h \ @@ -58,7 +56,6 @@ libspl_sys_HEADERS = \ %D%/sys/systeminfo.h \ %D%/sys/time.h \ %D%/sys/trace_spl.h \ - %D%/sys/trace_zfs.h \ %D%/sys/tunables.h \ %D%/sys/types.h \ %D%/sys/types32.h \ diff --git a/lib/libzpool/include/Makefile.am b/lib/libzpool/include/Makefile.am index 06fffdc75def..54d10e62358b 100644 --- a/lib/libzpool/include/Makefile.am +++ b/lib/libzpool/include/Makefile.am @@ -1,3 +1,6 @@ libzpool_sysdir = $(includedir)/libzpool/sys libzpool_sys_HEADERS = \ + %D%/sys/abd_os.h \ + %D%/sys/abd_impl_os.h \ + %D%/sys/trace_zfs.h \ %D%/sys/zfs_context_os.h diff --git a/lib/libspl/include/sys/abd_impl_os.h b/lib/libzpool/include/sys/abd_impl_os.h similarity index 100% rename from lib/libspl/include/sys/abd_impl_os.h rename to lib/libzpool/include/sys/abd_impl_os.h diff --git a/lib/libspl/include/sys/abd_os.h b/lib/libzpool/include/sys/abd_os.h similarity index 100% rename from lib/libspl/include/sys/abd_os.h rename to lib/libzpool/include/sys/abd_os.h diff --git a/lib/libspl/include/sys/trace_zfs.h b/lib/libzpool/include/sys/trace_zfs.h similarity index 100% rename from lib/libspl/include/sys/trace_zfs.h rename to lib/libzpool/include/sys/trace_zfs.h diff --git a/scripts/spdxcheck.pl b/scripts/spdxcheck.pl index 4d4e14368beb..e119f13518cc 100755 --- a/scripts/spdxcheck.pl +++ b/scripts/spdxcheck.pl @@ -130,8 +130,8 @@ my $untagged_patterns = q( lib/libspl/include/os/freebsd/sys/sysmacros.h lib/libspl/include/sys/string.h lib/libspl/include/sys/trace_spl.h - lib/libspl/include/sys/trace_zfs.h lib/libzdb/libzdb.c + lib/libzpool/include/sys/trace_zfs.h module/lua/setjmp/setjmp.S module/lua/setjmp/setjmp_ppc.S module/zstd/include/sparc_compat.h From ba2ff4b42c103e12572e42fce0311654da49b899 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Thu, 16 Oct 2025 13:52:57 +1100 Subject: [PATCH 37/91] libspl: move time definitions from zfs_context_os.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 33 ++---------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/timer.h | 64 ++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 31 deletions(-) create mode 100644 lib/libspl/include/sys/timer.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 7112d3ef5c99..39dca9939321 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -122,6 +122,8 @@ extern "C" { #include #include +#include + #include /* @@ -588,27 +590,6 @@ typedef struct vsecattr { /* * Random stuff */ -#define ddi_get_lbolt() (gethrtime() >> 23) -#define ddi_get_lbolt64() (gethrtime() >> 23) -#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */ - -#define ddi_time_before(a, b) (a < b) -#define ddi_time_after(a, b) ddi_time_before(b, a) -#define ddi_time_before_eq(a, b) (!ddi_time_after(a, b)) -#define ddi_time_after_eq(a, b) ddi_time_before_eq(b, a) - -#define ddi_time_before64(a, b) (a < b) -#define ddi_time_after64(a, b) ddi_time_before64(b, a) -#define ddi_time_before_eq64(a, b) (!ddi_time_after64(a, b)) -#define ddi_time_after_eq64(a, b) ddi_time_before_eq64(b, a) - -extern void delay(clock_t ticks); - -#define SEC_TO_TICK(sec) ((sec) * hz) -#define MSEC_TO_TICK(msec) (howmany((hrtime_t)(msec) * hz, MILLISEC)) -#define USEC_TO_TICK(usec) (howmany((hrtime_t)(usec) * hz, MICROSEC)) -#define NSEC_TO_TICK(nsec) (howmany((hrtime_t)(nsec) * hz, NANOSEC)) - #define max_ncpus 64 #define boot_ncpus (sysconf(_SC_NPROCESSORS_ONLN)) @@ -758,22 +739,12 @@ void ksiddomain_rele(ksiddomain_t *); #define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) \ sysevent_post_event(_c, _d, _b, "libzpool", _e, _f) -#define zfs_sleep_until(wakeup) \ - do { \ - hrtime_t delta = wakeup - gethrtime(); \ - struct timespec ts; \ - ts.tv_sec = delta / NANOSEC; \ - ts.tv_nsec = delta % NANOSEC; \ - (void) nanosleep(&ts, NULL); \ - } while (0) - typedef int fstrans_cookie_t; extern fstrans_cookie_t spl_fstrans_mark(void); extern void spl_fstrans_unmark(fstrans_cookie_t); extern int kmem_cache_reap_active(void); - /* * Kernel modules */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 4eb534d16ccc..98184340e664 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -55,6 +55,7 @@ libspl_sys_HEADERS = \ %D%/sys/sunddi.h \ %D%/sys/systeminfo.h \ %D%/sys/time.h \ + %D%/sys/timer.h \ %D%/sys/trace_spl.h \ %D%/sys/tunables.h \ %D%/sys/types.h \ diff --git a/lib/libspl/include/sys/timer.h b/lib/libspl/include/sys/timer.h new file mode 100644 index 000000000000..850d11f063c3 --- /dev/null +++ b/lib/libspl/include/sys/timer.h @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SPL_TIMER_H +#define _SPL_TIMER_H + +#include + +#define ddi_get_lbolt() (gethrtime() >> 23) +#define ddi_get_lbolt64() (gethrtime() >> 23) +#define hz 119 /* frequency when using gethrtime() >> 23 for lbolt */ + +#define ddi_time_before(a, b) (a < b) +#define ddi_time_after(a, b) ddi_time_before(b, a) +#define ddi_time_before_eq(a, b) (!ddi_time_after(a, b)) +#define ddi_time_after_eq(a, b) ddi_time_before_eq(b, a) + +#define ddi_time_before64(a, b) (a < b) +#define ddi_time_after64(a, b) ddi_time_before64(b, a) +#define ddi_time_before_eq64(a, b) (!ddi_time_after64(a, b)) +#define ddi_time_after_eq64(a, b) ddi_time_before_eq64(b, a) + +extern void delay(clock_t ticks); + +#define SEC_TO_TICK(sec) ((sec) * hz) +#define MSEC_TO_TICK(msec) (howmany((hrtime_t)(msec) * hz, MILLISEC)) +#define USEC_TO_TICK(usec) (howmany((hrtime_t)(usec) * hz, MICROSEC)) +#define NSEC_TO_TICK(nsec) (howmany((hrtime_t)(nsec) * hz, NANOSEC)) + +#define usleep_range(min, max) \ + do { \ + struct timespec ts; \ + ts.tv_sec = min / MICROSEC; \ + ts.tv_nsec = USEC2NSEC(min); \ + (void) nanosleep(&ts, NULL); \ + } while (0) + +#endif /* _SPL_TIMER_H */ From cc119fbb48d69bd7f0cf2c76a842548a6f8f43bc Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 9 Aug 2025 09:51:43 +1000 Subject: [PATCH 38/91] libspl: move mutex headers from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 25 +-------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/mutex.h | 58 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 lib/libspl/include/sys/mutex.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 39dca9939321..17d3ed20ce21 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -77,7 +77,6 @@ extern "C" { #include #else /* _KERNEL || _STANDALONE */ -#define _SYS_MUTEX_H #define _SYS_RWLOCK_H #define _SYS_CONDVAR_H #define _SYS_VNODE_H @@ -122,6 +121,7 @@ extern "C" { #include #include +#include #include #include @@ -253,29 +253,6 @@ extern kthread_t *zk_thread_create(const char *name, void (*func)(void *), #define kpreempt_disable() ((void)0) #define kpreempt_enable() ((void)0) -/* - * Mutexes - */ -typedef struct kmutex { - pthread_mutex_t m_lock; - pthread_t m_owner; -} kmutex_t; - -#define MUTEX_DEFAULT 0 -#define MUTEX_NOLOCKDEP MUTEX_DEFAULT -#define MUTEX_HELD(mp) pthread_equal((mp)->m_owner, pthread_self()) -#define MUTEX_NOT_HELD(mp) !MUTEX_HELD(mp) - -extern void mutex_init(kmutex_t *mp, char *name, int type, void *cookie); -extern void mutex_destroy(kmutex_t *mp); -extern void mutex_enter(kmutex_t *mp); -extern int mutex_enter_check_return(kmutex_t *mp); -extern void mutex_exit(kmutex_t *mp); -extern int mutex_tryenter(kmutex_t *mp); - -#define NESTED_SINGLE 1 -#define mutex_enter_nested(mp, class) mutex_enter(mp) -#define mutex_enter_interruptible(mp) mutex_enter_check_return(mp) /* * RW locks */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 98184340e664..d4649c2d5dd0 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -44,6 +44,7 @@ libspl_sys_HEADERS = \ %D%/sys/mhd.h \ %D%/sys/mkdev.h \ %D%/sys/mod.h \ + %D%/sys/mutex.h \ %D%/sys/policy.h \ %D%/sys/poll.h \ %D%/sys/priv.h \ diff --git a/lib/libspl/include/sys/mutex.h b/lib/libspl/include/sys/mutex.h new file mode 100644 index 000000000000..1da0e632d60f --- /dev/null +++ b/lib/libspl/include/sys/mutex.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_MUTEX_H +#define _SYS_MUTEX_H + +#include + +/* + * Mutexes + */ +typedef struct kmutex { + pthread_mutex_t m_lock; + pthread_t m_owner; +} kmutex_t; + +#define MUTEX_DEFAULT 0 +#define MUTEX_NOLOCKDEP MUTEX_DEFAULT +#define MUTEX_HELD(mp) pthread_equal((mp)->m_owner, pthread_self()) +#define MUTEX_NOT_HELD(mp) !MUTEX_HELD(mp) + +extern void mutex_init(kmutex_t *mp, char *name, int type, void *cookie); +extern void mutex_destroy(kmutex_t *mp); +extern void mutex_enter(kmutex_t *mp); +extern int mutex_enter_check_return(kmutex_t *mp); +extern void mutex_exit(kmutex_t *mp); +extern int mutex_tryenter(kmutex_t *mp); + +#define NESTED_SINGLE 1 +#define mutex_enter_nested(mp, class) mutex_enter(mp) +#define mutex_enter_interruptible(mp) mutex_enter_check_return(mp) + +#endif /* _SYS_MUTEX_H */ From 3e37ea85af2146db5fc6346262d235b0063afc3a Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 09:41:59 +1100 Subject: [PATCH 39/91] libspl: move mutex implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/mutex.c | 89 ++++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 56 -------------------------- 3 files changed, 90 insertions(+), 56 deletions(-) create mode 100644 lib/libspl/mutex.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index 0fd907d3011e..d03c61306835 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -19,6 +19,7 @@ libspl_la_SOURCES = \ %D%/getexecname.c \ %D%/list.c \ %D%/mkdirp.c \ + %D%/mutex.c \ %D%/page.c \ %D%/strlcat.c \ %D%/strlcpy.c \ diff --git a/lib/libspl/mutex.c b/lib/libspl/mutex.c new file mode 100644 index 000000000000..36e5bec396ed --- /dev/null +++ b/lib/libspl/mutex.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include +#include +#include +#include +#include + +/* + * ========================================================================= + * mutexes + * ========================================================================= + */ + +void +mutex_init(kmutex_t *mp, char *name, int type, void *cookie) +{ + (void) name, (void) type, (void) cookie; + VERIFY0(pthread_mutex_init(&mp->m_lock, NULL)); + memset(&mp->m_owner, 0, sizeof (pthread_t)); +} + +void +mutex_destroy(kmutex_t *mp) +{ + VERIFY0(pthread_mutex_destroy(&mp->m_lock)); +} + +void +mutex_enter(kmutex_t *mp) +{ + VERIFY0(pthread_mutex_lock(&mp->m_lock)); + mp->m_owner = pthread_self(); +} + +int +mutex_enter_check_return(kmutex_t *mp) +{ + int error = pthread_mutex_lock(&mp->m_lock); + if (error == 0) + mp->m_owner = pthread_self(); + return (error); +} + +int +mutex_tryenter(kmutex_t *mp) +{ + int error = pthread_mutex_trylock(&mp->m_lock); + if (error == 0) { + mp->m_owner = pthread_self(); + return (1); + } else { + VERIFY3S(error, ==, EBUSY); + return (0); + } +} + +void +mutex_exit(kmutex_t *mp) +{ + memset(&mp->m_owner, 0, sizeof (pthread_t)); + VERIFY0(pthread_mutex_unlock(&mp->m_lock)); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 452462a1700b..3c7637304a51 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -184,62 +184,6 @@ kstat_set_raw_ops(kstat_t *ksp, (void) ksp, (void) headers, (void) data, (void) addr; } -/* - * ========================================================================= - * mutexes - * ========================================================================= - */ - -void -mutex_init(kmutex_t *mp, char *name, int type, void *cookie) -{ - (void) name, (void) type, (void) cookie; - VERIFY0(pthread_mutex_init(&mp->m_lock, NULL)); - memset(&mp->m_owner, 0, sizeof (pthread_t)); -} - -void -mutex_destroy(kmutex_t *mp) -{ - VERIFY0(pthread_mutex_destroy(&mp->m_lock)); -} - -void -mutex_enter(kmutex_t *mp) -{ - VERIFY0(pthread_mutex_lock(&mp->m_lock)); - mp->m_owner = pthread_self(); -} - -int -mutex_enter_check_return(kmutex_t *mp) -{ - int error = pthread_mutex_lock(&mp->m_lock); - if (error == 0) - mp->m_owner = pthread_self(); - return (error); -} - -int -mutex_tryenter(kmutex_t *mp) -{ - int error = pthread_mutex_trylock(&mp->m_lock); - if (error == 0) { - mp->m_owner = pthread_self(); - return (1); - } else { - VERIFY3S(error, ==, EBUSY); - return (0); - } -} - -void -mutex_exit(kmutex_t *mp) -{ - memset(&mp->m_owner, 0, sizeof (pthread_t)); - VERIFY0(pthread_mutex_unlock(&mp->m_lock)); -} - /* * ========================================================================= * rwlocks From c7eb0a76332cb42b357ddc2714ac8d3ad1bac838 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 9 Aug 2025 09:51:43 +1000 Subject: [PATCH 40/91] libspl: move rwlock definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 30 +--------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/rwlock.h | 62 +++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 lib/libspl/include/sys/rwlock.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 17d3ed20ce21..d96113f26458 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -77,7 +77,6 @@ extern "C" { #include #else /* _KERNEL || _STANDALONE */ -#define _SYS_RWLOCK_H #define _SYS_CONDVAR_H #define _SYS_VNODE_H #define _SYS_VFS_H @@ -122,6 +121,7 @@ extern "C" { #include #include +#include #include #include @@ -253,34 +253,6 @@ extern kthread_t *zk_thread_create(const char *name, void (*func)(void *), #define kpreempt_disable() ((void)0) #define kpreempt_enable() ((void)0) -/* - * RW locks - */ -typedef struct krwlock { - pthread_rwlock_t rw_lock; - pthread_t rw_owner; - uint_t rw_readers; -} krwlock_t; - -typedef int krw_t; - -#define RW_READER 0 -#define RW_WRITER 1 -#define RW_DEFAULT RW_READER -#define RW_NOLOCKDEP RW_READER - -#define RW_READ_HELD(rw) ((rw)->rw_readers > 0) -#define RW_WRITE_HELD(rw) pthread_equal((rw)->rw_owner, pthread_self()) -#define RW_LOCK_HELD(rw) (RW_READ_HELD(rw) || RW_WRITE_HELD(rw)) - -extern void rw_init(krwlock_t *rwlp, char *name, int type, void *arg); -extern void rw_destroy(krwlock_t *rwlp); -extern void rw_enter(krwlock_t *rwlp, krw_t rw); -extern int rw_tryenter(krwlock_t *rwlp, krw_t rw); -extern int rw_tryupgrade(krwlock_t *rwlp); -extern void rw_exit(krwlock_t *rwlp); -#define rw_downgrade(rwlp) do { } while (0) - /* * Credentials */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index d4649c2d5dd0..f490bb9f7e6d 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -49,6 +49,7 @@ libspl_sys_HEADERS = \ %D%/sys/poll.h \ %D%/sys/priv.h \ %D%/sys/processor.h \ + %D%/sys/rwlock.h \ %D%/sys/simd.h \ %D%/sys/stack.h \ %D%/sys/stdtypes.h \ diff --git a/lib/libspl/include/sys/rwlock.h b/lib/libspl/include/sys/rwlock.h new file mode 100644 index 000000000000..9f82f270d939 --- /dev/null +++ b/lib/libspl/include/sys/rwlock.h @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_RWLOCK_H +#define _SYS_RWLOCK_H + +#include + +/* + * RW locks + */ +typedef struct krwlock { + pthread_rwlock_t rw_lock; + pthread_t rw_owner; + uint_t rw_readers; +} krwlock_t; + +typedef int krw_t; + +#define RW_READER 0 +#define RW_WRITER 1 +#define RW_DEFAULT RW_READER +#define RW_NOLOCKDEP RW_READER + +#define RW_READ_HELD(rw) ((rw)->rw_readers > 0) +#define RW_WRITE_HELD(rw) pthread_equal((rw)->rw_owner, pthread_self()) +#define RW_LOCK_HELD(rw) (RW_READ_HELD(rw) || RW_WRITE_HELD(rw)) + +extern void rw_init(krwlock_t *rwlp, char *name, int type, void *arg); +extern void rw_destroy(krwlock_t *rwlp); +extern void rw_enter(krwlock_t *rwlp, krw_t rw); +extern int rw_tryenter(krwlock_t *rwlp, krw_t rw); +extern int rw_tryupgrade(krwlock_t *rwlp); +extern void rw_exit(krwlock_t *rwlp); +#define rw_downgrade(rwlp) do { } while (0) + +#endif /* _SYS_RWLOCK_H */ From 40ddba8256b4f9c21e06326b6022f69c148e8cc9 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 09:56:32 +1100 Subject: [PATCH 41/91] libspl: move rwlock implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/rwlock.c | 108 +++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 75 ---------------------------- 3 files changed, 109 insertions(+), 75 deletions(-) create mode 100644 lib/libspl/rwlock.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index d03c61306835..3611d03dfb65 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -21,6 +21,7 @@ libspl_la_SOURCES = \ %D%/mkdirp.c \ %D%/mutex.c \ %D%/page.c \ + %D%/rwlock.c \ %D%/strlcat.c \ %D%/strlcpy.c \ %D%/timestamp.c \ diff --git a/lib/libspl/rwlock.c b/lib/libspl/rwlock.c new file mode 100644 index 000000000000..3712829ef594 --- /dev/null +++ b/lib/libspl/rwlock.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include +#include +#include +#include +#include + +/* + * ========================================================================= + * rwlocks + * ========================================================================= + */ + +void +rw_init(krwlock_t *rwlp, char *name, int type, void *arg) +{ + (void) name, (void) type, (void) arg; + VERIFY0(pthread_rwlock_init(&rwlp->rw_lock, NULL)); + rwlp->rw_readers = 0; + rwlp->rw_owner = 0; +} + +void +rw_destroy(krwlock_t *rwlp) +{ + VERIFY0(pthread_rwlock_destroy(&rwlp->rw_lock)); +} + +void +rw_enter(krwlock_t *rwlp, krw_t rw) +{ + if (rw == RW_READER) { + VERIFY0(pthread_rwlock_rdlock(&rwlp->rw_lock)); + atomic_inc_uint(&rwlp->rw_readers); + } else { + VERIFY0(pthread_rwlock_wrlock(&rwlp->rw_lock)); + rwlp->rw_owner = pthread_self(); + } +} + +void +rw_exit(krwlock_t *rwlp) +{ + if (RW_READ_HELD(rwlp)) + atomic_dec_uint(&rwlp->rw_readers); + else + rwlp->rw_owner = 0; + + VERIFY0(pthread_rwlock_unlock(&rwlp->rw_lock)); +} + +int +rw_tryenter(krwlock_t *rwlp, krw_t rw) +{ + int error; + + if (rw == RW_READER) + error = pthread_rwlock_tryrdlock(&rwlp->rw_lock); + else + error = pthread_rwlock_trywrlock(&rwlp->rw_lock); + + if (error == 0) { + if (rw == RW_READER) + atomic_inc_uint(&rwlp->rw_readers); + else + rwlp->rw_owner = pthread_self(); + + return (1); + } + + VERIFY3S(error, ==, EBUSY); + + return (0); +} + +int +rw_tryupgrade(krwlock_t *rwlp) +{ + (void) rwlp; + return (0); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 3c7637304a51..dc5d6e70d0ab 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -184,74 +184,6 @@ kstat_set_raw_ops(kstat_t *ksp, (void) ksp, (void) headers, (void) data, (void) addr; } -/* - * ========================================================================= - * rwlocks - * ========================================================================= - */ - -void -rw_init(krwlock_t *rwlp, char *name, int type, void *arg) -{ - (void) name, (void) type, (void) arg; - VERIFY0(pthread_rwlock_init(&rwlp->rw_lock, NULL)); - rwlp->rw_readers = 0; - rwlp->rw_owner = 0; -} - -void -rw_destroy(krwlock_t *rwlp) -{ - VERIFY0(pthread_rwlock_destroy(&rwlp->rw_lock)); -} - -void -rw_enter(krwlock_t *rwlp, krw_t rw) -{ - if (rw == RW_READER) { - VERIFY0(pthread_rwlock_rdlock(&rwlp->rw_lock)); - atomic_inc_uint(&rwlp->rw_readers); - } else { - VERIFY0(pthread_rwlock_wrlock(&rwlp->rw_lock)); - rwlp->rw_owner = pthread_self(); - } -} - -void -rw_exit(krwlock_t *rwlp) -{ - if (RW_READ_HELD(rwlp)) - atomic_dec_uint(&rwlp->rw_readers); - else - rwlp->rw_owner = 0; - - VERIFY0(pthread_rwlock_unlock(&rwlp->rw_lock)); -} - -int -rw_tryenter(krwlock_t *rwlp, krw_t rw) -{ - int error; - - if (rw == RW_READER) - error = pthread_rwlock_tryrdlock(&rwlp->rw_lock); - else - error = pthread_rwlock_trywrlock(&rwlp->rw_lock); - - if (error == 0) { - if (rw == RW_READER) - atomic_inc_uint(&rwlp->rw_readers); - else - rwlp->rw_owner = pthread_self(); - - return (1); - } - - VERIFY3S(error, ==, EBUSY); - - return (0); -} - uint32_t zone_get_hostid(void *zonep) { @@ -262,13 +194,6 @@ zone_get_hostid(void *zonep) return (hostid); } -int -rw_tryupgrade(krwlock_t *rwlp) -{ - (void) rwlp; - return (0); -} - /* * ========================================================================= * condition variables From a9f37333762f9cdee6332b7681fce5ae31725e0d Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 9 Aug 2025 09:51:43 +1000 Subject: [PATCH 42/91] libspl: move condvar definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 31 +-------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/condvar.h | 65 ++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 30 deletions(-) create mode 100644 lib/libspl/include/sys/condvar.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index d96113f26458..564a8c4894be 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -77,7 +77,6 @@ extern "C" { #include #else /* _KERNEL || _STANDALONE */ -#define _SYS_CONDVAR_H #define _SYS_VNODE_H #define _SYS_VFS_H #define _SYS_SUNDDI_H @@ -122,6 +121,7 @@ extern "C" { #include #include +#include #include #include @@ -262,35 +262,6 @@ extern gid_t crgetgid(cred_t *cr); extern int crgetngroups(cred_t *cr); extern gid_t *crgetgroups(cred_t *cr); -/* - * Condition variables - */ -typedef pthread_cond_t kcondvar_t; - -#define CV_DEFAULT 0 -#define CALLOUT_FLAG_ABSOLUTE 0x2 - -extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg); -extern void cv_destroy(kcondvar_t *cv); -extern void cv_wait(kcondvar_t *cv, kmutex_t *mp); -extern int cv_wait_sig(kcondvar_t *cv, kmutex_t *mp); -extern int cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime); -extern int cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, - hrtime_t res, int flag); -extern void cv_signal(kcondvar_t *cv); -extern void cv_broadcast(kcondvar_t *cv); - -#define cv_timedwait_io(cv, mp, at) cv_timedwait(cv, mp, at) -#define cv_timedwait_idle(cv, mp, at) cv_timedwait(cv, mp, at) -#define cv_timedwait_sig(cv, mp, at) cv_timedwait(cv, mp, at) -#define cv_wait_io(cv, mp) cv_wait(cv, mp) -#define cv_wait_idle(cv, mp) cv_wait(cv, mp) -#define cv_wait_io_sig(cv, mp) cv_wait_sig(cv, mp) -#define cv_timedwait_sig_hires(cv, mp, t, r, f) \ - cv_timedwait_hires(cv, mp, t, r, f) -#define cv_timedwait_idle_hires(cv, mp, t, r, f) \ - cv_timedwait_hires(cv, mp, t, r, f) - /* * Thread-specific data */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index f490bb9f7e6d..e2c5f89acf56 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -30,6 +30,7 @@ libspl_sys_HEADERS = \ %D%/sys/backtrace.h \ %D%/sys/callb.h \ %D%/sys/cmn_err.h \ + %D%/sys/condvar.h \ %D%/sys/cred.h \ %D%/sys/debug.h \ %D%/sys/dkio.h \ diff --git a/lib/libspl/include/sys/condvar.h b/lib/libspl/include/sys/condvar.h new file mode 100644 index 000000000000..9a05c41d1510 --- /dev/null +++ b/lib/libspl/include/sys/condvar.h @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_CONDVAR_H +#define _SYS_CONDVAR_H + +#include +#include +#include + +/* + * Condition variables + */ +typedef pthread_cond_t kcondvar_t; + +#define CV_DEFAULT 0 +#define CALLOUT_FLAG_ABSOLUTE 0x2 + +extern void cv_init(kcondvar_t *cv, char *name, int type, void *arg); +extern void cv_destroy(kcondvar_t *cv); +extern void cv_wait(kcondvar_t *cv, kmutex_t *mp); +extern int cv_wait_sig(kcondvar_t *cv, kmutex_t *mp); +extern int cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime); +extern int cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, + hrtime_t res, int flag); +extern void cv_signal(kcondvar_t *cv); +extern void cv_broadcast(kcondvar_t *cv); + +#define cv_timedwait_io(cv, mp, at) cv_timedwait(cv, mp, at) +#define cv_timedwait_idle(cv, mp, at) cv_timedwait(cv, mp, at) +#define cv_timedwait_sig(cv, mp, at) cv_timedwait(cv, mp, at) +#define cv_wait_io(cv, mp) cv_wait(cv, mp) +#define cv_wait_idle(cv, mp) cv_wait(cv, mp) +#define cv_wait_io_sig(cv, mp) cv_wait_sig(cv, mp) +#define cv_timedwait_sig_hires(cv, mp, t, r, f) \ + cv_timedwait_hires(cv, mp, t, r, f) +#define cv_timedwait_idle_hires(cv, mp, t, r, f) \ + cv_timedwait_hires(cv, mp, t, r, f) + +#endif /* _SYS_CONDVAR_H */ From e7a856d954b86b0dd6e0c20febd452710f2d071e Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 10:17:08 +1100 Subject: [PATCH 43/91] libspl: move condvar implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/condvar.c | 153 +++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 119 -------------------------------- 3 files changed, 154 insertions(+), 119 deletions(-) create mode 100644 lib/libspl/condvar.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index 3611d03dfb65..badc8ffcc568 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -16,6 +16,7 @@ libspl_assert_la_SOURCES = \ libspl_la_SOURCES = \ %D%/libspl_impl.h \ %D%/atomic.c \ + %D%/condvar.c \ %D%/getexecname.c \ %D%/list.c \ %D%/mkdirp.c \ diff --git a/lib/libspl/condvar.c b/lib/libspl/condvar.c new file mode 100644 index 000000000000..3d70fe152089 --- /dev/null +++ b/lib/libspl/condvar.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include +#include +#include +#include +#include +#include + +/* + * ========================================================================= + * condition variables + * ========================================================================= + */ + +void +cv_init(kcondvar_t *cv, char *name, int type, void *arg) +{ + (void) name, (void) type, (void) arg; + VERIFY0(pthread_cond_init(cv, NULL)); +} + +void +cv_destroy(kcondvar_t *cv) +{ + VERIFY0(pthread_cond_destroy(cv)); +} + +void +cv_wait(kcondvar_t *cv, kmutex_t *mp) +{ + memset(&mp->m_owner, 0, sizeof (pthread_t)); + VERIFY0(pthread_cond_wait(cv, &mp->m_lock)); + mp->m_owner = pthread_self(); +} + +int +cv_wait_sig(kcondvar_t *cv, kmutex_t *mp) +{ + cv_wait(cv, mp); + return (1); +} + +int +cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime) +{ + int error; + struct timeval tv; + struct timespec ts; + clock_t delta; + + delta = abstime - ddi_get_lbolt(); + if (delta <= 0) + return (-1); + + VERIFY0(gettimeofday(&tv, NULL)); + + ts.tv_sec = tv.tv_sec + delta / hz; + ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % hz) * (NANOSEC / hz); + if (ts.tv_nsec >= NANOSEC) { + ts.tv_sec++; + ts.tv_nsec -= NANOSEC; + } + + memset(&mp->m_owner, 0, sizeof (pthread_t)); + error = pthread_cond_timedwait(cv, &mp->m_lock, &ts); + mp->m_owner = pthread_self(); + + if (error == ETIMEDOUT) + return (-1); + + VERIFY0(error); + + return (1); +} + +int +cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res, + int flag) +{ + (void) res; + int error; + struct timeval tv; + struct timespec ts; + hrtime_t delta; + + ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE); + + delta = tim; + if (flag & CALLOUT_FLAG_ABSOLUTE) + delta -= gethrtime(); + + if (delta <= 0) + return (-1); + + VERIFY0(gettimeofday(&tv, NULL)); + + ts.tv_sec = tv.tv_sec + delta / NANOSEC; + ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % NANOSEC); + if (ts.tv_nsec >= NANOSEC) { + ts.tv_sec++; + ts.tv_nsec -= NANOSEC; + } + + memset(&mp->m_owner, 0, sizeof (pthread_t)); + error = pthread_cond_timedwait(cv, &mp->m_lock, &ts); + mp->m_owner = pthread_self(); + + if (error == ETIMEDOUT) + return (-1); + + VERIFY0(error); + + return (1); +} + +void +cv_signal(kcondvar_t *cv) +{ + VERIFY0(pthread_cond_signal(cv)); +} + +void +cv_broadcast(kcondvar_t *cv) +{ + VERIFY0(pthread_cond_broadcast(cv)); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index dc5d6e70d0ab..9ab704a28f58 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -194,125 +194,6 @@ zone_get_hostid(void *zonep) return (hostid); } -/* - * ========================================================================= - * condition variables - * ========================================================================= - */ - -void -cv_init(kcondvar_t *cv, char *name, int type, void *arg) -{ - (void) name, (void) type, (void) arg; - VERIFY0(pthread_cond_init(cv, NULL)); -} - -void -cv_destroy(kcondvar_t *cv) -{ - VERIFY0(pthread_cond_destroy(cv)); -} - -void -cv_wait(kcondvar_t *cv, kmutex_t *mp) -{ - memset(&mp->m_owner, 0, sizeof (pthread_t)); - VERIFY0(pthread_cond_wait(cv, &mp->m_lock)); - mp->m_owner = pthread_self(); -} - -int -cv_wait_sig(kcondvar_t *cv, kmutex_t *mp) -{ - cv_wait(cv, mp); - return (1); -} - -int -cv_timedwait(kcondvar_t *cv, kmutex_t *mp, clock_t abstime) -{ - int error; - struct timeval tv; - struct timespec ts; - clock_t delta; - - delta = abstime - ddi_get_lbolt(); - if (delta <= 0) - return (-1); - - VERIFY0(gettimeofday(&tv, NULL)); - - ts.tv_sec = tv.tv_sec + delta / hz; - ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % hz) * (NANOSEC / hz); - if (ts.tv_nsec >= NANOSEC) { - ts.tv_sec++; - ts.tv_nsec -= NANOSEC; - } - - memset(&mp->m_owner, 0, sizeof (pthread_t)); - error = pthread_cond_timedwait(cv, &mp->m_lock, &ts); - mp->m_owner = pthread_self(); - - if (error == ETIMEDOUT) - return (-1); - - VERIFY0(error); - - return (1); -} - -int -cv_timedwait_hires(kcondvar_t *cv, kmutex_t *mp, hrtime_t tim, hrtime_t res, - int flag) -{ - (void) res; - int error; - struct timeval tv; - struct timespec ts; - hrtime_t delta; - - ASSERT(flag == 0 || flag == CALLOUT_FLAG_ABSOLUTE); - - delta = tim; - if (flag & CALLOUT_FLAG_ABSOLUTE) - delta -= gethrtime(); - - if (delta <= 0) - return (-1); - - VERIFY0(gettimeofday(&tv, NULL)); - - ts.tv_sec = tv.tv_sec + delta / NANOSEC; - ts.tv_nsec = tv.tv_usec * NSEC_PER_USEC + (delta % NANOSEC); - if (ts.tv_nsec >= NANOSEC) { - ts.tv_sec++; - ts.tv_nsec -= NANOSEC; - } - - memset(&mp->m_owner, 0, sizeof (pthread_t)); - error = pthread_cond_timedwait(cv, &mp->m_lock, &ts); - mp->m_owner = pthread_self(); - - if (error == ETIMEDOUT) - return (-1); - - VERIFY0(error); - - return (1); -} - -void -cv_signal(kcondvar_t *cv) -{ - VERIFY0(pthread_cond_signal(cv)); -} - -void -cv_broadcast(kcondvar_t *cv) -{ - VERIFY0(pthread_cond_broadcast(cv)); -} - /* * ========================================================================= * procfs list From 7234d69748a2b5a3d151f1c2acaf69afe04b7147 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 9 Aug 2025 10:44:05 +1000 Subject: [PATCH 44/91] libspl: move cmn_err definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 32 +------------------------------- lib/libspl/include/sys/cmn_err.h | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 564a8c4894be..25e00f502d0c 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -122,6 +122,7 @@ extern "C" { #include #include #include +#include #include #include @@ -134,37 +135,6 @@ extern "C" { #define likely(x) __builtin_expect((x), 1) #define unlikely(x) __builtin_expect((x), 0) -/* - * Debugging - */ - -/* - * Note that we are not using the debugging levels. - */ - -#define CE_CONT 0 /* continuation */ -#define CE_NOTE 1 /* notice */ -#define CE_WARN 2 /* warning */ -#define CE_PANIC 3 /* panic */ -#define CE_IGNORE 4 /* print nothing */ - -/* - * ZFS debugging - */ - -extern void dprintf_setup(int *argc, char **argv); - -extern void cmn_err(int, const char *, ...) - __attribute__((format(printf, 2, 3))); -extern void vcmn_err(int, const char *, va_list) - __attribute__((format(printf, 2, 0))); -extern void panic(const char *, ...) - __attribute__((format(printf, 1, 2), noreturn)); -extern void vpanic(const char *, va_list) - __attribute__((format(printf, 1, 0), noreturn)); - -#define fm_panic panic - /* * DTrace SDT probes have different signatures in userland than they do in * the kernel. If they're being used in kernel code, re-define them out of diff --git a/lib/libspl/include/sys/cmn_err.h b/lib/libspl/include/sys/cmn_err.h index 32930adaeffa..5e7136f7fdc2 100644 --- a/lib/libspl/include/sys/cmn_err.h +++ b/lib/libspl/include/sys/cmn_err.h @@ -62,4 +62,31 @@ do { \ } \ } while (0) +/* + * Note that we are not using the debugging levels. + */ + +#define CE_CONT 0 /* continuation */ +#define CE_NOTE 1 /* notice */ +#define CE_WARN 2 /* warning */ +#define CE_PANIC 3 /* panic */ +#define CE_IGNORE 4 /* print nothing */ + +/* + * ZFS debugging + */ + +extern void dprintf_setup(int *argc, char **argv); + +extern void cmn_err(int, const char *, ...) + __attribute__((format(printf, 2, 3))); +extern void vcmn_err(int, const char *, va_list) + __attribute__((format(printf, 2, 0))); +extern void panic(const char *, ...) + __attribute__((format(printf, 1, 2), noreturn)); +extern void vpanic(const char *, va_list) + __attribute__((format(printf, 1, 0), noreturn)); + +#define fm_panic panic + #endif From 21ae59a53bc80862db0a89944b0493eb6d4923c9 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 25 Aug 2025 21:45:35 +1000 Subject: [PATCH 45/91] libspl: move thread definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 49 +------------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/thread.h | 81 +++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 48 deletions(-) create mode 100644 lib/libspl/include/sys/thread.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 25e00f502d0c..62c3487c4df6 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -90,7 +90,6 @@ extern "C" { #include #include #include -#include #include #include #include @@ -123,6 +122,7 @@ extern "C" { #include #include #include +#include #include #include @@ -176,53 +176,6 @@ extern "C" { #endif /* DTRACE_PROBE4 */ #define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) -/* - * Threads. - */ -typedef pthread_t kthread_t; - -#define TS_RUN 0x00000002 -#define TS_JOINABLE 0x00000004 - -#define curthread ((void *)(uintptr_t)pthread_self()) -#define getcomm() "unknown" - -#define thread_create_named(name, stk, stksize, func, arg, len, \ - pp, state, pri) \ - zk_thread_create(name, func, arg, stksize, state) -#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \ - zk_thread_create(#func, func, arg, stksize, state) -#define thread_exit() pthread_exit(NULL) -#define thread_join(t) pthread_join((pthread_t)(t), NULL) - -#define newproc(f, a, cid, pri, ctp, pid) (ENOSYS) -/* - * Check if the current thread is a memory reclaim thread. - * Always returns false in userspace (no memory reclaim thread). - */ -#define current_is_reclaim_thread() (0) - -/* in libzpool, p0 exists only to have its address taken */ -typedef struct proc { - uintptr_t this_is_never_used_dont_dereference_it; -} proc_t; - -extern struct proc p0; -#define curproc (&p0) - -#define PS_NONE -1 - -extern kthread_t *zk_thread_create(const char *name, void (*func)(void *), - void *arg, size_t stksize, int state); - -#define issig() (FALSE) - -#define KPREEMPT_SYNC (-1) - -#define kpreempt(x) sched_yield() -#define kpreempt_disable() ((void)0) -#define kpreempt_enable() ((void)0) - /* * Credentials */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index e2c5f89acf56..cc43493b1fa1 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -57,6 +57,7 @@ libspl_sys_HEADERS = \ %D%/sys/string.h \ %D%/sys/sunddi.h \ %D%/sys/systeminfo.h \ + %D%/sys/thread.h \ %D%/sys/time.h \ %D%/sys/timer.h \ %D%/sys/trace_spl.h \ diff --git a/lib/libspl/include/sys/thread.h b/lib/libspl/include/sys/thread.h new file mode 100644 index 000000000000..a5108a03d45f --- /dev/null +++ b/lib/libspl/include/sys/thread.h @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_THREAD_H +#define _SYS_THREAD_H + +#include + +/* + * Threads. + */ +typedef pthread_t kthread_t; + +#define TS_RUN 0x00000002 +#define TS_JOINABLE 0x00000004 + +#define curthread ((void *)(uintptr_t)pthread_self()) +#define getcomm() "unknown" + +#define thread_create_named(name, stk, stksize, func, arg, len, \ + pp, state, pri) \ + zk_thread_create(name, func, arg, stksize, state) +#define thread_create(stk, stksize, func, arg, len, pp, state, pri) \ + zk_thread_create(#func, func, arg, stksize, state) +#define thread_exit() pthread_exit(NULL) +#define thread_join(t) pthread_join((pthread_t)(t), NULL) + +#define newproc(f, a, cid, pri, ctp, pid) (ENOSYS) +/* + * Check if the current thread is a memory reclaim thread. + * Always returns false in userspace (no memory reclaim thread). + */ +#define current_is_reclaim_thread() (0) + +/* in libzpool, p0 exists only to have its address taken */ +typedef struct proc { + uintptr_t this_is_never_used_dont_dereference_it; +} proc_t; + +extern struct proc p0; +#define curproc (&p0) + +#define PS_NONE -1 + +extern kthread_t *zk_thread_create(const char *name, void (*func)(void *), + void *arg, size_t stksize, int state); + +#define issig() (FALSE) + +#define KPREEMPT_SYNC (-1) + +#define kpreempt(x) sched_yield() +#define kpreempt_disable() ((void)0) +#define kpreempt_enable() ((void)0) + +#endif /* _SYS_THREAD_H */ From 0c60920d0989fd36e04d8b3210038a93848022a9 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 13:30:12 +1100 Subject: [PATCH 46/91] libspl: move thread implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/thread.c | 118 +++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 86 ------------------------------ 3 files changed, 119 insertions(+), 86 deletions(-) create mode 100644 lib/libspl/thread.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index badc8ffcc568..10920ae8c606 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -25,6 +25,7 @@ libspl_la_SOURCES = \ %D%/rwlock.c \ %D%/strlcat.c \ %D%/strlcpy.c \ + %D%/thread.c \ %D%/timestamp.c \ %D%/tunables.c \ %D%/include/sys/list.h \ diff --git a/lib/libspl/thread.c b/lib/libspl/thread.c new file mode 100644 index 000000000000..17c36c754621 --- /dev/null +++ b/lib/libspl/thread.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include +#include +#include +#include + +/* this only exists to have its address taken */ +struct proc p0; + +/* + * ========================================================================= + * threads + * ========================================================================= + * + * TS_STACK_MIN is dictated by the minimum allowed pthread stack size. While + * TS_STACK_MAX is somewhat arbitrary, it was selected to be large enough for + * the expected stack depth while small enough to avoid exhausting address + * space with high thread counts. + */ +#define TS_STACK_MIN MAX(PTHREAD_STACK_MIN, 32768) +#define TS_STACK_MAX (256 * 1024) + +struct zk_thread_wrapper { + void (*func)(void *); + void *arg; +}; + +static void * +zk_thread_wrapper(void *arg) +{ + struct zk_thread_wrapper ztw; + memcpy(&ztw, arg, sizeof (ztw)); + free(arg); + ztw.func(ztw.arg); + return (NULL); +} + +kthread_t * +zk_thread_create(const char *name, void (*func)(void *), void *arg, + size_t stksize, int state) +{ + pthread_attr_t attr; + pthread_t tid; + char *stkstr; + struct zk_thread_wrapper *ztw; + int detachstate = PTHREAD_CREATE_DETACHED; + + VERIFY0(pthread_attr_init(&attr)); + + if (state & TS_JOINABLE) + detachstate = PTHREAD_CREATE_JOINABLE; + + VERIFY0(pthread_attr_setdetachstate(&attr, detachstate)); + + /* + * We allow the default stack size in user space to be specified by + * setting the ZFS_STACK_SIZE environment variable. This allows us + * the convenience of observing and debugging stack overruns in + * user space. Explicitly specified stack sizes will be honored. + * The usage of ZFS_STACK_SIZE is discussed further in the + * ENVIRONMENT VARIABLES sections of the ztest(1) man page. + */ + if (stksize == 0) { + stkstr = getenv("ZFS_STACK_SIZE"); + + if (stkstr == NULL) + stksize = TS_STACK_MAX; + else + stksize = MAX(atoi(stkstr), TS_STACK_MIN); + } + + VERIFY3S(stksize, >, 0); + stksize = P2ROUNDUP(MAX(stksize, TS_STACK_MIN), PAGESIZE); + + /* + * If this ever fails, it may be because the stack size is not a + * multiple of system page size. + */ + VERIFY0(pthread_attr_setstacksize(&attr, stksize)); + VERIFY0(pthread_attr_setguardsize(&attr, PAGESIZE)); + + VERIFY(ztw = malloc(sizeof (*ztw))); + ztw->func = func; + ztw->arg = arg; + VERIFY0(pthread_create(&tid, &attr, zk_thread_wrapper, ztw)); + VERIFY0(pthread_attr_destroy(&attr)); + + pthread_setname_np(tid, name); + + return ((void *)(uintptr_t)tid); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 9ab704a28f58..704c8faff8d5 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -63,92 +63,6 @@ struct utsname hw_utsname; /* If set, all blocks read will be copied to the specified directory. */ char *vn_dumpdir = NULL; -/* this only exists to have its address taken */ -struct proc p0; - -/* - * ========================================================================= - * threads - * ========================================================================= - * - * TS_STACK_MIN is dictated by the minimum allowed pthread stack size. While - * TS_STACK_MAX is somewhat arbitrary, it was selected to be large enough for - * the expected stack depth while small enough to avoid exhausting address - * space with high thread counts. - */ -#define TS_STACK_MIN MAX(PTHREAD_STACK_MIN, 32768) -#define TS_STACK_MAX (256 * 1024) - -struct zk_thread_wrapper { - void (*func)(void *); - void *arg; -}; - -static void * -zk_thread_wrapper(void *arg) -{ - struct zk_thread_wrapper ztw; - memcpy(&ztw, arg, sizeof (ztw)); - free(arg); - ztw.func(ztw.arg); - return (NULL); -} - -kthread_t * -zk_thread_create(const char *name, void (*func)(void *), void *arg, - size_t stksize, int state) -{ - pthread_attr_t attr; - pthread_t tid; - char *stkstr; - struct zk_thread_wrapper *ztw; - int detachstate = PTHREAD_CREATE_DETACHED; - - VERIFY0(pthread_attr_init(&attr)); - - if (state & TS_JOINABLE) - detachstate = PTHREAD_CREATE_JOINABLE; - - VERIFY0(pthread_attr_setdetachstate(&attr, detachstate)); - - /* - * We allow the default stack size in user space to be specified by - * setting the ZFS_STACK_SIZE environment variable. This allows us - * the convenience of observing and debugging stack overruns in - * user space. Explicitly specified stack sizes will be honored. - * The usage of ZFS_STACK_SIZE is discussed further in the - * ENVIRONMENT VARIABLES sections of the ztest(1) man page. - */ - if (stksize == 0) { - stkstr = getenv("ZFS_STACK_SIZE"); - - if (stkstr == NULL) - stksize = TS_STACK_MAX; - else - stksize = MAX(atoi(stkstr), TS_STACK_MIN); - } - - VERIFY3S(stksize, >, 0); - stksize = P2ROUNDUP(MAX(stksize, TS_STACK_MIN), PAGESIZE); - - /* - * If this ever fails, it may be because the stack size is not a - * multiple of system page size. - */ - VERIFY0(pthread_attr_setstacksize(&attr, stksize)); - VERIFY0(pthread_attr_setguardsize(&attr, PAGESIZE)); - - VERIFY(ztw = malloc(sizeof (*ztw))); - ztw->func = func; - ztw->arg = arg; - VERIFY0(pthread_create(&tid, &attr, zk_thread_wrapper, ztw)); - VERIFY0(pthread_attr_destroy(&attr)); - - pthread_setname_np(tid, name); - - return ((void *)(uintptr_t)tid); -} - /* * ========================================================================= * kstats From a2e10ebfd332b2716473390f7c2868e76e9ecd4e Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 16 Aug 2025 20:23:25 +1000 Subject: [PATCH 47/91] libspl: move taskq definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 79 +--------------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/taskq.h | 116 +++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 78 deletions(-) create mode 100644 lib/libspl/include/sys/taskq.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 62c3487c4df6..6f7ae6b069ef 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -123,6 +123,7 @@ extern "C" { #include #include #include +#include #include #include @@ -280,84 +281,6 @@ typedef enum kmem_cbrc { KMEM_CBRC_DONT_KNOW } kmem_cbrc_t; -/* - * Task queues - */ - -#define TASKQ_NAMELEN 31 - -typedef uintptr_t taskqid_t; -typedef void (task_func_t)(void *); - -typedef struct taskq_ent { - struct taskq_ent *tqent_next; - struct taskq_ent *tqent_prev; - task_func_t *tqent_func; - void *tqent_arg; - uintptr_t tqent_flags; -} taskq_ent_t; - -typedef struct taskq { - char tq_name[TASKQ_NAMELEN + 1]; - kmutex_t tq_lock; - krwlock_t tq_threadlock; - kcondvar_t tq_dispatch_cv; - kcondvar_t tq_wait_cv; - kthread_t **tq_threadlist; - int tq_flags; - int tq_active; - int tq_nthreads; - int tq_nalloc; - int tq_minalloc; - int tq_maxalloc; - kcondvar_t tq_maxalloc_cv; - int tq_maxalloc_wait; - taskq_ent_t *tq_freelist; - taskq_ent_t tq_task; -} taskq_t; - -#define TQENT_FLAG_PREALLOC 0x1 /* taskq_dispatch_ent used */ - -#define TASKQ_PREPOPULATE 0x0001 -#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */ -#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */ -#define TASKQ_THREADS_CPU_PCT 0x0008 /* Scale # threads by # cpus */ -#define TASKQ_DC_BATCH 0x0010 /* Mark threads as batch */ - -#define TQ_SLEEP KM_SLEEP /* Can block for memory */ -#define TQ_NOSLEEP KM_NOSLEEP /* cannot block for memory; may fail */ -#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */ -#define TQ_FRONT 0x08 /* Queue in front */ - -#define TASKQID_INVALID ((taskqid_t)0) - -extern taskq_t *system_taskq; -extern taskq_t *system_delay_taskq; - -extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t); -extern taskq_t *taskq_create_synced(const char *, int, pri_t, int, int, uint_t, - kthread_t ***); -#define taskq_create_proc(a, b, c, d, e, p, f) \ - (taskq_create(a, b, c, d, e, f)) -#define taskq_create_sysdc(a, b, d, e, p, dc, f) \ - ((void) sizeof (dc), taskq_create(a, b, maxclsyspri, d, e, f)) -extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t); -extern taskqid_t taskq_dispatch_delay(taskq_t *, task_func_t, void *, uint_t, - clock_t); -extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, - taskq_ent_t *); -extern int taskq_empty_ent(taskq_ent_t *); -extern void taskq_init_ent(taskq_ent_t *); -extern void taskq_destroy(taskq_t *); -extern void taskq_wait(taskq_t *); -extern void taskq_wait_id(taskq_t *, taskqid_t); -extern void taskq_wait_outstanding(taskq_t *, taskqid_t); -extern int taskq_member(taskq_t *, kthread_t *); -extern taskq_t *taskq_of_curthread(void); -extern int taskq_cancel_id(taskq_t *, taskqid_t); -extern void system_taskq_init(void); -extern void system_taskq_fini(void); - #define XVA_MAPSIZE 3 #define XVA_MAGIC 0x78766174 diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index cc43493b1fa1..7d5e1b7b3f66 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -58,6 +58,7 @@ libspl_sys_HEADERS = \ %D%/sys/sunddi.h \ %D%/sys/systeminfo.h \ %D%/sys/thread.h \ + %D%/sys/taskq.h \ %D%/sys/time.h \ %D%/sys/timer.h \ %D%/sys/trace_spl.h \ diff --git a/lib/libspl/include/sys/taskq.h b/lib/libspl/include/sys/taskq.h new file mode 100644 index 000000000000..63238734b4fd --- /dev/null +++ b/lib/libspl/include/sys/taskq.h @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_TASKQ_H +#define _SYS_TASKQ_H + +#include +#include +#include +#include +#include + +/* + * Task queues + */ + +#define TASKQ_NAMELEN 31 + +typedef uintptr_t taskqid_t; +typedef void (task_func_t)(void *); + +typedef struct taskq_ent { + struct taskq_ent *tqent_next; + struct taskq_ent *tqent_prev; + task_func_t *tqent_func; + void *tqent_arg; + uintptr_t tqent_flags; +} taskq_ent_t; + +typedef struct taskq { + char tq_name[TASKQ_NAMELEN + 1]; + kmutex_t tq_lock; + krwlock_t tq_threadlock; + kcondvar_t tq_dispatch_cv; + kcondvar_t tq_wait_cv; + kthread_t **tq_threadlist; + int tq_flags; + int tq_active; + int tq_nthreads; + int tq_nalloc; + int tq_minalloc; + int tq_maxalloc; + kcondvar_t tq_maxalloc_cv; + int tq_maxalloc_wait; + taskq_ent_t *tq_freelist; + taskq_ent_t tq_task; +} taskq_t; + +#define TQENT_FLAG_PREALLOC 0x1 /* taskq_dispatch_ent used */ + +#define TASKQ_PREPOPULATE 0x0001 +#define TASKQ_CPR_SAFE 0x0002 /* Use CPR safe protocol */ +#define TASKQ_DYNAMIC 0x0004 /* Use dynamic thread scheduling */ +#define TASKQ_THREADS_CPU_PCT 0x0008 /* Scale # threads by # cpus */ +#define TASKQ_DC_BATCH 0x0010 /* Mark threads as batch */ + +#define TQ_SLEEP KM_SLEEP /* Can block for memory */ +#define TQ_NOSLEEP KM_NOSLEEP /* cannot block for memory; may fail */ +#define TQ_NOQUEUE 0x02 /* Do not enqueue if can't dispatch */ +#define TQ_FRONT 0x08 /* Queue in front */ + +#define TASKQID_INVALID ((taskqid_t)0) + +extern taskq_t *system_taskq; +extern taskq_t *system_delay_taskq; + +extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t); +extern taskq_t *taskq_create_synced(const char *, int, pri_t, int, int, uint_t, + kthread_t ***); +#define taskq_create_proc(a, b, c, d, e, p, f) \ + (taskq_create(a, b, c, d, e, f)) +#define taskq_create_sysdc(a, b, d, e, p, dc, f) \ + ((void) sizeof (dc), taskq_create(a, b, maxclsyspri, d, e, f)) +extern taskqid_t taskq_dispatch(taskq_t *, task_func_t, void *, uint_t); +extern taskqid_t taskq_dispatch_delay(taskq_t *, task_func_t, void *, uint_t, + clock_t); +extern void taskq_dispatch_ent(taskq_t *, task_func_t, void *, uint_t, + taskq_ent_t *); +extern int taskq_empty_ent(taskq_ent_t *); +extern void taskq_init_ent(taskq_ent_t *); +extern void taskq_destroy(taskq_t *); +extern void taskq_wait(taskq_t *); +extern void taskq_wait_id(taskq_t *, taskqid_t); +extern void taskq_wait_outstanding(taskq_t *, taskqid_t); +extern int taskq_member(taskq_t *, kthread_t *); +extern taskq_t *taskq_of_curthread(void); +extern int taskq_cancel_id(taskq_t *, taskqid_t); +extern void system_taskq_init(void); +extern void system_taskq_fini(void); + +#endif /* _SYS_TASKQ_H */ From 3823492ca1d50d4ba8e9d015b8c93a258db36ffe Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 09:08:01 +1100 Subject: [PATCH 48/91] libspl: move taskq implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/{libzpool => libspl}/taskq.c | 0 lib/libzpool/Makefile.am | 1 - 3 files changed, 1 insertion(+), 1 deletion(-) rename lib/{libzpool => libspl}/taskq.c (100%) diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index 10920ae8c606..cb70fb29614f 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -25,6 +25,7 @@ libspl_la_SOURCES = \ %D%/rwlock.c \ %D%/strlcat.c \ %D%/strlcpy.c \ + %D%/taskq.c \ %D%/thread.c \ %D%/timestamp.c \ %D%/tunables.c \ diff --git a/lib/libzpool/taskq.c b/lib/libspl/taskq.c similarity index 100% rename from lib/libzpool/taskq.c rename to lib/libspl/taskq.c diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index db8458885235..2156385bfd82 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -14,7 +14,6 @@ dist_libzpool_la_SOURCES = \ %D%/abd_os.c \ %D%/arc_os.c \ %D%/kernel.c \ - %D%/taskq.c \ %D%/util.c \ %D%/vdev_label_os.c \ %D%/zfs_racct.c \ From 52cf8eac428effa920772b24d58ece86a5a7a14e Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 25 Aug 2025 22:00:24 +1000 Subject: [PATCH 49/91] libspl: move cred definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 15 --------------- lib/libspl/include/sys/cred.h | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 6f7ae6b069ef..e7d164a176e0 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -177,15 +177,6 @@ extern "C" { #endif /* DTRACE_PROBE4 */ #define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) -/* - * Credentials - */ -extern uid_t crgetuid(cred_t *cr); -extern uid_t crgetruid(cred_t *cr); -extern gid_t crgetgid(cred_t *cr); -extern int crgetngroups(cred_t *cr); -extern gid_t *crgetgroups(cred_t *cr); - /* * Thread-specific data */ @@ -371,12 +362,6 @@ typedef struct vsecattr { #define CPU_SEQID ((uintptr_t)pthread_self() & (max_ncpus - 1)) #define CPU_SEQID_UNSTABLE CPU_SEQID -#define kcred NULL -#define CRED() NULL - -#define crhold(cr) ((void)cr) -#define crfree(cr) ((void)cr) - #define ptob(x) ((x) * PAGESIZE) #define NN_DIVISOR_1000 (1U << 0) diff --git a/lib/libspl/include/sys/cred.h b/lib/libspl/include/sys/cred.h index 4f6183762a0a..deceecee0f19 100644 --- a/lib/libspl/include/sys/cred.h +++ b/lib/libspl/include/sys/cred.h @@ -28,6 +28,24 @@ #ifndef _LIBSPL_SYS_CRED_H #define _LIBSPL_SYS_CRED_H +#include + +/* + * Credentials + */ + typedef struct cred cred_t; +extern uid_t crgetuid(cred_t *cr); +extern uid_t crgetruid(cred_t *cr); +extern gid_t crgetgid(cred_t *cr); +extern int crgetngroups(cred_t *cr); +extern gid_t *crgetgroups(cred_t *cr); + +#define kcred NULL +#define CRED() NULL + +#define crhold(cr) ((void)cr) +#define crfree(cr) ((void)cr) + #endif From c0984c936f56f18b37ceff63c59e29a1fdd04a7c Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 14:14:41 +1100 Subject: [PATCH 50/91] libspl: move cred implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/cred.c | 65 ++++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 35 ----------------------- 3 files changed, 66 insertions(+), 35 deletions(-) create mode 100644 lib/libspl/cred.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index cb70fb29614f..b13cb676633e 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -17,6 +17,7 @@ libspl_la_SOURCES = \ %D%/libspl_impl.h \ %D%/atomic.c \ %D%/condvar.c \ + %D%/cred.c \ %D%/getexecname.c \ %D%/list.c \ %D%/mkdirp.c \ diff --git a/lib/libspl/cred.c b/lib/libspl/cred.c new file mode 100644 index 000000000000..48527b1998f3 --- /dev/null +++ b/lib/libspl/cred.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include + +uid_t +crgetuid(cred_t *cr) +{ + (void) cr; + return (0); +} + +uid_t +crgetruid(cred_t *cr) +{ + (void) cr; + return (0); +} + +gid_t +crgetgid(cred_t *cr) +{ + (void) cr; + return (0); +} + +int +crgetngroups(cred_t *cr) +{ + (void) cr; + return (0); +} + +gid_t * +crgetgroups(cred_t *cr) +{ + (void) cr; + return (NULL); +} + diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 704c8faff8d5..019f4e573fd3 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -635,41 +635,6 @@ kernel_fini(void) random_fini(); } -uid_t -crgetuid(cred_t *cr) -{ - (void) cr; - return (0); -} - -uid_t -crgetruid(cred_t *cr) -{ - (void) cr; - return (0); -} - -gid_t -crgetgid(cred_t *cr) -{ - (void) cr; - return (0); -} - -int -crgetngroups(cred_t *cr) -{ - (void) cr; - return (0); -} - -gid_t * -crgetgroups(cred_t *cr) -{ - (void) cr; - return (NULL); -} - int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) { From 8c022088a775f51f028d0dab2b74561f1f5fc7c3 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Wed, 15 Oct 2025 17:31:31 +1100 Subject: [PATCH 51/91] libspl: move tsd definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 8 +------ lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/tsd.h | 42 ++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 1 + 4 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 lib/libspl/include/sys/tsd.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index e7d164a176e0..64aee9dc31eb 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -124,6 +124,7 @@ extern "C" { #include #include #include +#include #include #include @@ -177,13 +178,6 @@ extern "C" { #endif /* DTRACE_PROBE4 */ #define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) -/* - * Thread-specific data - */ -#define tsd_get(k) pthread_getspecific(k) -#define tsd_set(k, v) pthread_setspecific(k, v) -#define tsd_create(kp, d) pthread_key_create((pthread_key_t *)kp, d) -#define tsd_destroy(kp) /* nothing */ #ifdef __FreeBSD__ typedef off_t loff_t; #endif diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 7d5e1b7b3f66..c5e6111fabd6 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -62,6 +62,7 @@ libspl_sys_HEADERS = \ %D%/sys/time.h \ %D%/sys/timer.h \ %D%/sys/trace_spl.h \ + %D%/sys/tsd.h \ %D%/sys/tunables.h \ %D%/sys/types.h \ %D%/sys/types32.h \ diff --git a/lib/libspl/include/sys/tsd.h b/lib/libspl/include/sys/tsd.h new file mode 100644 index 000000000000..fa91519b3de5 --- /dev/null +++ b/lib/libspl/include/sys/tsd.h @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_TSD_H +#define _SYS_TSD_H + +#include + +/* + * Thread-specific data + */ +#define tsd_get(k) pthread_getspecific(k) +#define tsd_set(k, v) pthread_setspecific(k, v) +#define tsd_create(kp, d) pthread_key_create((pthread_key_t *)kp, d) +#define tsd_destroy(kp) /* nothing */ + +#endif /* _SYS_MUTEX_H */ diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 019f4e573fd3..aed0a96bb58e 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include From ce7a894af19c44fc475e8c4bc9007b592800c84b Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Thu, 16 Oct 2025 12:39:35 +1100 Subject: [PATCH 52/91] libspl: move kstat definitions from zfs_context.h, slim down to basics Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 12 - lib/libspl/include/sys/kstat.h | 743 ++------------------------------- 2 files changed, 25 insertions(+), 730 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 64aee9dc31eb..bb36d0baa93f 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -182,18 +182,6 @@ extern "C" { typedef off_t loff_t; #endif -/* - * kstat creation, installation and deletion - */ -extern kstat_t *kstat_create(const char *, int, - const char *, const char *, uchar_t, ulong_t, uchar_t); -extern void kstat_install(kstat_t *); -extern void kstat_delete(kstat_t *); -extern void kstat_set_raw_ops(kstat_t *ksp, - int (*headers)(char *buf, size_t size), - int (*data)(char *buf, size_t size, void *data), - void *(*addr)(kstat_t *ksp, loff_t index)); - /* * procfs list manipulation */ diff --git a/lib/libspl/include/sys/kstat.h b/lib/libspl/include/sys/kstat.h index 7777888c31eb..361f24df3f58 100644 --- a/lib/libspl/include/sys/kstat.h +++ b/lib/libspl/include/sys/kstat.h @@ -27,758 +27,65 @@ #ifndef _SYS_KSTAT_H #define _SYS_KSTAT_H - - -/* - * Definition of general kernel statistics structures and /dev/kstat ioctls - */ - #include #include -#ifdef __cplusplus -extern "C" { -#endif - -typedef int kid_t; /* unique kstat id */ - -/* - * Kernel statistics driver (/dev/kstat) ioctls - */ - -#define KSTAT_IOC_BASE ('K' << 8) - -#define KSTAT_IOC_CHAIN_ID KSTAT_IOC_BASE | 0x01 -#define KSTAT_IOC_READ KSTAT_IOC_BASE | 0x02 -#define KSTAT_IOC_WRITE KSTAT_IOC_BASE | 0x03 - -/* - * /dev/kstat ioctl usage (kd denotes /dev/kstat descriptor): - * - * kcid = ioctl(kd, KSTAT_IOC_CHAIN_ID, NULL); - * kcid = ioctl(kd, KSTAT_IOC_READ, kstat_t *); - * kcid = ioctl(kd, KSTAT_IOC_WRITE, kstat_t *); - */ - #define KSTAT_STRLEN 255 /* 254 chars + NULL; must be 16 * n - 1 */ -/* - * The generic kstat header - */ - typedef struct kstat { - /* - * Fields relevant to both kernel and user - */ - hrtime_t ks_crtime; /* creation time (from gethrtime()) */ - struct kstat *ks_next; /* kstat chain linkage */ - kid_t ks_kid; /* unique kstat ID */ - char ks_module[KSTAT_STRLEN]; /* provider module name */ - uchar_t ks_resv; /* reserved, currently just padding */ - int ks_instance; /* provider module's instance */ - char ks_name[KSTAT_STRLEN]; /* kstat name */ - uchar_t ks_type; /* kstat data type */ - char ks_class[KSTAT_STRLEN]; /* kstat class */ - uchar_t ks_flags; /* kstat flags */ - void *ks_data; /* kstat type-specific data */ - uint_t ks_ndata; /* # of type-specific data records */ - size_t ks_data_size; /* total size of kstat data section */ - hrtime_t ks_snaptime; /* time of last data snapshot */ - /* - * Fields relevant to kernel only - */ - int (*ks_update)(struct kstat *, int); /* dynamic update */ - void *ks_private; /* arbitrary provider-private data */ - int (*ks_snapshot)(struct kstat *, void *, int); - void *ks_lock; /* protects this kstat's data */ + uchar_t ks_flags; + void *ks_data; + uint_t ks_ndata; + size_t ks_data_size; + int (*ks_update)(struct kstat *, int); + void *ks_private; + void *ks_lock; } kstat_t; -/* - * kstat structure and locking strategy - * - * Each kstat consists of a header section (a kstat_t) and a data section. - * The system maintains a set of kstats, protected by kstat_chain_lock. - * kstat_chain_lock protects all additions to/deletions from this set, - * as well as all changes to kstat headers. kstat data sections are - * *optionally* protected by the per-kstat ks_lock. If ks_lock is non-NULL, - * kstat clients (e.g. /dev/kstat) will acquire this lock for all of their - * operations on that kstat. It is up to the kstat provider to decide whether - * guaranteeing consistent data to kstat clients is sufficiently important - * to justify the locking cost. Note, however, that most statistic updates - * already occur under one of the provider's mutexes, so if the provider sets - * ks_lock to point to that mutex, then kstat data locking is free. - * - * NOTE: variable-size kstats MUST employ kstat data locking, to prevent - * data-size races with kstat clients. - * - * NOTE: ks_lock is really of type (kmutex_t *); it is declared as (void *) - * in the kstat header so that users don't have to be exposed to all of the - * kernel's lock-related data structures. - */ - -#if defined(_KERNEL) - -#define KSTAT_ENTER(k) \ - { kmutex_t *lp = (k)->ks_lock; if (lp) mutex_enter(lp); } - -#define KSTAT_EXIT(k) \ - { kmutex_t *lp = (k)->ks_lock; if (lp) mutex_exit(lp); } - -#define KSTAT_UPDATE(k, rw) (*(k)->ks_update)((k), (rw)) - -#define KSTAT_SNAPSHOT(k, buf, rw) (*(k)->ks_snapshot)((k), (buf), (rw)) - -#endif /* defined(_KERNEL) */ - -/* - * kstat time - * - * All times associated with kstats (e.g. creation time, snapshot time, - * kstat_timer_t and kstat_io_t timestamps, etc.) are 64-bit nanosecond values, - * as returned by gethrtime(). The accuracy of these timestamps is machine - * dependent, but the precision (units) is the same across all platforms. - */ - -/* - * kstat identity (KID) - * - * Each kstat is assigned a unique KID (kstat ID) when it is added to the - * global kstat chain. The KID is used as a cookie by /dev/kstat to - * request information about the corresponding kstat. There is also - * an identity associated with the entire kstat chain, kstat_chain_id, - * which is bumped each time a kstat is added or deleted. /dev/kstat uses - * the chain ID to detect changes in the kstat chain (e.g., a new disk - * coming online) between ioctl()s. - */ - -/* - * kstat module, kstat instance - * - * ks_module and ks_instance contain the name and instance of the module - * that created the kstat. In cases where there can only be one instance, - * ks_instance is 0. The kernel proper (/kernel/unix) uses "unix" as its - * module name. - */ - -/* - * kstat name - * - * ks_name gives a meaningful name to a kstat. The full kstat namespace - * is module.instance.name, so the name only need be unique within a - * module. kstat_create() will fail if you try to create a kstat with - * an already-used (ks_module, ks_instance, ks_name) triplet. Spaces are - * allowed in kstat names, but strongly discouraged, since they hinder - * awk-style processing at user level. - */ - -/* - * kstat type - * - * The kstat mechanism provides several flavors of kstat data, defined - * below. The "raw" kstat type is just treated as an array of bytes; you - * can use this to export any kind of data you want. - * - * Some kstat types allow multiple data structures per kstat, e.g. - * KSTAT_TYPE_NAMED; others do not. This is part of the spec for each - * kstat data type. - * - * User-level tools should *not* rely on the #define KSTAT_NUM_TYPES. To - * get this information, read out the standard system kstat "kstat_types". - */ - -#define KSTAT_TYPE_RAW 0 /* can be anything */ - /* ks_ndata >= 1 */ -#define KSTAT_TYPE_NAMED 1 /* name/value pair */ - /* ks_ndata >= 1 */ -#define KSTAT_TYPE_INTR 2 /* interrupt statistics */ - /* ks_ndata == 1 */ -#define KSTAT_TYPE_IO 3 /* I/O statistics */ - /* ks_ndata == 1 */ -#define KSTAT_TYPE_TIMER 4 /* event timer */ - /* ks_ndata >= 1 */ - -#define KSTAT_NUM_TYPES 5 - -/* - * kstat class - * - * Each kstat can be characterized as belonging to some broad class - * of statistics, e.g. disk, tape, net, vm, streams, etc. This field - * can be used as a filter to extract related kstats. The following - * values are currently in use: disk, tape, net, controller, vm, kvm, - * hat, streams, kstat, and misc. (The kstat class encompasses things - * like kstat_types.) - */ - -/* - * kstat flags - * - * Any of the following flags may be passed to kstat_create(). They are - * all zero by default. - * - * KSTAT_FLAG_VIRTUAL: - * - * Tells kstat_create() not to allocate memory for the - * kstat data section; instead, you will set the ks_data - * field to point to the data you wish to export. This - * provides a convenient way to export existing data - * structures. - * - * KSTAT_FLAG_VAR_SIZE: - * - * The size of the kstat you are creating will vary over time. - * For example, you may want to use the kstat mechanism to - * export a linked list. NOTE: The kstat framework does not - * manage the data section, so all variable-size kstats must be - * virtual kstats. Moreover, variable-size kstats MUST employ - * kstat data locking to prevent data-size races with kstat - * clients. See the section on "kstat snapshot" for details. - * - * KSTAT_FLAG_WRITABLE: - * - * Makes the kstat's data section writable by root. - * The ks_snapshot routine (see below) does not need to check for - * this; permission checking is handled in the kstat driver. - * - * KSTAT_FLAG_PERSISTENT: - * - * Indicates that this kstat is to be persistent over time. - * For persistent kstats, kstat_delete() simply marks the - * kstat as dormant; a subsequent kstat_create() reactivates - * the kstat. This feature is provided so that statistics - * are not lost across driver close/open (e.g., raw disk I/O - * on a disk with no mounted partitions.) - * NOTE: Persistent kstats cannot be virtual, since ks_data - * points to garbage as soon as the driver goes away. - * - * The following flags are maintained by the kstat framework: - * - * KSTAT_FLAG_DORMANT: - * - * For persistent kstats, indicates that the kstat is in the - * dormant state (e.g., the corresponding device is closed). - * - * KSTAT_FLAG_INVALID: - * - * This flag is set when a kstat is in a transitional state, - * e.g. between kstat_create() and kstat_install(). - * kstat clients must not attempt to access the kstat's data - * if this flag is set. - */ +#define KSTAT_TYPE_RAW 0 +#define KSTAT_TYPE_NAMED 1 #define KSTAT_FLAG_VIRTUAL 0x01 -#define KSTAT_FLAG_VAR_SIZE 0x02 -#define KSTAT_FLAG_WRITABLE 0x04 -#define KSTAT_FLAG_PERSISTENT 0x08 -#define KSTAT_FLAG_DORMANT 0x10 -#define KSTAT_FLAG_INVALID 0x20 -#define KSTAT_FLAG_LONGSTRINGS 0x40 #define KSTAT_FLAG_NO_HEADERS 0x80 -/* - * Dynamic update support - * - * The kstat mechanism allows for an optional ks_update function to update - * kstat data. This is useful for drivers where the underlying device - * keeps cheap hardware stats, but extraction is expensive. Instead of - * constantly keeping the kstat data section up to date, you can supply a - * ks_update function which updates the kstat's data section on demand. - * To take advantage of this feature, simply set the ks_update field before - * calling kstat_install(). - * - * The ks_update function, if supplied, must have the following structure: - * - * int - * foo_kstat_update(kstat_t *ksp, int rw) - * { - * if (rw == KSTAT_WRITE) { - * ... update the native stats from ksp->ks_data; - * return EACCES if you don't support this - * } else { - * ... update ksp->ks_data from the native stats - * } - * } - * - * The ks_update return codes are: 0 for success, EACCES if you don't allow - * KSTAT_WRITE, and EIO for any other type of error. - * - * In general, the ks_update function may need to refer to provider-private - * data; for example, it may need a pointer to the provider's raw statistics. - * The ks_private field is available for this purpose. Its use is entirely - * at the provider's discretion. - * - * All variable-size kstats MUST supply a ks_update routine, which computes - * and sets ks_data_size (and ks_ndata if that is meaningful), since these - * are needed to perform kstat snapshots (see below). - * - * No kstat locking should be done inside the ks_update routine. The caller - * will already be holding the kstat's ks_lock (to ensure consistent data). - */ - #define KSTAT_READ 0 #define KSTAT_WRITE 1 -/* - * Kstat snapshot - * - * In order to get a consistent view of a kstat's data, clients must obey - * the kstat's locking strategy. However, these clients may need to perform - * operations on the data which could cause a fault (e.g. copyout()), or - * operations which are simply expensive. Doing so could cause deadlock - * (e.g. if you're holding a disk's kstat lock which is ultimately required - * to resolve a copyout() fault), performance degradation (since the providers' - * activity is serialized at the kstat lock), device timing problems, etc. - * - * To avoid these problems, kstat data is provided via snapshots. Taking - * a snapshot is a simple process: allocate a wired-down kernel buffer, - * acquire the kstat's data lock, copy the data into the buffer ("take the - * snapshot"), and release the lock. This ensures that the kstat's data lock - * will be held as briefly as possible, and that no faults will occur while - * the lock is held. - * - * Normally, the snapshot is taken by default_kstat_snapshot(), which - * timestamps the data (sets ks_snaptime), copies it, and does a little - * massaging to deal with incomplete transactions on i/o kstats. However, - * this routine only works for kstats with contiguous data (the typical case). - * If you create a kstat whose data is, say, a linked list, you must provide - * your own ks_snapshot routine. The routine you supply must have the - * following prototype (replace "foo" with something appropriate): - * - * int foo_kstat_snapshot(kstat_t *ksp, void *buf, int rw); - * - * The minimal snapshot routine -- one which copies contiguous data that - * doesn't need any massaging -- would be this: - * - * ksp->ks_snaptime = gethrtime(); - * if (rw == KSTAT_WRITE) - * memcpy(ksp->ks_data, buf, ksp->ks_data_size); - * else - * memcpy(buf, ksp->ks_data, ksp->ks_data_size); - * return (0); - * - * A more illuminating example is taking a snapshot of a linked list: - * - * ksp->ks_snaptime = gethrtime(); - * if (rw == KSTAT_WRITE) - * return (EACCES); ... See below ... - * for (foo = first_foo; foo; foo = foo->next) { - * memcpy(buf, foo, sizeof (struct foo)); - * buf = ((struct foo *) buf) + 1; - * } - * return (0); - * - * In the example above, we have decided that we don't want to allow - * KSTAT_WRITE access, so we return EACCES if this is attempted. - * - * The key points are: - * - * (1) ks_snaptime must be set (via gethrtime()) to timestamp the data. - * (2) Data gets copied from the kstat to the buffer on KSTAT_READ, - * and from the buffer to the kstat on KSTAT_WRITE. - * (3) ks_snapshot return values are: 0 for success, EACCES if you - * don't allow KSTAT_WRITE, and EIO for any other type of error. - * - * Named kstats (see section on "Named statistics" below) containing long - * strings (KSTAT_DATA_STRING) need special handling. The kstat driver - * assumes that all strings are copied into the buffer after the array of - * named kstats, and the pointers (KSTAT_NAMED_STR_PTR()) are updated to point - * into the copy within the buffer. The default snapshot routine does this, - * but overriding routines should contain at least the following: - * - * if (rw == KSTAT_READ) { - * kstat_named_t *knp = buf; - * char *end = knp + ksp->ks_ndata; - * uint_t i; - * - * ... Do the regular copy ... - * memcpy(buf, ksp->ks_data, sizeof (kstat_named_t) * ksp->ks_ndata); - * - * for (i = 0; i < ksp->ks_ndata; i++, knp++) { - * if (knp[i].data_type == KSTAT_DATA_STRING && - * KSTAT_NAMED_STR_PTR(knp) != NULL) { - * memcpy(end, KSTAT_NAMED_STR_PTR(knp), - * KSTAT_NAMED_STR_BUFLEN(knp)); - * KSTAT_NAMED_STR_PTR(knp) = end; - * end += KSTAT_NAMED_STR_BUFLEN(knp); - * } - * } - */ - -/* - * Named statistics. - * - * List of arbitrary name=value statistics. - */ - typedef struct kstat_named { - char name[KSTAT_STRLEN]; /* name of counter */ - uchar_t data_type; /* data type */ + char name[KSTAT_STRLEN]; + uchar_t data_type; union { - char c[16]; /* enough for 128-bit ints */ - int32_t i32; - uint32_t ui32; struct { union { - char *ptr; /* NULL-term string */ -#if defined(_KERNEL) && defined(_MULTI_DATAMODEL) - caddr32_t ptr32; -#endif - char __pad[8]; /* 64-bit padding */ + char *ptr; + char __pad[8]; } addr; - uint32_t len; /* # bytes for strlen + '\0' */ + uint32_t len; } str; -/* - * The int64_t and uint64_t types are not valid for a maximally conformant - * 32-bit compilation environment (cc -Xc) using compilers prior to the - * introduction of C99 conforming compiler (reference ISO/IEC 9899:1990). - * In these cases, the visibility of i64 and ui64 is only permitted for - * 64-bit compilation environments or 32-bit non-maximally conformant - * C89 or C90 ANSI C compilation environments (cc -Xt and cc -Xa). In the - * C99 ANSI C compilation environment, the long long type is supported. - * The _INT64_TYPE is defined by the implementation (see sys/inttypes.h). - */ -#if defined(_INT64_TYPE) int64_t i64; uint64_t ui64; -#endif - long l; - ulong_t ul; - - /* These structure members are obsolete */ - - longlong_t ll; - u_longlong_t ull; - float f; - double d; - } value; /* value of counter */ + } value; } kstat_named_t; -#define KSTAT_DATA_CHAR 0 -#define KSTAT_DATA_INT32 1 #define KSTAT_DATA_UINT32 2 #define KSTAT_DATA_INT64 3 #define KSTAT_DATA_UINT64 4 - -#if !defined(_LP64) -#define KSTAT_DATA_LONG KSTAT_DATA_INT32 -#define KSTAT_DATA_ULONG KSTAT_DATA_UINT32 -#else -#if !defined(_KERNEL) -#define KSTAT_DATA_LONG KSTAT_DATA_INT64 -#define KSTAT_DATA_ULONG KSTAT_DATA_UINT64 -#else -#define KSTAT_DATA_LONG 7 /* only visible to the kernel */ -#define KSTAT_DATA_ULONG 8 /* only visible to the kernel */ -#endif /* !_KERNEL */ -#endif /* !_LP64 */ - -/* - * Statistics exporting named kstats with long strings (KSTAT_DATA_STRING) - * may not make the assumption that ks_data_size is equal to (ks_ndata * sizeof - * (kstat_named_t)). ks_data_size in these cases is equal to the sum of the - * amount of space required to store the strings (ie, the sum of - * KSTAT_NAMED_STR_BUFLEN() for all KSTAT_DATA_STRING statistics) plus the - * space required to store the kstat_named_t's. - * - * The default update routine will update ks_data_size automatically for - * variable-length kstats containing long strings (using the default update - * routine only makes sense if the string is the only thing that is changing - * in size, and ks_ndata is constant). Fixed-length kstats containing long - * strings must explicitly change ks_data_size (after creation but before - * initialization) to reflect the correct amount of space required for the - * long strings and the kstat_named_t's. - */ #define KSTAT_DATA_STRING 9 -/* These types are obsolete */ - -#define KSTAT_DATA_LONGLONG KSTAT_DATA_INT64 -#define KSTAT_DATA_ULONGLONG KSTAT_DATA_UINT64 -#define KSTAT_DATA_FLOAT 5 -#define KSTAT_DATA_DOUBLE 6 - -#define KSTAT_NAMED_PTR(kptr) ((kstat_named_t *)(kptr)->ks_data) +#define KSTAT_NAMED_PTR(kptr) ((kstat_named_t *)(kptr)->ks_data) +#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.str.addr.ptr) +#define KSTAT_NAMED_STR_BUFLEN(knptr) ((knptr)->value.str.len) /* - * Retrieve the pointer of the string contained in the given named kstat. + * kstat creation, installation and deletion */ -#define KSTAT_NAMED_STR_PTR(knptr) ((knptr)->value.str.addr.ptr) - -/* - * Retrieve the length of the buffer required to store the string in the given - * named kstat. - */ -#define KSTAT_NAMED_STR_BUFLEN(knptr) ((knptr)->value.str.len) - -/* - * Interrupt statistics. - * - * An interrupt is a hard interrupt (sourced from the hardware device - * itself), a soft interrupt (induced by the system via the use of - * some system interrupt source), a watchdog interrupt (induced by - * a periodic timer call), spurious (an interrupt entry point was - * entered but there was no interrupt condition to service), - * or multiple service (an interrupt condition was detected and - * serviced just prior to returning from any of the other types). - * - * Measurement of the spurious class of interrupts is useful for - * autovectored devices in order to pinpoint any interrupt latency - * problems in a particular system configuration. - * - * Devices that have more than one interrupt of the same - * type should use multiple structures. - */ - -#define KSTAT_INTR_HARD 0 -#define KSTAT_INTR_SOFT 1 -#define KSTAT_INTR_WATCHDOG 2 -#define KSTAT_INTR_SPURIOUS 3 -#define KSTAT_INTR_MULTSVC 4 - -#define KSTAT_NUM_INTRS 5 - -typedef struct kstat_intr { - uint_t intrs[KSTAT_NUM_INTRS]; /* interrupt counters */ -} kstat_intr_t; - -#define KSTAT_INTR_PTR(kptr) ((kstat_intr_t *)(kptr)->ks_data) - -/* - * I/O statistics. - */ - -typedef struct kstat_io { - - /* - * Basic counters. - * - * The counters should be updated at the end of service - * (e.g., just prior to calling biodone()). - */ - - u_longlong_t nread; /* number of bytes read */ - u_longlong_t nwritten; /* number of bytes written */ - uint_t reads; /* number of read operations */ - uint_t writes; /* number of write operations */ - - /* - * Accumulated time and queue length statistics. - * - * Accumulated time statistics are kept as a running sum - * of "active" time. Queue length statistics are kept as a - * running sum of the product of queue length and elapsed time - * at that length -- i.e., a Riemann sum for queue length - * integrated against time. (You can also think of the active time - * as a Riemann sum, for the boolean function (queue_length > 0) - * integrated against time, or you can think of it as the - * Lebesgue measure of the set on which queue_length > 0.) - * - * ^ - * | _________ - * 8 | i4 | - * | | | - * Queue 6 | | - * Length | _________ | | - * 4 | i2 |_______| | - * | | i3 | - * 2_______| | - * | i1 | - * |_______________________________| - * Time-> t1 t2 t3 t4 - * - * At each change of state (entry or exit from the queue), - * we add the elapsed time (since the previous state change) - * to the active time if the queue length was non-zero during - * that interval; and we add the product of the elapsed time - * times the queue length to the running length*time sum. - * - * This method is generalizable to measuring residency - * in any defined system: instead of queue lengths, think - * of "outstanding RPC calls to server X". - * - * A large number of I/O subsystems have at least two basic - * "lists" of transactions they manage: one for transactions - * that have been accepted for processing but for which processing - * has yet to begin, and one for transactions which are actively - * being processed (but not done). For this reason, two cumulative - * time statistics are defined here: wait (pre-service) time, - * and run (service) time. - * - * All times are 64-bit nanoseconds (hrtime_t), as returned by - * gethrtime(). - * - * The units of cumulative busy time are accumulated nanoseconds. - * The units of cumulative length*time products are elapsed time - * times queue length. - * - * Updates to the fields below are performed implicitly by calls to - * these five functions: - * - * kstat_waitq_enter() - * kstat_waitq_exit() - * kstat_runq_enter() - * kstat_runq_exit() - * - * kstat_waitq_to_runq() (see below) - * kstat_runq_back_to_waitq() (see below) - * - * Since kstat_waitq_exit() is typically followed immediately - * by kstat_runq_enter(), there is a single kstat_waitq_to_runq() - * function which performs both operations. This is a performance - * win since only one timestamp is required. - * - * In some instances, it may be necessary to move a request from - * the run queue back to the wait queue, e.g. for write throttling. - * For these situations, call kstat_runq_back_to_waitq(). - * - * These fields should never be updated by any other means. - */ - - hrtime_t wtime; /* cumulative wait (pre-service) time */ - hrtime_t wlentime; /* cumulative wait length*time product */ - hrtime_t wlastupdate; /* last time wait queue changed */ - hrtime_t rtime; /* cumulative run (service) time */ - hrtime_t rlentime; /* cumulative run length*time product */ - hrtime_t rlastupdate; /* last time run queue changed */ - - uint_t wcnt; /* count of elements in wait state */ - uint_t rcnt; /* count of elements in run state */ - -} kstat_io_t; - -#define KSTAT_IO_PTR(kptr) ((kstat_io_t *)(kptr)->ks_data) - -/* - * Event timer statistics - cumulative elapsed time and number of events. - * - * Updates to these fields are performed implicitly by calls to - * kstat_timer_start() and kstat_timer_stop(). - */ - -typedef struct kstat_timer { - char name[KSTAT_STRLEN]; /* event name */ - uchar_t resv; /* reserved */ - u_longlong_t num_events; /* number of events */ - hrtime_t elapsed_time; /* cumulative elapsed time */ - hrtime_t min_time; /* shortest event duration */ - hrtime_t max_time; /* longest event duration */ - hrtime_t start_time; /* previous event start time */ - hrtime_t stop_time; /* previous event stop time */ -} kstat_timer_t; - -#define KSTAT_TIMER_PTR(kptr) ((kstat_timer_t *)(kptr)->ks_data) - -#if defined(_KERNEL) - -#include - -extern kid_t kstat_chain_id; /* bumped at each state change */ -extern void kstat_init(void); /* initialize kstat framework */ - -/* - * Adding and deleting kstats. - * - * The typical sequence to add a kstat is: - * - * ksp = kstat_create(module, instance, name, class, type, ndata, flags); - * if (ksp) { - * ... provider initialization, if necessary - * kstat_install(ksp); - * } - * - * There are three logically distinct steps here: - * - * Step 1: System Initialization (kstat_create) - * - * kstat_create() performs system initialization. kstat_create() - * allocates memory for the entire kstat (header plus data), initializes - * all header fields, initializes the data section to all zeroes, assigns - * a unique KID, and puts the kstat onto the system's kstat chain. - * The returned kstat is marked invalid (KSTAT_FLAG_INVALID is set), - * because the provider (caller) has not yet had a chance to initialize - * the data section. - * - * By default, kstats are exported to all zones on the system. A kstat may be - * created via kstat_create_zone() to specify a zone to which the statistics - * should be exported. kstat_zone_add() may be used to specify additional - * zones to which the statistics are to be exported. - * - * Step 2: Provider Initialization - * - * The provider performs any necessary initialization of the data section, - * e.g. setting the name fields in a KSTAT_TYPE_NAMED. Virtual kstats set - * the ks_data field at this time. The provider may also set the ks_update, - * ks_snapshot, ks_private, and ks_lock fields if necessary. - * - * Step 3: Installation (kstat_install) - * - * Once the kstat is completely initialized, kstat_install() clears the - * INVALID flag, thus making the kstat accessible to the outside world. - * kstat_install() also clears the DORMANT flag for persistent kstats. - * - * Removing a kstat from the system - * - * kstat_delete(ksp) removes ksp from the kstat chain and frees all - * associated system resources. NOTE: When you call kstat_delete(), - * you must NOT be holding that kstat's ks_lock. Otherwise, you may - * deadlock with a kstat reader. - * - * Persistent kstats - * - * From the provider's point of view, persistence is transparent. The only - * difference between ephemeral (normal) kstats and persistent kstats - * is that you pass KSTAT_FLAG_PERSISTENT to kstat_create(). Magically, - * this has the effect of making your data visible even when you're - * not home. Persistence is important to tools like iostat, which want - * to get a meaningful picture of disk activity. Without persistence, - * raw disk i/o statistics could never accumulate: they would come and - * go with each open/close of the raw device. - * - * The magic of persistence works by slightly altering the behavior of - * kstat_create() and kstat_delete(). The first call to kstat_create() - * creates a new kstat, as usual. However, kstat_delete() does not - * actually delete the kstat: it performs one final update of the data - * (i.e., calls the ks_update routine), marks the kstat as dormant, and - * sets the ks_lock, ks_update, ks_private, and ks_snapshot fields back - * to their default values (since they might otherwise point to garbage, - * e.g. if the provider is going away). kstat clients can still access - * the dormant kstat just like a live kstat; they just continue to see - * the final data values as long as the kstat remains dormant. - * All subsequent kstat_create() calls simply find the already-existing, - * dormant kstat and return a pointer to it, without altering any fields. - * The provider then performs its usual initialization sequence, and - * calls kstat_install(). kstat_install() uses the old data values to - * initialize the native data (i.e., ks_update is called with KSTAT_WRITE), - * thus making it seem like you were never gone. - */ - -extern kstat_t *kstat_create(const char *, int, const char *, const char *, - uchar_t, uint_t, uchar_t); -extern kstat_t *kstat_create_zone(const char *, int, const char *, - const char *, uchar_t, uint_t, uchar_t, zoneid_t); +extern kstat_t *kstat_create(const char *, int, + const char *, const char *, uchar_t, ulong_t, uchar_t); extern void kstat_install(kstat_t *); extern void kstat_delete(kstat_t *); -extern void kstat_named_setstr(kstat_named_t *knp, const char *src); -extern void kstat_set_string(char *, const char *); -extern void kstat_delete_byname(const char *, int, const char *); -extern void kstat_delete_byname_zone(const char *, int, const char *, zoneid_t); -extern void kstat_named_init(kstat_named_t *, const char *, uchar_t); -extern void kstat_timer_init(kstat_timer_t *, const char *); -extern void kstat_timer_start(kstat_timer_t *); -extern void kstat_timer_stop(kstat_timer_t *); - -extern void kstat_zone_add(kstat_t *, zoneid_t); -extern void kstat_zone_remove(kstat_t *, zoneid_t); -extern int kstat_zone_find(kstat_t *, zoneid_t); - -extern kstat_t *kstat_hold_bykid(kid_t kid, zoneid_t); -extern kstat_t *kstat_hold_byname(const char *, int, const char *, zoneid_t); -extern void kstat_rele(kstat_t *); - -#endif /* defined(_KERNEL) */ - -#ifdef __cplusplus -} -#endif +extern void kstat_set_raw_ops(kstat_t *ksp, + int (*headers)(char *buf, size_t size), + int (*data)(char *buf, size_t size, void *data), + void *(*addr)(kstat_t *ksp, loff_t index)); #endif /* _SYS_KSTAT_H */ From 586eba95dee2352ead318ec370925bbabf56b4da Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 13:38:26 +1100 Subject: [PATCH 53/91] libspl: move kstat implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/kstat.c | 64 ++++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 35 ----------------------- 3 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 lib/libspl/kstat.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index b13cb676633e..77e7461951ed 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -19,6 +19,7 @@ libspl_la_SOURCES = \ %D%/condvar.c \ %D%/cred.c \ %D%/getexecname.c \ + %D%/kstat.c \ %D%/list.c \ %D%/mkdirp.c \ %D%/mutex.c \ diff --git a/lib/libspl/kstat.c b/lib/libspl/kstat.c new file mode 100644 index 000000000000..af4b870edadf --- /dev/null +++ b/lib/libspl/kstat.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include + +/* + * ========================================================================= + * kstats + * ========================================================================= + */ +kstat_t * +kstat_create(const char *module, int instance, const char *name, + const char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag) +{ + (void) module, (void) instance, (void) name, (void) class, (void) type, + (void) ndata, (void) ks_flag; + return (NULL); +} + +void +kstat_install(kstat_t *ksp) +{ + (void) ksp; +} + +void +kstat_delete(kstat_t *ksp) +{ + (void) ksp; +} + +void +kstat_set_raw_ops(kstat_t *ksp, + int (*headers)(char *buf, size_t size), + int (*data)(char *buf, size_t size, void *data), + void *(*addr)(kstat_t *ksp, loff_t index)) +{ + (void) ksp, (void) headers, (void) data, (void) addr; +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index aed0a96bb58e..f57c082351ff 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -64,41 +64,6 @@ struct utsname hw_utsname; /* If set, all blocks read will be copied to the specified directory. */ char *vn_dumpdir = NULL; -/* - * ========================================================================= - * kstats - * ========================================================================= - */ -kstat_t * -kstat_create(const char *module, int instance, const char *name, - const char *class, uchar_t type, ulong_t ndata, uchar_t ks_flag) -{ - (void) module, (void) instance, (void) name, (void) class, (void) type, - (void) ndata, (void) ks_flag; - return (NULL); -} - -void -kstat_install(kstat_t *ksp) -{ - (void) ksp; -} - -void -kstat_delete(kstat_t *ksp) -{ - (void) ksp; -} - -void -kstat_set_raw_ops(kstat_t *ksp, - int (*headers)(char *buf, size_t size), - int (*data)(char *buf, size_t size, void *data), - void *(*addr)(kstat_t *ksp, loff_t index)) -{ - (void) ksp, (void) headers, (void) data, (void) addr; -} - uint32_t zone_get_hostid(void *zonep) { From 8700fc669b2cbf9bab6129f775757924e6176ac9 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Thu, 16 Oct 2025 13:12:30 +1100 Subject: [PATCH 54/91] libspl: move procfs_list definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 36 +-------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/procfs_list.h | 69 ++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 lib/libspl/include/sys/procfs_list.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index bb36d0baa93f..1c636436ebc9 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -125,6 +125,7 @@ extern "C" { #include #include #include +#include #include #include @@ -182,41 +183,6 @@ extern "C" { typedef off_t loff_t; #endif -/* - * procfs list manipulation - */ - -typedef struct procfs_list { - void *pl_private; - kmutex_t pl_lock; - list_t pl_list; - uint64_t pl_next_id; - size_t pl_node_offset; -} procfs_list_t; - -#ifndef __cplusplus -struct seq_file { }; -void seq_printf(struct seq_file *m, const char *fmt, ...); - -typedef struct procfs_list_node { - list_node_t pln_link; - uint64_t pln_id; -} procfs_list_node_t; - -void procfs_list_install(const char *module, - const char *submodule, - const char *name, - mode_t mode, - procfs_list_t *procfs_list, - int (*show)(struct seq_file *f, void *p), - int (*show_header)(struct seq_file *f), - int (*clear)(procfs_list_t *procfs_list), - size_t procfs_list_node_off); -void procfs_list_uninstall(procfs_list_t *procfs_list); -void procfs_list_destroy(procfs_list_t *procfs_list); -void procfs_list_add(procfs_list_t *procfs_list, void *p); -#endif - /* * Kernel memory */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index c5e6111fabd6..486cce3f161c 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -50,6 +50,7 @@ libspl_sys_HEADERS = \ %D%/sys/poll.h \ %D%/sys/priv.h \ %D%/sys/processor.h \ + %D%/sys/procfs_list.h \ %D%/sys/rwlock.h \ %D%/sys/simd.h \ %D%/sys/stack.h \ diff --git a/lib/libspl/include/sys/procfs_list.h b/lib/libspl/include/sys/procfs_list.h new file mode 100644 index 000000000000..93b80a4bfdb6 --- /dev/null +++ b/lib/libspl/include/sys/procfs_list.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_PROCFS_LIST_H +#define _SYS_PROCFS_LIST_H + +#include +#include +#include + +/* + * procfs list manipulation + */ + +typedef struct procfs_list { + void *pl_private; + kmutex_t pl_lock; + list_t pl_list; + uint64_t pl_next_id; + size_t pl_node_offset; +} procfs_list_t; + +struct seq_file { }; +void seq_printf(struct seq_file *m, const char *fmt, ...); + +typedef struct procfs_list_node { + list_node_t pln_link; + uint64_t pln_id; +} procfs_list_node_t; + +void procfs_list_install(const char *module, + const char *submodule, + const char *name, + mode_t mode, + procfs_list_t *procfs_list, + int (*show)(struct seq_file *f, void *p), + int (*show_header)(struct seq_file *f), + int (*clear)(procfs_list_t *procfs_list), + size_t procfs_list_node_off); +void procfs_list_uninstall(procfs_list_t *procfs_list); +void procfs_list_destroy(procfs_list_t *procfs_list); +void procfs_list_add(procfs_list_t *procfs_list, void *p); + +#endif /* _SYS_PROCFS_LIST_H */ From ee89fefe4d618171ea4228cb81b8d3d883d8e6c8 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 13:49:15 +1100 Subject: [PATCH 55/91] libspl: move procfs_list implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/procfs_list.c | 93 ++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 59 ------------------------- 3 files changed, 94 insertions(+), 59 deletions(-) create mode 100644 lib/libspl/procfs_list.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index 77e7461951ed..b7f519871f77 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -24,6 +24,7 @@ libspl_la_SOURCES = \ %D%/mkdirp.c \ %D%/mutex.c \ %D%/page.c \ + %D%/procfs_list.c \ %D%/rwlock.c \ %D%/strlcat.c \ %D%/strlcpy.c \ diff --git a/lib/libspl/procfs_list.c b/lib/libspl/procfs_list.c new file mode 100644 index 000000000000..0ce327db6343 --- /dev/null +++ b/lib/libspl/procfs_list.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include +#include +#include +#include +#include +#include + +/* + * ========================================================================= + * procfs list + * ========================================================================= + */ + +void +seq_printf(struct seq_file *m, const char *fmt, ...) +{ + (void) m, (void) fmt; +} + +void +procfs_list_install(const char *module, + const char *submodule, + const char *name, + mode_t mode, + procfs_list_t *procfs_list, + int (*show)(struct seq_file *f, void *p), + int (*show_header)(struct seq_file *f), + int (*clear)(procfs_list_t *procfs_list), + size_t procfs_list_node_off) +{ + (void) module, (void) submodule, (void) name, (void) mode, (void) show, + (void) show_header, (void) clear; + mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL); + list_create(&procfs_list->pl_list, + procfs_list_node_off + sizeof (procfs_list_node_t), + procfs_list_node_off + offsetof(procfs_list_node_t, pln_link)); + procfs_list->pl_next_id = 1; + procfs_list->pl_node_offset = procfs_list_node_off; +} + +void +procfs_list_uninstall(procfs_list_t *procfs_list) +{ + (void) procfs_list; +} + +void +procfs_list_destroy(procfs_list_t *procfs_list) +{ + ASSERT(list_is_empty(&procfs_list->pl_list)); + list_destroy(&procfs_list->pl_list); + mutex_destroy(&procfs_list->pl_lock); +} + +#define NODE_ID(procfs_list, obj) \ + (((procfs_list_node_t *)(((char *)obj) + \ + (procfs_list)->pl_node_offset))->pln_id) + +void +procfs_list_add(procfs_list_t *procfs_list, void *p) +{ + ASSERT(MUTEX_HELD(&procfs_list->pl_lock)); + NODE_ID(procfs_list, p) = procfs_list->pl_next_id++; + list_insert_tail(&procfs_list->pl_list, p); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index f57c082351ff..836af6565696 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -74,65 +74,6 @@ zone_get_hostid(void *zonep) return (hostid); } -/* - * ========================================================================= - * procfs list - * ========================================================================= - */ - -void -seq_printf(struct seq_file *m, const char *fmt, ...) -{ - (void) m, (void) fmt; -} - -void -procfs_list_install(const char *module, - const char *submodule, - const char *name, - mode_t mode, - procfs_list_t *procfs_list, - int (*show)(struct seq_file *f, void *p), - int (*show_header)(struct seq_file *f), - int (*clear)(procfs_list_t *procfs_list), - size_t procfs_list_node_off) -{ - (void) module, (void) submodule, (void) name, (void) mode, (void) show, - (void) show_header, (void) clear; - mutex_init(&procfs_list->pl_lock, NULL, MUTEX_DEFAULT, NULL); - list_create(&procfs_list->pl_list, - procfs_list_node_off + sizeof (procfs_list_node_t), - procfs_list_node_off + offsetof(procfs_list_node_t, pln_link)); - procfs_list->pl_next_id = 1; - procfs_list->pl_node_offset = procfs_list_node_off; -} - -void -procfs_list_uninstall(procfs_list_t *procfs_list) -{ - (void) procfs_list; -} - -void -procfs_list_destroy(procfs_list_t *procfs_list) -{ - ASSERT(list_is_empty(&procfs_list->pl_list)); - list_destroy(&procfs_list->pl_list); - mutex_destroy(&procfs_list->pl_lock); -} - -#define NODE_ID(procfs_list, obj) \ - (((procfs_list_node_t *)(((char *)obj) + \ - (procfs_list)->pl_node_offset))->pln_id) - -void -procfs_list_add(procfs_list_t *procfs_list, void *p) -{ - ASSERT(MUTEX_HELD(&procfs_list->pl_lock)); - NODE_ID(procfs_list, p) = procfs_list->pl_next_id++; - list_insert_tail(&procfs_list->pl_list, p); -} - /* * ========================================================================= * vnode operations From 8b5d919d4eed4b3c9d9273f9b97c5e84faa31f05 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Thu, 16 Oct 2025 13:27:43 +1100 Subject: [PATCH 56/91] libspl: move kmem definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 55 +---------------------------- lib/libspl/include/sys/kmem.h | 66 ++++++++++++++++++++++++++++------- lib/libspl/include/umem.h | 1 + 3 files changed, 55 insertions(+), 67 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 1c636436ebc9..f043249a289e 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -92,7 +92,6 @@ extern "C" { #include #include #include -#include #include #include #include @@ -126,6 +125,7 @@ extern "C" { #include #include #include +#include #include #include @@ -183,43 +183,6 @@ extern "C" { typedef off_t loff_t; #endif -/* - * Kernel memory - */ -#define KM_SLEEP UMEM_NOFAIL -#define KM_PUSHPAGE KM_SLEEP -#define KM_NOSLEEP UMEM_DEFAULT -#define KM_NORMALPRI 0 /* not needed with UMEM_DEFAULT */ -#define KMC_NODEBUG UMC_NODEBUG -#define KMC_KVMEM 0x0 -#define KMC_RECLAIMABLE 0x0 -#define kmem_alloc(_s, _f) umem_alloc(_s, _f) -#define kmem_zalloc(_s, _f) umem_zalloc(_s, _f) -#define kmem_free(_b, _s) umem_free(_b, _s) -#define vmem_alloc(_s, _f) kmem_alloc(_s, _f) -#define vmem_zalloc(_s, _f) kmem_zalloc(_s, _f) -#define vmem_free(_b, _s) kmem_free(_b, _s) -#define kmem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) \ - umem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) -#define kmem_cache_destroy(_c) umem_cache_destroy(_c) -#define kmem_cache_alloc(_c, _f) umem_cache_alloc(_c, _f) -#define kmem_cache_free(_c, _b) umem_cache_free(_c, _b) -#define kmem_debugging() 0 -#define kmem_cache_reap_now(_c) umem_cache_reap_now(_c); -#define kmem_cache_set_move(_c, _cb) /* nothing */ -#define POINTER_INVALIDATE(_pp) /* nothing */ -#define POINTER_IS_VALID(_p) 0 - -typedef umem_cache_t kmem_cache_t; - -typedef enum kmem_cbrc { - KMEM_CBRC_YES, - KMEM_CBRC_NO, - KMEM_CBRC_LATER, - KMEM_CBRC_DONT_NEED, - KMEM_CBRC_DONT_KNOW -} kmem_cbrc_t; - #define XVA_MAPSIZE 3 #define XVA_MAGIC 0x78766174 @@ -373,16 +336,6 @@ typedef struct callb_cpr { #define INGLOBALZONE(z) (1) extern uint32_t zone_get_hostid(void *zonep); -extern char *kmem_vasprintf(const char *fmt, va_list adx); -extern char *kmem_asprintf(const char *fmt, ...); -#define kmem_strfree(str) kmem_free((str), strlen(str) + 1) -#define kmem_strdup(s) strdup(s) - -#ifndef __cplusplus -extern int kmem_scnprintf(char *restrict str, size_t size, - const char *restrict fmt, ...); -#endif - /* * Hostname information */ @@ -438,12 +391,6 @@ void ksiddomain_rele(ksiddomain_t *); #define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) \ sysevent_post_event(_c, _d, _b, "libzpool", _e, _f) -typedef int fstrans_cookie_t; - -extern fstrans_cookie_t spl_fstrans_mark(void); -extern void spl_fstrans_unmark(fstrans_cookie_t); -extern int kmem_cache_reap_active(void); - /* * Kernel modules */ diff --git a/lib/libspl/include/sys/kmem.h b/lib/libspl/include/sys/kmem.h index 279461f8d4c1..0321f6a0d5ba 100644 --- a/lib/libspl/include/sys/kmem.h +++ b/lib/libspl/include/sys/kmem.h @@ -20,27 +20,67 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _SYS_KMEM_H #define _SYS_KMEM_H -#include +#include +#include -#ifdef __cplusplus -extern "C" { -#endif +/* + * Kernel memory + */ +#define KM_SLEEP UMEM_NOFAIL +#define KM_PUSHPAGE KM_SLEEP +#define KM_NOSLEEP UMEM_DEFAULT +#define KM_NORMALPRI 0 /* not needed with UMEM_DEFAULT */ +#define KMC_NODEBUG UMC_NODEBUG +#define KMC_KVMEM 0x0 +#define KMC_RECLAIMABLE 0x0 +#define kmem_alloc(_s, _f) umem_alloc(_s, _f) +#define kmem_zalloc(_s, _f) umem_zalloc(_s, _f) +#define kmem_free(_b, _s) umem_free(_b, _s) +#define vmem_alloc(_s, _f) kmem_alloc(_s, _f) +#define vmem_zalloc(_s, _f) kmem_zalloc(_s, _f) +#define vmem_free(_b, _s) kmem_free(_b, _s) +#define kmem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) \ + umem_cache_create(_a, _b, _c, _d, _e, _f, _g, _h, _i) +#define kmem_cache_destroy(_c) umem_cache_destroy(_c) +#define kmem_cache_alloc(_c, _f) umem_cache_alloc(_c, _f) +#define kmem_cache_free(_c, _b) umem_cache_free(_c, _b) +#define kmem_debugging() 0 +#define kmem_cache_reap_now(_c) umem_cache_reap_now(_c); +extern int kmem_cache_reap_active(void); +#define kmem_cache_set_move(_c, _cb) /* nothing */ +#define POINTER_INVALIDATE(_pp) /* nothing */ +#define POINTER_IS_VALID(_p) 0 -#define KM_SLEEP 0x00000000 /* same as KM_SLEEP */ -#define KM_NOSLEEP 0x00000001 /* same as KM_NOSLEEP */ +extern char *kmem_vasprintf(const char *fmt, va_list adx); +extern char *kmem_asprintf(const char *fmt, ...); +#define kmem_strfree(str) kmem_free((str), strlen(str) + 1) +#define kmem_strdup(s) strdup(s) -#define kmem_alloc(size, flags) ((void) sizeof (flags), malloc(size)) -#define kmem_free(ptr, size) ((void) sizeof (size), free(ptr)) +extern int kmem_scnprintf(char *restrict str, size_t size, + const char *restrict fmt, ...); -#ifdef __cplusplus -} -#endif +typedef umem_cache_t kmem_cache_t; + +typedef enum kmem_cbrc { + KMEM_CBRC_YES, + KMEM_CBRC_NO, + KMEM_CBRC_LATER, + KMEM_CBRC_DONT_NEED, + KMEM_CBRC_DONT_KNOW +} kmem_cbrc_t; + +typedef int fstrans_cookie_t; + +extern fstrans_cookie_t spl_fstrans_mark(void); +extern void spl_fstrans_unmark(fstrans_cookie_t); #endif /* _SYS_KMEM_H */ diff --git a/lib/libspl/include/umem.h b/lib/libspl/include/umem.h index 3e44610e4e21..1b79fee56d23 100644 --- a/lib/libspl/include/umem.h +++ b/lib/libspl/include/umem.h @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { From cf1044a15fb3ba21050138e9d6e8a59768315a74 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 14:12:20 +1100 Subject: [PATCH 57/91] libspl: move kmem implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/kmem.c | 102 +++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 73 ----------------------------- 3 files changed, 103 insertions(+), 73 deletions(-) create mode 100644 lib/libspl/kmem.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index b7f519871f77..a6afd17934e1 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -19,6 +19,7 @@ libspl_la_SOURCES = \ %D%/condvar.c \ %D%/cred.c \ %D%/getexecname.c \ + %D%/kmem.c \ %D%/kstat.c \ %D%/list.c \ %D%/mkdirp.c \ diff --git a/lib/libspl/kmem.c b/lib/libspl/kmem.c new file mode 100644 index 000000000000..c64e94597cf4 --- /dev/null +++ b/lib/libspl/kmem.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include + +char * +kmem_vasprintf(const char *fmt, va_list adx) +{ + char *buf = NULL; + va_list adx_copy; + + va_copy(adx_copy, adx); + VERIFY(vasprintf(&buf, fmt, adx_copy) != -1); + va_end(adx_copy); + + return (buf); +} + +char * +kmem_asprintf(const char *fmt, ...) +{ + char *buf = NULL; + va_list adx; + + va_start(adx, fmt); + VERIFY(vasprintf(&buf, fmt, adx) != -1); + va_end(adx); + + return (buf); +} + +/* + * kmem_scnprintf() will return the number of characters that it would have + * printed whenever it is limited by value of the size variable, rather than + * the number of characters that it did print. This can cause misbehavior on + * subsequent uses of the return value, so we define a safe version that will + * return the number of characters actually printed, minus the NULL format + * character. Subsequent use of this by the safe string functions is safe + * whether it is snprintf(), strlcat() or strlcpy(). + */ +int +kmem_scnprintf(char *restrict str, size_t size, const char *restrict fmt, ...) +{ + int n; + va_list ap; + + /* Make the 0 case a no-op so that we do not return -1 */ + if (size == 0) + return (0); + + va_start(ap, fmt); + n = vsnprintf(str, size, fmt, ap); + va_end(ap); + + if (n >= size) + n = size - 1; + + return (n); +} + +fstrans_cookie_t +spl_fstrans_mark(void) +{ + return ((fstrans_cookie_t)0); +} + +void +spl_fstrans_unmark(fstrans_cookie_t cookie) +{ + (void) cookie; +} + +int +kmem_cache_reap_active(void) +{ + return (0); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 836af6565696..d73495203b12 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -587,61 +587,6 @@ ksiddomain_rele(ksiddomain_t *ksid) umem_free(ksid, sizeof (ksiddomain_t)); } -char * -kmem_vasprintf(const char *fmt, va_list adx) -{ - char *buf = NULL; - va_list adx_copy; - - va_copy(adx_copy, adx); - VERIFY(vasprintf(&buf, fmt, adx_copy) != -1); - va_end(adx_copy); - - return (buf); -} - -char * -kmem_asprintf(const char *fmt, ...) -{ - char *buf = NULL; - va_list adx; - - va_start(adx, fmt); - VERIFY(vasprintf(&buf, fmt, adx) != -1); - va_end(adx); - - return (buf); -} - -/* - * kmem_scnprintf() will return the number of characters that it would have - * printed whenever it is limited by value of the size variable, rather than - * the number of characters that it did print. This can cause misbehavior on - * subsequent uses of the return value, so we define a safe version that will - * return the number of characters actually printed, minus the NULL format - * character. Subsequent use of this by the safe string functions is safe - * whether it is snprintf(), strlcat() or strlcpy(). - */ -int -kmem_scnprintf(char *restrict str, size_t size, const char *restrict fmt, ...) -{ - int n; - va_list ap; - - /* Make the 0 case a no-op so that we do not return -1 */ - if (size == 0) - return (0); - - va_start(ap, fmt); - n = vsnprintf(str, size, fmt, ap); - va_end(ap); - - if (n >= size) - n = size - 1; - - return (n); -} - zfs_file_t * zfs_onexit_fd_hold(int fd, minor_t *minorp) { @@ -664,24 +609,6 @@ zfs_onexit_add_cb(minor_t minor, void (*func)(void *), void *data, return (0); } -fstrans_cookie_t -spl_fstrans_mark(void) -{ - return ((fstrans_cookie_t)0); -} - -void -spl_fstrans_unmark(fstrans_cookie_t cookie) -{ - (void) cookie; -} - -int -kmem_cache_reap_active(void) -{ - return (0); -} - void zvol_create_minors(const char *name) { From db1c58095eff78bc2443461bb6ec687fee42ad5c Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 17 Oct 2025 22:25:23 +1100 Subject: [PATCH 58/91] libspl: move vattr and xvattr definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_acl.h | 2 +- include/sys/zfs_context.h | 72 +--------------------------------- lib/libspl/include/sys/vnode.h | 35 +++++++++++++++-- 3 files changed, 34 insertions(+), 75 deletions(-) diff --git a/include/sys/zfs_acl.h b/include/sys/zfs_acl.h index 753a128873d5..f9afee372c94 100644 --- a/include/sys/zfs_acl.h +++ b/include/sys/zfs_acl.h @@ -29,8 +29,8 @@ #ifdef _KERNEL #include #include -#include #endif +#include #include #include #include diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index f043249a289e..dac1e4b6922e 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -77,7 +77,6 @@ extern "C" { #include #else /* _KERNEL || _STANDALONE */ -#define _SYS_VNODE_H #define _SYS_VFS_H #define _SYS_SUNDDI_H #define _SYS_CALLB_H @@ -127,6 +126,7 @@ extern "C" { #include #include #include +#include #include @@ -183,77 +183,7 @@ extern "C" { typedef off_t loff_t; #endif -#define XVA_MAPSIZE 3 -#define XVA_MAGIC 0x78766174 - extern char *vn_dumpdir; -#define AV_SCANSTAMP_SZ 32 /* length of anti-virus scanstamp */ - -typedef struct xoptattr { - inode_timespec_t xoa_createtime; /* Create time of file */ - uint8_t xoa_archive; - uint8_t xoa_system; - uint8_t xoa_readonly; - uint8_t xoa_hidden; - uint8_t xoa_nounlink; - uint8_t xoa_immutable; - uint8_t xoa_appendonly; - uint8_t xoa_nodump; - uint8_t xoa_settable; - uint8_t xoa_opaque; - uint8_t xoa_av_quarantined; - uint8_t xoa_av_modified; - uint8_t xoa_av_scanstamp[AV_SCANSTAMP_SZ]; - uint8_t xoa_reparse; - uint8_t xoa_offline; - uint8_t xoa_sparse; -} xoptattr_t; - -typedef struct vattr { - uint_t va_mask; /* bit-mask of attributes */ - u_offset_t va_size; /* file size in bytes */ -} vattr_t; - - -typedef struct xvattr { - vattr_t xva_vattr; /* Embedded vattr structure */ - uint32_t xva_magic; /* Magic Number */ - uint32_t xva_mapsize; /* Size of attr bitmap (32-bit words) */ - uint32_t *xva_rtnattrmapp; /* Ptr to xva_rtnattrmap[] */ - uint32_t xva_reqattrmap[XVA_MAPSIZE]; /* Requested attrs */ - uint32_t xva_rtnattrmap[XVA_MAPSIZE]; /* Returned attrs */ - xoptattr_t xva_xoptattrs; /* Optional attributes */ -} xvattr_t; - -typedef struct vsecattr { - uint_t vsa_mask; /* See below */ - int vsa_aclcnt; /* ACL entry count */ - void *vsa_aclentp; /* pointer to ACL entries */ - int vsa_dfaclcnt; /* default ACL entry count */ - void *vsa_dfaclentp; /* pointer to default ACL entries */ - size_t vsa_aclentsz; /* ACE size in bytes of vsa_aclentp */ -} vsecattr_t; - -#define AT_MODE 0x00002 -#define AT_UID 0x00004 -#define AT_GID 0x00008 -#define AT_FSID 0x00010 -#define AT_NODEID 0x00020 -#define AT_NLINK 0x00040 -#define AT_SIZE 0x00080 -#define AT_ATIME 0x00100 -#define AT_MTIME 0x00200 -#define AT_CTIME 0x00400 -#define AT_RDEV 0x00800 -#define AT_BLKSIZE 0x01000 -#define AT_NBLOCKS 0x02000 -#define AT_SEQ 0x08000 -#define AT_XVATTR 0x10000 - -#define CRCREAT 0 - -#define F_FREESP 11 -#define FIGNORECASE 0x80000 /* request case-insensitive lookups */ /* * Random stuff diff --git a/lib/libspl/include/sys/vnode.h b/lib/libspl/include/sys/vnode.h index 49afe12c52b1..ed9901eede22 100644 --- a/lib/libspl/include/sys/vnode.h +++ b/lib/libspl/include/sys/vnode.h @@ -25,7 +25,36 @@ * Use is subject to license terms. */ -#ifndef _LIBSPL_SYS_VNODE_H -#define _LIBSPL_SYS_VNODE_H +#ifndef _SYS_VNODE_H +#define _SYS_VNODE_H -#endif /* _LIBSPL_SYS_VNODE_H */ +typedef struct vattr { + uint_t va_mask; /* bit-mask of attributes */ + u_offset_t va_size; /* file size in bytes */ +} vattr_t; + +#define AT_MODE 0x00002 +#define AT_UID 0x00004 +#define AT_GID 0x00008 +#define AT_FSID 0x00010 +#define AT_NODEID 0x00020 +#define AT_NLINK 0x00040 +#define AT_SIZE 0x00080 +#define AT_ATIME 0x00100 +#define AT_MTIME 0x00200 +#define AT_CTIME 0x00400 +#define AT_RDEV 0x00800 +#define AT_BLKSIZE 0x01000 +#define AT_NBLOCKS 0x02000 +#define AT_SEQ 0x08000 +#define AT_XVATTR 0x10000 + +#define ATTR_XVATTR AT_XVATTR + +#define CRCREAT 0 + +#define F_FREESP 11 +#define FIGNORECASE 0x80000 /* request case-insensitive lookups */ + + +#endif /* _SYS_VNODE_H */ From bca4ca79494cdb89b5bd9915c00efadbda16a04b Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Wed, 22 Oct 2025 13:52:22 +1100 Subject: [PATCH 59/91] libspl: add include guards for sys/string.h The extra inclusion via xvattr.h appears to upset the linter in CI. I'm not entirely sure what its complaint is, but removing sys/string.h entirely is not quite possible yet, and include guards are rarely a bad idea, so this will do. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/include/sys/string.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/libspl/include/sys/string.h b/lib/libspl/include/sys/string.h index 3b2f5900276f..55ccbd09041a 100644 --- a/lib/libspl/include/sys/string.h +++ b/lib/libspl/include/sys/string.h @@ -1 +1,4 @@ +#ifndef _LIBSPL_SYS_STRING_H +#define _LIBSPL_SYS_STRING_H #include +#endif From 335f46b219c3843901482a1dbf49f72e048039f7 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 18 Oct 2025 22:24:06 +1100 Subject: [PATCH 60/91] libspl: move ptob() from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 2 -- lib/libspl/include/os/freebsd/sys/param.h | 2 ++ lib/libspl/include/os/linux/sys/param.h | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index dac1e4b6922e..770cb73f224b 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -203,8 +203,6 @@ extern char *vn_dumpdir; #define CPU_SEQID ((uintptr_t)pthread_self() & (max_ncpus - 1)) #define CPU_SEQID_UNSTABLE CPU_SEQID -#define ptob(x) ((x) * PAGESIZE) - #define NN_DIVISOR_1000 (1U << 0) #define NN_NUMBUF_SZ (6) diff --git a/lib/libspl/include/os/freebsd/sys/param.h b/lib/libspl/include/os/freebsd/sys/param.h index 55fa1de0e8ff..a693149115db 100644 --- a/lib/libspl/include/os/freebsd/sys/param.h +++ b/lib/libspl/include/os/freebsd/sys/param.h @@ -58,6 +58,8 @@ extern size_t spl_pagesize(void); #define PAGESIZE (spl_pagesize()) +#define ptob(x) ((x) * PAGESIZE) + #ifndef HAVE_EXECVPE extern int execvpe(const char *name, char * const argv[], char * const envp[]); #endif diff --git a/lib/libspl/include/os/linux/sys/param.h b/lib/libspl/include/os/linux/sys/param.h index 814f8feaf37f..169d5875fcf0 100644 --- a/lib/libspl/include/os/linux/sys/param.h +++ b/lib/libspl/include/os/linux/sys/param.h @@ -65,4 +65,6 @@ extern size_t spl_pagesize(void); #define PAGESIZE (spl_pagesize()) +#define ptob(x) ((x) * PAGESIZE) + #endif From 0c6be03fd7bbac2447588942677c59b477c4024f Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 18 Oct 2025 22:35:57 +1100 Subject: [PATCH 61/91] zfs_context: remove duplicated access control stuff; remove kernel gate Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 15 --------------- lib/libspl/include/sys/acl.h | 4 ---- 2 files changed, 19 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 770cb73f224b..49d3b207a31d 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -283,21 +283,6 @@ struct bootstat { uint64_t st_size; }; -typedef struct ace_object { - uid_t a_who; - uint32_t a_access_mask; - uint16_t a_flags; - uint16_t a_type; - uint8_t a_obj_type[16]; - uint8_t a_inherit_obj_type[16]; -} ace_object_t; - - -#define ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE 0x05 -#define ACE_ACCESS_DENIED_OBJECT_ACE_TYPE 0x06 -#define ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE 0x07 -#define ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE 0x08 - extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr); extern int zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr); diff --git a/lib/libspl/include/sys/acl.h b/lib/libspl/include/sys/acl.h index 602043bbb196..3e79040c5307 100644 --- a/lib/libspl/include/sys/acl.h +++ b/lib/libspl/include/sys/acl.h @@ -141,8 +141,6 @@ typedef struct acl_info acl_t; #define ACE_ALL_TYPES 0x001F -#if defined(_KERNEL) - typedef struct ace_object { uid_t a_who; /* uid or gid */ uint32_t a_access_mask; /* read,write,... */ @@ -152,8 +150,6 @@ typedef struct ace_object { uint8_t a_inherit_obj_type[16]; /* inherit obj */ } ace_object_t; -#endif - #define ACE_ALL_PERMS (ACE_READ_DATA|ACE_LIST_DIRECTORY|ACE_WRITE_DATA| \ ACE_ADD_FILE|ACE_APPEND_DATA|ACE_ADD_SUBDIRECTORY|ACE_READ_NAMED_ATTRS| \ ACE_WRITE_NAMED_ATTRS|ACE_EXECUTE|ACE_DELETE_CHILD|ACE_READ_ATTRIBUTES| \ From 4e3b88927c2f9ad702aaf308b0b83d9bcc09aac6 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 24 Oct 2025 22:37:54 +1100 Subject: [PATCH 62/91] libzpool: separate driver-side include Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- cmd/raidz_test/raidz_test.c | 1 + cmd/zdb/zdb.c | 1 + cmd/zhack.c | 1 + cmd/ztest.c | 1 + include/Makefile.am | 1 + include/libzpool.h | 49 +++++++++++++++++++++++++++++++++++++ include/sys/zfs_context.h | 6 ----- lib/libzpool/kernel.c | 3 +++ lib/libzpool/util.c | 1 + 9 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 include/libzpool.h diff --git a/cmd/raidz_test/raidz_test.c b/cmd/raidz_test/raidz_test.c index cf3e123c6090..4839e909e4f7 100644 --- a/cmd/raidz_test/raidz_test.c +++ b/cmd/raidz_test/raidz_test.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "raidz_test.h" static int *rand_data; diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c index fa8e7fa691db..09e144f66c68 100644 --- a/cmd/zdb/zdb.c +++ b/cmd/zdb/zdb.c @@ -89,6 +89,7 @@ #include #include +#include #include #include #include diff --git a/cmd/zhack.c b/cmd/zhack.c index 8ffbf91ffb30..536e3880718c 100644 --- a/cmd/zhack.c +++ b/cmd/zhack.c @@ -55,6 +55,7 @@ #include #include #include +#include static importargs_t g_importargs; static char *g_pool; diff --git a/cmd/ztest.c b/cmd/ztest.c index 89b1f68606ea..54b4fdb4c48a 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -139,6 +139,7 @@ #include #include #include +#include static int ztest_fd_data = -1; static int ztest_fd_rand = -1; diff --git a/include/Makefile.am b/include/Makefile.am index 7588cd0aedc9..42457519e746 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -191,6 +191,7 @@ USER_H = \ libzfs.h \ libzfs_core.h \ libzfsbootenv.h \ + libzpool.h \ libzutil.h \ thread_pool.h diff --git a/include/libzpool.h b/include/libzpool.h new file mode 100644 index 000000000000..3fd6c694d2f3 --- /dev/null +++ b/include/libzpool.h @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _LIBZPOOL_H +#define _LIBZPOOL_H extern __attribute__((visibility("default"))) + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +_LIBZPOOL_H void kernel_init(int mode); +_LIBZPOOL_H void kernel_fini(void); + +struct spa; +_LIBZPOOL_H void show_pool_stats(struct spa *); +_LIBZPOOL_H int handle_tunable_option(const char *, boolean_t); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 49d3b207a31d..ef5899b11972 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -230,15 +230,9 @@ random_in_range(uint32_t range) return (r % range); } -extern void kernel_init(int mode); -extern void kernel_fini(void); extern void random_init(void); extern void random_fini(void); -struct spa; -extern void show_pool_stats(struct spa *); -extern int handle_tunable_option(const char *, boolean_t); - typedef struct callb_cpr { kmutex_t *cc_lockp; } callb_cpr_t; diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index d73495203b12..d7ff74cba62a 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -45,6 +45,9 @@ #include #include #include + +#include +#include #include #include #include diff --git a/lib/libzpool/util.c b/lib/libzpool/util.c index 66d6f43967d5..a0b4480c4bcf 100644 --- a/lib/libzpool/util.c +++ b/lib/libzpool/util.c @@ -38,6 +38,7 @@ #include #include #include +#include /* * Routines needed by more than one client of libzpool. From d02ea5170a42bb62663e07bdc0ec2054fb0d6e27 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 24 Oct 2025 22:32:31 +1100 Subject: [PATCH 63/91] libspl: init/fini Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/include/Makefile.am | 1 + lib/libspl/include/libspl.h | 40 ++++++++++++++++++++++++++++++++++ lib/libspl/libspl.c | 36 ++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 4 ++++ 5 files changed, 82 insertions(+) create mode 100644 lib/libspl/include/libspl.h create mode 100644 lib/libspl/libspl.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index a6afd17934e1..3d46829ed01e 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -21,6 +21,7 @@ libspl_la_SOURCES = \ %D%/getexecname.c \ %D%/kmem.c \ %D%/kstat.c \ + %D%/libspl.c \ %D%/list.c \ %D%/mkdirp.c \ %D%/mutex.c \ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 486cce3f161c..41139d33ef82 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -4,6 +4,7 @@ libspl_HEADERS = \ %D%/atomic.h \ %D%/libgen.h \ %D%/libshare.h \ + %D%/libspl.h \ %D%/statcommon.h \ %D%/stdlib.h \ %D%/string.h \ diff --git a/lib/libspl/include/libspl.h b/lib/libspl/include/libspl.h new file mode 100644 index 000000000000..68756bb9597b --- /dev/null +++ b/lib/libspl/include/libspl.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2025, Rob Norris + */ + +#ifndef _LIBSPL_H +#define _LIBSPL_H extern __attribute__((visibility("default"))) + +#ifdef __cplusplus +extern "C" { +#endif + +_LIBSPL_H void libspl_init(void); +_LIBSPL_H void libspl_fini(void); + +#ifdef __cplusplus +}; +#endif + +#endif /* _LIBSPL_H */ diff --git a/lib/libspl/libspl.c b/lib/libspl/libspl.c new file mode 100644 index 000000000000..7c24f5cc0668 --- /dev/null +++ b/lib/libspl/libspl.c @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2025, Rob Norris + */ + +#include + +void +libspl_init(void) +{ +} + +void +libspl_fini(void) +{ +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index d7ff74cba62a..24d6fada3c1e 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -505,6 +505,8 @@ kernel_init(int mode) { extern uint_t rrw_tsd_key; + libspl_init(); + umem_nofail_callback(umem_out_of_memory); physmem = sysconf(_SC_PHYS_PAGES); @@ -543,6 +545,8 @@ kernel_fini(void) system_taskq_fini(); random_fini(); + + libspl_fini(); } int From 6cf6f091cf9f0e7d9a9c21bf7db40916bb8c2d50 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 24 Oct 2025 23:19:53 +1100 Subject: [PATCH 64/91] libspl: move physmem to sys/systm.h; initialise at libspl_init() Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 5 ++++- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/systm.h | 34 ++++++++++++++++++++++++++++++++++ lib/libspl/libspl.c | 8 ++++++++ lib/libzpool/kernel.c | 3 --- 5 files changed, 47 insertions(+), 4 deletions(-) create mode 100644 lib/libspl/include/sys/systm.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index ef5899b11972..d9eb64b1cbf4 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -127,6 +127,10 @@ extern "C" { #include #include #include +#include +#include +#include +#include #include @@ -206,7 +210,6 @@ extern char *vn_dumpdir; #define NN_DIVISOR_1000 (1U << 0) #define NN_NUMBUF_SZ (6) -extern uint64_t physmem; extern const char *random_path; extern const char *urandom_path; diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 41139d33ef82..8c5bb7b72986 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -59,6 +59,7 @@ libspl_sys_HEADERS = \ %D%/sys/string.h \ %D%/sys/sunddi.h \ %D%/sys/systeminfo.h \ + %D%/sys/systm.h \ %D%/sys/thread.h \ %D%/sys/taskq.h \ %D%/sys/time.h \ diff --git a/lib/libspl/include/sys/systm.h b/lib/libspl/include/sys/systm.h new file mode 100644 index 000000000000..94fcfdd2a303 --- /dev/null +++ b/lib/libspl/include/sys/systm.h @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _LIBSPL_SYS_SYSTM_H +#define _LIBSPL_SYS_SYSTM_H + +extern uint64_t physmem; + +#endif diff --git a/lib/libspl/libspl.c b/lib/libspl/libspl.c index 7c24f5cc0668..d189357a1c30 100644 --- a/lib/libspl/libspl.c +++ b/lib/libspl/libspl.c @@ -20,14 +20,22 @@ * CDDL HEADER END */ /* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. * Copyright (c) 2025, Rob Norris */ #include +#include + +uint64_t physmem; void libspl_init(void) { + physmem = sysconf(_SC_PHYS_PAGES); } void diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 24d6fada3c1e..25663882b6e7 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -60,7 +60,6 @@ * Emulation of kernel services in userland. */ -uint64_t physmem; uint32_t hostid; struct utsname hw_utsname; @@ -509,8 +508,6 @@ kernel_init(int mode) umem_nofail_callback(umem_out_of_memory); - physmem = sysconf(_SC_PHYS_PAGES); - dprintf("physmem = %llu pages (%.2f GB)\n", (u_longlong_t)physmem, (double)physmem * sysconf(_SC_PAGE_SIZE) / (1ULL << 30)); From daff6b7e35e5d72dd436c8b35aa85a09b956507d Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 24 Oct 2025 23:39:20 +1100 Subject: [PATCH 65/91] libspl: move utsname() etc to sys/misc.h; initialise in libspl_init() Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 5 +---- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/misc.h | 40 ++++++++++++++++++++++++++++++++++ lib/libspl/libspl.c | 12 ++++++++++ lib/libzpool/kernel.c | 10 --------- 5 files changed, 54 insertions(+), 14 deletions(-) create mode 100644 lib/libspl/include/sys/misc.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index d9eb64b1cbf4..d1cf0bde046d 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -113,7 +113,6 @@ extern "C" { #include #include #include -#include #include #include @@ -131,6 +130,7 @@ extern "C" { #include #include #include +#include #include @@ -267,9 +267,6 @@ extern uint32_t zone_get_hostid(void *zonep); extern int ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result); -typedef struct utsname utsname_t; -extern utsname_t *utsname(void); - /* ZFS Boot Related stuff. */ struct _buf { diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 8c5bb7b72986..dece09145b97 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -43,6 +43,7 @@ libspl_sys_HEADERS = \ %D%/sys/kstat.h \ %D%/sys/list.h \ %D%/sys/list_impl.h \ + %D%/sys/misc.h \ %D%/sys/mhd.h \ %D%/sys/mkdev.h \ %D%/sys/mod.h \ diff --git a/lib/libspl/include/sys/misc.h b/lib/libspl/include/sys/misc.h new file mode 100644 index 000000000000..171bbc1de798 --- /dev/null +++ b/lib/libspl/include/sys/misc.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _LIBSPL_SYS_MISC_H +#define _LIBSPL_SYS_MISC_H + +#include + +/* + * Hostname information + */ +typedef struct utsname utsname_t; +extern utsname_t *utsname(void); + +#endif diff --git a/lib/libspl/libspl.c b/lib/libspl/libspl.c index d189357a1c30..84e44ef51194 100644 --- a/lib/libspl/libspl.c +++ b/lib/libspl/libspl.c @@ -28,14 +28,26 @@ */ #include +#include #include +#include +#include uint64_t physmem; +struct utsname hw_utsname; + +utsname_t * +utsname(void) +{ + return (&hw_utsname); +} void libspl_init(void) { physmem = sysconf(_SC_PHYS_PAGES); + + VERIFY0(uname(&hw_utsname)); } void diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 25663882b6e7..0d658be13057 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -44,7 +44,6 @@ #include #include #include -#include #include #include @@ -61,7 +60,6 @@ */ uint32_t hostid; -struct utsname hw_utsname; /* If set, all blocks read will be copied to the specified directory. */ char *vn_dumpdir = NULL; @@ -405,12 +403,6 @@ ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result) return (0); } -utsname_t * -utsname(void) -{ - return (&hw_utsname); -} - /* * ========================================================================= * kernel emulation setup & teardown @@ -515,8 +507,6 @@ kernel_init(int mode) random_init(); - VERIFY0(uname(&hw_utsname)); - system_taskq_init(); icp_init(); From 55fb30ebe691d3b9e9088adbe335523fb19e53b9 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 24 Oct 2025 23:42:12 +1100 Subject: [PATCH 66/91] zfs_context: move vn_dumpdir to libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/libzpool.h | 2 ++ include/sys/zfs_context.h | 2 -- lib/libspl/cred.c | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/include/libzpool.h b/include/libzpool.h index 3fd6c694d2f3..95991e68116e 100644 --- a/include/libzpool.h +++ b/include/libzpool.h @@ -35,6 +35,8 @@ extern "C" { #endif +extern char *vn_dumpdir; + _LIBZPOOL_H void kernel_init(int mode); _LIBZPOOL_H void kernel_fini(void); diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index d1cf0bde046d..741e3bd3c094 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -187,8 +187,6 @@ extern "C" { typedef off_t loff_t; #endif -extern char *vn_dumpdir; - /* * Random stuff */ diff --git a/lib/libspl/cred.c b/lib/libspl/cred.c index 48527b1998f3..130323ea91a7 100644 --- a/lib/libspl/cred.c +++ b/lib/libspl/cred.c @@ -62,4 +62,3 @@ crgetgroups(cred_t *cr) (void) cr; return (NULL); } - From 1911501c7dffbc0636577143f25b47a79edbab82 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 18 Oct 2025 23:39:19 +1100 Subject: [PATCH 67/91] libspl: move random definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 25 +---------------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/misc.h | 3 ++ lib/libspl/include/sys/random.h | 50 +++++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 24 deletions(-) create mode 100644 lib/libspl/include/sys/random.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 741e3bd3c094..a209c19d22ab 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -126,11 +126,11 @@ extern "C" { #include #include #include -#include #include #include #include #include +#include #include @@ -208,31 +208,8 @@ typedef off_t loff_t; #define NN_DIVISOR_1000 (1U << 0) #define NN_NUMBUF_SZ (6) -extern const char *random_path; -extern const char *urandom_path; - extern int highbit64(uint64_t i); extern int lowbit64(uint64_t i); -extern int random_get_bytes(uint8_t *ptr, size_t len); -extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len); - -static __inline__ uint32_t -random_in_range(uint32_t range) -{ - uint32_t r; - - ASSERT(range != 0); - - if (range == 1) - return (0); - - (void) random_get_pseudo_bytes((uint8_t *)&r, sizeof (r)); - - return (r % range); -} - -extern void random_init(void); -extern void random_fini(void); typedef struct callb_cpr { kmutex_t *cc_lockp; diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index dece09145b97..c7a39fccb206 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -53,6 +53,7 @@ libspl_sys_HEADERS = \ %D%/sys/priv.h \ %D%/sys/processor.h \ %D%/sys/procfs_list.h \ + %D%/sys/random.h \ %D%/sys/rwlock.h \ %D%/sys/simd.h \ %D%/sys/stack.h \ diff --git a/lib/libspl/include/sys/misc.h b/lib/libspl/include/sys/misc.h index 171bbc1de798..8f2f5f9332e7 100644 --- a/lib/libspl/include/sys/misc.h +++ b/lib/libspl/include/sys/misc.h @@ -31,6 +31,9 @@ #include +extern const char *random_path; +extern const char *urandom_path; + /* * Hostname information */ diff --git a/lib/libspl/include/sys/random.h b/lib/libspl/include/sys/random.h new file mode 100644 index 000000000000..27f2d4e3a684 --- /dev/null +++ b/lib/libspl/include/sys/random.h @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_RANDOM_H +#define _SYS_RANDOM_H + +extern int random_get_bytes(uint8_t *ptr, size_t len); +extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len); + +static __inline__ uint32_t +random_in_range(uint32_t range) +{ + uint32_t r; + + ASSERT(range != 0); + + if (range == 1) + return (0); + + (void) random_get_pseudo_bytes((uint8_t *)&r, sizeof (r)); + + return (r % range); +} + +#endif /* _SYS_RANDOM_H */ From 9d609098cd7e23069bf14a443fbf5c4b257cfe56 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Fri, 24 Oct 2025 23:58:42 +1100 Subject: [PATCH 68/91] libspl: move random impl from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/libspl.c | 4 ++ lib/libspl/libspl_impl.h | 7 ++++ lib/libspl/random.c | 84 ++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 55 -------------------------- 5 files changed, 96 insertions(+), 55 deletions(-) create mode 100644 lib/libspl/random.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index 3d46829ed01e..c075be60bf35 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -27,6 +27,7 @@ libspl_la_SOURCES = \ %D%/mutex.c \ %D%/page.c \ %D%/procfs_list.c \ + %D%/random.c \ %D%/rwlock.c \ %D%/strlcat.c \ %D%/strlcpy.c \ diff --git a/lib/libspl/libspl.c b/lib/libspl/libspl.c index 84e44ef51194..63e948bc2829 100644 --- a/lib/libspl/libspl.c +++ b/lib/libspl/libspl.c @@ -32,6 +32,7 @@ #include #include #include +#include "libspl_impl.h" uint64_t physmem; struct utsname hw_utsname; @@ -48,9 +49,12 @@ libspl_init(void) physmem = sysconf(_SC_PHYS_PAGES); VERIFY0(uname(&hw_utsname)); + + random_init(); } void libspl_fini(void) { + random_fini(); } diff --git a/lib/libspl/libspl_impl.h b/lib/libspl/libspl_impl.h index 39392da09ef5..446801f2564b 100644 --- a/lib/libspl/libspl_impl.h +++ b/lib/libspl/libspl_impl.h @@ -21,5 +21,12 @@ * CDDL HEADER END */ +#ifndef _LIBSPL_IMPL_H +#define _LIBSPL_IMPL_H extern ssize_t getexecname_impl(char *execname); + +extern void random_init(void); +extern void random_fini(void); + +#endif diff --git a/lib/libspl/random.c b/lib/libspl/random.c new file mode 100644 index 000000000000..0392737908fe --- /dev/null +++ b/lib/libspl/random.c @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include +#include +#include +#include +#include "libspl_impl.h" + +const char *random_path = "/dev/random"; +const char *urandom_path = "/dev/urandom"; +static int random_fd = -1, urandom_fd = -1; + +void +random_init(void) +{ + VERIFY((random_fd = open(random_path, O_RDONLY | O_CLOEXEC)) != -1); + VERIFY((urandom_fd = open(urandom_path, O_RDONLY | O_CLOEXEC)) != -1); +} + +void +random_fini(void) +{ + close(random_fd); + close(urandom_fd); + + random_fd = -1; + urandom_fd = -1; +} + +static int +random_get_bytes_common(uint8_t *ptr, size_t len, int fd) +{ + size_t resid = len; + ssize_t bytes; + + ASSERT(fd != -1); + + while (resid != 0) { + bytes = read(fd, ptr, resid); + ASSERT3S(bytes, >=, 0); + ptr += bytes; + resid -= bytes; + } + + return (0); +} + +int +random_get_bytes(uint8_t *ptr, size_t len) +{ + return (random_get_bytes_common(ptr, len, random_fd)); +} + +int +random_get_pseudo_bytes(uint8_t *ptr, size_t len) +{ + return (random_get_bytes_common(ptr, len, urandom_fd)); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 0d658be13057..44a85f1ad62d 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -342,57 +342,6 @@ lowbit64(uint64_t i) return (__builtin_ffsll(i)); } -const char *random_path = "/dev/random"; -const char *urandom_path = "/dev/urandom"; -static int random_fd = -1, urandom_fd = -1; - -void -random_init(void) -{ - VERIFY((random_fd = open(random_path, O_RDONLY | O_CLOEXEC)) != -1); - VERIFY((urandom_fd = open(urandom_path, O_RDONLY | O_CLOEXEC)) != -1); -} - -void -random_fini(void) -{ - close(random_fd); - close(urandom_fd); - - random_fd = -1; - urandom_fd = -1; -} - -static int -random_get_bytes_common(uint8_t *ptr, size_t len, int fd) -{ - size_t resid = len; - ssize_t bytes; - - ASSERT(fd != -1); - - while (resid != 0) { - bytes = read(fd, ptr, resid); - ASSERT3S(bytes, >=, 0); - ptr += bytes; - resid -= bytes; - } - - return (0); -} - -int -random_get_bytes(uint8_t *ptr, size_t len) -{ - return (random_get_bytes_common(ptr, len, random_fd)); -} - -int -random_get_pseudo_bytes(uint8_t *ptr, size_t len) -{ - return (random_get_bytes_common(ptr, len, urandom_fd)); -} - int ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result) { @@ -505,8 +454,6 @@ kernel_init(int mode) hostid = (mode & SPA_MODE_WRITE) ? get_system_hostid() : 0; - random_init(); - system_taskq_init(); icp_init(); @@ -531,8 +478,6 @@ kernel_fini(void) icp_fini(); system_taskq_fini(); - random_fini(); - libspl_fini(); } From 2b4a0dd6c007e3c895e2e575ea0d949db669d5c6 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 18 Oct 2025 23:45:31 +1100 Subject: [PATCH 69/91] libspl: move callb stubs from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 23 +---------------------- lib/libspl/include/sys/callb.h | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index a209c19d22ab..c11c2c9e243f 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -79,7 +79,6 @@ extern "C" { #define _SYS_VFS_H #define _SYS_SUNDDI_H -#define _SYS_CALLB_H #include #include @@ -131,6 +130,7 @@ extern "C" { #include #include #include +#include #include @@ -211,27 +211,6 @@ typedef off_t loff_t; extern int highbit64(uint64_t i); extern int lowbit64(uint64_t i); -typedef struct callb_cpr { - kmutex_t *cc_lockp; -} callb_cpr_t; - -#define CALLB_CPR_INIT(cp, lockp, func, name) { \ - (cp)->cc_lockp = lockp; \ -} - -#define CALLB_CPR_SAFE_BEGIN(cp) { \ - ASSERT(MUTEX_HELD((cp)->cc_lockp)); \ -} - -#define CALLB_CPR_SAFE_END(cp, lockp) { \ - ASSERT(MUTEX_HELD((cp)->cc_lockp)); \ -} - -#define CALLB_CPR_EXIT(cp) { \ - ASSERT(MUTEX_HELD((cp)->cc_lockp)); \ - mutex_exit((cp)->cc_lockp); \ -} - #define zone_dataset_visible(x, y) (1) #define INGLOBALZONE(z) (1) extern uint32_t zone_get_hostid(void *zonep); diff --git a/lib/libspl/include/sys/callb.h b/lib/libspl/include/sys/callb.h index 46ed166e52f8..6e8e22338b8b 100644 --- a/lib/libspl/include/sys/callb.h +++ b/lib/libspl/include/sys/callb.h @@ -21,11 +21,36 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _SYS_CALLB_H #define _SYS_CALLB_H +#include + +typedef struct callb_cpr { + kmutex_t *cc_lockp; +} callb_cpr_t; + +#define CALLB_CPR_INIT(cp, lockp, func, name) { \ + (cp)->cc_lockp = lockp; \ +} + +#define CALLB_CPR_SAFE_BEGIN(cp) { \ + ASSERT(MUTEX_HELD((cp)->cc_lockp)); \ +} + +#define CALLB_CPR_SAFE_END(cp, lockp) { \ + ASSERT(MUTEX_HELD((cp)->cc_lockp)); \ +} + +#define CALLB_CPR_EXIT(cp) { \ + ASSERT(MUTEX_HELD((cp)->cc_lockp)); \ + mutex_exit((cp)->cc_lockp); \ +} + #endif From faa295b9a60ef2689e9e78c2bc779ca815a07227 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 12:13:32 +1100 Subject: [PATCH 70/91] libspl: move SID definitions from zfs_context.h; remove kernel gate Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 10 -------- lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/sid.h | 44 ++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 1 + module/zfs/zfs_fuid.c | 2 +- 5 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 lib/libspl/include/sys/sid.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index c11c2c9e243f..bec036db5309 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -238,16 +238,6 @@ extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr); extern int secpolicy_zfs(const cred_t *cr); extern zoneid_t getzoneid(void); -/* SID stuff */ -typedef struct ksiddomain { - uint_t kd_ref; - uint_t kd_len; - char *kd_name; -} ksiddomain_t; - -ksiddomain_t *ksid_lookupdomain(const char *); -void ksiddomain_rele(ksiddomain_t *); - #define DDI_SLEEP KM_SLEEP #define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) \ sysevent_post_event(_c, _d, _b, "libzpool", _e, _f) diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index c7a39fccb206..6784823e58dc 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -55,6 +55,7 @@ libspl_sys_HEADERS = \ %D%/sys/procfs_list.h \ %D%/sys/random.h \ %D%/sys/rwlock.h \ + %D%/sys/sid.h \ %D%/sys/simd.h \ %D%/sys/stack.h \ %D%/sys/stdtypes.h \ diff --git a/lib/libspl/include/sys/sid.h b/lib/libspl/include/sys/sid.h new file mode 100644 index 000000000000..74789c5d9a62 --- /dev/null +++ b/lib/libspl/include/sys/sid.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_SID_H +#define _SYS_SID_H + +#include + +/* SID stuff */ +typedef struct ksiddomain { + uint_t kd_ref; + uint_t kd_len; + char *kd_name; +} ksiddomain_t; + +ksiddomain_t *ksid_lookupdomain(const char *); +void ksiddomain_rele(ksiddomain_t *); + +#endif diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 44a85f1ad62d..33e03b127709 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include diff --git a/module/zfs/zfs_fuid.c b/module/zfs/zfs_fuid.c index 7f786c00b93a..aa10741ba870 100644 --- a/module/zfs/zfs_fuid.c +++ b/module/zfs/zfs_fuid.c @@ -28,8 +28,8 @@ #include #include #include -#ifdef _KERNEL #include +#ifdef _KERNEL #include #include #endif From 70a1fadaf24ec7e7578215c9cd35414a03b672cd Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Mon, 27 Oct 2025 14:37:06 +1100 Subject: [PATCH 71/91] libspl: move SID implementation from libzpool Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/Makefile.am | 1 + lib/libspl/sid.c | 47 ++++++++++++++++++++++++++++++++++++++++++ lib/libzpool/kernel.c | 17 --------------- 3 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 lib/libspl/sid.c diff --git a/lib/libspl/Makefile.am b/lib/libspl/Makefile.am index c075be60bf35..27f004634487 100644 --- a/lib/libspl/Makefile.am +++ b/lib/libspl/Makefile.am @@ -29,6 +29,7 @@ libspl_la_SOURCES = \ %D%/procfs_list.c \ %D%/random.c \ %D%/rwlock.c \ + %D%/sid.c \ %D%/strlcat.c \ %D%/strlcpy.c \ %D%/taskq.c \ diff --git a/lib/libspl/sid.c b/lib/libspl/sid.c new file mode 100644 index 000000000000..b7d5b5f2e778 --- /dev/null +++ b/lib/libspl/sid.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2016 Actifio, Inc. All rights reserved. + * Copyright (c) 2025, Klara, Inc. + */ + +#include +#include + +ksiddomain_t * +ksid_lookupdomain(const char *dom) +{ + ksiddomain_t *kd; + + kd = umem_zalloc(sizeof (ksiddomain_t), UMEM_NOFAIL); + kd->kd_name = strdup(dom); + return (kd); +} + +void +ksiddomain_rele(ksiddomain_t *ksid) +{ + free(ksid->kd_name); + umem_free(ksid, sizeof (ksiddomain_t)); +} diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 33e03b127709..8fd9157f47c7 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -510,23 +510,6 @@ secpolicy_zfs(const cred_t *cr) return (0); } -ksiddomain_t * -ksid_lookupdomain(const char *dom) -{ - ksiddomain_t *kd; - - kd = umem_zalloc(sizeof (ksiddomain_t), UMEM_NOFAIL); - kd->kd_name = spa_strdup(dom); - return (kd); -} - -void -ksiddomain_rele(ksiddomain_t *ksid) -{ - spa_strfree(ksid->kd_name); - umem_free(ksid, sizeof (ksiddomain_t)); -} - zfs_file_t * zfs_onexit_fd_hold(int fd, minor_t *minorp) { From b5af61b569613885e94d6962b7faf1f75a21aa03 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 13:09:34 +1100 Subject: [PATCH 72/91] libspl: move zone definitions from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 6 +----- lib/libspl/include/sys/zone.h | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index bec036db5309..d8c544663d65 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -113,6 +113,7 @@ extern "C" { #include #include #include +#include #include #include @@ -211,10 +212,6 @@ typedef off_t loff_t; extern int highbit64(uint64_t i); extern int lowbit64(uint64_t i); -#define zone_dataset_visible(x, y) (1) -#define INGLOBALZONE(z) (1) -extern uint32_t zone_get_hostid(void *zonep); - /* * Hostname information */ @@ -236,7 +233,6 @@ extern int zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr); extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr); extern int secpolicy_zfs(const cred_t *cr); -extern zoneid_t getzoneid(void); #define DDI_SLEEP KM_SLEEP #define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) \ diff --git a/lib/libspl/include/sys/zone.h b/lib/libspl/include/sys/zone.h index f4037b4875a9..179cc004fdb8 100644 --- a/lib/libspl/include/sys/zone.h +++ b/lib/libspl/include/sys/zone.h @@ -21,11 +21,19 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ -#ifndef _LIBSPL_SYS_ZONE_H -#define _LIBSPL_SYS_ZONE_H +#ifndef _SYS_ZONE_H +#define _SYS_ZONE_H -#endif +#define zone_dataset_visible(x, y) (1) + +#define INGLOBALZONE(z) (1) + +extern uint32_t zone_get_hostid(void *zonep); + +#endif /* _SYS_ZONE_H */ From ee0e86cfb560506f65b16659195b156c74f17969 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 13:18:12 +1100 Subject: [PATCH 73/91] libzpool: remove unused userspace ioctl policy functions Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 6 ------ lib/libzpool/kernel.c | 28 ---------------------------- 2 files changed, 34 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index d8c544663d65..1d5d6e45a764 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -228,12 +228,6 @@ struct bootstat { uint64_t st_size; }; -extern int zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr); -extern int zfs_secpolicy_rename_perms(const char *from, const char *to, - cred_t *cr); -extern int zfs_secpolicy_destroy_perms(const char *name, cred_t *cr); -extern int secpolicy_zfs(const cred_t *cr); - #define DDI_SLEEP KM_SLEEP #define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) \ sysevent_post_event(_c, _d, _b, "libzpool", _e, _f) diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c index 8fd9157f47c7..7e3ffec3b81d 100644 --- a/lib/libzpool/kernel.c +++ b/lib/libzpool/kernel.c @@ -482,34 +482,6 @@ kernel_fini(void) libspl_fini(); } -int -zfs_secpolicy_snapshot_perms(const char *name, cred_t *cr) -{ - (void) name, (void) cr; - return (0); -} - -int -zfs_secpolicy_rename_perms(const char *from, const char *to, cred_t *cr) -{ - (void) from, (void) to, (void) cr; - return (0); -} - -int -zfs_secpolicy_destroy_perms(const char *name, cred_t *cr) -{ - (void) name, (void) cr; - return (0); -} - -int -secpolicy_zfs(const cred_t *cr) -{ - (void) cr; - return (0); -} - zfs_file_t * zfs_onexit_fd_hold(int fd, minor_t *minorp) { From 559597b66ce7996b81451631833c88c811a7eeec Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 13:25:44 +1100 Subject: [PATCH 74/91] zfs_context: remove misc unused Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 1d5d6e45a764..0cde355bea99 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -77,7 +77,6 @@ extern "C" { #include #else /* _KERNEL || _STANDALONE */ -#define _SYS_VFS_H #define _SYS_SUNDDI_H #include @@ -206,7 +205,6 @@ typedef off_t loff_t; #define CPU_SEQID ((uintptr_t)pthread_self() & (max_ncpus - 1)) #define CPU_SEQID_UNSTABLE CPU_SEQID -#define NN_DIVISOR_1000 (1U << 0) #define NN_NUMBUF_SZ (6) extern int highbit64(uint64_t i); @@ -218,20 +216,6 @@ extern int lowbit64(uint64_t i); extern int ddi_strtoull(const char *str, char **nptr, int base, u_longlong_t *result); -/* ZFS Boot Related stuff. */ - -struct _buf { - intptr_t _fd; -}; - -struct bootstat { - uint64_t st_size; -}; - -#define DDI_SLEEP KM_SLEEP -#define ddi_log_sysevent(_a, _b, _c, _d, _e, _f, _g) \ - sysevent_post_event(_c, _d, _b, "libzpool", _e, _f) - /* * Kernel modules */ From 03b2e5c40c508dc51a28f821ae273b5de0863c05 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 13:34:14 +1100 Subject: [PATCH 75/91] libspl: move remaining ddi_* prototypes from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 8 -------- lib/libspl/include/sys/sunddi.h | 8 +++++++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 0cde355bea99..50f43c10c20b 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -77,8 +77,6 @@ extern "C" { #include #else /* _KERNEL || _STANDALONE */ -#define _SYS_SUNDDI_H - #include #include #include @@ -210,12 +208,6 @@ typedef off_t loff_t; extern int highbit64(uint64_t i); extern int lowbit64(uint64_t i); -/* - * Hostname information - */ -extern int ddi_strtoull(const char *str, char **nptr, int base, - u_longlong_t *result); - /* * Kernel modules */ diff --git a/lib/libspl/include/sys/sunddi.h b/lib/libspl/include/sys/sunddi.h index 8489c7139bad..48e0b15a4542 100644 --- a/lib/libspl/include/sys/sunddi.h +++ b/lib/libspl/include/sys/sunddi.h @@ -21,10 +21,16 @@ * CDDL HEADER END */ /* - * Copyright (c) 2008 by Sun Microsystems, Inc. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _SYS_SUNDDI_H #define _SYS_SUNDDI_H +extern int ddi_strtoull(const char *str, char **nptr, int base, + u_longlong_t *result); + #endif /* _SYS_SUNDDI_H */ From 248c7ed0d29d5ecde64456ec30ba850e23074478 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 13:42:49 +1100 Subject: [PATCH 76/91] libspl: move DTRACE_PROBE macros from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 42 +------------------ lib/libspl/include/Makefile.am | 1 + lib/libspl/include/sys/trace.h | 73 ++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 41 deletions(-) create mode 100644 lib/libspl/include/sys/trace.h diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 50f43c10c20b..da16f4ceea8a 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -129,6 +129,7 @@ extern "C" { #include #include #include +#include #include @@ -140,47 +141,6 @@ extern "C" { #define likely(x) __builtin_expect((x), 1) #define unlikely(x) __builtin_expect((x), 0) -/* - * DTrace SDT probes have different signatures in userland than they do in - * the kernel. If they're being used in kernel code, re-define them out of - * existence for their counterparts in libzpool. - * - * Here's an example of how to use the set-error probes in userland: - * zfs$target:::set-error /arg0 == EBUSY/ {stack();} - * - * Here's an example of how to use DTRACE_PROBE probes in userland: - * If there is a probe declared as follows: - * DTRACE_PROBE2(zfs__probe_name, uint64_t, blkid, dnode_t *, dn); - * Then you can use it as follows: - * zfs$target:::probe2 /copyinstr(arg0) == "zfs__probe_name"/ - * {printf("%u %p\n", arg1, arg2);} - */ - -#ifdef DTRACE_PROBE -#undef DTRACE_PROBE -#endif /* DTRACE_PROBE */ -#define DTRACE_PROBE(a) - -#ifdef DTRACE_PROBE1 -#undef DTRACE_PROBE1 -#endif /* DTRACE_PROBE1 */ -#define DTRACE_PROBE1(a, b, c) - -#ifdef DTRACE_PROBE2 -#undef DTRACE_PROBE2 -#endif /* DTRACE_PROBE2 */ -#define DTRACE_PROBE2(a, b, c, d, e) - -#ifdef DTRACE_PROBE3 -#undef DTRACE_PROBE3 -#endif /* DTRACE_PROBE3 */ -#define DTRACE_PROBE3(a, b, c, d, e, f, g) - -#ifdef DTRACE_PROBE4 -#undef DTRACE_PROBE4 -#endif /* DTRACE_PROBE4 */ -#define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) - #ifdef __FreeBSD__ typedef off_t loff_t; #endif diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 6784823e58dc..73c29cca5d6d 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -67,6 +67,7 @@ libspl_sys_HEADERS = \ %D%/sys/taskq.h \ %D%/sys/time.h \ %D%/sys/timer.h \ + %D%/sys/trace.h \ %D%/sys/trace_spl.h \ %D%/sys/tsd.h \ %D%/sys/tunables.h \ diff --git a/lib/libspl/include/sys/trace.h b/lib/libspl/include/sys/trace.h new file mode 100644 index 000000000000..17b812faed20 --- /dev/null +++ b/lib/libspl/include/sys/trace.h @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ + +#ifndef _SYS_TRACE_H +#define _SYS_TRACE_H + +/* + * DTrace SDT probes have different signatures in userland than they do in + * the kernel. If they're being used in kernel code, re-define them out of + * existence for their counterparts in libzpool. + * + * Here's an example of how to use the set-error probes in userland: + * zfs$target:::set-error /arg0 == EBUSY/ {stack();} + * + * Here's an example of how to use DTRACE_PROBE probes in userland: + * If there is a probe declared as follows: + * DTRACE_PROBE2(zfs__probe_name, uint64_t, blkid, dnode_t *, dn); + * Then you can use it as follows: + * zfs$target:::probe2 /copyinstr(arg0) == "zfs__probe_name"/ + * {printf("%u %p\n", arg1, arg2);} + */ + +#ifdef DTRACE_PROBE +#undef DTRACE_PROBE +#endif /* DTRACE_PROBE */ +#define DTRACE_PROBE(a) + +#ifdef DTRACE_PROBE1 +#undef DTRACE_PROBE1 +#endif /* DTRACE_PROBE1 */ +#define DTRACE_PROBE1(a, b, c) + +#ifdef DTRACE_PROBE2 +#undef DTRACE_PROBE2 +#endif /* DTRACE_PROBE2 */ +#define DTRACE_PROBE2(a, b, c, d, e) + +#ifdef DTRACE_PROBE3 +#undef DTRACE_PROBE3 +#endif /* DTRACE_PROBE3 */ +#define DTRACE_PROBE3(a, b, c, d, e, f, g) + +#ifdef DTRACE_PROBE4 +#undef DTRACE_PROBE4 +#endif /* DTRACE_PROBE4 */ +#define DTRACE_PROBE4(a, b, c, d, e, f, g, h, i) + +#endif /* _SYS_TRACE_H */ From b9d2e7782ffc28239095cc3e2bbffb18f8905a74 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 13:57:19 +1100 Subject: [PATCH 77/91] libspl: common sysmacros.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 21 --------- lib/libspl/include/Makefile.am | 5 +-- lib/libspl/include/os/freebsd/sys/sysmacros.h | 1 - .../include/{os/linux => }/sys/sysmacros.h | 43 ++++++++++++++----- scripts/spdxcheck.pl | 1 - 5 files changed, 35 insertions(+), 36 deletions(-) delete mode 100644 lib/libspl/include/os/freebsd/sys/sysmacros.h rename lib/libspl/include/{os/linux => }/sys/sysmacros.h (72%) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index da16f4ceea8a..08c0b58a574c 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -145,29 +145,8 @@ extern "C" { typedef off_t loff_t; #endif -/* - * Random stuff - */ -#define max_ncpus 64 -#define boot_ncpus (sysconf(_SC_NPROCESSORS_ONLN)) - -/* - * Process priorities as defined by setpriority(2) and getpriority(2). - */ -#define minclsyspri 19 -#define defclsyspri 0 -/* Write issue taskq priority. */ -#define wtqclsyspri -19 -#define maxclsyspri -20 - -#define CPU_SEQID ((uintptr_t)pthread_self() & (max_ncpus - 1)) -#define CPU_SEQID_UNSTABLE CPU_SEQID - #define NN_NUMBUF_SZ (6) -extern int highbit64(uint64_t i); -extern int lowbit64(uint64_t i); - /* * Kernel modules */ diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 73c29cca5d6d..202f15944762 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -61,6 +61,7 @@ libspl_sys_HEADERS = \ %D%/sys/stdtypes.h \ %D%/sys/string.h \ %D%/sys/sunddi.h \ + %D%/sys/sysmacros.h \ %D%/sys/systeminfo.h \ %D%/sys/systm.h \ %D%/sys/thread.h \ @@ -88,8 +89,7 @@ libspl_sys_HEADERS += \ %D%/os/linux/sys/mount.h \ %D%/os/linux/sys/param.h \ %D%/os/linux/sys/stat.h \ - %D%/os/linux/sys/sysmacros.h \ - %D%/os/linux/sys/vfs.h \ + %D%/os/linux/sys/vfs.h libspl_ia32_HEADERS = \ %D%/os/linux/sys/ia32/asm_linkage.h @@ -104,7 +104,6 @@ libspl_sys_HEADERS += \ %D%/os/freebsd/sys/mount.h \ %D%/os/freebsd/sys/param.h \ %D%/os/freebsd/sys/stat.h \ - %D%/os/freebsd/sys/sysmacros.h \ %D%/os/freebsd/sys/vfs.h libspl_ia32_HEADERS = \ diff --git a/lib/libspl/include/os/freebsd/sys/sysmacros.h b/lib/libspl/include/os/freebsd/sys/sysmacros.h deleted file mode 100644 index d9639d27b60e..000000000000 --- a/lib/libspl/include/os/freebsd/sys/sysmacros.h +++ /dev/null @@ -1 +0,0 @@ -/* keep me */ diff --git a/lib/libspl/include/os/linux/sys/sysmacros.h b/lib/libspl/include/sys/sysmacros.h similarity index 72% rename from lib/libspl/include/os/linux/sys/sysmacros.h rename to lib/libspl/include/sys/sysmacros.h index 66e0da6b5afe..e33915c8d96b 100644 --- a/lib/libspl/include/os/linux/sys/sysmacros.h +++ b/lib/libspl/include/sys/sysmacros.h @@ -3,9 +3,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or https://opensource.org/licenses/CDDL-1.0. @@ -21,14 +20,26 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _LIBSPL_SYS_SYSMACROS_H #define _LIBSPL_SYS_SYSMACROS_H +#include + +#ifdef __linux__ +/* + * On Linux, we need the system-provided sysmacros.h to get the makedev(), + * major() and minor() definitions for makedevice() below. FreeBSD does not + * have this header, so include_next won't find it and will abort. So, we + * protect it with a platform check. + */ #include_next +#endif /* common macros */ #ifndef MIN @@ -94,10 +105,22 @@ #define P2SAMEHIGHBIT_TYPED(x, y, type) \ (((type)(x) ^ (type)(y)) < ((type)(x) & (type)(y))) +#define max_ncpus 64 +#define boot_ncpus (sysconf(_SC_NPROCESSORS_ONLN)) -/* avoid any possibility of clashing with version */ -#if defined(_KERNEL) && !defined(_KMEMUSER) && !defined(offsetof) -#define offsetof(s, m) ((size_t)(&(((s *)0)->m))) -#endif +/* + * Process priorities as defined by setpriority(2) and getpriority(2). + */ +#define minclsyspri 19 +#define defclsyspri 0 +/* Write issue taskq priority. */ +#define wtqclsyspri -19 +#define maxclsyspri -20 -#endif /* _LIBSPL_SYS_SYSMACROS_H */ +#define CPU_SEQID ((uintptr_t)pthread_self() & (max_ncpus - 1)) +#define CPU_SEQID_UNSTABLE CPU_SEQID + +extern int lowbit64(uint64_t i); +extern int highbit64(uint64_t i); + +#endif /* _SYS_SYSMACROS_H */ diff --git a/scripts/spdxcheck.pl b/scripts/spdxcheck.pl index e119f13518cc..1b3dd639318f 100755 --- a/scripts/spdxcheck.pl +++ b/scripts/spdxcheck.pl @@ -127,7 +127,6 @@ my $untagged_patterns = q( include/os/freebsd/spl/sys/trace_zfs.h include/os/freebsd/zfs/sys/zpl.h include/os/linux/kernel/linux/page_compat.h - lib/libspl/include/os/freebsd/sys/sysmacros.h lib/libspl/include/sys/string.h lib/libspl/include/sys/trace_spl.h lib/libzdb/libzdb.c From a43edeefaf7102dff2980c9dd401ae3dfe4ecf2f Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 14:27:26 +1100 Subject: [PATCH 78/91] libzutil: move NN_NUMBUF_SZ from zfs_context.h nearer to nicenum() Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/libzutil.h | 1 + include/sys/zfs_context.h | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/include/libzutil.h b/include/libzutil.h index 001ece2280f6..59599b0f63f4 100644 --- a/include/libzutil.h +++ b/include/libzutil.h @@ -165,6 +165,7 @@ _LIBZUTIL_H void zfs_nicetime(uint64_t, char *, size_t); _LIBZUTIL_H void zfs_niceraw(uint64_t, char *, size_t); #define nicenum(num, buf, size) zfs_nicenum(num, buf, size) +#define NN_NUMBUF_SZ (6) _LIBZUTIL_H void zpool_dump_ddt(const ddt_stat_t *, const ddt_histogram_t *); _LIBZUTIL_H int zpool_history_unpack(char *, uint64_t, uint64_t *, nvlist_t ***, diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 08c0b58a574c..d010b4eb39a2 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -145,8 +145,6 @@ extern "C" { typedef off_t loff_t; #endif -#define NN_NUMBUF_SZ (6) - /* * Kernel modules */ From 292438295daedf76b58a83319ca68ac541702312 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 14:41:38 +1100 Subject: [PATCH 79/91] libspl: move compiler attribute macros from zfs_context.h sys/debug.h is not really the right place for them, but we already have some there for libspl, so it is at least convenient. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 8 -------- lib/libspl/include/sys/debug.h | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index d010b4eb39a2..7c410dc23baa 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -133,14 +133,6 @@ extern "C" { #include -/* - * Stack - */ - -#define noinline __attribute__((noinline)) -#define likely(x) __builtin_expect((x), 1) -#define unlikely(x) __builtin_expect((x), 0) - #ifdef __FreeBSD__ typedef off_t loff_t; #endif diff --git a/lib/libspl/include/sys/debug.h b/lib/libspl/include/sys/debug.h index 02f33a68b75b..6ce8c88f6aa4 100644 --- a/lib/libspl/include/sys/debug.h +++ b/lib/libspl/include/sys/debug.h @@ -24,6 +24,12 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* + * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright (c) 2012, 2018 by Delphix. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. + */ #ifndef _LIBSPL_SYS_DEBUG_H #define _LIBSPL_SYS_DEBUG_H @@ -42,4 +48,16 @@ #define __must_check __attribute__((warn_unused_result)) #endif +#ifndef noinline +#define noinline __attribute__((noinline)) +#endif + +#ifndef likely +#define likely(x) __builtin_expect((x), 1) +#endif + +#ifndef unlikely +#define unlikely(x) __builtin_expect((x), 0) +#endif + #endif From 5305d0f8b913c9ea15ae617d78ff87b8f28a2c8b Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 14:44:14 +1100 Subject: [PATCH 80/91] zfs_context: move empty __init/__exit macros to sys/debug.h These are kind-of compiler attribute placeholders, so go here with the others for now. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 6 ------ lib/libspl/include/sys/debug.h | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 7c410dc23baa..dfd37930f7e8 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -137,12 +137,6 @@ extern "C" { typedef off_t loff_t; #endif -/* - * Kernel modules - */ -#define __init -#define __exit - #endif /* _KERNEL || _STANDALONE */ #ifdef __cplusplus diff --git a/lib/libspl/include/sys/debug.h b/lib/libspl/include/sys/debug.h index 6ce8c88f6aa4..2bd077686f1c 100644 --- a/lib/libspl/include/sys/debug.h +++ b/lib/libspl/include/sys/debug.h @@ -60,4 +60,10 @@ #define unlikely(x) __builtin_expect((x), 0) #endif +/* + * Kernel modules + */ +#define __init +#define __exit + #endif From eceb5b32e9c3e8b5cdf6ddc664455e54b9dca03c Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 19 Oct 2025 15:09:48 +1100 Subject: [PATCH 81/91] libspl: move loff_t declaration from zfs_context.h Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 4 ---- lib/libspl/include/sys/types.h | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index dfd37930f7e8..4be22835d2a2 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -133,10 +133,6 @@ extern "C" { #include -#ifdef __FreeBSD__ -typedef off_t loff_t; -#endif - #endif /* _KERNEL || _STANDALONE */ #ifdef __cplusplus diff --git a/lib/libspl/include/sys/types.h b/lib/libspl/include/sys/types.h index f4bb85c7942e..9af20d781674 100644 --- a/lib/libspl/include/sys/types.h +++ b/lib/libspl/include/sys/types.h @@ -50,4 +50,8 @@ typedef int projid_t; #include /* for NBBY */ +#ifdef __FreeBSD__ +typedef off_t loff_t; +#endif + #endif From 801d9b4f9685560e154ccb0b26fef5a2f0aa38d4 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 30 Oct 2025 17:23:27 -0700 Subject: [PATCH 82/91] debug: move all of the debug bits out of the spl Pull all of the internal debug infrastructure up in to the zfs code to clean up the layering. Remove all the dodgy usage of SET_ERROR and DTRACE_PROBE from the spl. Luckily it was lightly used in the spl layer so we're not losing much. Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/os/freebsd/Makefile.am | 4 +-- .../os/freebsd/{spl => zfs}/sys/trace_zfs.h | 0 .../{spl/sys/sdt.h => zfs/sys/zfs_debug_os.h} | 9 +++--- include/os/linux/Makefile.am | 2 +- include/os/linux/spl/sys/sysmacros.h | 8 ----- include/os/linux/zfs/sys/zfs_debug_os.h | 29 +++++++++++++++++++ include/sys/zfs_context.h | 1 - include/sys/zfs_debug.h | 1 + lib/libspl/include/Makefile.am | 1 - lib/libspl/include/sys/trace_spl.h | 24 --------------- lib/libzpool/include/Makefile.am | 3 +- lib/libzpool/include/sys/trace_zfs.h | 25 +--------------- lib/libzpool/include/sys/zfs_debug_os.h | 29 +++++++++++++++++++ module/os/freebsd/spl/spl_uio.c | 2 +- module/os/linux/spl/spl-taskq.c | 14 --------- scripts/spdxcheck.pl | 1 - 16 files changed, 71 insertions(+), 82 deletions(-) rename include/os/freebsd/{spl => zfs}/sys/trace_zfs.h (100%) rename include/os/freebsd/{spl/sys/sdt.h => zfs/sys/zfs_debug_os.h} (92%) create mode 100644 include/os/linux/zfs/sys/zfs_debug_os.h delete mode 100644 lib/libspl/include/sys/trace_spl.h create mode 100644 lib/libzpool/include/sys/zfs_debug_os.h diff --git a/include/os/freebsd/Makefile.am b/include/os/freebsd/Makefile.am index d6b6923d033f..47cf6756ab7d 100644 --- a/include/os/freebsd/Makefile.am +++ b/include/os/freebsd/Makefile.am @@ -44,7 +44,6 @@ noinst_HEADERS = \ %D%/spl/sys/procfs_list.h \ %D%/spl/sys/random.h \ %D%/spl/sys/rwlock.h \ - %D%/spl/sys/sdt.h \ %D%/spl/sys/sid.h \ %D%/spl/sys/sig.h \ %D%/spl/sys/simd.h \ @@ -63,7 +62,6 @@ noinst_HEADERS = \ %D%/spl/sys/time.h \ %D%/spl/sys/timer.h \ %D%/spl/sys/trace.h \ - %D%/spl/sys/trace_zfs.h \ %D%/spl/sys/types.h \ %D%/spl/sys/types32.h \ %D%/spl/sys/uio.h \ @@ -82,10 +80,12 @@ noinst_HEADERS = \ %D%/zfs/sys/arc_os.h \ %D%/zfs/sys/freebsd_crypto.h \ %D%/zfs/sys/freebsd_event.h \ + %D%/zfs/sys/trace_zfs.h \ %D%/zfs/sys/vdev_os.h \ %D%/zfs/sys/zfs_bootenv_os.h \ %D%/zfs/sys/zfs_context_os.h \ %D%/zfs/sys/zfs_ctldir.h \ + %D%/zfs/sys/zfs_debug_os.h \ %D%/zfs/sys/zfs_dir.h \ %D%/zfs/sys/zfs_ioctl_compat.h \ %D%/zfs/sys/zfs_vfsops_os.h \ diff --git a/include/os/freebsd/spl/sys/trace_zfs.h b/include/os/freebsd/zfs/sys/trace_zfs.h similarity index 100% rename from include/os/freebsd/spl/sys/trace_zfs.h rename to include/os/freebsd/zfs/sys/trace_zfs.h diff --git a/include/os/freebsd/spl/sys/sdt.h b/include/os/freebsd/zfs/sys/zfs_debug_os.h similarity index 92% rename from include/os/freebsd/spl/sys/sdt.h rename to include/os/freebsd/zfs/sys/zfs_debug_os.h index ef1dad6c14c9..cc7540c4f83c 100644 --- a/include/os/freebsd/spl/sys/sdt.h +++ b/include/os/freebsd/zfs/sys/zfs_debug_os.h @@ -27,10 +27,11 @@ * $FreeBSD$ */ -#ifndef _OPENSOLARIS_SYS_SDT_H_ -#define _OPENSOLARIS_SYS_SDT_H_ +#ifndef _SYS_ZFS_DEBUG_OS_H +#define _SYS_ZFS_DEBUG_OS_H + +#include -#include_next #ifdef KDTRACE_HOOKS SDT_PROBE_DECLARE(sdt, , , set__error); @@ -44,4 +45,4 @@ SDT_PROBE_DECLARE(sdt, , , set__error); #define SET_ERROR(err) (err) #endif -#endif /* _OPENSOLARIS_SYS_SDT_H_ */ +#endif /* _SYS_ZFS_DEBUG_OS_H */ diff --git a/include/os/linux/Makefile.am b/include/os/linux/Makefile.am index e156ca183dbd..9188a974cc22 100644 --- a/include/os/linux/Makefile.am +++ b/include/os/linux/Makefile.am @@ -41,6 +41,7 @@ kernel_sys_HEADERS = \ %D%/zfs/sys/zfs_bootenv_os.h \ %D%/zfs/sys/zfs_context_os.h \ %D%/zfs/sys/zfs_ctldir.h \ + %D%/zfs/sys/zfs_debug_os.h \ %D%/zfs/sys/zfs_dir.h \ %D%/zfs/sys/zfs_vfsops_os.h \ %D%/zfs/sys/zfs_vnops_os.h \ @@ -97,7 +98,6 @@ kernel_spl_sys_HEADERS = \ %D%/spl/sys/time.h \ %D%/spl/sys/timer.h \ %D%/spl/sys/trace.h \ - %D%/spl/sys/trace_spl.h \ %D%/spl/sys/trace_taskq.h \ %D%/spl/sys/tsd.h \ %D%/spl/sys/types.h \ diff --git a/include/os/linux/spl/sys/sysmacros.h b/include/os/linux/spl/sys/sysmacros.h index db48222b712a..dc9e9e492ae4 100644 --- a/include/os/linux/spl/sys/sysmacros.h +++ b/include/os/linux/spl/sys/sysmacros.h @@ -34,11 +34,6 @@ #include #include - -#ifndef _KERNEL -#define _KERNEL __KERNEL__ -#endif - #define FALSE 0 #define TRUE 1 @@ -202,9 +197,6 @@ makedev(unsigned int major, unsigned int minor) #define P2SAMEHIGHBIT_TYPED(x, y, type) \ (((type)(x) ^ (type)(y)) < ((type)(x) & (type)(y))) -#define SET_ERROR(err) \ - (__set_error(__FILE__, __func__, __LINE__, err), err) - #include #define qsort(base, num, size, cmp) \ sort(base, num, size, cmp, NULL) diff --git a/include/os/linux/zfs/sys/zfs_debug_os.h b/include/os/linux/zfs/sys/zfs_debug_os.h new file mode 100644 index 000000000000..2841809528b6 --- /dev/null +++ b/include/os/linux/zfs/sys/zfs_debug_os.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#ifndef _SYS_ZFS_DEBUG_OS_H +#define _SYS_ZFS_DEBUG_OS_H + +#define SET_ERROR(err) \ + (__set_error(__FILE__, __func__, __LINE__, err), err) + +#endif /* _SYS_ZFS_DEBUG_OS_H */ diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index 4be22835d2a2..aeac81df9ea8 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -109,7 +109,6 @@ extern "C" { #include #include #include -#include #include #include diff --git a/include/sys/zfs_debug.h b/include/sys/zfs_debug.h index 4d4cd4c39e97..0f021d15157b 100644 --- a/include/sys/zfs_debug.h +++ b/include/sys/zfs_debug.h @@ -40,6 +40,7 @@ extern "C" { #endif #include +#include extern int zfs_flags; extern int zfs_recover; diff --git a/lib/libspl/include/Makefile.am b/lib/libspl/include/Makefile.am index 202f15944762..e68742409839 100644 --- a/lib/libspl/include/Makefile.am +++ b/lib/libspl/include/Makefile.am @@ -69,7 +69,6 @@ libspl_sys_HEADERS = \ %D%/sys/time.h \ %D%/sys/timer.h \ %D%/sys/trace.h \ - %D%/sys/trace_spl.h \ %D%/sys/tsd.h \ %D%/sys/tunables.h \ %D%/sys/types.h \ diff --git a/lib/libspl/include/sys/trace_spl.h b/lib/libspl/include/sys/trace_spl.h deleted file mode 100644 index b80d288f7332..000000000000 --- a/lib/libspl/include/sys/trace_spl.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Here to keep the libspl build happy */ - -#ifndef _LIBSPL_SPL_TRACE_H -#define _LIBSPL_SPL_TRACE_H - -/* - * The set-error SDT probe is extra static, in that we declare its fake - * function literally, rather than with the DTRACE_PROBE1() macro. This is - * necessary so that SET_ERROR() can evaluate to a value, which wouldn't - * be possible if it required multiple statements (to declare the function - * and then call it). - * - * SET_ERROR() uses the comma operator so that it can be used without much - * additional code. For example, "return (EINVAL);" becomes - * "return (SET_ERROR(EINVAL));". Note that the argument will be evaluated - * twice, so it should not have side effects (e.g. something like: - * "return (SET_ERROR(log_error(EINVAL, info)));" would log the error twice). - */ -#undef SET_ERROR -#define SET_ERROR(err) \ - (__set_error(__FILE__, __func__, __LINE__, err), err) - - -#endif diff --git a/lib/libzpool/include/Makefile.am b/lib/libzpool/include/Makefile.am index 54d10e62358b..420b6f64666b 100644 --- a/lib/libzpool/include/Makefile.am +++ b/lib/libzpool/include/Makefile.am @@ -3,4 +3,5 @@ libzpool_sys_HEADERS = \ %D%/sys/abd_os.h \ %D%/sys/abd_impl_os.h \ %D%/sys/trace_zfs.h \ - %D%/sys/zfs_context_os.h + %D%/sys/zfs_context_os.h \ + %D%/sys/zfs_debug_os.h diff --git a/lib/libzpool/include/sys/trace_zfs.h b/lib/libzpool/include/sys/trace_zfs.h index 87ed5ad3c3be..d9639d27b60e 100644 --- a/lib/libzpool/include/sys/trace_zfs.h +++ b/lib/libzpool/include/sys/trace_zfs.h @@ -1,24 +1 @@ -/* Here to keep the libspl build happy */ - -#ifndef _LIBSPL_ZFS_TRACE_H -#define _LIBSPL_ZFS_TRACE_H - -/* - * The set-error SDT probe is extra static, in that we declare its fake - * function literally, rather than with the DTRACE_PROBE1() macro. This is - * necessary so that SET_ERROR() can evaluate to a value, which wouldn't - * be possible if it required multiple statements (to declare the function - * and then call it). - * - * SET_ERROR() uses the comma operator so that it can be used without much - * additional code. For example, "return (EINVAL);" becomes - * "return (SET_ERROR(EINVAL));". Note that the argument will be evaluated - * twice, so it should not have side effects (e.g. something like: - * "return (SET_ERROR(log_error(EINVAL, info)));" would log the error twice). - */ -#undef SET_ERROR -#define SET_ERROR(err) \ - (__set_error(__FILE__, __func__, __LINE__, err), err) - - -#endif +/* keep me */ diff --git a/lib/libzpool/include/sys/zfs_debug_os.h b/lib/libzpool/include/sys/zfs_debug_os.h new file mode 100644 index 000000000000..b59165a6c903 --- /dev/null +++ b/lib/libzpool/include/sys/zfs_debug_os.h @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +#ifndef _SYS_ZFS_DEBUG_OS_H +#define _SYS_ZFS_DEBUG_OS_H + +#define SET_ERROR(err) \ + (__set_error(__FILE__, __func__, __LINE__, err), err) + +#endif diff --git a/module/os/freebsd/spl/spl_uio.c b/module/os/freebsd/spl/spl_uio.c index 54d4029c5e6f..b92be3710f3c 100644 --- a/module/os/freebsd/spl/spl_uio.c +++ b/module/os/freebsd/spl/spl_uio.c @@ -238,7 +238,7 @@ zfs_uio_iov_step(struct iovec v, zfs_uio_t *uio, int *numpages) zfs_uio_rw(uio), &uio->uio_dio.pages[uio->uio_dio.npages]); if (res != n) - return (SET_ERROR(EFAULT)); + return (EFAULT); ASSERT3U(len, ==, res * PAGE_SIZE); *numpages = res; diff --git a/module/os/linux/spl/spl-taskq.c b/module/os/linux/spl/spl-taskq.c index 092f090d934b..00ff789265c6 100644 --- a/module/os/linux/spl/spl-taskq.c +++ b/module/os/linux/spl/spl-taskq.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include @@ -325,7 +324,6 @@ task_expire_impl(taskq_ent_t *t) } t->tqent_birth = jiffies; - DTRACE_PROBE1(taskq_ent__birth, taskq_ent_t *, t); /* * The priority list must be maintained in strict task id order @@ -713,9 +711,7 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t flags) t->tqent_taskq = tq; t->tqent_timer.function = NULL; t->tqent_timer.expires = 0; - t->tqent_birth = jiffies; - DTRACE_PROBE1(taskq_ent__birth, taskq_ent_t *, t); ASSERT(!(t->tqent_flags & TQENT_FLAG_PREALLOC)); @@ -840,9 +836,7 @@ taskq_dispatch_ent(taskq_t *tq, task_func_t func, void *arg, uint_t flags, t->tqent_func = func; t->tqent_arg = arg; t->tqent_taskq = tq; - t->tqent_birth = jiffies; - DTRACE_PROBE1(taskq_ent__birth, taskq_ent_t *, t); spin_unlock(&t->tqent_lock); @@ -1054,11 +1048,6 @@ taskq_thread(void *args) * A TQENT_FLAG_PREALLOC task may be reused or freed * during the task function call. Store tqent_id and * tqent_flags here. - * - * Also use an on stack taskq_ent_t for tqt_task - * assignment in this case; we want to make sure - * to duplicate all fields, so the values are - * correct when it's accessed via DTRACE_PROBE*. */ tqt->tqt_id = t->tqent_id; tqt->tqt_flags = t->tqent_flags; @@ -1074,13 +1063,10 @@ taskq_thread(void *args) spin_unlock_irqrestore(&tq->tq_lock, flags); TQSTAT_INC(tq, threads_active); - DTRACE_PROBE1(taskq_ent__start, taskq_ent_t *, t); /* Perform the requested task */ t->tqent_func(t->tqent_arg); - DTRACE_PROBE1(taskq_ent__finish, taskq_ent_t *, t); - TQSTAT_DEC(tq, threads_active); if ((t->tqent_flags & TQENT_LIST_MASK) == TQENT_LIST_PENDING) diff --git a/scripts/spdxcheck.pl b/scripts/spdxcheck.pl index 1b3dd639318f..59300ea860f9 100755 --- a/scripts/spdxcheck.pl +++ b/scripts/spdxcheck.pl @@ -128,7 +128,6 @@ my $untagged_patterns = q( include/os/freebsd/zfs/sys/zpl.h include/os/linux/kernel/linux/page_compat.h lib/libspl/include/sys/string.h - lib/libspl/include/sys/trace_spl.h lib/libzdb/libzdb.c lib/libzpool/include/sys/trace_zfs.h module/lua/setjmp/setjmp.S From 99d7453b43dc0ef04a35e461ef14db72e1326c7c Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 8 Nov 2025 15:04:51 +1100 Subject: [PATCH 83/91] libzpool: add BE_POSIX_VENDOR for userspace bootenv This is mostly a placeholder; it's not actually clear if a boot environment makes any sense for userspace. Still, "posix" is the likely future name of libzpool as a port, and this define is mandatory, so lets roll with it for now. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_bootenv.h | 1 + lib/libzpool/include/Makefile.am | 1 + lib/libzpool/include/sys/zfs_bootenv_os.h | 39 +++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 lib/libzpool/include/sys/zfs_bootenv_os.h diff --git a/include/sys/zfs_bootenv.h b/include/sys/zfs_bootenv.h index 074e7e759576..4c4b2ab1ab1b 100644 --- a/include/sys/zfs_bootenv.h +++ b/include/sys/zfs_bootenv.h @@ -31,6 +31,7 @@ extern "C" { #define BE_FREEBSD_VENDOR "freebsd" #define BE_GRUB_VENDOR "grub" #define BE_LINUX_VENDOR "linux" +#define BE_POSIX_VENDOR "posix" #include diff --git a/lib/libzpool/include/Makefile.am b/lib/libzpool/include/Makefile.am index 420b6f64666b..6cfa2d5ce089 100644 --- a/lib/libzpool/include/Makefile.am +++ b/lib/libzpool/include/Makefile.am @@ -3,5 +3,6 @@ libzpool_sys_HEADERS = \ %D%/sys/abd_os.h \ %D%/sys/abd_impl_os.h \ %D%/sys/trace_zfs.h \ + %D%/sys/zfs_bootenv_os.h \ %D%/sys/zfs_context_os.h \ %D%/sys/zfs_debug_os.h diff --git a/lib/libzpool/include/sys/zfs_bootenv_os.h b/lib/libzpool/include/sys/zfs_bootenv_os.h new file mode 100644 index 000000000000..44afbb6f5b6b --- /dev/null +++ b/lib/libzpool/include/sys/zfs_bootenv_os.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: CDDL-1.0 +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or https://opensource.org/licenses/CDDL-1.0. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2025, Rob Norris + */ + +#ifndef _ZFS_BOOTENV_OS_H +#define _ZFS_BOOTENV_OS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BOOTENV_OS BE_POSIX_VENDOR + +#ifdef __cplusplus +} +#endif + +#endif /* _ZFS_BOOTENV_OS_H */ From 913bdbf4d191b4b9681f145da8f3d641c191cd02 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 30 Oct 2025 17:49:18 -0700 Subject: [PATCH 84/91] libzpool: remove global libzpool includes Only include the zfs headers where they're currently required to compile. Unfortunately, including zfs_ioctl.h in user space pulls in a bunch of internal zfs headers as a side effect. We'll need to move these structures in to a new shared header to avoid this. We should not need to add the LIBZPOOL_CPPFLAGS when building the zed, zinject, zpool, libzfs, ior libzfs_core. Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libspl/taskq.c | 7 ++++++- lib/libzfs/libzfs_crypto.c | 1 - lib/libzpool/Makefile.am | 1 - tests/zfs-tests/cmd/Makefile.am | 1 - tests/zfs-tests/cmd/ereports.c | 3 ++- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/libspl/taskq.c b/lib/libspl/taskq.c index 0457de21fa18..075d188930c1 100644 --- a/lib/libspl/taskq.c +++ b/lib/libspl/taskq.c @@ -29,7 +29,12 @@ * Copyright (c) 2014 by Delphix. All rights reserved. */ -#include +#include +#include +#include +#include +#include +#include int taskq_now; taskq_t *system_taskq; diff --git a/lib/libzfs/libzfs_crypto.c b/lib/libzfs/libzfs_crypto.c index f7cc1e84f804..f461ad41405b 100644 --- a/lib/libzfs/libzfs_crypto.c +++ b/lib/libzfs/libzfs_crypto.c @@ -19,7 +19,6 @@ * Copyright 2020 Joyent, Inc. */ -#include #include #include #include diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index 2156385bfd82..f4a78b666f63 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -4,7 +4,6 @@ libzpool_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) $(LIBRARY_CFLAGS) libzpool_la_CFLAGS += $(ZLIB_CFLAGS) libzpool_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS) -libzpool_la_CPPFLAGS += -I$(srcdir)/include/os/@ac_system_l@/zfs libzpool_la_CPPFLAGS += -DLIB_ZPOOL_BUILD lib_LTLIBRARIES += libzpool.la diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am index 85c3cf3c35a8..8d645248f8a2 100644 --- a/tests/zfs-tests/cmd/Makefile.am +++ b/tests/zfs-tests/cmd/Makefile.am @@ -60,7 +60,6 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/file_append %D%/file_check %D%/file_trunc scripts_zfs_tests_bin_PROGRAMS += %D%/libzfs_input_check -%C%_libzfs_input_check_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/include/os/@ac_system_l@/zfs %C%_libzfs_input_check_LDADD = \ libzfs_core.la \ libnvpair.la diff --git a/tests/zfs-tests/cmd/ereports.c b/tests/zfs-tests/cmd/ereports.c index f981d5b34438..a28495b762cd 100644 --- a/tests/zfs-tests/cmd/ereports.c +++ b/tests/zfs-tests/cmd/ereports.c @@ -22,11 +22,12 @@ #include #include #include -#include #include #include #include +#define ZEVENT_NONBLOCK 0x1 + /* * Command to output io and checksum ereport values, one per line. * Used by zpool_events_duplicates.ksh to check for duplicate events. From a49158c064ae287fe017fa6d807dc05da1d22236 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 30 Oct 2025 17:41:25 -0700 Subject: [PATCH 85/91] icp: remove global icp includes Only include the required icp headers. There's no need to include sys/zfs_context.h and pull in all of the zfs headers. Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- config/Rules.am | 1 - include/sys/crypto/common.h | 2 ++ lib/libicp/Makefile.am | 3 +++ module/icp/spi/kcf_spi.c | 1 - 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/config/Rules.am b/config/Rules.am index 9c0714c82513..ecc7ab23cd75 100644 --- a/config/Rules.am +++ b/config/Rules.am @@ -8,7 +8,6 @@ AM_CPPFLAGS = \ -include $(top_builddir)/zfs_config.h \ -I$(top_builddir)/include \ -I$(top_srcdir)/include \ - -I$(top_srcdir)/module/icp/include \ -I$(top_srcdir)/lib/libspl/include \ -I$(top_srcdir)/lib/libspl/include/os/@ac_system_l@ \ -I$(top_srcdir)/lib/libzpool/include diff --git a/include/sys/crypto/common.h b/include/sys/crypto/common.h index 4a9b4f0e1f76..2428fb2737a0 100644 --- a/include/sys/crypto/common.h +++ b/include/sys/crypto/common.h @@ -38,6 +38,8 @@ extern "C" { #endif #include +#include +#include /* Cryptographic Mechanisms */ diff --git a/lib/libicp/Makefile.am b/lib/libicp/Makefile.am index 23adba10bc44..b83ec461fda2 100644 --- a/lib/libicp/Makefile.am +++ b/lib/libicp/Makefile.am @@ -1,6 +1,9 @@ libicp_la_CCASFLAGS = $(AM_CCASFLAGS) libicp_la_CFLAGS = $(AM_CFLAGS) $(KERNEL_CFLAGS) $(LIBRARY_CFLAGS) +libicp_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBZPOOL_CPPFLAGS) +libicp_la_CPPFLAGS += -I$(top_srcdir)/module/icp/include + noinst_LTLIBRARIES += libicp.la nodist_libicp_la_SOURCES = \ diff --git a/module/icp/spi/kcf_spi.c b/module/icp/spi/kcf_spi.c index 806c0b028017..35fe55b2595d 100644 --- a/module/icp/spi/kcf_spi.c +++ b/module/icp/spi/kcf_spi.c @@ -31,7 +31,6 @@ */ -#include #include #include #include From 677d6ed730064cce1d2fb099a30250a73f95f31c Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Thu, 30 Oct 2025 18:04:15 -0700 Subject: [PATCH 86/91] zfs_context: remove duplicate includes Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- include/sys/zfs_context.h | 2 -- scripts/spdxcheck.pl | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h index aeac81df9ea8..5e571d497642 100644 --- a/include/sys/zfs_context.h +++ b/include/sys/zfs_context.h @@ -127,8 +127,6 @@ extern "C" { #include #include #include -#include -#include #include diff --git a/scripts/spdxcheck.pl b/scripts/spdxcheck.pl index 59300ea860f9..e1af3150bccd 100755 --- a/scripts/spdxcheck.pl +++ b/scripts/spdxcheck.pl @@ -124,7 +124,7 @@ my $untagged_patterns = q( include/os/freebsd/spl/sys/inttypes.h include/os/freebsd/spl/sys/mode.h include/os/freebsd/spl/sys/trace.h - include/os/freebsd/spl/sys/trace_zfs.h + include/os/freebsd/zfs/sys/trace_zfs.h include/os/freebsd/zfs/sys/zpl.h include/os/linux/kernel/linux/page_compat.h lib/libspl/include/sys/string.h From e282e98e79861a0a5cdbb9f387b25e317a12e0fc Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 8 Nov 2025 18:04:29 +1100 Subject: [PATCH 87/91] libzpool: add zfs_impl.c, remove from libicp This isn't used by libicp directly, but is by some clients, and relies on headers specific to the zfs module, which makes using it difficult otherwise. Also switch the checksum tests over to use libzpool, so they can get access to it. That's not exactly what we want in the long term, but the icp and zfs modules have a complicated relationship so this will do for now. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- lib/libicp/Makefile.am | 3 +-- lib/libzpool/Makefile.am | 1 + tests/zfs-tests/cmd/Makefile.am | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/libicp/Makefile.am b/lib/libicp/Makefile.am index b83ec461fda2..a8937e60b770 100644 --- a/lib/libicp/Makefile.am +++ b/lib/libicp/Makefile.am @@ -38,8 +38,7 @@ nodist_libicp_la_SOURCES = \ module/icp/core/kcf_prov_lib.c \ module/icp/core/kcf_callprov.c \ module/icp/core/kcf_mech_tabs.c \ - module/icp/core/kcf_prov_tabs.c \ - module/zfs/zfs_impl.c + module/icp/core/kcf_prov_tabs.c if TARGET_CPU_AARCH64 nodist_libicp_la_SOURCES += \ diff --git a/lib/libzpool/Makefile.am b/lib/libzpool/Makefile.am index f4a78b666f63..8340fe2efd71 100644 --- a/lib/libzpool/Makefile.am +++ b/lib/libzpool/Makefile.am @@ -180,6 +180,7 @@ nodist_libzpool_la_SOURCES = \ module/zfs/zfs_crrd.c \ module/zfs/zfs_fm.c \ module/zfs/zfs_fuid.c \ + module/zfs/zfs_impl.c \ module/zfs/zfs_ratelimit.c \ module/zfs/zfs_rlock.c \ module/zfs/zfs_sa.c \ diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am index 8d645248f8a2..b4efefdb7ab7 100644 --- a/tests/zfs-tests/cmd/Makefile.am +++ b/tests/zfs-tests/cmd/Makefile.am @@ -116,9 +116,7 @@ scripts_zfs_tests_bin_PROGRAMS += %D%/edonr_test %D%/skein_test \ %C%_edonr_test_SOURCES = %D%/checksum/edonr_test.c %C%_blake3_test_SOURCES = %D%/checksum/blake3_test.c %C%_skein_test_LDADD = \ - libicp.la \ - libspl.la \ - libspl_assert.la + libzpool.la %C%_sha2_test_LDADD = $(%C%_skein_test_LDADD) %C%_edonr_test_LDADD = $(%C%_skein_test_LDADD) %C%_blake3_test_LDADD = $(%C%_skein_test_LDADD) From 4d451bae8a31d09d81a502867eb6a4b6f8001291 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Tue, 11 Nov 2025 11:16:30 +1100 Subject: [PATCH 88/91] libspl: hide global data objects Currently libspl is a static archive that is linked into multiple shared objects, which then re-export its symbols. We intend to fix this soon. For the moment though, most programs shipped with OpenZFS depend on two or more of these shared objects, and see the same symbols twice. For functions this is not a problem, as they do not have any mutable state and so the linker can simply select the first one and use that for all. For global data objects however, each shared object will have direct (non-relocatable) references to its own instance of the symbol, such that changes on one will not necessarily be seen by the other. While this shouldn't be a problem in practice as these reexported interfaces are not supposed to be used, they are technically undefined behaviour in C (C17 6.9.2) and are reported by ASAN as a violation of C++'s "One Definition Rule". To fix this, we hide these globals inside their compilation units, and add access functions and macros as appropriate to preserve the existing API (though not ABI). Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- cmd/zstream/zstream_redup.c | 4 ++-- cmd/ztest.c | 19 ++++------------- lib/libspl/include/sys/misc.h | 3 --- lib/libspl/include/sys/systm.h | 4 +++- lib/libspl/include/sys/taskq.h | 7 +++++-- lib/libspl/include/sys/thread.h | 6 ++---- lib/libspl/libspl.c | 13 +++++++++--- lib/libspl/random.c | 15 +++++++++---- lib/libspl/taskq.c | 37 ++++++++++++++++++--------------- lib/libspl/thread.c | 2 +- 10 files changed, 58 insertions(+), 52 deletions(-) diff --git a/cmd/zstream/zstream_redup.c b/cmd/zstream/zstream_redup.c index 0e18c52496fd..c1cb6d4d3ad7 100644 --- a/cmd/zstream/zstream_redup.c +++ b/cmd/zstream/zstream_redup.c @@ -191,9 +191,9 @@ zfs_redup_stream(int infd, int outfd, boolean_t verbose) #ifdef _ILP32 uint64_t max_rde_size = SMALLEST_POSSIBLE_MAX_RDT_MB << 20; #else - uint64_t physmem = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); + uint64_t physbytes = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); uint64_t max_rde_size = - MAX((physmem * MAX_RDT_PHYSMEM_PERCENT) / 100, + MAX((physbytes * MAX_RDT_PHYSMEM_PERCENT) / 100, SMALLEST_POSSIBLE_MAX_RDT_MB << 20); #endif diff --git a/cmd/ztest.c b/cmd/ztest.c index 54b4fdb4c48a..d94451906aa0 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -140,9 +140,9 @@ #include #include #include +#include static int ztest_fd_data = -1; -static int ztest_fd_rand = -1; typedef struct ztest_shared_hdr { uint64_t zh_hdr_size; @@ -903,13 +903,10 @@ ztest_random(uint64_t range) { uint64_t r; - ASSERT3S(ztest_fd_rand, >=, 0); - if (range == 0) return (0); - if (read(ztest_fd_rand, &r, sizeof (r)) != sizeof (r)) - fatal(B_TRUE, "short read from /dev/urandom"); + random_get_pseudo_bytes((uint8_t *)&r, sizeof (r)); return (r % range); } @@ -8146,10 +8143,8 @@ ztest_raidz_expand_run(ztest_shared_t *zs, spa_t *spa) /* Setup a 1 MiB buffer of random data */ uint64_t bufsize = 1024 * 1024; void *buffer = umem_alloc(bufsize, UMEM_NOFAIL); + random_get_pseudo_bytes((uint8_t *)&buffer, bufsize); - if (read(ztest_fd_rand, buffer, bufsize) != bufsize) { - fatal(B_TRUE, "short read from /dev/urandom"); - } /* * Put some data in the pool and then attach a vdev to initiate * reflow. @@ -8955,13 +8950,7 @@ main(int argc, char **argv) exit(EXIT_FAILURE); } - /* - * Force random_get_bytes() to use /dev/urandom in order to prevent - * ztest from needlessly depleting the system entropy pool. - */ - random_path = "/dev/urandom"; - ztest_fd_rand = open(random_path, O_RDONLY | O_CLOEXEC); - ASSERT3S(ztest_fd_rand, >=, 0); + libspl_init(); if (!fd_data_str) { process_options(argc, argv); diff --git a/lib/libspl/include/sys/misc.h b/lib/libspl/include/sys/misc.h index 8f2f5f9332e7..171bbc1de798 100644 --- a/lib/libspl/include/sys/misc.h +++ b/lib/libspl/include/sys/misc.h @@ -31,9 +31,6 @@ #include -extern const char *random_path; -extern const char *urandom_path; - /* * Hostname information */ diff --git a/lib/libspl/include/sys/systm.h b/lib/libspl/include/sys/systm.h index 94fcfdd2a303..f984125c3315 100644 --- a/lib/libspl/include/sys/systm.h +++ b/lib/libspl/include/sys/systm.h @@ -29,6 +29,8 @@ #ifndef _LIBSPL_SYS_SYSTM_H #define _LIBSPL_SYS_SYSTM_H -extern uint64_t physmem; +uint64_t libspl_physmem(void); + +#define physmem libspl_physmem() #endif diff --git a/lib/libspl/include/sys/taskq.h b/lib/libspl/include/sys/taskq.h index 63238734b4fd..fbe3f388c05f 100644 --- a/lib/libspl/include/sys/taskq.h +++ b/lib/libspl/include/sys/taskq.h @@ -86,8 +86,11 @@ typedef struct taskq { #define TASKQID_INVALID ((taskqid_t)0) -extern taskq_t *system_taskq; -extern taskq_t *system_delay_taskq; +extern taskq_t *_system_taskq(void); +extern taskq_t *_system_delay_taskq(void); + +#define system_taskq _system_taskq() +#define system_delay_taskq _system_delay_taskq() extern taskq_t *taskq_create(const char *, int, pri_t, int, int, uint_t); extern taskq_t *taskq_create_synced(const char *, int, pri_t, int, int, uint_t, diff --git a/lib/libspl/include/sys/thread.h b/lib/libspl/include/sys/thread.h index a5108a03d45f..6390c5bfd863 100644 --- a/lib/libspl/include/sys/thread.h +++ b/lib/libspl/include/sys/thread.h @@ -58,11 +58,9 @@ typedef pthread_t kthread_t; #define current_is_reclaim_thread() (0) /* in libzpool, p0 exists only to have its address taken */ -typedef struct proc { - uintptr_t this_is_never_used_dont_dereference_it; -} proc_t; +typedef void (proc_t)(void); +extern void p0(void); -extern struct proc p0; #define curproc (&p0) #define PS_NONE -1 diff --git a/lib/libspl/libspl.c b/lib/libspl/libspl.c index 63e948bc2829..208b3e428536 100644 --- a/lib/libspl/libspl.c +++ b/lib/libspl/libspl.c @@ -31,11 +31,18 @@ #include #include #include +#include #include #include "libspl_impl.h" -uint64_t physmem; -struct utsname hw_utsname; +static uint64_t hw_physmem = 0; +static struct utsname hw_utsname = {}; + +uint64_t +libspl_physmem(void) +{ + return (hw_physmem); +} utsname_t * utsname(void) @@ -46,7 +53,7 @@ utsname(void) void libspl_init(void) { - physmem = sysconf(_SC_PHYS_PAGES); + hw_physmem = sysconf(_SC_PHYS_PAGES); VERIFY0(uname(&hw_utsname)); diff --git a/lib/libspl/random.c b/lib/libspl/random.c index 0392737908fe..30281504f599 100644 --- a/lib/libspl/random.c +++ b/lib/libspl/random.c @@ -32,15 +32,22 @@ #include #include "libspl_impl.h" -const char *random_path = "/dev/random"; -const char *urandom_path = "/dev/urandom"; +#define RANDOM_PATH "/dev/random" +#define URANDOM_PATH "/dev/urandom" + static int random_fd = -1, urandom_fd = -1; void random_init(void) { - VERIFY((random_fd = open(random_path, O_RDONLY | O_CLOEXEC)) != -1); - VERIFY((urandom_fd = open(urandom_path, O_RDONLY | O_CLOEXEC)) != -1); + /* Handle multiple calls. */ + if (random_fd != -1) { + ASSERT3U(urandom_fd, !=, -1); + return; + } + + VERIFY((random_fd = open(RANDOM_PATH, O_RDONLY | O_CLOEXEC)) != -1); + VERIFY((urandom_fd = open(URANDOM_PATH, O_RDONLY | O_CLOEXEC)) != -1); } void diff --git a/lib/libspl/taskq.c b/lib/libspl/taskq.c index 075d188930c1..043f70225551 100644 --- a/lib/libspl/taskq.c +++ b/lib/libspl/taskq.c @@ -36,9 +36,20 @@ #include #include -int taskq_now; -taskq_t *system_taskq; -taskq_t *system_delay_taskq; +static taskq_t *__system_taskq = NULL; +static taskq_t *__system_delay_taskq = NULL; + +taskq_t +*_system_taskq(void) +{ + return (__system_taskq); +} + +taskq_t +*_system_delay_taskq(void) +{ + return (__system_delay_taskq); +} static pthread_key_t taskq_tsd; @@ -111,11 +122,6 @@ taskq_dispatch(taskq_t *tq, task_func_t func, void *arg, uint_t tqflags) { taskq_ent_t *t; - if (taskq_now) { - func(arg); - return (1); - } - mutex_enter(&tq->tq_lock); ASSERT(tq->tq_flags & TASKQ_ACTIVE); if ((t = task_alloc(tq, tqflags)) == NULL) { @@ -378,9 +384,6 @@ taskq_member(taskq_t *tq, kthread_t *t) { int i; - if (taskq_now) - return (1); - for (i = 0; i < tq->tq_nthreads; i++) if (tq->tq_threadlist[i] == t) return (1); @@ -405,18 +408,18 @@ void system_taskq_init(void) { VERIFY0(pthread_key_create(&taskq_tsd, NULL)); - system_taskq = taskq_create("system_taskq", 64, maxclsyspri, 4, 512, + __system_taskq = taskq_create("system_taskq", 64, maxclsyspri, 4, 512, TASKQ_DYNAMIC | TASKQ_PREPOPULATE); - system_delay_taskq = taskq_create("delay_taskq", 4, maxclsyspri, 4, + __system_delay_taskq = taskq_create("delay_taskq", 4, maxclsyspri, 4, 512, TASKQ_DYNAMIC | TASKQ_PREPOPULATE); } void system_taskq_fini(void) { - taskq_destroy(system_taskq); - system_taskq = NULL; /* defensive */ - taskq_destroy(system_delay_taskq); - system_delay_taskq = NULL; + taskq_destroy(__system_taskq); + __system_taskq = NULL; /* defensive */ + taskq_destroy(__system_delay_taskq); + __system_delay_taskq = NULL; VERIFY0(pthread_key_delete(taskq_tsd)); } diff --git a/lib/libspl/thread.c b/lib/libspl/thread.c index 17c36c754621..f00e0a01a06b 100644 --- a/lib/libspl/thread.c +++ b/lib/libspl/thread.c @@ -32,7 +32,7 @@ #include /* this only exists to have its address taken */ -struct proc p0; +void p0(void) {} /* * ========================================================================= From 23d17f35879ae499b5fa0f0976c7058ded633be7 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Tue, 11 Nov 2025 11:16:30 +1100 Subject: [PATCH 89/91] libspl/random: add switch to force pseudo-random numbers for all calls ztest wants to force all kernel random calls to use the pseudo-random generator (/dev/urandom), to avoid depleting the system entropy pool just for testing. Up until the previous commit, it did this by switching the path that the libzpool (now libspl) random API would use to get random data from; that is, it took advantage of an implementation detail. Now that that hole is closed to it, we need another method. This commit introduces that; a simple API call to enable/disable "force pseudo" mode. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Brian Behlendorf Signed-off-by: Rob Norris Closes #17861 --- cmd/ztest.c | 6 ++++++ lib/libspl/include/sys/random.h | 2 ++ lib/libspl/random.c | 10 ++++++++++ 3 files changed, 18 insertions(+) diff --git a/cmd/ztest.c b/cmd/ztest.c index d94451906aa0..dc8ac85b6991 100644 --- a/cmd/ztest.c +++ b/cmd/ztest.c @@ -8952,6 +8952,12 @@ main(int argc, char **argv) libspl_init(); + /* + * Force random_get_bytes() to use /dev/urandom in order to prevent + * ztest from needlessly depleting the system entropy pool. + */ + random_force_pseudo(B_TRUE); + if (!fd_data_str) { process_options(argc, argv); diff --git a/lib/libspl/include/sys/random.h b/lib/libspl/include/sys/random.h index 27f2d4e3a684..d11580829ed2 100644 --- a/lib/libspl/include/sys/random.h +++ b/lib/libspl/include/sys/random.h @@ -32,6 +32,8 @@ extern int random_get_bytes(uint8_t *ptr, size_t len); extern int random_get_pseudo_bytes(uint8_t *ptr, size_t len); +extern void random_force_pseudo(boolean_t onoff); + static __inline__ uint32_t random_in_range(uint32_t range) { diff --git a/lib/libspl/random.c b/lib/libspl/random.c index 30281504f599..c6f0ee7ae0f7 100644 --- a/lib/libspl/random.c +++ b/lib/libspl/random.c @@ -37,6 +37,8 @@ static int random_fd = -1, urandom_fd = -1; +static boolean_t force_pseudo = B_FALSE; + void random_init(void) { @@ -60,6 +62,12 @@ random_fini(void) urandom_fd = -1; } +void +random_force_pseudo(boolean_t onoff) +{ + force_pseudo = onoff; +} + static int random_get_bytes_common(uint8_t *ptr, size_t len, int fd) { @@ -81,6 +89,8 @@ random_get_bytes_common(uint8_t *ptr, size_t len, int fd) int random_get_bytes(uint8_t *ptr, size_t len) { + if (force_pseudo) + return (random_get_pseudo_bytes(ptr, len)); return (random_get_bytes_common(ptr, len, random_fd)); } From 6015edb3743df6a993e2ea30bb27fbaa5da535aa Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Wed, 12 Nov 2025 10:09:50 -0800 Subject: [PATCH 90/91] lib: update ABI meta following libspl changes In theory they should not have resulted in a change. In practice, the way visibility is set up currently means that many of our convenience libraries will "leak through" into the available symbols in our public libraries. In this commit, we're seeing all the new symbols in libspl through libuutil, libzfs and libzfs_core. Importantly, none have been removed, so consumers of these libraries will not notice. Sponsored-by: https://despairlabs.com/sponsor/ Signed-off-by: Rob Norris Signed-off-by: Brian Behlendorf Closes #17861 --- lib/libuutil/libuutil.abi | 1097 +++++++++++++++++++++++++++++-- lib/libzfs/libzfs.abi | 850 +++++++++++++++++++++++- lib/libzfs_core/libzfs_core.abi | 1069 +++++++++++++++++++++++++++++- 3 files changed, 2934 insertions(+), 82 deletions(-) diff --git a/lib/libuutil/libuutil.abi b/lib/libuutil/libuutil.abi index 52a00d9830b1..ca2bcdb57dbf 100644 --- a/lib/libuutil/libuutil.abi +++ b/lib/libuutil/libuutil.abi @@ -6,6 +6,8 @@ + + @@ -144,6 +146,19 @@ + + + + + + + + + + + + + @@ -151,8 +166,21 @@ + + + + + + + + + + + + + @@ -178,10 +206,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -244,6 +314,7 @@ + @@ -612,7 +683,6 @@ - @@ -631,8 +701,6 @@ - - @@ -796,6 +864,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -805,6 +1097,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -917,7 +1379,6 @@ - @@ -967,6 +1428,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -977,7 +1471,6 @@ - @@ -988,27 +1481,6 @@ - - - - - - - - - - - - - - - - - - - - - @@ -1119,21 +1591,10 @@ - - - - - - - - - - - @@ -1198,14 +1659,294 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1214,9 +1955,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -1310,8 +2317,6 @@ - - @@ -2265,10 +3270,6 @@ - - - - diff --git a/lib/libzfs/libzfs.abi b/lib/libzfs/libzfs.abi index 9ce2ffa55df9..f481b6221e4d 100644 --- a/lib/libzfs/libzfs.abi +++ b/lib/libzfs/libzfs.abi @@ -15,6 +15,8 @@ + + @@ -160,6 +162,19 @@ + + + + + + + + + + + + + @@ -195,9 +210,22 @@ + + + + + + + + + + + + + @@ -243,10 +271,32 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -254,10 +304,29 @@ + + + + + + + + + + + + + + + + + + + @@ -270,6 +339,7 @@ + @@ -473,6 +543,7 @@ + @@ -1315,6 +1386,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1324,6 +1495,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1454,6 +1779,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1469,6 +1827,486 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1842,10 +2680,6 @@ - - - - @@ -2566,9 +3400,6 @@ - - - @@ -2585,6 +3416,9 @@ + + + @@ -3213,7 +4047,6 @@ - @@ -3515,6 +4348,7 @@ + diff --git a/lib/libzfs_core/libzfs_core.abi b/lib/libzfs_core/libzfs_core.abi index 7f3c8f2ff0d7..238151d432f1 100644 --- a/lib/libzfs_core/libzfs_core.abi +++ b/lib/libzfs_core/libzfs_core.abi @@ -7,6 +7,8 @@ + + @@ -127,6 +129,19 @@ + + + + + + + + + + + + + @@ -134,8 +149,21 @@ + + + + + + + + + + + + + @@ -218,28 +246,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - @@ -613,7 +669,6 @@ - @@ -794,6 +849,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -803,6 +1075,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -914,7 +1368,6 @@ - @@ -963,6 +1416,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -973,7 +1479,6 @@ - @@ -1145,14 +1650,273 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1161,6 +1925,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1256,8 +2275,6 @@ - - @@ -2274,10 +3291,10 @@ - + - + From e63d026b91b822dd9b363ab9a1e39d9a66493601 Mon Sep 17 00:00:00 2001 From: Toomas Soome Date: Sat, 15 Nov 2025 01:58:50 +0200 Subject: [PATCH 91/91] cmd/zpool cstyle issues add missing headers. usage() is no-return, so anything after call to it is unreachable code. use (void) cast where we do ignore return value. Reviewed-by: Brian Behlendorf Signed-off-by: Toomas Soome Closes #17885 --- cmd/zpool/zpool_main.c | 411 ++++++++++++++++++++++------------------- cmd/zpool/zpool_vdev.c | 8 +- 2 files changed, 228 insertions(+), 191 deletions(-) diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 04908f14795c..b0e05aa2776a 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -634,7 +636,7 @@ zpool_power_on_and_disk_wait(zpool_handle_t *zhp, char *vdev) if (rc != 0) return (rc); - zpool_disk_wait(vdev_name_to_path(zhp, vdev)); + (void) zpool_disk_wait(vdev_name_to_path(zhp, vdev)); return (0); } @@ -664,7 +666,7 @@ zpool_power_on_pool_and_wait_for_devices(zpool_handle_t *zhp) */ FOR_EACH_REAL_LEAF_VDEV(zhp, nv) { path = fnvlist_lookup_string(nv, ZPOOL_CONFIG_PATH); - zpool_disk_wait(path); + (void) zpool_disk_wait(path); } return (0); @@ -847,7 +849,6 @@ zpool_do_initialize(int argc, char **argv) if (argc < 1 && !initialize_all) { (void) fprintf(stderr, gettext("missing pool name argument\n")); usage(B_FALSE); - return (-1); } if (wait && (cmd_type != POOL_INITIALIZE_START)) { @@ -1038,9 +1039,10 @@ nice_num_str_nvlist(nvlist_t *item, const char *key, uint64_t value, boolean_t literal, boolean_t as_int, int format) { char buf[256]; + if (literal) { if (!as_int) - snprintf(buf, 256, "%llu", (u_longlong_t)value); + (void) snprintf(buf, 256, "%llu", (u_longlong_t)value); } else { switch (format) { case ZFS_NICENUM_1024: @@ -1086,7 +1088,7 @@ zpool_json_schema(int maj_v, int min_v) nvlist_t *sch = fnvlist_alloc(); nvlist_t *ov = fnvlist_alloc(); - snprintf(cmd, MAX_CMD_LEN, "zpool %s", current_command->name); + (void) snprintf(cmd, MAX_CMD_LEN, "zpool %s", current_command->name); fnvlist_add_string(ov, "command", cmd); fnvlist_add_uint32(ov, "vers_major", maj_v); fnvlist_add_uint32(ov, "vers_minor", min_v); @@ -1117,12 +1119,12 @@ fill_pool_info(nvlist_t *list, zpool_handle_t *zhp, boolean_t addtype, } else { char value[ZFS_MAXPROPLEN]; if (guid) { - snprintf(value, ZFS_MAXPROPLEN, "%llu", + (void) snprintf(value, ZFS_MAXPROPLEN, "%llu", (u_longlong_t)guid); fnvlist_add_string(list, ZPOOL_CONFIG_POOL_GUID, value); } if (txg) { - snprintf(value, ZFS_MAXPROPLEN, "%llu", + (void) snprintf(value, ZFS_MAXPROPLEN, "%llu", (u_longlong_t)txg); fnvlist_add_string(list, ZPOOL_CONFIG_POOL_TXG, value); } @@ -1181,7 +1183,7 @@ fill_vdev_info(nvlist_t *list, zpool_handle_t *zhp, char *name, fnvlist_add_uint64(list, "guid", guid); } else { char buf[ZFS_MAXPROPLEN]; - snprintf(buf, ZFS_MAXPROPLEN, "%llu", + (void) snprintf(buf, ZFS_MAXPROPLEN, "%llu", (u_longlong_t)guid); fnvlist_add_string(list, "guid", buf); } @@ -1763,7 +1765,7 @@ vdev_is_active(char *vdev_path) return (1); /* cant open O_EXCL - disk is active */ } - close(fd); + (void) close(fd); return (0); /* disk is inactive in the pool */ } @@ -2414,12 +2416,12 @@ zpool_export_one(zpool_handle_t *zhp, void *data) * So we serialize access here for 'zpool export -a' parallel case. */ if (cb->tpool != NULL) - pthread_mutex_lock(&cb->mnttab_lock); + (void) pthread_mutex_lock(&cb->mnttab_lock); int retval = zpool_disable_datasets(zhp, cb->force); if (cb->tpool != NULL) - pthread_mutex_unlock(&cb->mnttab_lock); + (void) pthread_mutex_unlock(&cb->mnttab_lock); if (retval) return (1); @@ -2532,7 +2534,7 @@ zpool_do_export(int argc, char **argv) cb.tpool = tpool_create(1, 5 * sysconf(_SC_NPROCESSORS_ONLN), 0, NULL); - pthread_mutex_init(&cb.mnttab_lock, NULL); + (void) pthread_mutex_init(&cb.mnttab_lock, NULL); /* Asynchronously call zpool_export_one using thread pool */ ret = for_each_pool(argc, argv, B_TRUE, NULL, ZFS_TYPE_POOL, @@ -2650,7 +2652,7 @@ zpool_nvlist_cmd(vdev_cmd_data_list_t *vcdl, const char *pool, const char *path, for (j = data->cols_cnt; j < data->lines_cnt; j++) { if (data->lines[j]) { - snprintf(tmp, 256, "extra_%d", k++); + (void) snprintf(tmp, 256, "extra_%d", k++); fnvlist_add_string(item, tmp, data->lines[j]); } @@ -2696,17 +2698,17 @@ zpool_print_cmd(vdev_cmd_data_list_t *vcdl, const char *pool, const char *path) printf("%*s", vcdl->uniq_cols_width[j], val); if (j < vcdl->uniq_cols_cnt - 1) - fputs(" ", stdout); + (void) fputs(" ", stdout); } /* Print out any values that aren't in a column at the end */ for (j = data->cols_cnt; j < data->lines_cnt; j++) { /* Did we have any columns? If so print a spacer. */ if (vcdl->uniq_cols_cnt > 0) - fputs(" ", stdout); + (void) fputs(" ", stdout); val = data->lines[j]; - fputs(val ?: "", stdout); + (void) fputs(val ?: "", stdout); } break; } @@ -2919,7 +2921,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name, return; } - printf_color(health_str_to_color(state), + (void) printf_color(health_str_to_color(state), "\t%*s%-*s %-8s", depth, "", cb->cb_namewidth - depth, name, state); @@ -2937,26 +2939,26 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name, scolor = ANSI_BLUE; if (cb->cb_literal) { - fputc(' ', stdout); - printf_color(rcolor, "%5llu", + (void) fputc(' ', stdout); + (void) printf_color(rcolor, "%5llu", (u_longlong_t)vs->vs_read_errors); - fputc(' ', stdout); - printf_color(wcolor, "%5llu", + (void) fputc(' ', stdout); + (void) printf_color(wcolor, "%5llu", (u_longlong_t)vs->vs_write_errors); - fputc(' ', stdout); - printf_color(ccolor, "%5llu", + (void) fputc(' ', stdout); + (void) printf_color(ccolor, "%5llu", (u_longlong_t)vs->vs_checksum_errors); } else { zfs_nicenum(vs->vs_read_errors, rbuf, sizeof (rbuf)); zfs_nicenum(vs->vs_write_errors, wbuf, sizeof (wbuf)); zfs_nicenum(vs->vs_checksum_errors, cbuf, sizeof (cbuf)); - fputc(' ', stdout); - printf_color(rcolor, "%5s", rbuf); - fputc(' ', stdout); - printf_color(wcolor, "%5s", wbuf); - fputc(' ', stdout); - printf_color(ccolor, "%5s", cbuf); + (void) fputc(' ', stdout); + (void) printf_color(rcolor, "%5s", rbuf); + (void) fputc(' ', stdout); + (void) printf_color(wcolor, "%5s", wbuf); + (void) fputc(' ', stdout); + (void) printf_color(ccolor, "%5s", cbuf); } if (cb->cb_print_slow_ios) { if (children == 0) { @@ -2964,14 +2966,14 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name, zfs_nicenum(vs->vs_slow_ios, rbuf, sizeof (rbuf)); } else { - snprintf(rbuf, sizeof (rbuf), "-"); + (void) snprintf(rbuf, sizeof (rbuf), "-"); } if (cb->cb_literal) - printf_color(scolor, " %5llu", + (void) printf_color(scolor, " %5llu", (u_longlong_t)vs->vs_slow_ios); else - printf_color(scolor, " %5s", rbuf); + (void) printf_color(scolor, " %5s", rbuf); } if (cb->cb_print_power) { if (children == 0) { @@ -2980,7 +2982,7 @@ print_status_config(zpool_handle_t *zhp, status_cbdata_t *cb, const char *name, fnvlist_lookup_string(nv, ZPOOL_CONFIG_PATH))) { case 0: - printf_color(ANSI_RED, " %5s", + (void) printf_color(ANSI_RED, " %5s", gettext("off")); break; case 1: @@ -3426,70 +3428,70 @@ show_import(nvlist_t *config, boolean_t report_error) if (reason != ZPOOL_STATUS_OK) { (void) printf("%s", indent); - printf_color(ANSI_BOLD, gettext("status: ")); + (void) printf_color(ANSI_BOLD, gettext("status: ")); } switch (reason) { case ZPOOL_STATUS_MISSING_DEV_R: case ZPOOL_STATUS_MISSING_DEV_NR: case ZPOOL_STATUS_BAD_GUID_SUM: - printf_color(ANSI_YELLOW, gettext("One or more devices are " - "missing from the system.\n")); + (void) printf_color(ANSI_YELLOW, gettext("One or more devices " + "are missing from the system.\n")); break; case ZPOOL_STATUS_CORRUPT_LABEL_R: case ZPOOL_STATUS_CORRUPT_LABEL_NR: - printf_color(ANSI_YELLOW, gettext("One or more devices " + (void) printf_color(ANSI_YELLOW, gettext("One or more devices " "contains corrupted data.\n")); break; case ZPOOL_STATUS_CORRUPT_DATA: - printf_color(ANSI_YELLOW, gettext("The pool data is " + (void) printf_color(ANSI_YELLOW, gettext("The pool data is " "corrupted.\n")); break; case ZPOOL_STATUS_OFFLINE_DEV: - printf_color(ANSI_YELLOW, gettext("One or more devices " + (void) printf_color(ANSI_YELLOW, gettext("One or more devices " "are offlined.\n")); break; case ZPOOL_STATUS_CORRUPT_POOL: - printf_color(ANSI_YELLOW, gettext("The pool metadata is " + (void) printf_color(ANSI_YELLOW, gettext("The pool metadata is " "corrupted.\n")); break; case ZPOOL_STATUS_VERSION_OLDER: - printf_color(ANSI_YELLOW, gettext("The pool is formatted using " - "a legacy on-disk version.\n")); + (void) printf_color(ANSI_YELLOW, gettext("The pool is " + "formatted using a legacy on-disk version.\n")); break; case ZPOOL_STATUS_VERSION_NEWER: - printf_color(ANSI_YELLOW, gettext("The pool is formatted using " - "an incompatible version.\n")); + (void) printf_color(ANSI_YELLOW, gettext("The pool is " + "formatted using an incompatible version.\n")); break; case ZPOOL_STATUS_FEAT_DISABLED: - printf_color(ANSI_YELLOW, gettext("Some supported " + (void) printf_color(ANSI_YELLOW, gettext("Some supported " "features are not enabled on the pool.\n" "\t%s(Note that they may be intentionally disabled if the\n" "\t%s'compatibility' property is set.)\n"), indent, indent); break; case ZPOOL_STATUS_COMPATIBILITY_ERR: - printf_color(ANSI_YELLOW, gettext("Error reading or parsing " - "the file(s) indicated by the 'compatibility'\n" + (void) printf_color(ANSI_YELLOW, gettext("Error reading or " + "parsing the file(s) indicated by the 'compatibility'\n" "\t%sproperty.\n"), indent); break; case ZPOOL_STATUS_INCOMPATIBLE_FEAT: - printf_color(ANSI_YELLOW, gettext("One or more features " + (void) printf_color(ANSI_YELLOW, gettext("One or more features " "are enabled on the pool despite not being\n" "\t%srequested by the 'compatibility' property.\n"), indent); break; case ZPOOL_STATUS_UNSUP_FEAT_READ: - printf_color(ANSI_YELLOW, gettext("The pool uses the following " - "feature(s) not supported on this system:\n")); + (void) printf_color(ANSI_YELLOW, gettext("The pool uses the " + "following feature(s) not supported on this system:\n")); color_start(ANSI_YELLOW); zpool_collect_unsup_feat(config, buf, 2048); (void) printf("%s", buf); @@ -3497,7 +3499,7 @@ show_import(nvlist_t *config, boolean_t report_error) break; case ZPOOL_STATUS_UNSUP_FEAT_WRITE: - printf_color(ANSI_YELLOW, gettext("The pool can only be " + (void) printf_color(ANSI_YELLOW, gettext("The pool can only be " "accessed in read-only mode on this system. It\n" "\t%scannot be accessed in read-write mode because it uses " "the following\n" @@ -3510,47 +3512,48 @@ show_import(nvlist_t *config, boolean_t report_error) break; case ZPOOL_STATUS_HOSTID_ACTIVE: - printf_color(ANSI_YELLOW, gettext("The pool is currently " - "imported by another system.\n")); + (void) printf_color(ANSI_YELLOW, gettext("The pool is " + "currently imported by another system.\n")); break; case ZPOOL_STATUS_HOSTID_REQUIRED: - printf_color(ANSI_YELLOW, gettext("The pool has the " + (void) printf_color(ANSI_YELLOW, gettext("The pool has the " "multihost property on. It cannot\n" "\t%sbe safely imported when the system hostid is not " "set.\n"), indent); break; case ZPOOL_STATUS_HOSTID_MISMATCH: - printf_color(ANSI_YELLOW, gettext("The pool was last accessed " - "by another system.\n")); + (void) printf_color(ANSI_YELLOW, gettext("The pool was last " + "accessed by another system.\n")); break; case ZPOOL_STATUS_FAULTED_DEV_R: case ZPOOL_STATUS_FAULTED_DEV_NR: - printf_color(ANSI_YELLOW, gettext("One or more devices are " - "faulted.\n")); + (void) printf_color(ANSI_YELLOW, gettext("One or more devices " + "are faulted.\n")); break; case ZPOOL_STATUS_BAD_LOG: - printf_color(ANSI_YELLOW, gettext("An intent log record cannot " - "be read.\n")); + (void) printf_color(ANSI_YELLOW, gettext("An intent log record " + "cannot be read.\n")); break; case ZPOOL_STATUS_RESILVERING: case ZPOOL_STATUS_REBUILDING: - printf_color(ANSI_YELLOW, gettext("One or more devices were " - "being resilvered.\n")); + (void) printf_color(ANSI_YELLOW, gettext("One or more devices " + "were being resilvered.\n")); break; case ZPOOL_STATUS_ERRATA: - printf_color(ANSI_YELLOW, gettext("Errata #%d detected.\n"), + (void) printf_color(ANSI_YELLOW, + gettext("Errata #%d detected.\n"), errata); break; case ZPOOL_STATUS_NON_NATIVE_ASHIFT: - printf_color(ANSI_YELLOW, gettext("One or more devices are " - "configured to use a non-native block size.\n" + (void) printf_color(ANSI_YELLOW, gettext("One or more devices " + "are configured to use a non-native block size.\n" "\t%sExpect reduced performance.\n"), indent); break; @@ -4922,7 +4925,8 @@ print_cmd_columns(vdev_cmd_data_list_t *vcdl, int use_dashes) for (j = 0; j < vcdl->uniq_cols_width[i]; j++) printf("-"); } else { - printf_color(ANSI_BOLD, "%*s", vcdl->uniq_cols_width[i], + (void) printf_color(ANSI_BOLD, "%*s", + vcdl->uniq_cols_width[i], vcdl->uniq_cols[i]); } } @@ -5073,15 +5077,15 @@ print_iostat_header(iostat_cbdata_t *cb) static void print_stat_color(const char *statbuf, unsigned int column_size) { - fputs(" ", stdout); + (void) fputs(" ", stdout); size_t len = strlen(statbuf); while (len < column_size) { - fputc(' ', stdout); + (void) fputc(' ', stdout); column_size--; } if (*statbuf == '0') { color_start(ANSI_GRAY); - fputc('0', stdout); + (void) fputc('0', stdout); } else { for (; *statbuf; statbuf++) { if (*statbuf == 'K') color_start(ANSI_GREEN); @@ -5090,7 +5094,7 @@ print_stat_color(const char *statbuf, unsigned int column_size) else if (*statbuf == 'T') color_start(ANSI_BOLD_BLUE); else if (*statbuf == 'P') color_start(ANSI_MAGENTA); else if (*statbuf == 'E') color_start(ANSI_CYAN); - fputc(*statbuf, stdout); + (void) fputc(*statbuf, stdout); if (--column_size <= 0) break; } @@ -5998,7 +6002,7 @@ get_stat_flags(zpool_list_t *list) * get_stat_flags_cb() will lop off bits from "mask" until only the * flags that are supported on all pools remain. */ - pool_list_iter(list, B_FALSE, get_stat_flags_cb, &mask); + (void) pool_list_iter(list, B_FALSE, get_stat_flags_cb, &mask); return (mask); } @@ -6247,7 +6251,7 @@ print_zpool_dir_scripts(char *dirpath) print_zpool_script_help(ent->d_name, fullpath); } - closedir(dir); + (void) closedir(dir); } } @@ -6507,7 +6511,6 @@ zpool_do_iostat(int argc, char **argv) argv[0], &cb.cb_vdevs); fprintf(stderr, "\n"); usage(B_FALSE); - return (1); } } else { /* @@ -6550,7 +6553,6 @@ zpool_do_iostat(int argc, char **argv) (void) fprintf(stderr, gettext("[-r|-w] isn't allowed with [-c|-l|-q]\n")); usage(B_FALSE); - return (1); } if (l_histo && rq_histo) { @@ -6558,7 +6560,6 @@ zpool_do_iostat(int argc, char **argv) (void) fprintf(stderr, gettext("Only one of [-r|-w] can be passed at a time\n")); usage(B_FALSE); - return (1); } /* @@ -6687,7 +6688,7 @@ zpool_do_iostat(int argc, char **argv) continue; } - pool_list_iter(list, B_FALSE, print_iostat, &cb); + (void) pool_list_iter(list, B_FALSE, print_iostat, &cb); /* * If there's more than one pool, and we're not in @@ -6902,7 +6903,7 @@ collect_pool(zpool_handle_t *zhp, list_cbdata_t *cb) uint64_t guid = fnvlist_lookup_uint64( zpool_get_config(zhp, NULL), ZPOOL_CONFIG_POOL_GUID); - snprintf(pool_guid, 256, "%llu", + (void) snprintf(pool_guid, 256, "%llu", (u_longlong_t)guid); fnvlist_add_nvlist(d, pool_guid, item); } else { @@ -6969,8 +6970,8 @@ collect_vdev_prop(zpool_prop_t prop, uint64_t value, const char *str, (void) strlcpy(propval, "-", sizeof (propval)); if (json) { - zprop_nvlist_one_property(zpool_prop_to_name(prop), propval, - ZPROP_SRC_NONE, NULL, NULL, nvl, as_int); + (void) zprop_nvlist_one_property(zpool_prop_to_name(prop), + propval, ZPROP_SRC_NONE, NULL, NULL, nvl, as_int); } else { if (scripted) (void) printf("\t%s", propval); @@ -7301,7 +7302,7 @@ list_callback(zpool_handle_t *zhp, void *data) if (cbp->cb_json_pool_key_guid) { guid = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID); - snprintf(pool_guid, 256, "%llu", + (void) snprintf(pool_guid, 256, "%llu", (u_longlong_t)guid); p = fnvlist_lookup_nvlist(d, pool_guid); } else { @@ -8130,14 +8131,12 @@ zpool_do_offline(int argc, char **argv) (void) fprintf(stderr, gettext("-0 and -f cannot be used together\n")); usage(B_FALSE); - return (1); } if (is_power_off && istmp) { (void) fprintf(stderr, gettext("-0 and -t cannot be used together\n")); usage(B_FALSE); - return (1); } argc -= optind; @@ -8175,7 +8174,8 @@ zpool_do_offline(int argc, char **argv) gettext("unable to power off slot for"), argv[i], ret); } - zpool_vdev_set_removed_state(zhp, guid, VDEV_AUX_NONE); + (void) zpool_vdev_set_removed_state(zhp, guid, + VDEV_AUX_NONE); } else if (fault) { vdev_aux_t aux; @@ -8291,9 +8291,9 @@ zpool_do_clear(int argc, char **argv) if (is_power_on) { if (device == NULL) { - zpool_power_on_pool_and_wait_for_devices(zhp); + (void) zpool_power_on_pool_and_wait_for_devices(zhp); } else { - zpool_power_on_and_disk_wait(zhp, device); + (void) zpool_power_on_and_disk_wait(zhp, device); } } @@ -8776,7 +8776,6 @@ zpool_do_trim(int argc, char **argv) if (argc < 1 && !trimall) { (void) fprintf(stderr, gettext("missing pool name argument\n")); usage(B_FALSE); - return (-1); } if (wait && (cmd_type != POOL_TRIM_START)) { @@ -8925,7 +8924,7 @@ print_scan_scrub_resilver_status(pool_scan_stat_t *ps) char total_i_buf[7], srate_buf[7], irate_buf[7], time_buf[32]; printf(" "); - printf_color(ANSI_BOLD, gettext("scan:")); + (void) printf_color(ANSI_BOLD, gettext("scan:")); printf(" "); /* If there's never been a scan, there's not much to say. */ @@ -9065,7 +9064,7 @@ print_rebuild_status_impl(vdev_rebuild_stat_t *vrs, uint_t c, char *vdev_name) return; printf(" "); - printf_color(ANSI_BOLD, gettext("scan:")); + (void) printf_color(ANSI_BOLD, gettext("scan:")); printf(" "); uint64_t bytes_scanned = vrs->vrs_bytes_scanned; @@ -9768,7 +9767,7 @@ dedup_stats_nvlist(zpool_handle_t *zhp, status_cbdata_t *cb, nvlist_t *item) entry = fnvlist_alloc(); ddt_stats_nvlist(&ddh->ddh_stat[h], cb, entry); - snprintf(buf, 16, "%d", h); + (void) snprintf(buf, 16, "%d", h); fnvlist_add_nvlist(hist, buf, entry); fnvlist_free(entry); } @@ -10147,7 +10146,7 @@ print_removal_status(zpool_handle_t *zhp, pool_removal_stat_t *prs) vdev_name = zpool_vdev_name(g_zfs, zhp, child[prs->prs_removing_vdev], B_TRUE); - printf_color(ANSI_BOLD, gettext("remove: ")); + (void) printf_color(ANSI_BOLD, gettext("remove: ")); start = prs->prs_start_time; end = prs->prs_end_time; @@ -10247,7 +10246,7 @@ print_raidz_expand_status(zpool_handle_t *zhp, pool_raidz_expand_stat_t *pres) &child, &children) == 0); assert(pres->pres_expanding_vdev < children); - printf_color(ANSI_BOLD, gettext("expand: ")); + (void) printf_color(ANSI_BOLD, gettext("expand: ")); time_t start = pres->pres_start_time; time_t end = pres->pres_end_time; @@ -10491,32 +10490,38 @@ print_status_reason(zpool_handle_t *zhp, status_cbdata_t *cbp, switch (reason) { case ZPOOL_STATUS_MISSING_DEV_R: - snprintf(status, ST_SIZE, gettext("One or more devices could " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices could " "not be opened. Sufficient replicas exist for\n\tthe pool " "to continue functioning in a degraded state.\n")); - snprintf(action, AC_SIZE, gettext("Attach the missing device " + (void) snprintf(action, AC_SIZE, + gettext("Attach the missing device " "and online it using 'zpool online'.\n")); break; case ZPOOL_STATUS_MISSING_DEV_NR: - snprintf(status, ST_SIZE, gettext("One or more devices could " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices could " "not be opened. There are insufficient\n\treplicas for the" " pool to continue functioning.\n")); - snprintf(action, AC_SIZE, gettext("Attach the missing device " + (void) snprintf(action, AC_SIZE, + gettext("Attach the missing device " "and online it using 'zpool online'.\n")); break; case ZPOOL_STATUS_CORRUPT_LABEL_R: - snprintf(status, ST_SIZE, gettext("One or more devices could " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices could " "not be used because the label is missing or\n\tinvalid. " "Sufficient replicas exist for the pool to continue\n\t" "functioning in a degraded state.\n")); - snprintf(action, AC_SIZE, gettext("Replace the device using " - "'zpool replace'.\n")); + (void) snprintf(action, AC_SIZE, + gettext("Replace the device using 'zpool replace'.\n")); break; case ZPOOL_STATUS_CORRUPT_LABEL_NR: - snprintf(status, ST_SIZE, gettext("One or more devices could " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices could " "not be used because the label is missing \n\tor invalid. " "There are insufficient replicas for the pool to " "continue\n\tfunctioning.\n")); @@ -10526,63 +10531,70 @@ print_status_reason(zpool_handle_t *zhp, status_cbdata_t *cbp, break; case ZPOOL_STATUS_FAILING_DEV: - snprintf(status, ST_SIZE, gettext("One or more devices has " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices has " "experienced an unrecoverable error. An\n\tattempt was " "made to correct the error. Applications are " "unaffected.\n")); - snprintf(action, AC_SIZE, gettext("Determine if the " + (void) snprintf(action, AC_SIZE, gettext("Determine if the " "device needs to be replaced, and clear the errors\n\tusing" " 'zpool clear' or replace the device with 'zpool " "replace'.\n")); break; case ZPOOL_STATUS_OFFLINE_DEV: - snprintf(status, ST_SIZE, gettext("One or more devices has " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices has " "been taken offline by the administrator.\n\tSufficient " "replicas exist for the pool to continue functioning in " "a\n\tdegraded state.\n")); - snprintf(action, AC_SIZE, gettext("Online the device " + (void) snprintf(action, AC_SIZE, gettext("Online the device " "using 'zpool online' or replace the device with\n\t'zpool " "replace'.\n")); break; case ZPOOL_STATUS_REMOVED_DEV: - snprintf(status, ST_SIZE, gettext("One or more devices have " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices have " "been removed.\n\tSufficient replicas exist for the pool " "to continue functioning in a\n\tdegraded state.\n")); - snprintf(action, AC_SIZE, gettext("Online the device " + (void) snprintf(action, AC_SIZE, gettext("Online the device " "using zpool online' or replace the device with\n\t'zpool " "replace'.\n")); break; case ZPOOL_STATUS_RESILVERING: case ZPOOL_STATUS_REBUILDING: - snprintf(status, ST_SIZE, gettext("One or more devices is " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices is " "currently being resilvered. The pool will\n\tcontinue " "to function, possibly in a degraded state.\n")); - snprintf(action, AC_SIZE, gettext("Wait for the resilver to " - "complete.\n")); + (void) snprintf(action, AC_SIZE, + gettext("Wait for the resilver to complete.\n")); break; case ZPOOL_STATUS_REBUILD_SCRUB: - snprintf(status, ST_SIZE, gettext("One or more devices have " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices have " "been sequentially resilvered, scrubbing\n\tthe pool " "is recommended.\n")); - snprintf(action, AC_SIZE, gettext("Use 'zpool scrub' to " + (void) snprintf(action, AC_SIZE, gettext("Use 'zpool scrub' to " "verify all data checksums.\n")); break; case ZPOOL_STATUS_CORRUPT_DATA: - snprintf(status, ST_SIZE, gettext("One or more devices has " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices has " "experienced an error resulting in data\n\tcorruption. " "Applications may be affected.\n")); - snprintf(action, AC_SIZE, gettext("Restore the file in question" + (void) snprintf(action, AC_SIZE, + gettext("Restore the file in question" " if possible. Otherwise restore the\n\tentire pool from " "backup.\n")); break; case ZPOOL_STATUS_CORRUPT_POOL: - snprintf(status, ST_SIZE, gettext("The pool metadata is " + (void) snprintf(status, ST_SIZE, gettext("The pool metadata is " "corrupted and the pool cannot be opened.\n")); zpool_explain_recover(zpool_get_handle(zhp), zpool_get_name(zhp), reason, zpool_get_config(zhp, NULL), @@ -10590,75 +10602,84 @@ print_status_reason(zpool_handle_t *zhp, status_cbdata_t *cbp, break; case ZPOOL_STATUS_VERSION_OLDER: - snprintf(status, ST_SIZE, gettext("The pool is formatted using " + (void) snprintf(status, ST_SIZE, + gettext("The pool is formatted using " "a legacy on-disk format. The pool can\n\tstill be used, " "but some features are unavailable.\n")); - snprintf(action, AC_SIZE, gettext("Upgrade the pool using " + (void) snprintf(action, AC_SIZE, + gettext("Upgrade the pool using " "'zpool upgrade'. Once this is done, the\n\tpool will no " "longer be accessible on software that does not support\n\t" "feature flags.\n")); break; case ZPOOL_STATUS_VERSION_NEWER: - snprintf(status, ST_SIZE, gettext("The pool has been upgraded " + (void) snprintf(status, ST_SIZE, + gettext("The pool has been upgraded " "to a newer, incompatible on-disk version.\n\tThe pool " "cannot be accessed on this system.\n")); - snprintf(action, AC_SIZE, gettext("Access the pool from a " + (void) snprintf(action, AC_SIZE, + gettext("Access the pool from a " "system running more recent software, or\n\trestore the " "pool from backup.\n")); break; case ZPOOL_STATUS_FEAT_DISABLED: - snprintf(status, ST_SIZE, gettext("Some supported and " + (void) snprintf(status, ST_SIZE, gettext("Some supported and " "requested features are not enabled on the pool.\n\t" "The pool can still be used, but some features are " "unavailable.\n")); - snprintf(action, AC_SIZE, gettext("Enable all features using " + (void) snprintf(action, AC_SIZE, + gettext("Enable all features using " "'zpool upgrade'. Once this is done,\n\tthe pool may no " "longer be accessible by software that does not support\n\t" "the features. See zpool-features(7) for details.\n")); break; case ZPOOL_STATUS_COMPATIBILITY_ERR: - snprintf(status, ST_SIZE, gettext("This pool has a " + (void) snprintf(status, ST_SIZE, gettext("This pool has a " "compatibility list specified, but it could not be\n\t" "read/parsed at this time. The pool can still be used, " "but this\n\tshould be investigated.\n")); - snprintf(action, AC_SIZE, gettext("Check the value of the " + (void) snprintf(action, AC_SIZE, + gettext("Check the value of the " "'compatibility' property against the\n\t" "appropriate file in " ZPOOL_SYSCONF_COMPAT_D " or " ZPOOL_DATA_COMPAT_D ".\n")); break; case ZPOOL_STATUS_INCOMPATIBLE_FEAT: - snprintf(status, ST_SIZE, gettext("One or more features " + (void) snprintf(status, ST_SIZE, gettext("One or more features " "are enabled on the pool despite not being\n\t" "requested by the 'compatibility' property.\n")); - snprintf(action, AC_SIZE, gettext("Consider setting " + (void) snprintf(action, AC_SIZE, gettext("Consider setting " "'compatibility' to an appropriate value, or\n\t" "adding needed features to the relevant file in\n\t" ZPOOL_SYSCONF_COMPAT_D " or " ZPOOL_DATA_COMPAT_D ".\n")); break; case ZPOOL_STATUS_UNSUP_FEAT_READ: - snprintf(status, ST_SIZE, gettext("The pool cannot be accessed " + (void) snprintf(status, ST_SIZE, + gettext("The pool cannot be accessed " "on this system because it uses the\n\tfollowing feature(s)" " not supported on this system:\n")); zpool_collect_unsup_feat(zpool_get_config(zhp, NULL), status, 1024); - snprintf(action, AC_SIZE, gettext("Access the pool from a " + (void) snprintf(action, AC_SIZE, + gettext("Access the pool from a " "system that supports the required feature(s),\n\tor " "restore the pool from backup.\n")); break; case ZPOOL_STATUS_UNSUP_FEAT_WRITE: - snprintf(status, ST_SIZE, gettext("The pool can only be " + (void) snprintf(status, ST_SIZE, gettext("The pool can only be " "accessed in read-only mode on this system. It\n\tcannot be" " accessed in read-write mode because it uses the " "following\n\tfeature(s) not supported on this system:\n")); zpool_collect_unsup_feat(zpool_get_config(zhp, NULL), status, 1024); - snprintf(action, AC_SIZE, gettext("The pool cannot be accessed " + (void) snprintf(action, AC_SIZE, + gettext("The pool cannot be accessed " "in read-write mode. Import the pool with\n" "\t\"-o readonly=on\", access the pool from a system that " "supports the\n\trequired feature(s), or restore the " @@ -10666,90 +10687,105 @@ print_status_reason(zpool_handle_t *zhp, status_cbdata_t *cbp, break; case ZPOOL_STATUS_FAULTED_DEV_R: - snprintf(status, ST_SIZE, gettext("One or more devices are " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices are " "faulted in response to persistent errors.\n\tSufficient " "replicas exist for the pool to continue functioning " "in a\n\tdegraded state.\n")); - snprintf(action, AC_SIZE, gettext("Replace the faulted device, " + (void) snprintf(action, AC_SIZE, + gettext("Replace the faulted device, " "or use 'zpool clear' to mark the device\n\trepaired.\n")); break; case ZPOOL_STATUS_FAULTED_DEV_NR: - snprintf(status, ST_SIZE, gettext("One or more devices are " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices are " "faulted in response to persistent errors. There are " "insufficient replicas for the pool to\n\tcontinue " "functioning.\n")); - snprintf(action, AC_SIZE, gettext("Destroy and re-create the " + (void) snprintf(action, AC_SIZE, + gettext("Destroy and re-create the " "pool from a backup source. Manually marking the device\n" "\trepaired using 'zpool clear' may allow some data " "to be recovered.\n")); break; case ZPOOL_STATUS_IO_FAILURE_MMP: - snprintf(status, ST_SIZE, gettext("The pool is suspended " + (void) snprintf(status, ST_SIZE, + gettext("The pool is suspended " "because multihost writes failed or were delayed;\n\t" "another system could import the pool undetected.\n")); - snprintf(action, AC_SIZE, gettext("Make sure the pool's devices" + (void) snprintf(action, AC_SIZE, + gettext("Make sure the pool's devices" " are connected, then reboot your system and\n\timport the " "pool or run 'zpool clear' to resume the pool.\n")); break; case ZPOOL_STATUS_IO_FAILURE_WAIT: case ZPOOL_STATUS_IO_FAILURE_CONTINUE: - snprintf(status, ST_SIZE, gettext("One or more devices are " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices are " "faulted in response to IO failures.\n")); - snprintf(action, AC_SIZE, gettext("Make sure the affected " + (void) snprintf(action, AC_SIZE, + gettext("Make sure the affected " "devices are connected, then run 'zpool clear'.\n")); break; case ZPOOL_STATUS_BAD_LOG: - snprintf(status, ST_SIZE, gettext("An intent log record " + (void) snprintf(status, ST_SIZE, gettext("An intent log record " "could not be read.\n" "\tWaiting for administrator intervention to fix the " "faulted pool.\n")); - snprintf(action, AC_SIZE, gettext("Either restore the affected " + (void) snprintf(action, AC_SIZE, + gettext("Either restore the affected " "device(s) and run 'zpool online',\n" "\tor ignore the intent log records by running " "'zpool clear'.\n")); break; case ZPOOL_STATUS_NON_NATIVE_ASHIFT: - snprintf(status, ST_SIZE, gettext("One or more devices are " + (void) snprintf(status, ST_SIZE, + gettext("One or more devices are " "configured to use a non-native block size.\n" "\tExpect reduced performance.\n")); - snprintf(action, AC_SIZE, gettext("Replace affected devices " + (void) snprintf(action, AC_SIZE, + gettext("Replace affected devices " "with devices that support the\n\tconfigured block size, " "or migrate data to a properly configured\n\tpool.\n")); break; case ZPOOL_STATUS_HOSTID_MISMATCH: - snprintf(status, ST_SIZE, gettext("Mismatch between pool hostid" + (void) snprintf(status, ST_SIZE, + gettext("Mismatch between pool hostid" " and system hostid on imported pool.\n\tThis pool was " "previously imported into a system with a different " "hostid,\n\tand then was verbatim imported into this " "system.\n")); - snprintf(action, AC_SIZE, gettext("Export this pool on all " + (void) snprintf(action, AC_SIZE, + gettext("Export this pool on all " "systems on which it is imported.\n" "\tThen import it to correct the mismatch.\n")); break; case ZPOOL_STATUS_ERRATA: - snprintf(status, ST_SIZE, gettext("Errata #%d detected.\n"), - errata); + (void) snprintf(status, ST_SIZE, + gettext("Errata #%d detected.\n"), errata); switch (errata) { case ZPOOL_ERRATA_NONE: break; case ZPOOL_ERRATA_ZOL_2094_SCRUB: - snprintf(action, AC_SIZE, gettext("To correct the issue" - " run 'zpool scrub'.\n")); + (void) snprintf(action, AC_SIZE, + gettext("To correct the issue run " + "'zpool scrub'.\n")); break; case ZPOOL_ERRATA_ZOL_6845_ENCRYPTION: (void) strlcat(status, gettext("\tExisting encrypted " "datasets contain an on-disk incompatibility\n\t " "which needs to be corrected.\n"), ST_SIZE); - snprintf(action, AC_SIZE, gettext("To correct the issue" + (void) snprintf(action, AC_SIZE, + gettext("To correct the issue" " backup existing encrypted datasets to new\n\t" "encrypted datasets and destroy the old ones. " "'zfs mount -o ro' can\n\tbe used to temporarily " @@ -10762,7 +10798,8 @@ print_status_reason(zpool_handle_t *zhp, status_cbdata_t *cbp, "incompatibility. This may cause on-disk " "corruption if they are used\n\twith " "'zfs recv'.\n"), ST_SIZE); - snprintf(action, AC_SIZE, gettext("To correct the" + (void) snprintf(action, AC_SIZE, + gettext("To correct the" "issue, enable the bookmark_v2 feature. No " "additional\n\taction is needed if there are no " "encrypted snapshots or bookmarks.\n\tIf preserving" @@ -10792,8 +10829,8 @@ print_status_reason(zpool_handle_t *zhp, status_cbdata_t *cbp, if (cbp->cb_json) fnvlist_add_string(item, "status", status); else { - printf_color(ANSI_BOLD, gettext("status: ")); - printf_color(ANSI_YELLOW, status); + (void) printf_color(ANSI_BOLD, gettext("status: ")); + (void) printf_color(ANSI_YELLOW, status); } } @@ -10801,8 +10838,8 @@ print_status_reason(zpool_handle_t *zhp, status_cbdata_t *cbp, if (cbp->cb_json) fnvlist_add_string(item, "action", action); else { - printf_color(ANSI_BOLD, gettext("action: ")); - printf_color(ANSI_YELLOW, action); + (void) printf_color(ANSI_BOLD, gettext("action: ")); + (void) printf_color(ANSI_YELLOW, action); } } } @@ -10852,13 +10889,14 @@ status_callback_json(zpool_handle_t *zhp, void *data) if (cbp->cb_json_pool_key_guid) { guid = fnvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_GUID); - snprintf(pool_guid, 256, "%llu", (u_longlong_t)guid); + (void) snprintf(pool_guid, 256, "%llu", + (u_longlong_t)guid); } cbp->cb_count++; print_status_reason(zhp, cbp, reason, errata, item); if (msgid != NULL) { - snprintf(msgbuf, 256, + (void) snprintf(msgbuf, 256, "https://openzfs.github.io/openzfs-docs/msg/%s", msgid); fnvlist_add_string(item, "msgid", msgid); @@ -10981,19 +11019,19 @@ status_callback(zpool_handle_t *zhp, void *data) health = zpool_get_state_str(zhp); printf(" "); - printf_color(ANSI_BOLD, gettext("pool:")); + (void) printf_color(ANSI_BOLD, gettext("pool:")); printf(" %s\n", zpool_get_name(zhp)); - fputc(' ', stdout); - printf_color(ANSI_BOLD, gettext("state: ")); + (void) fputc(' ', stdout); + (void) printf_color(ANSI_BOLD, gettext("state: ")); - printf_color(health_str_to_color(health), "%s", health); + (void) printf_color(health_str_to_color(health), "%s", health); - fputc('\n', stdout); + (void) fputc('\n', stdout); print_status_reason(zhp, cbp, reason, errata, NULL); if (msgid != NULL) { printf(" "); - printf_color(ANSI_BOLD, gettext("see:")); + (void) printf_color(ANSI_BOLD, gettext("see:")); printf(gettext( " https://openzfs.github.io/openzfs-docs/msg/%s\n"), msgid); @@ -11034,15 +11072,16 @@ status_callback(zpool_handle_t *zhp, void *data) color_end(); if (cbp->cb_print_slow_ios) { - printf_color(ANSI_BOLD, " %5s", gettext("SLOW")); + (void) printf_color(ANSI_BOLD, " %5s", gettext("SLOW")); } if (cbp->cb_print_power) { - printf_color(ANSI_BOLD, " %5s", gettext("POWER")); + (void) printf_color(ANSI_BOLD, " %5s", + gettext("POWER")); } if (cbp->cb_print_dio_verify) { - printf_color(ANSI_BOLD, " %5s", gettext("DIO")); + (void) printf_color(ANSI_BOLD, " %5s", gettext("DIO")); } if (cbp->vcdl != NULL) @@ -11359,7 +11398,7 @@ check_unsupp_fs(zfs_handle_t *zhp, void *unsupp_fs) (*count)++; } - zfs_iter_filesystems_v2(zhp, 0, check_unsupp_fs, unsupp_fs); + (void) zfs_iter_filesystems_v2(zhp, 0, check_unsupp_fs, unsupp_fs); zfs_close(zhp); @@ -12187,17 +12226,17 @@ zpool_do_events_nvprint(nvlist_t *nvl, int depth) FM_EREPORT_PAYLOAD_ZFS_ZIO_STAGE) == 0 || strcmp(name, FM_EREPORT_PAYLOAD_ZFS_ZIO_PIPELINE) == 0) { - zfs_valstr_zio_stage(i32, flagstr, + (void) zfs_valstr_zio_stage(i32, flagstr, sizeof (flagstr)); printf(gettext("0x%x [%s]"), i32, flagstr); } else if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_ZIO_TYPE) == 0) { - zfs_valstr_zio_type(i32, flagstr, + (void) zfs_valstr_zio_type(i32, flagstr, sizeof (flagstr)); printf(gettext("0x%x [%s]"), i32, flagstr); } else if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_ZIO_PRIORITY) == 0) { - zfs_valstr_zio_priority(i32, flagstr, + (void) zfs_valstr_zio_priority(i32, flagstr, sizeof (flagstr)); printf(gettext("0x%x [%s]"), i32, flagstr); } else { @@ -12225,7 +12264,7 @@ zpool_do_events_nvprint(nvlist_t *nvl, int depth) (u_longlong_t)i64); } else if (strcmp(name, FM_EREPORT_PAYLOAD_ZFS_ZIO_FLAGS) == 0) { - zfs_valstr_zio_flag(i64, flagstr, + (void) zfs_valstr_zio_flag(i64, flagstr, sizeof (flagstr)); printf(gettext("0x%llx [%s]"), (u_longlong_t)i64, flagstr); @@ -12539,7 +12578,7 @@ get_callback_vdev(zpool_handle_t *zhp, char *vdevname, void *data) if (zpool_get_vdev_prop(zhp, vdevname, pl->pl_prop, prop_name, value, sizeof (value), &srctype, cbp->cb_literal) == 0) { - zprop_collect_property(vdevname, cbp, prop_name, + (void) zprop_collect_property(vdevname, cbp, prop_name, value, srctype, NULL, NULL, props); } } @@ -12611,19 +12650,19 @@ get_callback(zpool_handle_t *zhp, void *data) } if (strcmp(cbp->cb_vdevs.cb_names[0], "all-vdevs") == 0) { - for_each_vdev(zhp, get_callback_vdev_cb, data); + (void) for_each_vdev(zhp, get_callback_vdev_cb, data); } else { /* Adjust column widths for vdev properties */ for (vid = 0; vid < cbp->cb_vdevs.cb_names_count; vid++) { - vdev_expand_proplist(zhp, + (void) vdev_expand_proplist(zhp, cbp->cb_vdevs.cb_names[vid], &cbp->cb_proplist); } /* Display the properties */ for (vid = 0; vid < cbp->cb_vdevs.cb_names_count; vid++) { - get_callback_vdev(zhp, + (void) get_callback_vdev(zhp, cbp->cb_vdevs.cb_names[vid], data); } } @@ -12696,7 +12735,7 @@ get_callback(zpool_handle_t *zhp, void *data) uint64_t guid = fnvlist_lookup_uint64( zpool_get_config(zhp, NULL), ZPOOL_CONFIG_POOL_GUID); - snprintf(buf, 256, "%llu", + (void) snprintf(buf, 256, "%llu", (u_longlong_t)guid); fnvlist_add_nvlist(d, buf, item); } else { @@ -12895,7 +12934,6 @@ found: argv[0], &cb.cb_vdevs); fprintf(stderr, "\n"); usage(B_FALSE); - return (1); } } else { if (cb.cb_json) { @@ -13391,11 +13429,11 @@ wait_status_thread(void *arg) } else { timeout.tv_nsec = nanos; } - pthread_mutex_lock(&wd->wd_mutex); + (void) pthread_mutex_lock(&wd->wd_mutex); if (!wd->wd_should_exit) ret = pthread_cond_timedwait(&wd->wd_cv, &wd->wd_mutex, &timeout); - pthread_mutex_unlock(&wd->wd_mutex); + (void) pthread_mutex_unlock(&wd->wd_mutex); if (ret == 0) { break; /* signaled by main thread */ } else if (ret != ETIMEDOUT) { @@ -13426,8 +13464,8 @@ zpool_do_wait(int argc, char **argv) wd.wd_headers_once = B_FALSE; wd.wd_should_exit = B_FALSE; - pthread_mutex_init(&wd.wd_mutex, NULL); - pthread_cond_init(&wd.wd_cv, NULL); + (void) pthread_mutex_init(&wd.wd_mutex, NULL); + (void) pthread_cond_init(&wd.wd_cv, NULL); /* By default, wait for all types of activity. */ for (i = 0; i < ZPOOL_WAIT_NUM_ACTIVITIES; i++) @@ -13551,17 +13589,17 @@ found:; if (verbose) { uintptr_t status; - pthread_mutex_lock(&wd.wd_mutex); + (void) pthread_mutex_lock(&wd.wd_mutex); wd.wd_should_exit = B_TRUE; - pthread_cond_signal(&wd.wd_cv); - pthread_mutex_unlock(&wd.wd_mutex); + (void) pthread_cond_signal(&wd.wd_cv); + (void) pthread_mutex_unlock(&wd.wd_mutex); (void) pthread_join(status_thr, (void *)&status); if (status != 0) error = status; } - pthread_mutex_destroy(&wd.wd_mutex); - pthread_cond_destroy(&wd.wd_cv); + (void) pthread_mutex_destroy(&wd.wd_mutex); + (void) pthread_cond_destroy(&wd.wd_cv); return (error); } @@ -13714,14 +13752,14 @@ zpool_do_help(int argc, char **argv) { char page[MAXNAMELEN]; if (argc < 3 || strcmp(argv[2], "zpool") == 0) - strcpy(page, "zpool"); + (void) strcpy(page, "zpool"); else if (strcmp(argv[2], "concepts") == 0 || strcmp(argv[2], "props") == 0) - snprintf(page, sizeof (page), "zpool%s", argv[2]); + (void) snprintf(page, sizeof (page), "zpool%s", argv[2]); else - snprintf(page, sizeof (page), "zpool-%s", argv[2]); + (void) snprintf(page, sizeof (page), "zpool-%s", argv[2]); - execlp("man", "man", page, NULL); + (void) execlp("man", "man", page, NULL); fprintf(stderr, "couldn't run man program: %s", strerror(errno)); return (-1); @@ -13848,7 +13886,6 @@ main(int argc, char **argv) (void) fprintf(stderr, gettext("unrecognized " "command '%s'\n"), cmdname); usage(B_FALSE); - ret = 1; } for (i = 0; i < argc; i++) diff --git a/cmd/zpool/zpool_vdev.c b/cmd/zpool/zpool_vdev.c index 222b5524669e..d1e9ef76dc10 100644 --- a/cmd/zpool/zpool_vdev.c +++ b/cmd/zpool/zpool_vdev.c @@ -195,7 +195,7 @@ is_shorthand_path(const char *arg, char *path, size_t path_size, return (0); } - strlcpy(path, arg, path_size); + (void) strlcpy(path, arg, path_size); memset(statbuf, 0, sizeof (*statbuf)); *wholedisk = B_FALSE; @@ -308,7 +308,7 @@ make_leaf_vdev(const char *arg, boolean_t is_primary, uint64_t ashift) } /* After whole disk check restore original passed path */ - strlcpy(path, arg, sizeof (path)); + (void) strlcpy(path, arg, sizeof (path)); } else if (zpool_is_draid_spare(arg)) { if (!is_primary) { (void) fprintf(stderr, @@ -318,7 +318,7 @@ make_leaf_vdev(const char *arg, boolean_t is_primary, uint64_t ashift) } wholedisk = B_TRUE; - strlcpy(path, arg, sizeof (path)); + (void) strlcpy(path, arg, sizeof (path)); type = VDEV_TYPE_DRAID_SPARE; } else { err = is_shorthand_path(arg, path, sizeof (path), @@ -1010,7 +1010,7 @@ make_disks(zpool_handle_t *zhp, nvlist_t *nv, boolean_t replacing) * window between when udev deletes and recreates the link * during which access attempts will fail with ENOENT. */ - strlcpy(udevpath, path, MAXPATHLEN); + (void) strlcpy(udevpath, path, MAXPATHLEN); (void) zfs_append_partition(udevpath, MAXPATHLEN); fd = open(devpath, O_RDWR|O_EXCL);