Skip to content

Commit f2010f8

Browse files
committed
Fix snapshot automount race causing AVL tree panic
Multiple threads racing to automount the same snapshot can both pass the initial mount check and attempt to add identical AVL tree entries, triggering a VERIFY() panic in avl_add(). The fix adds a recheck after acquiring the write lock to detect if another thread already added the entry during the mount operation. If found, the duplicate is freed instead of causing a panic. Reproducible with parallel access to a fresh snapshot: ls /mnt/test/.zfs/snapshot/snap1/ & ls /mnt/test/.zfs/snapshot/snap1/ & Signed-off-by: Ameer Hamza <ahamza@ixsystems.com>
1 parent e63d026 commit f2010f8

File tree

1 file changed

+19
-5
lines changed

1 file changed

+19
-5
lines changed

module/os/linux/zfs/zfs_ctldir.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,11 +1291,25 @@ zfsctl_snapshot_mount(struct path *path, int flags)
12911291
spath.mnt->mnt_flags |= MNT_SHRINKABLE;
12921292

12931293
rw_enter(&zfs_snapshot_lock, RW_WRITER);
1294-
se = zfsctl_snapshot_alloc(full_name, full_path,
1295-
snap_zfsvfs->z_os->os_spa, dmu_objset_id(snap_zfsvfs->z_os),
1296-
dentry);
1297-
zfsctl_snapshot_add(se);
1298-
zfsctl_snapshot_unmount_delay_impl(se, zfs_expire_snapshot);
1294+
/*
1295+
* Recheck if another thread added the entry while we were
1296+
* mounting. This handles the race where multiple threads
1297+
* simultaneously mount the same fresh snapshot.
1298+
*/
1299+
se = zfsctl_snapshot_find_by_name(full_name);
1300+
if (se != NULL) {
1301+
/* Already mounted by another thread - not an error */
1302+
zfsctl_snapshot_rele(se);
1303+
se = NULL;
1304+
} else {
1305+
/* We're first - allocate and add to AVL trees */
1306+
se = zfsctl_snapshot_alloc(full_name, full_path,
1307+
snap_zfsvfs->z_os->os_spa,
1308+
dmu_objset_id(snap_zfsvfs->z_os), dentry);
1309+
zfsctl_snapshot_add(se);
1310+
zfsctl_snapshot_unmount_delay_impl(se,
1311+
zfs_expire_snapshot);
1312+
}
12991313
rw_exit(&zfs_snapshot_lock);
13001314
}
13011315
path_put(&spath);

0 commit comments

Comments
 (0)