mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 19:19:32 +03:00
Fix zvol_state_t->zv_open_count race
5559ba0
added zv_state_lock to protect zvol_state_t internal data:
this, however, doesn't guard zv->zv_open_count and
zv->zv_disk->private_data in zvol_remove_minors_impl().
Fix this by taking zv->zv_state_lock before we check its zv_open_count.
P1 (z_zvol) P2 (systemd-udevd)
--- ---
zvol_remove_minors_impl()
: zv->zv_open_count==0
zvol_open()
->mutex_enter(zv_state_lock)
: zv->zv_open_count++
->mutex_exit(zv_state_lock)
->mutex_enter(zv->zv_state_lock)
->zvol_remove(zv)
->mutex_exit(zv->zv_state_lock)
: zv->zv_disk->private_data = NULL
->zvol_free()
-->ASSERT(zv->zv_open_count==0) *
zvol_release()
: zv = disk->private_data
->ASSERT(zv && zv->zv_open_count>0) *
--- ---
* ASSERT() fails
Reviewed by: Boris Protopopov <bprotopopov@hotmail.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #6213
This commit is contained in:
parent
627791f3c0
commit
97f8d7961e
@ -1964,22 +1964,27 @@ zvol_remove_minors_impl(const char *name)
|
||||
(strncmp(zv->zv_name, name, namelen) == 0 &&
|
||||
(zv->zv_name[namelen] == '/' ||
|
||||
zv->zv_name[namelen] == '@'))) {
|
||||
|
||||
/* If in use, leave alone */
|
||||
if (zv->zv_open_count > 0 ||
|
||||
atomic_read(&zv->zv_suspend_ref))
|
||||
continue;
|
||||
/*
|
||||
* By taking zv_state_lock here, we guarantee that no
|
||||
* one is currently using this zv
|
||||
*/
|
||||
mutex_enter(&zv->zv_state_lock);
|
||||
zvol_remove(zv);
|
||||
|
||||
/* If in use, leave alone */
|
||||
if (zv->zv_open_count > 0 ||
|
||||
atomic_read(&zv->zv_suspend_ref)) {
|
||||
mutex_exit(&zv->zv_state_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
zvol_remove(zv);
|
||||
|
||||
/* clear this so zvol_open won't open it */
|
||||
zv->zv_disk->private_data = NULL;
|
||||
|
||||
/* Drop zv_state_lock before zvol_free() */
|
||||
mutex_exit(&zv->zv_state_lock);
|
||||
|
||||
/* try parallel zv_free, if failed do it in place */
|
||||
t = taskq_dispatch(system_taskq, zvol_free, zv,
|
||||
TQ_SLEEP);
|
||||
@ -2021,19 +2026,24 @@ zvol_remove_minor_impl(const char *name)
|
||||
zv_next = list_next(&zvol_state_list, zv);
|
||||
|
||||
if (strcmp(zv->zv_name, name) == 0) {
|
||||
/* If in use, leave alone */
|
||||
if (zv->zv_open_count > 0 ||
|
||||
atomic_read(&zv->zv_suspend_ref))
|
||||
continue;
|
||||
/*
|
||||
* By taking zv_state_lock here, we guarantee that no
|
||||
* one is currently using this zv
|
||||
*/
|
||||
mutex_enter(&zv->zv_state_lock);
|
||||
zvol_remove(zv);
|
||||
|
||||
/* If in use, leave alone */
|
||||
if (zv->zv_open_count > 0 ||
|
||||
atomic_read(&zv->zv_suspend_ref)) {
|
||||
mutex_exit(&zv->zv_state_lock);
|
||||
continue;
|
||||
}
|
||||
zvol_remove(zv);
|
||||
|
||||
/* clear this so zvol_open won't open it */
|
||||
zv->zv_disk->private_data = NULL;
|
||||
|
||||
mutex_exit(&zv->zv_state_lock);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user