diff --git a/module/os/linux/zfs/zpl_super.c b/module/os/linux/zfs/zpl_super.c index 63ba731dd8..c5c230bee1 100644 --- a/module/os/linux/zfs/zpl_super.c +++ b/module/os/linux/zfs/zpl_super.c @@ -20,6 +20,7 @@ */ /* * Copyright (c) 2011, Lawrence Livermore National Security, LLC. + * Copyright (c) 2023, Datto Inc. All rights reserved. */ @@ -276,11 +277,28 @@ zpl_test_super(struct super_block *s, void *data) { zfsvfs_t *zfsvfs = s->s_fs_info; objset_t *os = data; + int match; - if (zfsvfs == NULL) + /* + * If the os doesn't match the z_os in the super_block, assume it is + * not a match. Matching would imply a multimount of a dataset. It is + * possible that during a multimount, there is a simultaneous operation + * that changes the z_os, e.g., rollback, where the match will be + * missed, but in that case the user will get an EBUSY. + */ + if (zfsvfs == NULL || os != zfsvfs->z_os) return (0); - return (os == zfsvfs->z_os); + /* + * If they do match, recheck with the lock held to prevent mounting the + * wrong dataset since z_os can be stale when the teardown lock is held. + */ + if (zpl_enter(zfsvfs, FTAG) != 0) + return (0); + match = (os == zfsvfs->z_os); + zpl_exit(zfsvfs, FTAG); + + return (match); } static struct super_block *