From 7b215d93bcc0a72d7020ccc050c64f39aa7f2be8 Mon Sep 17 00:00:00 2001 From: Ryan Moeller Date: Thu, 17 Mar 2022 13:18:23 -0400 Subject: [PATCH 1/9] Fix module build with -Werror This is a direct commit to zfs-2.1-release to fix release builds that error out on an unused variable. The issue is avoided on master by a huge series of commits that change how the ASSERT macros work, but that is not feasible to backport. Reviewed-by: Tony Hutter Reviewed-by: Brian Behlendorf Reviewed-by: Igor Kozhukhov Signed-off-by: Ryan Moeller Closes #13194 Closes #13196 --- module/zfs/arc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 9984c2d27534..47b58b6c2e0c 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -1205,7 +1205,7 @@ static void hdr_l2only_dest(void *vbuf, void *unused) { (void) unused; - arc_buf_hdr_t *hdr = vbuf; + arc_buf_hdr_t *hdr __maybe_unused = vbuf; ASSERT(HDR_EMPTY(hdr)); arc_space_return(HDR_L2ONLY_SIZE, ARC_SPACE_L2HDRS); From 0bebcbcf5e33e61ed146edef4f91b5f621512a8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=BD=D0=B0=D0=B1?= Date: Thu, 17 Mar 2022 18:22:13 +0100 Subject: [PATCH 2/9] get_key_material_https: removed bogus free() call The get_key_material_https() function error code path had a bogus free() call, either resulting in double-free or free() of undefined pointer. Reviewed-by: Brian Behlendorf Reviewed-by: Ahelenia Ziemia<84>ska Co-authored-by: Harry Sintonen Signed-off-by: Harry Sintonen Closes #13198 --- lib/libzfs/libzfs_crypto.c | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/libzfs/libzfs_crypto.c b/lib/libzfs/libzfs_crypto.c index 644dd26859f1..f77becd6a5c1 100644 --- a/lib/libzfs/libzfs_crypto.c +++ b/lib/libzfs/libzfs_crypto.c @@ -606,7 +606,6 @@ get_key_material_https(libzfs_handle_t *hdl, const char *uri, kfdok: if ((key = fdopen(kfd, "r+")) == NULL) { ret = errno; - free(path); (void) close(kfd); zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, "Couldn't reopen temporary file: %s"), strerror(ret)); From 275c756730e6a8502b4c805ed283a5cb56f54848 Mon Sep 17 00:00:00 2001 From: Mateusz Guzik Date: Thu, 17 Mar 2022 18:30:10 +0100 Subject: [PATCH 3/9] FreeBSD: add missing replay check to an assert in zfs_xvattr_set Reviewed-by: Ryan Moeller Reviewed-by: Brian Behlendorf Signed-off-by: Mateusz Guzik Closes #13219 --- module/os/freebsd/zfs/zfs_znode.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/module/os/freebsd/zfs/zfs_znode.c b/module/os/freebsd/zfs/zfs_znode.c index 317a35eefd0e..e4a1d2db7896 100644 --- a/module/os/freebsd/zfs/zfs_znode.c +++ b/module/os/freebsd/zfs/zfs_znode.c @@ -839,7 +839,9 @@ zfs_xvattr_set(znode_t *zp, xvattr_t *xvap, dmu_tx_t *tx) xoap = xva_getxoptattr(xvap); ASSERT3P(xoap, !=, NULL); - ASSERT_VOP_IN_SEQC(ZTOV(zp)); + if (zp->z_zfsvfs->z_replay == B_FALSE) { + ASSERT_VOP_IN_SEQC(ZTOV(zp)); + } if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { uint64_t times[2]; From 421750672bba0ae43ba4a0d8d237bf71d6ae9285 Mon Sep 17 00:00:00 2001 From: Kyle Evans Date: Thu, 17 Mar 2022 12:14:00 -0500 Subject: [PATCH 4/9] module: freebsd: avoid a taking a destroyed lock in zfs_zevent bits At shutdown time, we drain all of the zevents and set the ZEVENT_SHUTDOWN flag. On FreeBSD, we may end up calling zfs_zevent_destroy() after the zevent_lock has been destroyed while the sysevent thread is winding down; we observe ESHUTDOWN, then back out. Events have already been drained, so just inline the kmem_free call in sysevent_worker() to avoid the race, and document the assumption that zfs_zevent_destroy doesn't do anything else useful at that point. This fixes a panic that can occur at module unload time. Reviewed-by: Ryan Moeller Reviewed-by: Brian Behlendorf Signed-off-by: Kyle Evans Closes #13220 --- module/os/freebsd/spl/spl_sysevent.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/module/os/freebsd/spl/spl_sysevent.c b/module/os/freebsd/spl/spl_sysevent.c index d5d50080fafd..16188c71b53d 100644 --- a/module/os/freebsd/spl/spl_sysevent.c +++ b/module/os/freebsd/spl/spl_sysevent.c @@ -250,7 +250,17 @@ sysevent_worker(void *arg __unused) nvlist_free(event); } } - zfs_zevent_destroy(ze); + + /* + * We avoid zfs_zevent_destroy() here because we're otherwise racing + * against fm_fini() destroying the zevent_lock. zfs_zevent_destroy() + * will currently only clear `ze->ze_zevent` from an event list then + * free `ze`, so just inline the free() here -- events have already + * been drained. + */ + VERIFY3P(ze->ze_zevent, ==, NULL); + kmem_free(ze, sizeof (zfs_zevent_t)); + kthread_exit(); } From 9e3619c5355268948cefba4d8fbcd1aea3616236 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Sat, 19 Mar 2022 12:48:28 -0700 Subject: [PATCH 5/9] Linux 5.16 compat: restore FSR and FSAVE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 3b52ccd7d introduced a flaw where FSR and FSAVE are not restored when using a Linux 5.16 kernel. These instructions are only used when XSAVE is not supported by the processor meaning only some systems will encounter this issue. Reviewed-by: Tony Hutter Reviewed-by: Attila Fülöp Signed-off-by: Brian Behlendorf Closes #13210 Closes #13236 --- include/os/linux/kernel/linux/simd_x86.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/os/linux/kernel/linux/simd_x86.h b/include/os/linux/kernel/linux/simd_x86.h index 6d4c7a09fe82..0f6a222ba667 100644 --- a/include/os/linux/kernel/linux/simd_x86.h +++ b/include/os/linux/kernel/linux/simd_x86.h @@ -420,9 +420,9 @@ kfpu_end(void) if (static_cpu_has(X86_FEATURE_XSAVE)) { kfpu_do_xrstor("xrstor", &state->xsave, ~0); } else if (static_cpu_has(X86_FEATURE_FXSR)) { - kfpu_save_fxsr(&state->fxsave); + kfpu_restore_fxsr(&state->fxsave); } else { - kfpu_save_fsave(&state->fsave); + kfpu_restore_fsave(&state->fsave); } out: local_irq_enable(); From 847d03060f9724fd6c40940e7e03b6b600316605 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Sun, 20 Mar 2022 21:21:18 -0700 Subject: [PATCH 6/9] Fix ACL checks for NFS kernel server This PR changes ZFS ACL checks to evaluate fsuid / fsgid rather than euid / egid to avoid accidentally granting elevated permissions to NFS clients. Reviewed-by: Serapheim Dimitropoulos Reviewed-by: Brian Behlendorf Co-authored-by: Andrew Walker Co-authored-by: Ryan Moeller Signed-off-by: Ryan Moeller Closes #13221 --- include/os/freebsd/spl/sys/Makefile.am | 1 - include/os/freebsd/spl/sys/cred.h | 136 ++----------------------- include/os/freebsd/spl/sys/kidmap.h | 41 -------- include/os/freebsd/spl/sys/sid.h | 25 ----- include/os/linux/spl/sys/cred.h | 5 - module/Makefile.bsd | 2 +- module/os/freebsd/zfs/zfs_acl.c | 6 +- module/os/freebsd/zfs/zfs_vnops_os.c | 19 +--- module/os/linux/spl/spl-cred.c | 42 +------- module/os/linux/zfs/policy.c | 10 +- module/os/linux/zfs/zpl_inode.c | 4 +- module/os/linux/zfs/zpl_xattr.c | 4 +- 12 files changed, 26 insertions(+), 269 deletions(-) delete mode 100644 include/os/freebsd/spl/sys/kidmap.h diff --git a/include/os/freebsd/spl/sys/Makefile.am b/include/os/freebsd/spl/sys/Makefile.am index 232aaf569fa2..7488e56c7649 100644 --- a/include/os/freebsd/spl/sys/Makefile.am +++ b/include/os/freebsd/spl/sys/Makefile.am @@ -22,7 +22,6 @@ KERNEL_H = \ inttypes.h \ isa_defs.h \ kmem_cache.h \ - kidmap.h \ kmem.h \ kstat.h \ list_impl.h \ diff --git a/include/os/freebsd/spl/sys/cred.h b/include/os/freebsd/spl/sys/cred.h index 86f79011d6da..db986af57bf5 100644 --- a/include/os/freebsd/spl/sys/cred.h +++ b/include/os/freebsd/spl/sys/cred.h @@ -48,138 +48,20 @@ extern "C" { typedef struct ucred cred_t; #define CRED() curthread->td_ucred -#define kcred (thread0.td_ucred) - -#define KUID_TO_SUID(x) (x) -#define KGID_TO_SGID(x) (x) -#define crgetuid(cred) ((cred)->cr_uid) -#define crgetruid(cred) ((cred)->cr_ruid) -#define crgetgid(cred) ((cred)->cr_gid) -#define crgetgroups(cred) ((cred)->cr_groups) -#define crgetngroups(cred) ((cred)->cr_ngroups) -#define crgetsid(cred, i) (NULL) -struct proc; /* cred.h is included in proc.h */ -struct prcred; -struct ksid; -struct ksidlist; -struct credklpd; -struct credgrp; - -struct auditinfo_addr; /* cred.h is included in audit.h */ - -extern int ngroups_max; /* * kcred is used when you need all privileges. */ +#define kcred (thread0.td_ucred) -extern void cred_init(void); -extern void crfree(cred_t *); -extern cred_t *cralloc(void); /* all but ref uninitialized */ -extern cred_t *cralloc_ksid(void); /* cralloc() + ksid alloc'ed */ -extern cred_t *crget(void); /* initialized */ -extern void crcopy_to(cred_t *, cred_t *); -extern cred_t *crdup(cred_t *); -extern void crdup_to(cred_t *, cred_t *); -extern cred_t *crgetcred(void); -extern void crset(struct proc *, cred_t *); -extern void crset_zone_privall(cred_t *); -extern int supgroupmember(gid_t, const cred_t *); -extern int hasprocperm(const cred_t *, const cred_t *); -extern int prochasprocperm(struct proc *, struct proc *, const cred_t *); -extern int crcmp(const cred_t *, const cred_t *); -extern cred_t *zone_kcred(void); - -extern gid_t crgetrgid(const cred_t *); -extern gid_t crgetsgid(const cred_t *); - -#define crgetzoneid(cr) ((cr)->cr_prison->pr_id) -extern projid_t crgetprojid(const cred_t *); - -extern cred_t *crgetmapped(const cred_t *); - - -extern const struct auditinfo_addr *crgetauinfo(const cred_t *); -extern struct auditinfo_addr *crgetauinfo_modifiable(cred_t *); - -extern uint_t crgetref(const cred_t *); - -extern const gid_t *crgetggroups(const struct credgrp *); - - -/* - * Sets real, effective and/or saved uid/gid; - * -1 argument accepted as "no change". - */ -extern int crsetresuid(cred_t *, uid_t, uid_t, uid_t); -extern int crsetresgid(cred_t *, gid_t, gid_t, gid_t); - -/* - * Sets real, effective and saved uids/gids all to the same - * values. Both values must be non-negative and <= MAXUID - */ -extern int crsetugid(cred_t *, uid_t, gid_t); - -/* - * Functions to handle the supplemental group list. - */ -extern struct credgrp *crgrpcopyin(int, gid_t *); -extern void crgrprele(struct credgrp *); -extern void crsetcredgrp(cred_t *, struct credgrp *); - -/* - * Private interface for setting zone association of credential. - */ -struct zone; -extern void crsetzone(cred_t *, struct zone *); -extern struct zone *crgetzone(const cred_t *); - -/* - * Private interface for setting project id in credential. - */ -extern void crsetprojid(cred_t *, projid_t); - -/* - * Private interface for nfs. - */ -extern cred_t *crnetadjust(cred_t *); - -/* - * Private interface for procfs. - */ -extern void cred2prcred(const cred_t *, struct prcred *); - -/* - * Private interfaces for Rampart Trusted Solaris. - */ -struct ts_label_s; -extern struct ts_label_s *crgetlabel(const cred_t *); -extern boolean_t crisremote(const cred_t *); - -/* - * Private interfaces for ephemeral uids. - */ -#define VALID_UID(id, zn) \ - ((id) <= MAXUID || valid_ephemeral_uid((zn), (id))) - -#define VALID_GID(id, zn) \ - ((id) <= MAXUID || valid_ephemeral_gid((zn), (id))) - -extern boolean_t valid_ephemeral_uid(struct zone *, uid_t); -extern boolean_t valid_ephemeral_gid(struct zone *, gid_t); - -extern int eph_uid_alloc(struct zone *, int, uid_t *, int); -extern int eph_gid_alloc(struct zone *, int, gid_t *, int); - -extern void crsetsid(cred_t *, struct ksid *, int); -extern void crsetsidlist(cred_t *, struct ksidlist *); - -extern struct ksidlist *crgetsidlist(const cred_t *); - -extern int crsetpriv(cred_t *, ...); - -extern struct credklpd *crgetcrklpd(const cred_t *); -extern void crsetcrklpd(cred_t *, struct credklpd *); +#define KUID_TO_SUID(x) (x) +#define KGID_TO_SGID(x) (x) +#define crgetuid(cr) ((cr)->cr_uid) +#define crgetruid(cr) ((cr)->cr_ruid) +#define crgetgid(cr) ((cr)->cr_gid) +#define crgetgroups(cr) ((cr)->cr_groups) +#define crgetngroups(cr) ((cr)->cr_ngroups) +#define crgetzoneid(cr) ((cr)->cr_prison->pr_id) #ifdef __cplusplus } diff --git a/include/os/freebsd/spl/sys/kidmap.h b/include/os/freebsd/spl/sys/kidmap.h deleted file mode 100644 index dc0cf5988a42..000000000000 --- a/include/os/freebsd/spl/sys/kidmap.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2007 Pawel Jakub Dawidek - * 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 _OPENSOLARIS_SYS_KIDMAP_H_ -#define _OPENSOLARIS_SYS_KIDMAP_H_ - -#include - -typedef int32_t idmap_stat; -typedef void idmap_get_handle_t; - -#define kidmap_get_create() (NULL) -#define kidmap_get_destroy(hdl) do { } while (0) -#define kidmap_get_mappings(hdl) (NULL) - -#endif /* _OPENSOLARIS_SYS_KIDMAP_H_ */ diff --git a/include/os/freebsd/spl/sys/sid.h b/include/os/freebsd/spl/sys/sid.h index d3fab8b24744..f249d05d55a0 100644 --- a/include/os/freebsd/spl/sys/sid.h +++ b/include/os/freebsd/spl/sys/sid.h @@ -29,7 +29,6 @@ #ifndef _OPENSOLARIS_SYS_SID_H_ #define _OPENSOLARIS_SYS_SID_H_ #include -#include typedef struct ksiddomain { char *kd_name; /* Domain part of SID */ @@ -59,28 +58,4 @@ ksiddomain_rele(ksiddomain_t *kd) kmem_free(kd, sizeof (*kd)); } -static __inline uint_t -ksid_getid(ksid_t *ks) -{ - - panic("%s has been unexpectedly called", __func__); -} - -static __inline const char * -ksid_getdomain(ksid_t *ks) -{ - - panic("%s has been unexpectedly called", __func__); -} - -static __inline uint_t -ksid_getrid(ksid_t *ks) -{ - - panic("%s has been unexpectedly called", __func__); -} - -#define kidmap_getsidbyuid(zone, uid, sid_prefix, rid) (1) -#define kidmap_getsidbygid(zone, gid, sid_prefix, rid) (1) - #endif /* _OPENSOLARIS_SYS_SID_H_ */ diff --git a/include/os/linux/spl/sys/cred.h b/include/os/linux/spl/sys/cred.h index 9cc85deb5c8a..b7d3f38d70bb 100644 --- a/include/os/linux/spl/sys/cred.h +++ b/include/os/linux/spl/sys/cred.h @@ -49,12 +49,7 @@ extern void crhold(cred_t *cr); extern void crfree(cred_t *cr); extern uid_t crgetuid(const cred_t *cr); extern uid_t crgetruid(const cred_t *cr); -extern uid_t crgetsuid(const cred_t *cr); -extern uid_t crgetfsuid(const cred_t *cr); extern gid_t crgetgid(const cred_t *cr); -extern gid_t crgetrgid(const cred_t *cr); -extern gid_t crgetsgid(const cred_t *cr); -extern gid_t crgetfsgid(const cred_t *cr); extern int crgetngroups(const cred_t *cr); extern gid_t *crgetgroups(const cred_t *cr); extern int groupmember(gid_t gid, const cred_t *cr); diff --git a/module/Makefile.bsd b/module/Makefile.bsd index 8aa4ed22275e..dc6cc2b74243 100644 --- a/module/Makefile.bsd +++ b/module/Makefile.bsd @@ -32,7 +32,7 @@ CFLAGS+= -include ${INCDIR}/os/freebsd/spl/sys/ccompile.h CFLAGS+= -D__KERNEL__ -DFREEBSD_NAMECACHE -DBUILDING_ZFS -D__BSD_VISIBLE=1 \ -DHAVE_UIO_ZEROCOPY -DWITHOUT_NETDUMP -D__KERNEL -D_SYS_CONDVAR_H_ \ - -D_SYS_VMEM_H_ -DKDTRACE_HOOKS -DSMP -DHAVE_KSID -DCOMPAT_FREEBSD11 + -D_SYS_VMEM_H_ -DKDTRACE_HOOKS -DSMP -DCOMPAT_FREEBSD11 .if ${MACHINE_ARCH} == "amd64" CFLAGS+= -DHAVE_AVX2 -DHAVE_AVX -D__x86_64 -DHAVE_SSE2 -DHAVE_AVX512F -DHAVE_SSSE3 diff --git a/module/os/freebsd/zfs/zfs_acl.c b/module/os/freebsd/zfs/zfs_acl.c index ae758bcefe21..fe0f69132321 100644 --- a/module/os/freebsd/zfs/zfs_acl.c +++ b/module/os/freebsd/zfs/zfs_acl.c @@ -1653,8 +1653,10 @@ zfs_acl_ids_create(znode_t *dzp, int flag, vattr_t *vap, cred_t *cr, ZFS_GROUP, &acl_ids->z_fuidp); gid = vap->va_gid; } else { - acl_ids->z_fuid = zfs_fuid_create_cred(zfsvfs, ZFS_OWNER, - cr, &acl_ids->z_fuidp); + uid_t id = crgetuid(cr); + if (IS_EPHEMERAL(id)) + id = UID_NOBODY; + acl_ids->z_fuid = (uint64_t)id; acl_ids->z_fgid = 0; if (vap->va_mask & AT_GID) { acl_ids->z_fgid = zfs_fuid_create(zfsvfs, diff --git a/module/os/freebsd/zfs/zfs_vnops_os.c b/module/os/freebsd/zfs/zfs_vnops_os.c index 7bcf80bf5a94..b2cc3d063f9c 100644 --- a/module/os/freebsd/zfs/zfs_vnops_os.c +++ b/module/os/freebsd/zfs/zfs_vnops_os.c @@ -1060,8 +1060,7 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode, objset_t *os; dmu_tx_t *tx; int error; - ksid_t *ksid; - uid_t uid; + uid_t uid = crgetuid(cr); gid_t gid = crgetgid(cr); uint64_t projid = ZFS_DEFAULT_PROJID; zfs_acl_ids_t acl_ids; @@ -1075,13 +1074,6 @@ zfs_create(znode_t *dzp, const char *name, vattr_t *vap, int excl, int mode, * If we have an ephemeral id, ACL, or XVATTR then * make sure file system is at proper version */ - - ksid = crgetsid(cr, KSID_OWNER); - if (ksid) - uid = ksid_getid(ksid); - else - uid = crgetuid(cr); - if (zfsvfs->z_use_fuids == B_FALSE && (vsecp || (vap->va_mask & AT_XVATTR) || IS_EPHEMERAL(uid) || IS_EPHEMERAL(gid))) @@ -1415,8 +1407,7 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp, uint64_t txtype; dmu_tx_t *tx; int error; - ksid_t *ksid; - uid_t uid; + uid_t uid = crgetuid(cr); gid_t gid = crgetgid(cr); zfs_acl_ids_t acl_ids; boolean_t fuid_dirtied; @@ -1427,12 +1418,6 @@ zfs_mkdir(znode_t *dzp, const char *dirname, vattr_t *vap, znode_t **zpp, * If we have an ephemeral id, ACL, or XVATTR then * make sure file system is at proper version */ - - ksid = crgetsid(cr, KSID_OWNER); - if (ksid) - uid = ksid_getid(ksid); - else - uid = crgetuid(cr); if (zfsvfs->z_use_fuids == B_FALSE && ((vap->va_mask & AT_XVATTR) || IS_EPHEMERAL(uid) || IS_EPHEMERAL(gid))) diff --git a/module/os/linux/spl/spl-cred.c b/module/os/linux/spl/spl-cred.c index 8fe1cc30ba99..f81b9540a639 100644 --- a/module/os/linux/spl/spl-cred.c +++ b/module/os/linux/spl/spl-cred.c @@ -128,7 +128,7 @@ groupmember(gid_t gid, const cred_t *cr) uid_t crgetuid(const cred_t *cr) { - return (KUID_TO_SUID(cr->euid)); + return (KUID_TO_SUID(cr->fsuid)); } /* Return the real user id */ @@ -138,44 +138,9 @@ crgetruid(const cred_t *cr) return (KUID_TO_SUID(cr->uid)); } -/* Return the saved user id */ -uid_t -crgetsuid(const cred_t *cr) -{ - return (KUID_TO_SUID(cr->suid)); -} - -/* Return the filesystem user id */ -uid_t -crgetfsuid(const cred_t *cr) -{ - return (KUID_TO_SUID(cr->fsuid)); -} - /* Return the effective group id */ gid_t crgetgid(const cred_t *cr) -{ - return (KGID_TO_SGID(cr->egid)); -} - -/* Return the real group id */ -gid_t -crgetrgid(const cred_t *cr) -{ - return (KGID_TO_SGID(cr->gid)); -} - -/* Return the saved group id */ -gid_t -crgetsgid(const cred_t *cr) -{ - return (KGID_TO_SGID(cr->sgid)); -} - -/* Return the filesystem group id */ -gid_t -crgetfsgid(const cred_t *cr) { return (KGID_TO_SGID(cr->fsgid)); } @@ -184,12 +149,7 @@ EXPORT_SYMBOL(crhold); EXPORT_SYMBOL(crfree); EXPORT_SYMBOL(crgetuid); EXPORT_SYMBOL(crgetruid); -EXPORT_SYMBOL(crgetsuid); -EXPORT_SYMBOL(crgetfsuid); EXPORT_SYMBOL(crgetgid); -EXPORT_SYMBOL(crgetrgid); -EXPORT_SYMBOL(crgetsgid); -EXPORT_SYMBOL(crgetfsgid); EXPORT_SYMBOL(crgetngroups); EXPORT_SYMBOL(crgetgroups); EXPORT_SYMBOL(groupmember); diff --git a/module/os/linux/zfs/policy.c b/module/os/linux/zfs/policy.c index bbccb2e572d9..5a52092bb90a 100644 --- a/module/os/linux/zfs/policy.c +++ b/module/os/linux/zfs/policy.c @@ -121,7 +121,7 @@ secpolicy_vnode_access2(const cred_t *cr, struct inode *ip, uid_t owner, int secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner) { - if (crgetfsuid(cr) == owner) + if (crgetuid(cr) == owner) return (0); if (zpl_inode_owner_or_capable(kcred->user_ns, ip)) @@ -147,7 +147,7 @@ secpolicy_vnode_any_access(const cred_t *cr, struct inode *ip, uid_t owner) int secpolicy_vnode_chown(const cred_t *cr, uid_t owner) { - if (crgetfsuid(cr) == owner) + if (crgetuid(cr) == owner) return (0); #if defined(CONFIG_USER_NS) @@ -184,7 +184,7 @@ secpolicy_vnode_remove(const cred_t *cr) int secpolicy_vnode_setdac(const cred_t *cr, uid_t owner) { - if (crgetfsuid(cr) == owner) + if (crgetuid(cr) == owner) return (0); #if defined(CONFIG_USER_NS) @@ -220,7 +220,7 @@ secpolicy_vnode_setids_setgids(const cred_t *cr, gid_t gid) if (!kgid_has_mapping(cr->user_ns, SGID_TO_KGID(gid))) return (EPERM); #endif - if (crgetfsgid(cr) != gid && !groupmember(gid, cr)) + if (crgetgid(cr) != gid && !groupmember(gid, cr)) return (priv_policy_user(cr, CAP_FSETID, EPERM)); return (0); @@ -286,7 +286,7 @@ secpolicy_setid_clear(vattr_t *vap, cred_t *cr) static int secpolicy_vnode_setid_modify(const cred_t *cr, uid_t owner) { - if (crgetfsuid(cr) == owner) + if (crgetuid(cr) == owner) return (0); #if defined(CONFIG_USER_NS) diff --git a/module/os/linux/zfs/zpl_inode.c b/module/os/linux/zfs/zpl_inode.c index 24a8b036bf0f..4f79265a0856 100644 --- a/module/os/linux/zfs/zpl_inode.c +++ b/module/os/linux/zfs/zpl_inode.c @@ -116,14 +116,14 @@ zpl_vap_init(vattr_t *vap, struct inode *dir, umode_t mode, cred_t *cr) { vap->va_mask = ATTR_MODE; vap->va_mode = mode; - vap->va_uid = crgetfsuid(cr); + vap->va_uid = crgetuid(cr); if (dir && dir->i_mode & S_ISGID) { vap->va_gid = KGID_TO_SGID(dir->i_gid); if (S_ISDIR(mode)) vap->va_mode |= S_ISGID; } else { - vap->va_gid = crgetfsgid(cr); + vap->va_gid = crgetgid(cr); } } diff --git a/module/os/linux/zfs/zpl_xattr.c b/module/os/linux/zfs/zpl_xattr.c index 928058ef677c..e088db5d29cf 100644 --- a/module/os/linux/zfs/zpl_xattr.c +++ b/module/os/linux/zfs/zpl_xattr.c @@ -492,8 +492,8 @@ zpl_xattr_set_dir(struct inode *ip, const char *name, const void *value, vap = kmem_zalloc(sizeof (vattr_t), KM_SLEEP); vap->va_mode = xattr_mode; vap->va_mask = ATTR_MODE; - vap->va_uid = crgetfsuid(cr); - vap->va_gid = crgetfsgid(cr); + vap->va_uid = crgetuid(cr); + vap->va_gid = crgetgid(cr); error = -zfs_create(dxzp, (char *)name, vap, 0, 0644, &xzp, cr, 0, NULL); From 90abfdf8ee7eb83612ce685dc15949acfbef891a Mon Sep 17 00:00:00 2001 From: Tony Hutter Date: Thu, 24 Feb 2022 11:43:39 -0800 Subject: [PATCH 7/9] zed: Misc multipath autoreplace fixes We recently had a case where our operators replaced a bad multipathed disk, only to see it fail to autoreplace. The zed logs showed that the multipath replacement disk did not pass the 'is_dm' test in zfs_process_add() even though it should have. is_dm is set if there exists a sysfs entry for to the underlying /dev/sd* paths for the multipath disk. It's possible this path didn't exist due to a race condition where the sysfs paths weren't created at the time the udev event came in to zed, but this was never verified. This patch updates the check to look for udev properties that indicate if the new autoreplace disk is an empty multipath disk, rather than looking for the underlying sysfs entries. It also adds in additional logging, and fixes a bug where zed allowed you to use an already zfs-formatted disk from another pool as a multipath auto-replacement disk. Furthermore, while testing this patch, I also ran across a case where a force-faulted disk did not have a ZPOOL_CONFIG_PHYS_PATH entry in its config. This prevented it from being autoreplaced. I added additional logic to derive the PHYS_PATH from the PATH if the PATH was a /dev/disk/by-vdev/ path. For example, if PATH was /dev/disk/by-vdev/L28, then PHYS_PATH would be L28. This is safe since by-vdev paths represent physical locations and do not change between boots. Reviewed-by: Brian Behlendorf Signed-off-by: Tony Hutter Closes #13023 --- cmd/zed/agents/zfs_mod.c | 179 +++++++++++++++++-- cmd/zed/zed_disk_event.c | 10 ++ lib/libzutil/os/linux/zutil_device_path_os.c | 29 +-- 3 files changed, 192 insertions(+), 26 deletions(-) diff --git a/cmd/zed/agents/zfs_mod.c b/cmd/zed/agents/zfs_mod.c index 3bcdf6e1d718..a510d646e1f9 100644 --- a/cmd/zed/agents/zfs_mod.c +++ b/cmd/zed/agents/zfs_mod.c @@ -183,14 +183,14 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled) nvlist_t *nvroot, *newvd; pendingdev_t *device; uint64_t wholedisk = 0ULL; - uint64_t offline = 0ULL; + uint64_t offline = 0ULL, faulted = 0ULL; uint64_t guid = 0ULL; char *physpath = NULL, *new_devid = NULL, *enc_sysfs_path = NULL; char rawpath[PATH_MAX], fullpath[PATH_MAX]; char devpath[PATH_MAX]; int ret; - boolean_t is_dm = B_FALSE; boolean_t is_sd = B_FALSE; + boolean_t is_mpath_wholedisk = B_FALSE; uint_t c; vdev_stat_t *vs; @@ -211,15 +211,73 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled) &enc_sysfs_path); (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK, &wholedisk); (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_OFFLINE, &offline); + (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_FAULTED, &faulted); + (void) nvlist_lookup_uint64(vdev, ZPOOL_CONFIG_GUID, &guid); - if (offline) - return; /* don't intervene if it was taken offline */ + /* + * Special case: + * + * We've seen times where a disk won't have a ZPOOL_CONFIG_PHYS_PATH + * entry in their config. For example, on this force-faulted disk: + * + * children[0]: + * type: 'disk' + * id: 0 + * guid: 14309659774640089719 + * path: '/dev/disk/by-vdev/L28' + * whole_disk: 0 + * DTL: 654 + * create_txg: 4 + * com.delphix:vdev_zap_leaf: 1161 + * faulted: 1 + * aux_state: 'external' + * children[1]: + * type: 'disk' + * id: 1 + * guid: 16002508084177980912 + * path: '/dev/disk/by-vdev/L29' + * devid: 'dm-uuid-mpath-35000c500a61d68a3' + * phys_path: 'L29' + * vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32' + * whole_disk: 0 + * DTL: 1028 + * create_txg: 4 + * com.delphix:vdev_zap_leaf: 131 + * + * If the disk's path is a /dev/disk/by-vdev/ path, then we can infer + * the ZPOOL_CONFIG_PHYS_PATH from the by-vdev disk name. + */ + if (physpath == NULL && path != NULL) { + /* If path begins with "/dev/disk/by-vdev/" ... */ + if (strncmp(path, DEV_BYVDEV_PATH, + strlen(DEV_BYVDEV_PATH)) == 0) { + /* Set physpath to the char after "/dev/disk/by-vdev" */ + physpath = &path[strlen(DEV_BYVDEV_PATH)]; + } + } + + /* + * We don't want to autoreplace offlined disks. However, we do want to + * replace force-faulted disks (`zpool offline -f`). Force-faulted + * disks have both offline=1 and faulted=1 in the nvlist. + */ + if (offline && !faulted) { + zed_log_msg(LOG_INFO, "%s: %s is offline, skip autoreplace", + __func__, path); + return; + } - is_dm = zfs_dev_is_dm(path); + is_mpath_wholedisk = is_mpath_whole_disk(path); zed_log_msg(LOG_INFO, "zfs_process_add: pool '%s' vdev '%s', phys '%s'" - " wholedisk %d, %s dm (guid %llu)", zpool_get_name(zhp), path, - physpath ? physpath : "NULL", wholedisk, is_dm ? "is" : "not", + " %s blank disk, %s mpath blank disk, %s labeled, enc sysfs '%s', " + "(guid %llu)", + zpool_get_name(zhp), path, + physpath ? physpath : "NULL", + wholedisk ? "is" : "not", + is_mpath_wholedisk? "is" : "not", + labeled ? "is" : "not", + enc_sysfs_path, (long long unsigned int)guid); /* @@ -253,8 +311,9 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled) ZFS_ONLINE_CHECKREMOVE | ZFS_ONLINE_UNSPARE, &newstate) == 0 && (newstate == VDEV_STATE_HEALTHY || newstate == VDEV_STATE_DEGRADED)) { - zed_log_msg(LOG_INFO, " zpool_vdev_online: vdev %s is %s", - fullpath, (newstate == VDEV_STATE_HEALTHY) ? + zed_log_msg(LOG_INFO, + " zpool_vdev_online: vdev '%s' ('%s') is " + "%s", fullpath, physpath, (newstate == VDEV_STATE_HEALTHY) ? "HEALTHY" : "DEGRADED"); return; } @@ -271,11 +330,12 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled) * vdev online to trigger a FMA fault by posting an ereport. */ if (!zpool_get_prop_int(zhp, ZPOOL_PROP_AUTOREPLACE, NULL) || - !(wholedisk || is_dm) || (physpath == NULL)) { + !(wholedisk || is_mpath_wholedisk) || (physpath == NULL)) { (void) zpool_vdev_online(zhp, fullpath, ZFS_ONLINE_FORCEFAULT, &newstate); zed_log_msg(LOG_INFO, "Pool's autoreplace is not enabled or " - "not a whole disk for '%s'", fullpath); + "not a blank disk for '%s' ('%s')", fullpath, + physpath); return; } @@ -287,7 +347,7 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled) (void) snprintf(rawpath, sizeof (rawpath), "%s%s", is_sd ? DEV_BYVDEV_PATH : DEV_BYPATH_PATH, physpath); - if (realpath(rawpath, devpath) == NULL && !is_dm) { + if (realpath(rawpath, devpath) == NULL && !is_mpath_wholedisk) { zed_log_msg(LOG_INFO, " realpath: %s failed (%s)", rawpath, strerror(errno)); @@ -303,12 +363,14 @@ zfs_process_add(zpool_handle_t *zhp, nvlist_t *vdev, boolean_t labeled) if ((vs->vs_state != VDEV_STATE_DEGRADED) && (vs->vs_state != VDEV_STATE_FAULTED) && (vs->vs_state != VDEV_STATE_CANT_OPEN)) { + zed_log_msg(LOG_INFO, " not autoreplacing since disk isn't in " + "a bad state (currently %d)", vs->vs_state); return; } nvlist_lookup_string(vdev, "new_devid", &new_devid); - if (is_dm) { + if (is_mpath_wholedisk) { /* Don't label device mapper or multipath disks. */ } else if (!labeled) { /* @@ -522,8 +584,11 @@ zfs_iter_vdev(zpool_handle_t *zhp, nvlist_t *nvl, void *data) * the dp->dd_compare value. */ if (nvlist_lookup_string(nvl, dp->dd_prop, &path) != 0 || - strcmp(dp->dd_compare, path) != 0) + strcmp(dp->dd_compare, path) != 0) { + zed_log_msg(LOG_INFO, " %s: no match (%s != vdev %s)", + __func__, dp->dd_compare, path); return; + } zed_log_msg(LOG_INFO, " zfs_iter_vdev: matched %s on %s", dp->dd_prop, path); @@ -571,6 +636,8 @@ zfs_iter_pool(zpool_handle_t *zhp, void *data) ZPOOL_CONFIG_VDEV_TREE, &nvl); zfs_iter_vdev(zhp, nvl, data); } + } else { + zed_log_msg(LOG_INFO, "%s: no config\n", __func__); } /* @@ -619,6 +686,72 @@ devphys_iter(const char *physical, const char *devid, zfs_process_func_t func, return (data.dd_found); } +/* + * Given a device identifier, find any vdevs with a matching by-vdev + * path. Normally we shouldn't need this as the comparison would be + * made earlier in the devphys_iter(). For example, if we were replacing + * /dev/disk/by-vdev/L28, normally devphys_iter() would match the + * ZPOOL_CONFIG_PHYS_PATH of "L28" from the old disk config to "L28" + * of the new disk config. However, we've seen cases where + * ZPOOL_CONFIG_PHYS_PATH was not in the config for the old disk. Here's + * an example of a real 2-disk mirror pool where one disk was force + * faulted: + * + * com.delphix:vdev_zap_top: 129 + * children[0]: + * type: 'disk' + * id: 0 + * guid: 14309659774640089719 + * path: '/dev/disk/by-vdev/L28' + * whole_disk: 0 + * DTL: 654 + * create_txg: 4 + * com.delphix:vdev_zap_leaf: 1161 + * faulted: 1 + * aux_state: 'external' + * children[1]: + * type: 'disk' + * id: 1 + * guid: 16002508084177980912 + * path: '/dev/disk/by-vdev/L29' + * devid: 'dm-uuid-mpath-35000c500a61d68a3' + * phys_path: 'L29' + * vdev_enc_sysfs_path: '/sys/class/enclosure/0:0:1:0/SLOT 30 32' + * whole_disk: 0 + * DTL: 1028 + * create_txg: 4 + * com.delphix:vdev_zap_leaf: 131 + * + * So in the case above, the only thing we could compare is the path. + * + * We can do this because we assume by-vdev paths are authoritative as physical + * paths. We could not assume this for normal paths like /dev/sda since the + * physical location /dev/sda points to could change over time. + */ +static boolean_t +by_vdev_path_iter(const char *by_vdev_path, const char *devid, + zfs_process_func_t func, boolean_t is_slice) +{ + dev_data_t data = { 0 }; + + data.dd_compare = by_vdev_path; + data.dd_func = func; + data.dd_prop = ZPOOL_CONFIG_PATH; + data.dd_found = B_FALSE; + data.dd_islabeled = is_slice; + data.dd_new_devid = devid; + + if (strncmp(by_vdev_path, DEV_BYVDEV_PATH, + strlen(DEV_BYVDEV_PATH)) != 0) { + /* by_vdev_path doesn't start with "/dev/disk/by-vdev/" */ + return (B_FALSE); + } + + (void) zpool_iter(g_zfshdl, zfs_iter_pool, &data); + + return (data.dd_found); +} + /* * Given a device identifier, find any vdevs with a matching devid. * On Linux we can match devid directly which is always a whole disk. @@ -683,15 +816,17 @@ guid_iter(uint64_t pool_guid, uint64_t vdev_guid, const char *devid, static int zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi) { - char *devpath = NULL, *devid; + char *devpath = NULL, *devid = NULL; uint64_t pool_guid = 0, vdev_guid = 0; boolean_t is_slice; /* * Expecting a devid string and an optional physical location and guid */ - if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0) + if (nvlist_lookup_string(nvl, DEV_IDENTIFIER, &devid) != 0) { + zed_log_msg(LOG_INFO, "%s: no dev identifier\n", __func__); return (-1); + } (void) nvlist_lookup_string(nvl, DEV_PHYS_PATH, &devpath); (void) nvlist_lookup_uint64(nvl, ZFS_EV_POOL_GUID, &pool_guid); @@ -707,6 +842,8 @@ zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi) * 1. ZPOOL_CONFIG_DEVID (identifies the unique disk) * 2. ZPOOL_CONFIG_PHYS_PATH (identifies disk physical location). * 3. ZPOOL_CONFIG_GUID (identifies unique vdev). + * 4. ZPOOL_CONFIG_PATH for /dev/disk/by-vdev devices only (since + * by-vdev paths represent physical paths). */ if (devid_iter(devid, zfs_process_add, is_slice)) return (0); @@ -717,6 +854,16 @@ zfs_deliver_add(nvlist_t *nvl, boolean_t is_lofi) (void) guid_iter(pool_guid, vdev_guid, devid, zfs_process_add, is_slice); + if (devpath != NULL) { + /* Can we match a /dev/disk/by-vdev/ path? */ + char by_vdev_path[MAXPATHLEN]; + snprintf(by_vdev_path, sizeof (by_vdev_path), + "/dev/disk/by-vdev/%s", devpath); + if (by_vdev_path_iter(by_vdev_path, devid, zfs_process_add, + is_slice)) + return (0); + } + return (0); } diff --git a/cmd/zed/zed_disk_event.c b/cmd/zed/zed_disk_event.c index 94e24236063c..52b80d8c4c93 100644 --- a/cmd/zed/zed_disk_event.c +++ b/cmd/zed/zed_disk_event.c @@ -215,6 +215,11 @@ zed_udev_monitor(void *arg) if (type != NULL && type[0] != '\0' && strcmp(type, "disk") == 0 && part != NULL && part[0] != '\0') { + zed_log_msg(LOG_INFO, + "%s: skip %s since it has a %s partition already", + __func__, + udev_device_get_property_value(dev, "DEVNAME"), + part); /* skip and wait for partition event */ udev_device_unref(dev); continue; @@ -229,6 +234,11 @@ zed_udev_monitor(void *arg) sectors = udev_device_get_sysattr_value(dev, "size"); if (sectors != NULL && strtoull(sectors, NULL, 10) < MINIMUM_SECTORS) { + zed_log_msg(LOG_INFO, + "%s: %s sectors %s < %llu (minimum)", + __func__, + udev_device_get_property_value(dev, "DEVNAME"), + sectors, MINIMUM_SECTORS); udev_device_unref(dev); continue; } diff --git a/lib/libzutil/os/linux/zutil_device_path_os.c b/lib/libzutil/os/linux/zutil_device_path_os.c index 13f8bd031612..83b077927f4b 100644 --- a/lib/libzutil/os/linux/zutil_device_path_os.c +++ b/lib/libzutil/os/linux/zutil_device_path_os.c @@ -527,7 +527,7 @@ zfs_dev_is_dm(const char *dev_name) boolean_t zfs_dev_is_whole_disk(const char *dev_name) { - struct dk_gpt *label; + struct dk_gpt *label = NULL; int fd; if ((fd = open(dev_name, O_RDONLY | O_DIRECT | O_CLOEXEC)) < 0) @@ -613,22 +613,27 @@ zfs_get_underlying_path(const char *dev_name) /* * A disk is considered a multipath whole disk when: * DEVNAME key value has "dm-" - * DM_NAME key value has "mpath" prefix + * MPATH_DEVICE_READY is present * DM_UUID key exists * ID_PART_TABLE_TYPE key does not exist or is not gpt + * ID_FS_LABEL key does not exist (disk isn't labeled) */ static boolean_t -udev_mpath_whole_disk(struct udev_device *dev) +is_mpath_udev_sane(struct udev_device *dev) { - const char *devname, *type, *uuid; + const char *devname, *type, *uuid, *label, *mpath_ready; devname = udev_device_get_property_value(dev, "DEVNAME"); type = udev_device_get_property_value(dev, "ID_PART_TABLE_TYPE"); uuid = udev_device_get_property_value(dev, "DM_UUID"); + label = udev_device_get_property_value(dev, "ID_FS_LABEL"); + mpath_ready = udev_device_get_property_value(dev, "MPATH_DEVICE_READY"); if ((devname != NULL && strncmp(devname, "/dev/dm-", 8) == 0) && ((type == NULL) || (strcmp(type, "gpt") != 0)) && - (uuid != NULL)) { + (uuid != NULL) && + (label == NULL) && + (mpath_ready != NULL && strncmp(mpath_ready, "1", 1) == 0)) { return (B_TRUE); } @@ -636,7 +641,11 @@ udev_mpath_whole_disk(struct udev_device *dev) } /* - * Check if a disk is effectively a multipath whole disk + * Check if a disk is a multipath "blank" disk: + * + * 1. The disk has udev values that suggest it's a multipath disk + * 2. The disk is not currently labeled with a filesystem of any type + * 3. There are no partitions on the disk */ boolean_t is_mpath_whole_disk(const char *path) @@ -645,7 +654,6 @@ is_mpath_whole_disk(const char *path) struct udev_device *dev = NULL; char nodepath[MAXPATHLEN]; char *sysname; - boolean_t wholedisk = B_FALSE; if (realpath(path, nodepath) == NULL) return (B_FALSE); @@ -660,10 +668,11 @@ is_mpath_whole_disk(const char *path) return (B_FALSE); } - wholedisk = udev_mpath_whole_disk(dev); - + /* Sanity check some udev values */ + boolean_t is_sane = is_mpath_udev_sane(dev); udev_device_unref(dev); - return (wholedisk); + + return (is_sane); } #else /* HAVE_LIBUDEV */ From 2b8b89c6b3f72b2378867c61159901b6d58d8662 Mon Sep 17 00:00:00 2001 From: Tony Hutter Date: Fri, 18 Mar 2022 14:06:40 -0700 Subject: [PATCH 8/9] zed: Fix mpath autoreplace on Centos 7 A prior commit included a udev check for MPATH_DEVICE_READY to determine if a path was multipath when doing an autoreplace: f2f6c18 zed: Misc multipath autoreplace fixes However, MPATH_DEVICE_READY is not provided by the older version of udev that's on Centos 7 (it is on Centos 8). This patch instead looks for 'mpath-' in the UUID, which works on both Centos 7 and 8. Reviewed-by: Brian Behlendorf Signed-off-by: Tony Hutter Closes #13222 --- lib/libzutil/os/linux/zutil_device_path_os.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/libzutil/os/linux/zutil_device_path_os.c b/lib/libzutil/os/linux/zutil_device_path_os.c index 83b077927f4b..45a6f6f5935b 100644 --- a/lib/libzutil/os/linux/zutil_device_path_os.c +++ b/lib/libzutil/os/linux/zutil_device_path_os.c @@ -613,27 +613,24 @@ zfs_get_underlying_path(const char *dev_name) /* * A disk is considered a multipath whole disk when: * DEVNAME key value has "dm-" - * MPATH_DEVICE_READY is present - * DM_UUID key exists + * DM_UUID key exists and starts with 'mpath-' * ID_PART_TABLE_TYPE key does not exist or is not gpt * ID_FS_LABEL key does not exist (disk isn't labeled) */ static boolean_t is_mpath_udev_sane(struct udev_device *dev) { - const char *devname, *type, *uuid, *label, *mpath_ready; + const char *devname, *type, *uuid, *label; devname = udev_device_get_property_value(dev, "DEVNAME"); type = udev_device_get_property_value(dev, "ID_PART_TABLE_TYPE"); uuid = udev_device_get_property_value(dev, "DM_UUID"); label = udev_device_get_property_value(dev, "ID_FS_LABEL"); - mpath_ready = udev_device_get_property_value(dev, "MPATH_DEVICE_READY"); if ((devname != NULL && strncmp(devname, "/dev/dm-", 8) == 0) && ((type == NULL) || (strcmp(type, "gpt") != 0)) && - (uuid != NULL) && - (label == NULL) && - (mpath_ready != NULL && strncmp(mpath_ready, "1", 1) == 0)) { + ((uuid != NULL) && (strncmp(uuid, "mpath-", 6) == 0)) && + (label == NULL)) { return (B_TRUE); } From 52bad4f23daaa5f827f802c8d05785a27b80275d Mon Sep 17 00:00:00 2001 From: Tony Hutter Date: Mon, 21 Mar 2022 14:38:12 -0700 Subject: [PATCH 9/9] Tag zfs-2.1.4 META file and changelog updated. Signed-off-by: Tony Hutter --- META | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/META b/META index 0437224b403f..76e59a42074c 100644 --- a/META +++ b/META @@ -1,10 +1,10 @@ Meta: 1 Name: zfs Branch: 1.0 -Version: 2.1.3 +Version: 2.1.4 Release: 1 Release-Tags: relext License: CDDL Author: OpenZFS -Linux-Maximum: 5.16 +Linux-Maximum: 5.17 Linux-Minimum: 3.10