diff options
| author | Martin Matuska <mm@FreeBSD.org> | 2021-12-19 15:21:10 +0000 |
|---|---|---|
| committer | Martin Matuska <mm@FreeBSD.org> | 2021-12-19 15:25:26 +0000 |
| commit | 3aa1cabca37db4ef3da06e92af17688783ccb00c (patch) | |
| tree | ac6e97937df069c532ea8f3d18eb2429789be8ae /sys/contrib/openzfs/module | |
| parent | 19592949abd2953a3c00cda59231113d29d4dd63 (diff) | |
| parent | af88d47f1ee86fae4abcfe0dabca67ea3c94d377 (diff) | |
zfs: merge openzfs/zfs@af88d47f1 (zfs-2.1-release) into stable/13
OpenZFS release 2.1.2
Notable upstream pull request merges:
#12668 FreeBSD: Catch up with recent VFS changes
#12704 Fix some FreeBSD VOPs to synchronize properly with teardown
#12717 VOP_RENAME fixes for FreeBSD
#12724 Fix lseek(SEEK_DATA/SEEK_HOLE) mmap consistency
#12745 Restore dirty dnode detection logic
#12770 ZFS send/recv with ashift 9->12 leads to data corruption
#12828 FreeBSD: Add vop_standard_writecount_nomsyn
#12828 FreeBSD: Catch up with more VFS changes
Obtained from: OpenZFS
OpenZFS commit: af88d47f1ee86fae4abcfe0dabca67ea3c94d377
OpenZFS tag: zfs-2.1.2
Relnotes: yes
Diffstat (limited to 'sys/contrib/openzfs/module')
38 files changed, 508 insertions, 259 deletions
diff --git a/sys/contrib/openzfs/module/Makefile.in b/sys/contrib/openzfs/module/Makefile.in index 089b3ff88490..05c673231cc5 100644 --- a/sys/contrib/openzfs/module/Makefile.in +++ b/sys/contrib/openzfs/module/Makefile.in @@ -114,7 +114,9 @@ modules_uninstall: modules_uninstall-@ac_system@ cppcheck-Linux: @CPPCHECK@ -j@CPU_COUNT@ --std=c99 --quiet --force --error-exitcode=2 \ - --inline-suppr --suppress=noValidConfiguration \ + --inline-suppr \ + --suppress=unmatchedSuppression \ + --suppress=noValidConfiguration \ --enable=warning,information -D_KERNEL \ --include=@LINUX_OBJ@/include/generated/autoconf.h \ --include=@top_srcdir@/zfs_config.h \ diff --git a/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c b/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c index 94e6937bcd76..9d303d022517 100644 --- a/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c +++ b/sys/contrib/openzfs/module/icp/core/kcf_prov_tabs.c @@ -377,7 +377,7 @@ kcf_provider_zero_refcnt(kcf_provider_desc_t *desc) mutex_exit(&desc->pd_lock); break; } - /* FALLTHRU */ + fallthrough; case CRYPTO_HW_PROVIDER: case CRYPTO_LOGICAL_PROVIDER: diff --git a/sys/contrib/openzfs/module/icp/io/aes.c b/sys/contrib/openzfs/module/icp/io/aes.c index e540af4473f7..c47c7567b900 100644 --- a/sys/contrib/openzfs/module/icp/io/aes.c +++ b/sys/contrib/openzfs/module/icp/io/aes.c @@ -976,7 +976,7 @@ aes_encrypt_atomic(crypto_provider_handle_t provider, case AES_GMAC_MECH_INFO_TYPE: if (plaintext->cd_length != 0) return (CRYPTO_ARGUMENTS_BAD); - /* FALLTHRU */ + fallthrough; case AES_GCM_MECH_INFO_TYPE: length_needed = plaintext->cd_length + aes_ctx.ac_tag_len; break; diff --git a/sys/contrib/openzfs/module/lua/lcode.c b/sys/contrib/openzfs/module/lua/lcode.c index ae9a3d91d810..4d88c792a281 100644 --- a/sys/contrib/openzfs/module/lua/lcode.c +++ b/sys/contrib/openzfs/module/lua/lcode.c @@ -8,6 +8,10 @@ #define lcode_c #define LUA_CORE +#if defined(HAVE_IMPLICIT_FALLTHROUGH) +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#endif + #include <sys/lua/lua.h> #include "lcode.h" diff --git a/sys/contrib/openzfs/module/lua/lgc.c b/sys/contrib/openzfs/module/lua/lgc.c index 55feb24119d3..227ad723a0b8 100644 --- a/sys/contrib/openzfs/module/lua/lgc.c +++ b/sys/contrib/openzfs/module/lua/lgc.c @@ -676,7 +676,7 @@ static void freeobj (lua_State *L, GCObject *o) { case LUA_TUSERDATA: luaM_freemem(L, o, sizeudata(gco2u(o))); break; case LUA_TSHRSTR: G(L)->strt.nuse--; - /* FALLTHROUGH */ + fallthrough; case LUA_TLNGSTR: { luaM_freemem(L, o, sizestring(gco2ts(o))); break; diff --git a/sys/contrib/openzfs/module/lua/llex.c b/sys/contrib/openzfs/module/lua/llex.c index 50c301f599f1..f2c9bf826c82 100644 --- a/sys/contrib/openzfs/module/lua/llex.c +++ b/sys/contrib/openzfs/module/lua/llex.c @@ -477,7 +477,7 @@ static int llex (LexState *ls, SemInfo *seminfo) { else if (!lisdigit(ls->current)) return '.'; /* else go through */ } - /* FALLTHROUGH */ + fallthrough; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { read_numeral(ls, seminfo); diff --git a/sys/contrib/openzfs/module/lua/lstrlib.c b/sys/contrib/openzfs/module/lua/lstrlib.c index 12027757bf53..46e3d8fb35bb 100644 --- a/sys/contrib/openzfs/module/lua/lstrlib.c +++ b/sys/contrib/openzfs/module/lua/lstrlib.c @@ -501,7 +501,7 @@ static const char *match (MatchState *ms, const char *s, const char *p) { } case '+': /* 1 or more repetitions */ s++; /* 1 match already done */ - /* FALLTHROUGH */ + fallthrough; case '*': /* 0 or more repetitions */ s = max_expand(ms, s, p, ep); break; diff --git a/sys/contrib/openzfs/module/lua/ltable.c b/sys/contrib/openzfs/module/lua/ltable.c index f60418721bef..f6872babc6e7 100644 --- a/sys/contrib/openzfs/module/lua/ltable.c +++ b/sys/contrib/openzfs/module/lua/ltable.c @@ -492,7 +492,7 @@ const TValue *luaH_get (Table *t, const TValue *key) { return luaH_getint(t, k); /* use specialized version */ /* else go through */ } - /* FALLTHROUGH */ + fallthrough; default: { Node *n = mainposition(t, key); do { /* check whether `key' is somewhere in the chain */ diff --git a/sys/contrib/openzfs/module/nvpair/nvpair.c b/sys/contrib/openzfs/module/nvpair/nvpair.c index 5f427c8cf2e7..9834dedd859d 100644 --- a/sys/contrib/openzfs/module/nvpair/nvpair.c +++ b/sys/contrib/openzfs/module/nvpair/nvpair.c @@ -533,12 +533,14 @@ nvt_add_nvpair(nvlist_t *nvl, nvpair_t *nvp) uint64_t index = hash & (priv->nvp_nbuckets - 1); ASSERT3U(index, <, priv->nvp_nbuckets); + // cppcheck-suppress nullPointerRedundantCheck i_nvp_t *bucket = tab[index]; /* insert link at the beginning of the bucket */ i_nvp_t *new_entry = NVPAIR2I_NVP(nvp); ASSERT3P(new_entry->nvi_hashtable_next, ==, NULL); new_entry->nvi_hashtable_next = bucket; + // cppcheck-suppress nullPointerRedundantCheck tab[index] = new_entry; priv->nvp_nentries++; @@ -3270,6 +3272,8 @@ NVS_BUILD_XDRPROC_T(u_longlong_t); static int nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp) { + ASSERT(nvs != NULL && nvp != NULL); + data_type_t type; char *buf; char *buf_end = (char *)nvp + nvp->nvp_size; @@ -3278,7 +3282,7 @@ nvs_xdr_nvp_op(nvstream_t *nvs, nvpair_t *nvp) bool_t ret = FALSE; XDR *xdr = nvs->nvs_private; - ASSERT(xdr != NULL && nvp != NULL); + ASSERT(xdr != NULL); /* name string */ if ((buf = NVP_NAME(nvp)) >= buf_end) diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c b/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c index 4ffa21495e74..2ef4811a8a4e 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/vdev_geom.c @@ -199,7 +199,6 @@ vdev_geom_orphan(struct g_consumer *cp) * async removal support to invoke a close on this * vdev once it is safe to do so. */ - // cppcheck-suppress All SLIST_FOREACH(elem, priv, elems) { // cppcheck-suppress uninitvar vdev_t *vd = elem->vd; diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c index 9b410863019e..ae758bcefe21 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_acl.c @@ -269,7 +269,7 @@ zfs_ace_fuid_size(void *acep) entry_type == OWNING_GROUP || entry_type == ACE_EVERYONE) return (sizeof (zfs_ace_hdr_t)); - /*FALLTHROUGH*/ + fallthrough; default: return (sizeof (zfs_ace_t)); } @@ -2153,7 +2153,7 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, break; case OWNING_GROUP: who = gowner; - /*FALLTHROUGH*/ + fallthrough; case ACE_IDENTIFIER_GROUP: checkit = zfs_groupmember(zfsvfs, who, cr); break; diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c index a9fe1b647238..cde40e87698b 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_ctldir.c @@ -815,6 +815,9 @@ static struct vop_vector zfsctl_ops_root = { .vop_vptocnp = zfsctl_root_vptocnp, .vop_pathconf = zfsctl_common_pathconf, .vop_getacl = zfsctl_common_getacl, +#if __FreeBSD_version >= 1400043 + .vop_add_writecount = vop_stdadd_writecount_nomsync, +#endif }; VFS_VOP_VECTOR_REGISTER(zfsctl_ops_root); @@ -1134,6 +1137,9 @@ static struct vop_vector zfsctl_ops_snapdir = { .vop_print = zfsctl_common_print, .vop_pathconf = zfsctl_common_pathconf, .vop_getacl = zfsctl_common_getacl, +#if __FreeBSD_version >= 1400043 + .vop_add_writecount = vop_stdadd_writecount_nomsync, +#endif }; VFS_VOP_VECTOR_REGISTER(zfsctl_ops_snapdir); @@ -1238,6 +1244,9 @@ static struct vop_vector zfsctl_ops_snapshot = { .vop_islocked = vop_stdislocked, .vop_advlockpurge = vop_stdadvlockpurge, /* called by vgone */ .vop_print = zfsctl_common_print, +#if __FreeBSD_version >= 1400043 + .vop_add_writecount = vop_stdadd_writecount_nomsync, +#endif }; VFS_VOP_VECTOR_REGISTER(zfsctl_ops_snapshot); diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_file_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_file_os.c index a3d67aaa11ba..fd86a75416e6 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_file_os.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_file_os.c @@ -207,7 +207,11 @@ zfs_file_getattr(zfs_file_t *fp, zfs_file_attr_t *zfattr) td = curthread; +#if __FreeBSD_version < 1400037 rc = fo_stat(fp, &sb, td->td_ucred, td); +#else + rc = fo_stat(fp, &sb, td->td_ucred); +#endif if (rc) return (SET_ERROR(rc)); zfattr->zfa_size = sb.st_size; diff --git a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c index 4672b9c2b8b3..8e48f78b7311 100644 --- a/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vnops_os.c @@ -775,8 +775,8 @@ zfs_lookup_lock(vnode_t *dvp, vnode_t *vp, const char *name, int lkflags) /* ARGSUSED */ static int zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, - struct componentname *cnp, int nameiop, cred_t *cr, kthread_t *td, - int flags, boolean_t cached) + struct componentname *cnp, int nameiop, cred_t *cr, int flags, + boolean_t cached) { znode_t *zdp = VTOZ(dvp); znode_t *zp; @@ -974,7 +974,7 @@ zfs_lookup(vnode_t *dvp, const char *nm, vnode_t **vpp, cnp->cn_flags |= SAVENAME; break; } - /* FALLTHROUGH */ + fallthrough; case DELETE: if (error == 0) cnp->cn_flags |= SAVENAME; @@ -1338,7 +1338,9 @@ zfs_lookup_internal(znode_t *dzp, const char *name, vnode_t **vpp, cnp->cn_flags = ISLASTCN | SAVENAME; cnp->cn_lkflags = LK_EXCLUSIVE | LK_RETRY; cnp->cn_cred = kcred; +#if __FreeBSD_version < 1400037 cnp->cn_thread = curthread; +#endif if (zfsvfs->z_use_namecache && !zfsvfs->z_replay) { struct vop_lookup_args a; @@ -1349,8 +1351,8 @@ zfs_lookup_internal(znode_t *dzp, const char *name, vnode_t **vpp, a.a_cnp = cnp; error = vfs_cache_lookup(&a); } else { - error = zfs_lookup(ZTOV(dzp), name, vpp, cnp, nameiop, kcred, - curthread, 0, B_FALSE); + error = zfs_lookup(ZTOV(dzp), name, vpp, cnp, nameiop, kcred, 0, + B_FALSE); } #ifdef ZFS_DEBUG if (error) { @@ -2220,7 +2222,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) { vnode_t *vp = ZTOV(zp); zfsvfs_t *zfsvfs = zp->z_zfsvfs; - objset_t *os = zfsvfs->z_os; + objset_t *os; zilog_t *zilog; dmu_tx_t *tx; vattr_t oldva; @@ -2255,6 +2257,7 @@ zfs_setattr(znode_t *zp, vattr_t *vap, int flags, cred_t *cr) ZFS_ENTER(zfsvfs); ZFS_VERIFY_ZP(zp); + os = zfsvfs->z_os; zilog = zfsvfs->z_log; /* @@ -2932,6 +2935,66 @@ out2: } /* + * Look up the directory entries corresponding to the source and target + * directory/name pairs. + */ +static int +zfs_rename_relock_lookup(znode_t *sdzp, const struct componentname *scnp, + znode_t **szpp, znode_t *tdzp, const struct componentname *tcnp, + znode_t **tzpp) +{ + zfsvfs_t *zfsvfs; + znode_t *szp, *tzp; + int error; + + /* + * Before using sdzp and tdzp we must ensure that they are live. + * As a porting legacy from illumos we have two things to worry + * about. One is typical for FreeBSD and it is that the vnode is + * not reclaimed (doomed). The other is that the znode is live. + * The current code can invalidate the znode without acquiring the + * corresponding vnode lock if the object represented by the znode + * and vnode is no longer valid after a rollback or receive operation. + * z_teardown_lock hidden behind ZFS_ENTER and ZFS_EXIT is the lock + * that protects the znodes from the invalidation. + */ + zfsvfs = sdzp->z_zfsvfs; + ASSERT3P(zfsvfs, ==, tdzp->z_zfsvfs); + ZFS_ENTER(zfsvfs); + ZFS_VERIFY_ZP(sdzp); + ZFS_VERIFY_ZP(tdzp); + + /* + * Re-resolve svp to be certain it still exists and fetch the + * correct vnode. + */ + error = zfs_dirent_lookup(sdzp, scnp->cn_nameptr, &szp, ZEXISTS); + if (error != 0) { + /* Source entry invalid or not there. */ + if ((scnp->cn_flags & ISDOTDOT) != 0 || + (scnp->cn_namelen == 1 && scnp->cn_nameptr[0] == '.')) + error = SET_ERROR(EINVAL); + goto out; + } + *szpp = szp; + + /* + * Re-resolve tvp, if it disappeared we just carry on. + */ + error = zfs_dirent_lookup(tdzp, tcnp->cn_nameptr, &tzp, 0); + if (error != 0) { + vrele(ZTOV(szp)); + if ((tcnp->cn_flags & ISDOTDOT) != 0) + error = SET_ERROR(EINVAL); + goto out; + } + *tzpp = tzp; +out: + ZFS_EXIT(zfsvfs); + return (error); +} + +/* * We acquire all but fdvp locks using non-blocking acquisitions. If we * fail to acquire any lock in the path we will drop all held locks, * acquire the new lock in a blocking fashion, and then release it and @@ -2944,12 +3007,9 @@ zfs_rename_relock(struct vnode *sdvp, struct vnode **svpp, struct vnode *tdvp, struct vnode **tvpp, const struct componentname *scnp, const struct componentname *tcnp) { - zfsvfs_t *zfsvfs; struct vnode *nvp, *svp, *tvp; znode_t *sdzp, *tdzp, *szp, *tzp; - const char *snm = scnp->cn_nameptr; - const char *tnm = tcnp->cn_nameptr; - int error; + int error; VOP_UNLOCK1(tdvp); if (*tvpp != NULL && *tvpp != tdvp) @@ -2959,8 +3019,6 @@ relock: error = vn_lock(sdvp, LK_EXCLUSIVE); if (error) goto out; - sdzp = VTOZ(sdvp); - error = vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT); if (error != 0) { VOP_UNLOCK1(sdvp); @@ -2973,74 +3031,16 @@ relock: goto relock; } tdzp = VTOZ(tdvp); + sdzp = VTOZ(sdvp); - /* - * Before using sdzp and tdzp we must ensure that they are live. - * As a porting legacy from illumos we have two things to worry - * about. One is typical for FreeBSD and it is that the vnode is - * not reclaimed (doomed). The other is that the znode is live. - * The current code can invalidate the znode without acquiring the - * corresponding vnode lock if the object represented by the znode - * and vnode is no longer valid after a rollback or receive operation. - * z_teardown_lock hidden behind ZFS_ENTER and ZFS_EXIT is the lock - * that protects the znodes from the invalidation. - */ - zfsvfs = sdzp->z_zfsvfs; - ASSERT3P(zfsvfs, ==, tdzp->z_zfsvfs); - ZFS_ENTER(zfsvfs); - - /* - * We can not use ZFS_VERIFY_ZP() here because it could directly return - * bypassing the cleanup code in the case of an error. - */ - if (tdzp->z_sa_hdl == NULL || sdzp->z_sa_hdl == NULL) { - ZFS_EXIT(zfsvfs); - VOP_UNLOCK1(sdvp); - VOP_UNLOCK1(tdvp); - error = SET_ERROR(EIO); - goto out; - } - - /* - * Re-resolve svp to be certain it still exists and fetch the - * correct vnode. - */ - error = zfs_dirent_lookup(sdzp, snm, &szp, ZEXISTS); + error = zfs_rename_relock_lookup(sdzp, scnp, &szp, tdzp, tcnp, &tzp); if (error != 0) { - /* Source entry invalid or not there. */ - ZFS_EXIT(zfsvfs); VOP_UNLOCK1(sdvp); VOP_UNLOCK1(tdvp); - if ((scnp->cn_flags & ISDOTDOT) != 0 || - (scnp->cn_namelen == 1 && scnp->cn_nameptr[0] == '.')) - error = SET_ERROR(EINVAL); goto out; } svp = ZTOV(szp); - - /* - * Re-resolve tvp, if it disappeared we just carry on. - */ - error = zfs_dirent_lookup(tdzp, tnm, &tzp, 0); - if (error != 0) { - ZFS_EXIT(zfsvfs); - VOP_UNLOCK1(sdvp); - VOP_UNLOCK1(tdvp); - vrele(svp); - if ((tcnp->cn_flags & ISDOTDOT) != 0) - error = SET_ERROR(EINVAL); - goto out; - } - if (tzp != NULL) - tvp = ZTOV(tzp); - else - tvp = NULL; - - /* - * At present the vnode locks must be acquired before z_teardown_lock, - * although it would be more logical to use the opposite order. - */ - ZFS_EXIT(zfsvfs); + tvp = tzp != NULL ? ZTOV(tzp) : NULL; /* * Now try acquire locks on svp and tvp. @@ -3177,17 +3177,22 @@ cache_vop_rename(struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, } #endif +static int +zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, + vnode_t *tdvp, vnode_t **tvpp, struct componentname *tcnp, + cred_t *cr); + /* * Move an entry from the provided source directory to the target * directory. Change the entry name as indicated. * * IN: sdvp - Source directory containing the "old entry". - * snm - Old entry name. + * scnp - Old entry name. * tdvp - Target directory to contain the "new entry". - * tnm - New entry name. + * tcnp - New entry name. * cr - credentials of caller. - * ct - caller context - * flags - case flags + * INOUT: svpp - Source file + * tvpp - Target file, may point to NULL initially * * RETURN: 0 on success, error code on failure. * @@ -3196,18 +3201,15 @@ cache_vop_rename(struct vnode *fdvp, struct vnode *fvp, struct vnode *tdvp, */ /*ARGSUSED*/ static int -zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, +zfs_do_rename(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, vnode_t *tdvp, vnode_t **tvpp, struct componentname *tcnp, - cred_t *cr, int log) + cred_t *cr) { - zfsvfs_t *zfsvfs; - znode_t *sdzp, *tdzp, *szp, *tzp; - zilog_t *zilog = NULL; - dmu_tx_t *tx; - const char *snm = scnp->cn_nameptr; - const char *tnm = tcnp->cn_nameptr; - int error = 0; - bool want_seqc_end __maybe_unused = false; + int error; + + ASSERT_VOP_ELOCKED(tdvp, __func__); + if (*tvpp != NULL) + ASSERT_VOP_ELOCKED(*tvpp, __func__); /* Reject renames across filesystems. */ if ((*svpp)->v_mount != tdvp->v_mount || @@ -3230,51 +3232,64 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, return (error); } + error = zfs_do_rename_impl(sdvp, svpp, scnp, tdvp, tvpp, tcnp, cr); + VOP_UNLOCK1(sdvp); + VOP_UNLOCK1(*svpp); +out: + if (*tvpp != NULL) + VOP_UNLOCK1(*tvpp); + if (tdvp != *tvpp) + VOP_UNLOCK1(tdvp); + + return (error); +} + +static int +zfs_do_rename_impl(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, + vnode_t *tdvp, vnode_t **tvpp, struct componentname *tcnp, + cred_t *cr) +{ + dmu_tx_t *tx; + zfsvfs_t *zfsvfs; + zilog_t *zilog; + znode_t *tdzp, *sdzp, *tzp, *szp; + const char *snm = scnp->cn_nameptr; + const char *tnm = tcnp->cn_nameptr; + int error; + tdzp = VTOZ(tdvp); sdzp = VTOZ(sdvp); zfsvfs = tdzp->z_zfsvfs; - zilog = zfsvfs->z_log; - /* - * After we re-enter ZFS_ENTER() we will have to revalidate all - * znodes involved. - */ ZFS_ENTER(zfsvfs); + ZFS_VERIFY_ZP(tdzp); + ZFS_VERIFY_ZP(sdzp); + zilog = zfsvfs->z_log; if (zfsvfs->z_utf8 && u8_validate(tnm, strlen(tnm), NULL, U8_VALIDATE_ENTIRE, &error) < 0) { error = SET_ERROR(EILSEQ); - goto unlockout; + goto out; } /* If source and target are the same file, there is nothing to do. */ if ((*svpp) == (*tvpp)) { error = 0; - goto unlockout; + goto out; } if (((*svpp)->v_type == VDIR && (*svpp)->v_mountedhere != NULL) || ((*tvpp) != NULL && (*tvpp)->v_type == VDIR && (*tvpp)->v_mountedhere != NULL)) { error = SET_ERROR(EXDEV); - goto unlockout; - } - - /* - * We can not use ZFS_VERIFY_ZP() here because it could directly return - * bypassing the cleanup code in the case of an error. - */ - if (tdzp->z_sa_hdl == NULL || sdzp->z_sa_hdl == NULL) { - error = SET_ERROR(EIO); - goto unlockout; + goto out; } szp = VTOZ(*svpp); + ZFS_VERIFY_ZP(szp); tzp = *tvpp == NULL ? NULL : VTOZ(*tvpp); - if (szp->z_sa_hdl == NULL || (tzp != NULL && tzp->z_sa_hdl == NULL)) { - error = SET_ERROR(EIO); - goto unlockout; - } + if (tzp != NULL) + ZFS_VERIFY_ZP(tzp); /* * This is to prevent the creation of links into attribute space @@ -3283,7 +3298,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, */ if ((tdzp->z_pflags & ZFS_XATTR) != (sdzp->z_pflags & ZFS_XATTR)) { error = SET_ERROR(EINVAL); - goto unlockout; + goto out; } /* @@ -3296,7 +3311,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, if (tdzp->z_pflags & ZFS_PROJINHERIT && tdzp->z_projid != szp->z_projid) { error = SET_ERROR(EXDEV); - goto unlockout; + goto out; } /* @@ -3306,7 +3321,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, * done in a single check. */ if ((error = zfs_zaccess_rename(sdzp, szp, tdzp, tzp, cr))) - goto unlockout; + goto out; if ((*svpp)->v_type == VDIR) { /* @@ -3316,7 +3331,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, sdzp == szp || (scnp->cn_flags | tcnp->cn_flags) & ISDOTDOT) { error = EINVAL; - goto unlockout; + goto out; } /* @@ -3324,7 +3339,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, * Can't do a move like this: /usr/a/b to /usr/a/b/c/d */ if ((error = zfs_rename_check(szp, sdzp, tdzp))) - goto unlockout; + goto out; } /* @@ -3337,7 +3352,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, if ((*svpp)->v_type == VDIR) { if ((*tvpp)->v_type != VDIR) { error = SET_ERROR(ENOTDIR); - goto unlockout; + goto out; } else { cache_purge(tdvp); if (sdvp != tdvp) @@ -3346,7 +3361,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, } else { if ((*tvpp)->v_type == VDIR) { error = SET_ERROR(EISDIR); - goto unlockout; + goto out; } } } @@ -3357,9 +3372,7 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, vn_seqc_write_begin(*tvpp); if (tdvp != *tvpp) vn_seqc_write_begin(tdvp); -#if __FreeBSD_version >= 1300102 - want_seqc_end = true; -#endif + vnevent_rename_src(*svpp, sdvp, scnp->cn_nameptr, ct); if (tzp) vnevent_rename_dest(*tvpp, tdvp, tnm, ct); @@ -3391,10 +3404,9 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, error = dmu_tx_assign(tx, TXG_WAIT); if (error) { dmu_tx_abort(tx); - goto unlockout; + goto out_seq; } - if (tzp) /* Attempt to remove the existing target */ error = zfs_link_destroy(tdzp, tnm, tzp, tx, 0, NULL); @@ -3441,29 +3453,19 @@ zfs_rename_(vnode_t *sdvp, vnode_t **svpp, struct componentname *scnp, dmu_tx_commit(tx); -unlockout: /* all 4 vnodes are locked, ZFS_ENTER called */ - ZFS_EXIT(zfsvfs); - if (want_seqc_end) { - vn_seqc_write_end(*svpp); - vn_seqc_write_end(sdvp); - if (*tvpp != NULL) - vn_seqc_write_end(*tvpp); - if (tdvp != *tvpp) - vn_seqc_write_end(tdvp); - want_seqc_end = false; - } - VOP_UNLOCK1(*svpp); - VOP_UNLOCK1(sdvp); +out_seq: + vn_seqc_write_end(*svpp); + vn_seqc_write_end(sdvp); + if (*tvpp != NULL) + vn_seqc_write_end(*tvpp); + if (tdvp != *tvpp) + vn_seqc_write_end(tdvp); -out: /* original two vnodes are locked */ - MPASS(!want_seqc_end); +out: if (error == 0 && zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) zil_commit(zilog, 0); + ZFS_EXIT(zfsvfs); - if (*tvpp != NULL) - VOP_UNLOCK1(*tvpp); - if (tdvp != *tvpp) - VOP_UNLOCK1(tdvp); return (error); } @@ -3495,7 +3497,7 @@ zfs_rename(znode_t *sdzp, const char *sname, znode_t *tdzp, const char *tname, goto fail; } - error = zfs_rename_(sdvp, &svp, &scn, tdvp, &tvp, &tcn, cr, 0); + error = zfs_do_rename(sdvp, &svp, &scn, tdvp, &tvp, &tcn, cr); fail: if (svp != NULL) vrele(svp); @@ -4058,7 +4060,6 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind, { znode_t *zp = VTOZ(vp); zfsvfs_t *zfsvfs = zp->z_zfsvfs; - objset_t *os = zp->z_zfsvfs->z_os; zfs_locked_range_t *lr; vm_object_t object; off_t start, end, obj_size; @@ -4128,8 +4129,8 @@ zfs_getpages(struct vnode *vp, vm_page_t *ma, int count, int *rbehind, * ZFS will panic if we request DMU to read beyond the end of the last * allocated block. */ - error = dmu_read_pages(os, zp->z_id, ma, count, &pgsin_b, &pgsin_a, - MIN(end, obj_size) - (end - PAGE_SIZE)); + error = dmu_read_pages(zfsvfs->z_os, zp->z_id, ma, count, &pgsin_b, + &pgsin_a, MIN(end, obj_size) - (end - PAGE_SIZE)); if (lr != NULL) zfs_rangelock_exit(lr); @@ -4593,7 +4594,7 @@ zfs_freebsd_lookup(struct vop_lookup_args *ap, boolean_t cached) strlcpy(nm, cnp->cn_nameptr, MIN(cnp->cn_namelen + 1, sizeof (nm))); return (zfs_lookup(ap->a_dvp, nm, ap->a_vpp, cnp, cnp->cn_nameiop, - cnp->cn_cred, cnp->cn_thread, 0, cached)); + cnp->cn_cred, 0, cached)); } static int @@ -4976,8 +4977,8 @@ zfs_freebsd_rename(struct vop_rename_args *ap) ASSERT(ap->a_fcnp->cn_flags & (SAVENAME|SAVESTART)); ASSERT(ap->a_tcnp->cn_flags & (SAVENAME|SAVESTART)); - error = zfs_rename_(fdvp, &fvp, ap->a_fcnp, tdvp, &tvp, - ap->a_tcnp, ap->a_fcnp->cn_cred, 1); + error = zfs_do_rename(fdvp, &fvp, ap->a_fcnp, tdvp, &tvp, + ap->a_tcnp, ap->a_fcnp->cn_cred); vrele(fdvp); vrele(fvp); @@ -5345,14 +5346,18 @@ zfs_getextattr_dir(struct vop_getextattr_args *ap, const char *attrname) vnode_t *xvp = NULL, *vp; int error, flags; - error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, + error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, LOOKUP_XATTR, B_FALSE); if (error != 0) return (error); flags = FREAD; +#if __FreeBSD_version < 1400043 NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, attrname, xvp, td); +#else + NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, attrname, xvp); +#endif error = vn_open_cred(&nd, &flags, 0, VN_OPEN_INVFS, ap->a_cred, NULL); vp = nd.ni_vp; NDFREE(&nd, NDF_ONLY_PNBUF); @@ -5454,18 +5459,22 @@ struct vop_deleteextattr { static int zfs_deleteextattr_dir(struct vop_deleteextattr_args *ap, const char *attrname) { - struct thread *td = ap->a_td; struct nameidata nd; vnode_t *xvp = NULL, *vp; int error; - error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, + error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, LOOKUP_XATTR, B_FALSE); if (error != 0) return (error); +#if __FreeBSD_version < 1400043 + NDINIT_ATVP(&nd, DELETE, NOFOLLOW | LOCKPARENT | LOCKLEAF, + UIO_SYSSPACE, attrname, xvp, ap->a_td); +#else NDINIT_ATVP(&nd, DELETE, NOFOLLOW | LOCKPARENT | LOCKLEAF, - UIO_SYSSPACE, attrname, xvp, td); + UIO_SYSSPACE, attrname, xvp); +#endif error = namei(&nd); vp = nd.ni_vp; if (error != 0) { @@ -5585,13 +5594,17 @@ zfs_setextattr_dir(struct vop_setextattr_args *ap, const char *attrname) vnode_t *xvp = NULL, *vp; int error, flags; - error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, + error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, LOOKUP_XATTR | CREATE_XATTR_DIR, B_FALSE); if (error != 0) return (error); flags = FFLAGS(O_WRONLY | O_CREAT); +#if __FreeBSD_version < 1400043 NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, attrname, xvp, td); +#else + NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, attrname, xvp); +#endif error = vn_open_cred(&nd, &flags, 0600, VN_OPEN_INVFS, ap->a_cred, NULL); vp = nd.ni_vp; @@ -5729,7 +5742,7 @@ zfs_listextattr_dir(struct vop_listextattr_args *ap, const char *attrprefix) vnode_t *xvp = NULL, *vp; int error, eof; - error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, td, + error = zfs_lookup(ap->a_vp, NULL, &xvp, NULL, 0, ap->a_cred, LOOKUP_XATTR, B_FALSE); if (error != 0) { /* @@ -5741,8 +5754,13 @@ zfs_listextattr_dir(struct vop_listextattr_args *ap, const char *attrprefix) return (error); } +#if __FreeBSD_version < 1400043 NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKSHARED, UIO_SYSSPACE, ".", xvp, td); +#else + NDINIT_ATVP(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | LOCKSHARED, + UIO_SYSSPACE, ".", xvp); +#endif error = namei(&nd); vp = nd.ni_vp; NDFREE(&nd, NDF_ONLY_PNBUF); @@ -6115,6 +6133,9 @@ struct vop_vector zfs_vnodeops = { .vop_unlock = vop_unlock, .vop_islocked = vop_islocked, #endif +#if __FreeBSD_version >= 1400043 + .vop_add_writecount = vop_stdadd_writecount_nomsync, +#endif }; VFS_VOP_VECTOR_REGISTER(zfs_vnodeops); @@ -6139,6 +6160,9 @@ struct vop_vector zfs_fifoops = { .vop_getacl = zfs_freebsd_getacl, .vop_setacl = zfs_freebsd_setacl, .vop_aclcheck = zfs_freebsd_aclcheck, +#if __FreeBSD_version >= 1400043 + .vop_add_writecount = vop_stdadd_writecount_nomsync, +#endif }; VFS_VOP_VECTOR_REGISTER(zfs_fifoops); @@ -6158,5 +6182,8 @@ struct vop_vector zfs_shareops = { .vop_reclaim = zfs_freebsd_reclaim, .vop_fid = zfs_freebsd_fid, .vop_pathconf = zfs_freebsd_pathconf, +#if __FreeBSD_version >= 1400043 + .vop_add_writecount = vop_stdadd_writecount_nomsync, +#endif }; VFS_VOP_VECTOR_REGISTER(zfs_shareops); diff --git a/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c b/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c index 91eeaccfdc47..5ea4fc635165 100644 --- a/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c +++ b/sys/contrib/openzfs/module/os/linux/spl/spl-generic.c @@ -657,6 +657,7 @@ hostid_read(uint32_t *hostid) return (error); } size = stat.size; + // cppcheck-suppress sizeofwithnumericparameter if (size < sizeof (HW_HOSTID_MASK)) { filp_close(filp, 0); return (EINVAL); diff --git a/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c b/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c index c56fd3a6ff21..a432a736453c 100644 --- a/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c +++ b/sys/contrib/openzfs/module/os/linux/zfs/vdev_disk.c @@ -37,6 +37,9 @@ #include <linux/blkpg.h> #include <linux/msdos_fs.h> #include <linux/vfs_compat.h> +#ifdef HAVE_LINUX_BLK_CGROUP_HEADER +#include <linux/blk-cgroup.h> +#endif typedef struct vdev_disk { struct block_device *vd_bdev; @@ -265,6 +268,11 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, * a ENOENT failure at this point is highly likely to be transient * and it is reasonable to sleep and retry before giving up. In * practice delays have been observed to be on the order of 100ms. + * + * When ERESTARTSYS is returned it indicates the block device is + * a zvol which could not be opened due to the deadlock detection + * logic in zvol_open(). Extend the timeout and retry the open + * subsequent attempts are expected to eventually succeed. */ hrtime_t start = gethrtime(); bdev = ERR_PTR(-ENXIO); @@ -273,6 +281,9 @@ vdev_disk_open(vdev_t *v, uint64_t *psize, uint64_t *max_psize, zfs_vdev_holder); if (unlikely(PTR_ERR(bdev) == -ENOENT)) { schedule_timeout(MSEC_TO_TICK(10)); + } else if (unlikely(PTR_ERR(bdev) == -ERESTARTSYS)) { + timeout = MSEC2NSEC(zfs_vdev_open_timeout_ms * 10); + continue; } else if (IS_ERR(bdev)) { break; } @@ -433,9 +444,9 @@ static inline void vdev_submit_bio_impl(struct bio *bio) { #ifdef HAVE_1ARG_SUBMIT_BIO - submit_bio(bio); + (void) submit_bio(bio); #else - submit_bio(0, bio); + (void) submit_bio(0, bio); #endif } @@ -485,6 +496,7 @@ vdev_blkg_tryget(struct blkcg_gq *blkg) #elif defined(HAVE_BLKG_TRYGET) #define vdev_blkg_tryget(bg) blkg_tryget(bg) #endif +#ifdef HAVE_BIO_SET_DEV_MACRO /* * The Linux 5.0 kernel updated the bio_set_dev() macro so it calls the * GPL-only bio_associate_blkg() symbol thus inadvertently converting @@ -506,7 +518,30 @@ vdev_bio_associate_blkg(struct bio *bio) if (q->root_blkg && vdev_blkg_tryget(q->root_blkg)) bio->bi_blkg = q->root_blkg; } + #define bio_associate_blkg vdev_bio_associate_blkg +#else +static inline void +vdev_bio_set_dev(struct bio *bio, struct block_device *bdev) +{ +#if defined(HAVE_BIO_BDEV_DISK) + struct request_queue *q = bdev->bd_disk->queue; +#else + struct request_queue *q = bio->bi_disk->queue; +#endif + bio_clear_flag(bio, BIO_REMAPPED); + if (bio->bi_bdev != bdev) + bio_clear_flag(bio, BIO_THROTTLED); + bio->bi_bdev = bdev; + + ASSERT3P(q, !=, NULL); + ASSERT3P(bio->bi_blkg, ==, NULL); + + if (q->root_blkg && vdev_blkg_tryget(q->root_blkg)) + bio->bi_blkg = q->root_blkg; +} +#define bio_set_dev vdev_bio_set_dev +#endif #endif #else /* diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c index f8bf55f75e97..cf37aecf8a22 100644 --- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c +++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_acl.c @@ -269,7 +269,7 @@ zfs_ace_fuid_size(void *acep) entry_type == OWNING_GROUP || entry_type == ACE_EVERYONE) return (sizeof (zfs_ace_hdr_t)); - /*FALLTHROUGH*/ + fallthrough; default: return (sizeof (zfs_ace_t)); } @@ -2317,7 +2317,7 @@ zfs_zaccess_aces_check(znode_t *zp, uint32_t *working_mode, break; case OWNING_GROUP: who = gowner; - /*FALLTHROUGH*/ + fallthrough; case ACE_IDENTIFIER_GROUP: checkit = zfs_groupmember(zfsvfs, who, cr); break; diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c index ef99c4864d3c..a1a0e44bb31f 100644 --- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c +++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_vnops_os.c @@ -3556,7 +3556,11 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc) if (wbc->sync_mode != WB_SYNC_NONE) { if (PageWriteback(pp)) +#ifdef HAVE_PAGEMAP_FOLIO_WAIT_BIT + folio_wait_bit(page_folio(pp), PG_writeback); +#else wait_on_page_bit(pp, PG_writeback); +#endif } ZFS_EXIT(zfsvfs); diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c b/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c index c841cc0fc8b5..cd80049df142 100644 --- a/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c +++ b/sys/contrib/openzfs/module/os/linux/zfs/zfs_znode.c @@ -430,7 +430,7 @@ zfs_inode_set_ops(zfsvfs_t *zfsvfs, struct inode *ip) case S_IFBLK: (void) sa_lookup(ITOZ(ip)->z_sa_hdl, SA_ZPL_RDEV(zfsvfs), &rdev, sizeof (rdev)); - /*FALLTHROUGH*/ + fallthrough; case S_IFIFO: case S_IFSOCK: init_special_inode(ip, ip->i_mode, rdev); diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c b/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c index 63002fe3b932..7e88eae33711 100644 --- a/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c +++ b/sys/contrib/openzfs/module/os/linux/zfs/zpl_file.c @@ -251,10 +251,16 @@ zpl_uio_init(zfs_uio_t *uio, struct kiocb *kiocb, struct iov_iter *to, #if defined(HAVE_VFS_IOV_ITER) zfs_uio_iov_iter_init(uio, to, pos, count, skip); #else +#ifdef HAVE_IOV_ITER_TYPE + zfs_uio_iovec_init(uio, to->iov, to->nr_segs, pos, + iov_iter_type(to) & ITER_KVEC ? UIO_SYSSPACE : UIO_USERSPACE, + count, skip); +#else zfs_uio_iovec_init(uio, to->iov, to->nr_segs, pos, to->type & ITER_KVEC ? UIO_SYSSPACE : UIO_USERSPACE, count, skip); #endif +#endif } static ssize_t diff --git a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c index c17423426319..44caadd587f7 100644 --- a/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c +++ b/sys/contrib/openzfs/module/os/linux/zfs/zvol_os.c @@ -46,6 +46,7 @@ unsigned int zvol_request_sync = 0; unsigned int zvol_prefetch_bytes = (128 * 1024); unsigned long zvol_max_discard_blocks = 16384; unsigned int zvol_threads = 32; +unsigned int zvol_open_timeout_ms = 1000; struct zvol_state_os { struct gendisk *zvo_disk; /* generic disk */ @@ -336,8 +337,13 @@ zvol_read_task(void *arg) } #ifdef HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS +#ifdef HAVE_BDEV_SUBMIT_BIO_RETURNS_VOID +static void +zvol_submit_bio(struct bio *bio) +#else static blk_qc_t zvol_submit_bio(struct bio *bio) +#endif #else static MAKE_REQUEST_FN_RET zvol_request(struct request_queue *q, struct bio *bio) @@ -478,8 +484,9 @@ zvol_request(struct request_queue *q, struct bio *bio) out: spl_fstrans_unmark(cookie); -#if defined(HAVE_MAKE_REQUEST_FN_RET_QC) || \ - defined(HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS) +#if (defined(HAVE_MAKE_REQUEST_FN_RET_QC) || \ + defined(HAVE_SUBMIT_BIO_IN_BLOCK_DEVICE_OPERATIONS)) && \ + !defined(HAVE_BDEV_SUBMIT_BIO_RETURNS_VOID) return (BLK_QC_T_NONE); #endif } @@ -490,7 +497,13 @@ zvol_open(struct block_device *bdev, fmode_t flag) zvol_state_t *zv; int error = 0; boolean_t drop_suspend = B_TRUE; + boolean_t drop_namespace = B_FALSE; +#ifndef HAVE_BLKDEV_GET_ERESTARTSYS + hrtime_t timeout = MSEC2NSEC(zvol_open_timeout_ms); + hrtime_t start = gethrtime(); +retry: +#endif rw_enter(&zvol_state_lock, RW_READER); /* * Obtain a copy of private_data under the zvol_state_lock to make @@ -504,6 +517,49 @@ zvol_open(struct block_device *bdev, fmode_t flag) return (SET_ERROR(-ENXIO)); } + if (zv->zv_open_count == 0 && !mutex_owned(&spa_namespace_lock)) { + /* + * In all other call paths the spa_namespace_lock is taken + * before the bdev->bd_mutex lock. However, on open(2) + * the __blkdev_get() function calls fops->open() with the + * bdev->bd_mutex lock held. This can result in a deadlock + * when zvols from one pool are used as vdevs in another. + * + * To prevent a lock inversion deadlock we preemptively + * take the spa_namespace_lock. Normally the lock will not + * be contended and this is safe because spa_open_common() + * handles the case where the caller already holds the + * spa_namespace_lock. + * + * When the lock cannot be aquired after multiple retries + * this must be the vdev on zvol deadlock case and we have + * no choice but to return an error. For 5.12 and older + * kernels returning -ERESTARTSYS will result in the + * bdev->bd_mutex being dropped, then reacquired, and + * fops->open() being called again. This process can be + * repeated safely until both locks are acquired. For 5.13 + * and newer the -ERESTARTSYS retry logic was removed from + * the kernel so the only option is to return the error for + * the caller to handle it. + */ + if (!mutex_tryenter(&spa_namespace_lock)) { + rw_exit(&zvol_state_lock); + +#ifdef HAVE_BLKDEV_GET_ERESTARTSYS + schedule(); + return (SET_ERROR(-ERESTARTSYS)); +#else + if ((gethrtime() - start) > timeout) + return (SET_ERROR(-ERESTARTSYS)); + + schedule_timeout(MSEC_TO_TICK(10)); + goto retry; +#endif + } else { + drop_namespace = B_TRUE; + } + } + mutex_enter(&zv->zv_state_lock); /* * make sure zvol is not suspended during first open @@ -543,6 +599,8 @@ zvol_open(struct block_device *bdev, fmode_t flag) zv->zv_open_count++; mutex_exit(&zv->zv_state_lock); + if (drop_namespace) + mutex_exit(&spa_namespace_lock); if (drop_suspend) rw_exit(&zv->zv_suspend_lock); @@ -556,12 +614,11 @@ out_open_count: out_mutex: mutex_exit(&zv->zv_state_lock); + if (drop_namespace) + mutex_exit(&spa_namespace_lock); if (drop_suspend) rw_exit(&zv->zv_suspend_lock); - if (error == -EINTR) { - error = -ERESTARTSYS; - schedule(); - } + return (SET_ERROR(error)); } diff --git a/sys/contrib/openzfs/module/unicode/u8_textprep.c b/sys/contrib/openzfs/module/unicode/u8_textprep.c index c1d9a325f511..bce5f19625cb 100644 --- a/sys/contrib/openzfs/module/unicode/u8_textprep.c +++ b/sys/contrib/openzfs/module/unicode/u8_textprep.c @@ -865,7 +865,9 @@ do_decomp(size_t uv, uchar_t *u8s, uchar_t *s, int sz, start_id = u8_decomp_b4_16bit_tbl[uv][b3_tbl][b4]; end_id = u8_decomp_b4_16bit_tbl[uv][b3_tbl][b4 + 1]; } else { + // cppcheck-suppress arrayIndexOutOfBoundsCond start_id = u8_decomp_b4_tbl[uv][b3_tbl][b4]; + // cppcheck-suppress arrayIndexOutOfBoundsCond end_id = u8_decomp_b4_tbl[uv][b3_tbl][b4 + 1]; } @@ -1012,7 +1014,9 @@ find_composition_start(size_t uv, uchar_t *s, size_t sz) start_id = u8_composition_b4_16bit_tbl[uv][b3_tbl][b4]; end_id = u8_composition_b4_16bit_tbl[uv][b3_tbl][b4 + 1]; } else { + // cppcheck-suppress arrayIndexOutOfBoundsCond start_id = u8_composition_b4_tbl[uv][b3_tbl][b4]; + // cppcheck-suppress arrayIndexOutOfBoundsCond end_id = u8_composition_b4_tbl[uv][b3_tbl][b4 + 1]; } diff --git a/sys/contrib/openzfs/module/zfs/abd.c b/sys/contrib/openzfs/module/zfs/abd.c index cc2d3575db63..03a7b1e033b3 100644 --- a/sys/contrib/openzfs/module/zfs/abd.c +++ b/sys/contrib/openzfs/module/zfs/abd.c @@ -1066,10 +1066,10 @@ abd_raidz_gen_iterate(abd_t **cabds, abd_t *dabd, switch (parity) { case 3: len = MIN(caiters[2].iter_mapsize, len); - /* falls through */ + fallthrough; case 2: len = MIN(caiters[1].iter_mapsize, len); - /* falls through */ + fallthrough; case 1: len = MIN(caiters[0].iter_mapsize, len); } @@ -1179,11 +1179,11 @@ abd_raidz_rec_iterate(abd_t **cabds, abd_t **tabds, case 3: len = MIN(xiters[2].iter_mapsize, len); len = MIN(citers[2].iter_mapsize, len); - /* falls through */ + fallthrough; case 2: len = MIN(xiters[1].iter_mapsize, len); len = MIN(citers[1].iter_mapsize, len); - /* falls through */ + fallthrough; case 1: len = MIN(xiters[0].iter_mapsize, len); len = MIN(citers[0].iter_mapsize, len); diff --git a/sys/contrib/openzfs/module/zfs/arc.c b/sys/contrib/openzfs/module/zfs/arc.c index b864394b42a0..875986de99f0 100644 --- a/sys/contrib/openzfs/module/zfs/arc.c +++ b/sys/contrib/openzfs/module/zfs/arc.c @@ -2063,7 +2063,6 @@ arc_buf_fill(arc_buf_t *buf, spa_t *spa, const zbookmark_phys_t *zb, } else { ASSERT(hdr_compressed); ASSERT(!compressed); - ASSERT3U(HDR_GET_LSIZE(hdr), !=, HDR_GET_PSIZE(hdr)); /* * If the buf is sharing its data with the hdr, unlink it and diff --git a/sys/contrib/openzfs/module/zfs/dmu.c b/sys/contrib/openzfs/module/zfs/dmu.c index 1c47430953b1..8302d506146f 100644 --- a/sys/contrib/openzfs/module/zfs/dmu.c +++ b/sys/contrib/openzfs/module/zfs/dmu.c @@ -2095,42 +2095,41 @@ int dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off) { dnode_t *dn; - int i, err; - boolean_t clean = B_TRUE; + int err; +restart: err = dnode_hold(os, object, FTAG, &dn); if (err) return (err); - /* - * Check if dnode is dirty - */ - for (i = 0; i < TXG_SIZE; i++) { - if (multilist_link_active(&dn->dn_dirty_link[i])) { - clean = B_FALSE; - break; - } - } + rw_enter(&dn->dn_struct_rwlock, RW_READER); - /* - * If compatibility option is on, sync any current changes before - * we go trundling through the block pointers. - */ - if (!clean && zfs_dmu_offset_next_sync) { - clean = B_TRUE; - dnode_rele(dn, FTAG); - txg_wait_synced(dmu_objset_pool(os), 0); - err = dnode_hold(os, object, FTAG, &dn); - if (err) - return (err); - } + if (dnode_is_dirty(dn)) { + /* + * If the zfs_dmu_offset_next_sync module option is enabled + * then strict hole reporting has been requested. Dirty + * dnodes must be synced to disk to accurately report all + * holes. When disabled (the default) dirty dnodes are + * reported to not have any holes which is always safe. + * + * When called by zfs_holey_common() the zp->z_rangelock + * is held to prevent zfs_write() and mmap writeback from + * re-dirtying the dnode after txg_wait_synced(). + */ + if (zfs_dmu_offset_next_sync) { + rw_exit(&dn->dn_struct_rwlock); + dnode_rele(dn, FTAG); + txg_wait_synced(dmu_objset_pool(os), 0); + goto restart; + } - if (clean) - err = dnode_next_offset(dn, - (hole ? DNODE_FIND_HOLE : 0), off, 1, 1, 0); - else err = SET_ERROR(EBUSY); + } else { + err = dnode_next_offset(dn, DNODE_FIND_HAVELOCK | + (hole ? DNODE_FIND_HOLE : 0), off, 1, 1, 0); + } + rw_exit(&dn->dn_struct_rwlock); dnode_rele(dn, FTAG); return (err); diff --git a/sys/contrib/openzfs/module/zfs/dmu_send.c b/sys/contrib/openzfs/module/zfs/dmu_send.c index 0658e13c2d25..2f2fd4c3d6c8 100644 --- a/sys/contrib/openzfs/module/zfs/dmu_send.c +++ b/sys/contrib/openzfs/module/zfs/dmu_send.c @@ -165,6 +165,7 @@ struct send_range { kmutex_t lock; kcondvar_t cv; boolean_t io_outstanding; + boolean_t io_compressed; int io_err; } data; struct srh { @@ -450,7 +451,8 @@ dump_redact(dmu_send_cookie_t *dscp, uint64_t object, uint64_t offset, static int dmu_dump_write(dmu_send_cookie_t *dscp, dmu_object_type_t type, uint64_t object, - uint64_t offset, int lsize, int psize, const blkptr_t *bp, void *data) + uint64_t offset, int lsize, int psize, const blkptr_t *bp, + boolean_t io_compressed, void *data) { uint64_t payload_size; boolean_t raw = (dscp->dsc_featureflags & DMU_BACKUP_FEATURE_RAW); @@ -487,7 +489,10 @@ dmu_dump_write(dmu_send_cookie_t *dscp, dmu_object_type_t type, uint64_t object, drrw->drr_logical_size = lsize; /* only set the compression fields if the buf is compressed or raw */ - if (raw || lsize != psize) { + boolean_t compressed = + (bp != NULL ? BP_GET_COMPRESS(bp) != ZIO_COMPRESS_OFF && + io_compressed : lsize != psize); + if (raw || compressed) { ASSERT(raw || dscp->dsc_featureflags & DMU_BACKUP_FEATURE_COMPRESSED); ASSERT(!BP_IS_EMBEDDED(bp)); @@ -1014,7 +1019,8 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range) int n = MIN(srdp->datablksz, SPA_OLD_MAXBLOCKSIZE); err = dmu_dump_write(dscp, srdp->obj_type, - range->object, offset, n, n, NULL, data); + range->object, offset, n, n, NULL, B_FALSE, + data); offset += n; /* * When doing dry run, data==NULL is used as a @@ -1028,7 +1034,8 @@ do_dump(dmu_send_cookie_t *dscp, struct send_range *range) } else { err = dmu_dump_write(dscp, srdp->obj_type, range->object, offset, - srdp->datablksz, srdp->datasz, bp, data); + srdp->datablksz, srdp->datasz, bp, + srdp->io_compressed, data); } return (err); } @@ -1081,6 +1088,7 @@ range_alloc(enum type type, uint64_t object, uint64_t start_blkid, cv_init(&range->sru.data.cv, NULL, CV_DEFAULT, NULL); range->sru.data.io_outstanding = 0; range->sru.data.io_err = 0; + range->sru.data.io_compressed = B_FALSE; } return (range); } @@ -1646,10 +1654,13 @@ issue_data_read(struct send_reader_thread_arg *srta, struct send_range *range) enum zio_flag zioflags = ZIO_FLAG_CANFAIL; - if (srta->featureflags & DMU_BACKUP_FEATURE_RAW) + if (srta->featureflags & DMU_BACKUP_FEATURE_RAW) { zioflags |= ZIO_FLAG_RAW; - else if (request_compressed) + srdp->io_compressed = B_TRUE; + } else if (request_compressed) { zioflags |= ZIO_FLAG_RAW_COMPRESS; + srdp->io_compressed = B_TRUE; + } srdp->datasz = (zioflags & ZIO_FLAG_RAW_COMPRESS) ? BP_GET_PSIZE(bp) : BP_GET_LSIZE(bp); diff --git a/sys/contrib/openzfs/module/zfs/dnode.c b/sys/contrib/openzfs/module/zfs/dnode.c index 7f741542ce02..7044c1fc6342 100644 --- a/sys/contrib/openzfs/module/zfs/dnode.c +++ b/sys/contrib/openzfs/module/zfs/dnode.c @@ -1648,6 +1648,26 @@ dnode_try_claim(objset_t *os, uint64_t object, int slots) slots, NULL, NULL)); } +/* + * Checks if the dnode contains any uncommitted dirty records. + */ +boolean_t +dnode_is_dirty(dnode_t *dn) +{ + mutex_enter(&dn->dn_mtx); + + for (int i = 0; i < TXG_SIZE; i++) { + if (multilist_link_active(&dn->dn_dirty_link[i])) { + mutex_exit(&dn->dn_mtx); + return (B_TRUE); + } + } + + mutex_exit(&dn->dn_mtx); + + return (B_FALSE); +} + void dnode_setdirty(dnode_t *dn, dmu_tx_t *tx) { diff --git a/sys/contrib/openzfs/module/zfs/dsl_prop.c b/sys/contrib/openzfs/module/zfs/dsl_prop.c index f6ff9ae47192..dfa04d7681be 100644 --- a/sys/contrib/openzfs/module/zfs/dsl_prop.c +++ b/sys/contrib/openzfs/module/zfs/dsl_prop.c @@ -749,7 +749,7 @@ dsl_prop_set_sync_impl(dsl_dataset_t *ds, const char *propname, ASSERT(err == 0 || err == ENOENT); err = zap_remove(mos, zapobj, inheritstr, tx); ASSERT(err == 0 || err == ENOENT); - /* FALLTHRU */ + fallthrough; case (ZPROP_SRC_NONE | ZPROP_SRC_RECEIVED): /* * remove propname$recvd diff --git a/sys/contrib/openzfs/module/zfs/spa.c b/sys/contrib/openzfs/module/zfs/spa.c index 55870bee47fb..a02fd198bed0 100644 --- a/sys/contrib/openzfs/module/zfs/spa.c +++ b/sys/contrib/openzfs/module/zfs/spa.c @@ -9710,7 +9710,7 @@ spa_activity_in_progress(spa_t *spa, zpool_wait_activity_t activity, case ZPOOL_WAIT_RESILVER: if ((*in_progress = vdev_rebuild_active(spa->spa_root_vdev))) break; - /* fall through */ + fallthrough; case ZPOOL_WAIT_SCRUB: { boolean_t scanning, paused, is_scrub; diff --git a/sys/contrib/openzfs/module/zfs/vdev.c b/sys/contrib/openzfs/module/zfs/vdev.c index 4e316d8135ee..d659ec5bf333 100644 --- a/sys/contrib/openzfs/module/zfs/vdev.c +++ b/sys/contrib/openzfs/module/zfs/vdev.c @@ -2374,6 +2374,7 @@ vdev_validate(vdev_t *vd) static void vdev_copy_path_impl(vdev_t *svd, vdev_t *dvd) { + char *old, *new; if (svd->vdev_path != NULL && dvd->vdev_path != NULL) { if (strcmp(svd->vdev_path, dvd->vdev_path) != 0) { zfs_dbgmsg("vdev_copy_path: vdev %llu: path changed " @@ -2387,6 +2388,29 @@ vdev_copy_path_impl(vdev_t *svd, vdev_t *dvd) zfs_dbgmsg("vdev_copy_path: vdev %llu: path set to '%s'", (u_longlong_t)dvd->vdev_guid, dvd->vdev_path); } + + /* + * Our enclosure sysfs path may have changed between imports + */ + old = dvd->vdev_enc_sysfs_path; + new = svd->vdev_enc_sysfs_path; + if ((old != NULL && new == NULL) || + (old == NULL && new != NULL) || + ((old != NULL && new != NULL) && strcmp(new, old) != 0)) { + zfs_dbgmsg("vdev_copy_path: vdev %llu: vdev_enc_sysfs_path " + "changed from '%s' to '%s'", (u_longlong_t)dvd->vdev_guid, + old, new); + + if (dvd->vdev_enc_sysfs_path) + spa_strfree(dvd->vdev_enc_sysfs_path); + + if (svd->vdev_enc_sysfs_path) { + dvd->vdev_enc_sysfs_path = spa_strdup( + svd->vdev_enc_sysfs_path); + } else { + dvd->vdev_enc_sysfs_path = NULL; + } + } } /* diff --git a/sys/contrib/openzfs/module/zfs/vdev_label.c b/sys/contrib/openzfs/module/zfs/vdev_label.c index 04202a9f8960..ec6bbc6fc610 100644 --- a/sys/contrib/openzfs/module/zfs/vdev_label.c +++ b/sys/contrib/openzfs/module/zfs/vdev_label.c @@ -1287,7 +1287,7 @@ vdev_label_read_bootenv(vdev_t *rvd, nvlist_t *bootenv) nvlist_free(config); break; } - /* FALLTHROUGH */ + fallthrough; default: /* Check for FreeBSD zfs bootonce command string */ buf = abd_to_buf(abd); diff --git a/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c b/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c index cd742e146ca6..9e9c15ff4ba2 100644 --- a/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c +++ b/sys/contrib/openzfs/module/zfs/vdev_raidz_math_scalar.c @@ -142,7 +142,7 @@ static const struct { a.b[6] = mul_lt[a.b[6]]; \ a.b[5] = mul_lt[a.b[5]]; \ a.b[4] = mul_lt[a.b[4]]; \ - /* falls through */ \ + fallthrough; \ case 4: \ a.b[3] = mul_lt[a.b[3]]; \ a.b[2] = mul_lt[a.b[2]]; \ diff --git a/sys/contrib/openzfs/module/zfs/zfs_replay.c b/sys/contrib/openzfs/module/zfs/zfs_replay.c index cba5e8c9cd0b..f3d209f1fbdb 100644 --- a/sys/contrib/openzfs/module/zfs/zfs_replay.c +++ b/sys/contrib/openzfs/module/zfs/zfs_replay.c @@ -362,7 +362,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap) zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); - /*FALLTHROUGH*/ + fallthrough; case TX_CREATE_ACL_ATTR: if (name == NULL) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); @@ -394,7 +394,7 @@ zfs_replay_create_acl(void *arg1, void *arg2, boolean_t byteswap) zfsvfs->z_fuid_replay = zfs_replay_fuids(fuidstart, (void *)&name, lracl->lr_fuidcnt, lracl->lr_domcnt, lr->lr_uid, lr->lr_gid); - /*FALLTHROUGH*/ + fallthrough; case TX_MKDIR_ACL_ATTR: if (name == NULL) { lrattr = (lr_attr_t *)(caddr_t)(lracl + 1); @@ -519,8 +519,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; - - /*FALLTHROUGH*/ + fallthrough; case TX_CREATE: if (name == NULL) name = (char *)start; @@ -537,8 +536,7 @@ zfs_replay_create(void *arg1, void *arg2, boolean_t byteswap) zfs_replay_fuid_domain(start, &start, lr->lr_uid, lr->lr_gid); name = (char *)start; - - /*FALLTHROUGH*/ + fallthrough; case TX_MKDIR: if (name == NULL) name = (char *)(lr + 1); diff --git a/sys/contrib/openzfs/module/zfs/zfs_vnops.c b/sys/contrib/openzfs/module/zfs/zfs_vnops.c index 8229bc9a93e5..170e392abe93 100644 --- a/sys/contrib/openzfs/module/zfs/zfs_vnops.c +++ b/sys/contrib/openzfs/module/zfs/zfs_vnops.c @@ -85,6 +85,7 @@ zfs_fsync(znode_t *zp, int syncflag, cred_t *cr) static int zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off) { + zfs_locked_range_t *lr; uint64_t noff = (uint64_t)*off; /* new offset */ uint64_t file_sz; int error; @@ -100,12 +101,18 @@ zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off) else hole = B_FALSE; + /* Flush any mmap()'d data to disk */ + if (zn_has_cached_data(zp)) + zn_flush_cached_data(zp, B_FALSE); + + lr = zfs_rangelock_enter(&zp->z_rangelock, 0, file_sz, RL_READER); error = dmu_offset_next(ZTOZSB(zp)->z_os, zp->z_id, hole, &noff); + zfs_rangelock_exit(lr); if (error == ESRCH) return (SET_ERROR(ENXIO)); - /* file was dirty, so fall back to using generic logic */ + /* File was dirty, so fall back to using generic logic */ if (error == EBUSY) { if (hole) *off = file_sz; diff --git a/sys/contrib/openzfs/module/zfs/zio_compress.c b/sys/contrib/openzfs/module/zfs/zio_compress.c index 33602bd471f3..1ff1e76d7f22 100644 --- a/sys/contrib/openzfs/module/zfs/zio_compress.c +++ b/sys/contrib/openzfs/module/zfs/zio_compress.c @@ -214,7 +214,7 @@ zio_compress_to_feature(enum zio_compress comp) case ZIO_COMPRESS_ZSTD: return (SPA_FEATURE_ZSTD_COMPRESS); default: - /* fallthru */; + break; } return (SPA_FEATURE_NONE); } diff --git a/sys/contrib/openzfs/module/zfs/zvol.c b/sys/contrib/openzfs/module/zfs/zvol.c index 88450aabb469..721a7b4b878e 100644 --- a/sys/contrib/openzfs/module/zfs/zvol.c +++ b/sys/contrib/openzfs/module/zfs/zvol.c @@ -909,54 +909,26 @@ int zvol_first_open(zvol_state_t *zv, boolean_t readonly) { objset_t *os; - int error, locked = 0; - boolean_t ro; + int error; ASSERT(RW_READ_HELD(&zv->zv_suspend_lock)); ASSERT(MUTEX_HELD(&zv->zv_state_lock)); + ASSERT(mutex_owned(&spa_namespace_lock)); - /* - * In all other cases the spa_namespace_lock is taken before the - * bdev->bd_mutex lock. But in this case the Linux __blkdev_get() - * function calls fops->open() with the bdev->bd_mutex lock held. - * This deadlock can be easily observed with zvols used as vdevs. - * - * To avoid a potential lock inversion deadlock we preemptively - * try to take the spa_namespace_lock(). Normally it will not - * be contended and this is safe because spa_open_common() handles - * the case where the caller already holds the spa_namespace_lock. - * - * When it is contended we risk a lock inversion if we were to - * block waiting for the lock. Luckily, the __blkdev_get() - * function allows us to return -ERESTARTSYS which will result in - * bdev->bd_mutex being dropped, reacquired, and fops->open() being - * called again. This process can be repeated safely until both - * locks are acquired. - */ - if (!mutex_owned(&spa_namespace_lock)) { - locked = mutex_tryenter(&spa_namespace_lock); - if (!locked) - return (SET_ERROR(EINTR)); - } - - ro = (readonly || (strchr(zv->zv_name, '@') != NULL)); + boolean_t ro = (readonly || (strchr(zv->zv_name, '@') != NULL)); error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, ro, B_TRUE, zv, &os); if (error) - goto out_mutex; + return (SET_ERROR(error)); zv->zv_objset = os; error = zvol_setup_zv(zv); - if (error) { dmu_objset_disown(os, 1, zv); zv->zv_objset = NULL; } -out_mutex: - if (locked) - mutex_exit(&spa_namespace_lock); - return (SET_ERROR(error)); + return (error); } void @@ -1038,6 +1010,68 @@ zvol_create_snap_minor_cb(const char *dsname, void *arg) } /* + * If spa_keystore_load_wkey() is called for an encrypted zvol, + * we need to look for any clones also using the key. This function + * is "best effort" - so we just skip over it if there are failures. + */ +static void +zvol_add_clones(const char *dsname, list_t *minors_list) +{ + /* Also check if it has clones */ + dsl_dir_t *dd = NULL; + dsl_pool_t *dp = NULL; + + if (dsl_pool_hold(dsname, FTAG, &dp) != 0) + return; + + if (!spa_feature_is_enabled(dp->dp_spa, + SPA_FEATURE_ENCRYPTION)) + goto out; + + if (dsl_dir_hold(dp, dsname, FTAG, &dd, NULL) != 0) + goto out; + + if (dsl_dir_phys(dd)->dd_clones == 0) + goto out; + + zap_cursor_t *zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP); + zap_attribute_t *za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); + objset_t *mos = dd->dd_pool->dp_meta_objset; + + for (zap_cursor_init(zc, mos, dsl_dir_phys(dd)->dd_clones); + zap_cursor_retrieve(zc, za) == 0; + zap_cursor_advance(zc)) { + dsl_dataset_t *clone; + minors_job_t *job; + + if (dsl_dataset_hold_obj(dd->dd_pool, + za->za_first_integer, FTAG, &clone) == 0) { + + char name[ZFS_MAX_DATASET_NAME_LEN]; + dsl_dataset_name(clone, name); + + char *n = kmem_strdup(name); + job = kmem_alloc(sizeof (minors_job_t), KM_SLEEP); + job->name = n; + job->list = minors_list; + job->error = 0; + list_insert_tail(minors_list, job); + + dsl_dataset_rele(clone, FTAG); + } + } + zap_cursor_fini(zc); + kmem_free(za, sizeof (zap_attribute_t)); + kmem_free(zc, sizeof (zap_cursor_t)); + +out: + if (dd != NULL) + dsl_dir_rele(dd, FTAG); + if (dp != NULL) + dsl_pool_rele(dp, FTAG); +} + +/* * Mask errors to continue dmu_objset_find() traversal */ static int @@ -1075,6 +1109,8 @@ zvol_create_minors_cb(const char *dsname, void *arg) taskq_dispatch(system_taskq, zvol_prefetch_minors_impl, job, TQ_SLEEP); + zvol_add_clones(dsname, minors_list); + if (snapdev == ZFS_SNAPDEV_VISIBLE) { /* * traverse snapshots only, do not traverse children, diff --git a/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h b/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h index 71adc78040fb..339713590f96 100644 --- a/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h +++ b/sys/contrib/openzfs/module/zstd/include/zstd_compat_wrapper.h @@ -406,6 +406,7 @@ zfs_ZSTD_insertAndFindFirstIndex_internal #define ZSTD_insertBlock zfs_ZSTD_insertBlock #define ZSTD_invalidateRepCodes zfs_ZSTD_invalidateRepCodes +#define ZSTD_isError zfs_ZSTD_isError #define ZSTD_isFrame zfs_ZSTD_isFrame #define ZSTD_ldm_adjustParameters zfs_ZSTD_ldm_adjustParameters #define ZSTD_ldm_blockCompress zfs_ZSTD_ldm_blockCompress diff --git a/sys/contrib/openzfs/module/zstd/lib/zstd.c b/sys/contrib/openzfs/module/zstd/lib/zstd.c index acdd4d9dac9d..2766e5b74f55 100644 --- a/sys/contrib/openzfs/module/zstd/lib/zstd.c +++ b/sys/contrib/openzfs/module/zstd/lib/zstd.c @@ -6340,7 +6340,6 @@ extern "C" { /* ---- static assert (debug) --- */ #define ZSTD_STATIC_ASSERT(c) DEBUG_STATIC_ASSERT(c) -#define ZSTD_isError ERR_isError /* for inlining */ #define FSE_isError ERR_isError #define HUF_isError ERR_isError @@ -7347,7 +7346,6 @@ const char* ZSTD_versionString(void) { return ZSTD_VERSION_STRING; } /*-**************************************** * ZSTD Error Management ******************************************/ -#undef ZSTD_isError /* defined within zstd_internal.h */ /*! ZSTD_isError() : * tells if a return value is an error code * symbol is required for external callers */ |
