Prevent incorrect datasets being mounted
During a mount, zpl_mount_impl(), uses sget() with the callback zpl_test_super() to find a super_block with a matching objset, stored in z_os. It does so without taking the teardown lock on the zfsvfs. The problem is that operations like rollback will replace the z_os. And, there is a window where the objset in the rollback is freed, but z_os still points to it. Then, a mount like operation, for instance a clone, can reallocate that exact same pointer and zpl_test_super() will then match the super_block associated with the rollback as opposed to the clone. This fix tests for a match and if so, takes the teardown lock before doing the final match test. Reviewed-by: Richard Yao <richard.yao@alumni.stonybrook.edu> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: John Poduska <jpoduska@datto.com> Closes #14518
This commit is contained in:
parent
4b9bc6345e
commit
73c383f541
|
@ -20,6 +20,7 @@
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, Lawrence Livermore National Security, LLC.
|
* 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;
|
zfsvfs_t *zfsvfs = s->s_fs_info;
|
||||||
objset_t *os = data;
|
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 (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 *
|
static struct super_block *
|
||||||
|
|
Loading…
Reference in New Issue