Skip to content

Commit 003825b

Browse files
committed
zvol: reject suspend attempts when zvol is shutting down
1 parent e0be5f1 commit 003825b

File tree

3 files changed

+22
-7
lines changed

3 files changed

+22
-7
lines changed

include/sys/zvol.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extern int zvol_set_volsize(const char *, uint64_t);
5353
extern int zvol_set_volthreading(const char *, boolean_t);
5454
extern int zvol_set_common(const char *, zfs_prop_t, zprop_source_t, uint64_t);
5555
extern int zvol_set_ro(const char *, boolean_t);
56-
extern zvol_state_handle_t *zvol_suspend(const char *);
56+
extern int zvol_suspend(const char *, zvol_state_handle_t **);
5757
extern int zvol_resume(zvol_state_handle_t *);
5858
extern void *zvol_tag(zvol_state_handle_t *);
5959

module/zfs/zfs_ioctl.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4726,7 +4726,7 @@ zfs_ioc_rollback(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
47264726
error = error ? error : resume_err;
47274727
}
47284728
zfs_vfs_rele(zfsvfs);
4729-
} else if ((zv = zvol_suspend(fsname)) != NULL) {
4729+
} else if (zvol_suspend(fsname, &zv) == 0) {
47304730
error = dsl_dataset_rollback(fsname, target, zvol_tag(zv),
47314731
outnvl);
47324732
zvol_resume(zv);
@@ -5448,7 +5448,7 @@ zfs_ioc_recv_impl(char *tofs, char *tosnap, const char *origin,
54485448
}
54495449
error = error ? error : end_err;
54505450
zfs_vfs_rele(zfsvfs);
5451-
} else if ((zv = zvol_suspend(tofs)) != NULL) {
5451+
} else if (zvol_suspend(tofs, &zv) == 0) {
54525452
error = dmu_recv_end(&drc, zvol_tag(zv));
54535453
zvol_resume(zv);
54545454
} else {

module/zfs/zvol.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1145,20 +1145,34 @@ zvol_tag(zvol_state_t *zv)
11451145
/*
11461146
* Suspend the zvol for recv and rollback.
11471147
*/
1148-
zvol_state_t *
1149-
zvol_suspend(const char *name)
1148+
int
1149+
zvol_suspend(const char *name, zvol_state_t **zvp)
11501150
{
11511151
zvol_state_t *zv;
11521152

11531153
zv = zvol_find_by_name(name, RW_WRITER);
11541154

11551155
if (zv == NULL)
1156-
return (NULL);
1156+
return (SET_ERROR(ENOENT));
11571157

11581158
/* block all I/O, release in zvol_resume. */
11591159
ASSERT(MUTEX_HELD(&zv->zv_state_lock));
11601160
ASSERT(RW_WRITE_HELD(&zv->zv_suspend_lock));
11611161

1162+
/*
1163+
* If it's being removed, unlock and return error. It doesn't make any
1164+
* sense to try to suspend a zvol being removed, but being here also
1165+
* means that zvol_remove_minors_impl() is about to call zvol_remove()
1166+
* and then destroy the zvol_state_t, so returning a pointer to it for
1167+
* the caller to mess with would be a disaster anyway.
1168+
*/
1169+
if (zv->zv_flags & ZVOL_REMOVING) {
1170+
mutex_exit(&zv->zv_state_lock);
1171+
rw_exit(&zv->zv_suspend_lock);
1172+
/* NB: Returning EIO here to match zfsvfs_teardown() */
1173+
return (SET_ERROR(EIO));
1174+
}
1175+
11621176
atomic_inc(&zv->zv_suspend_ref);
11631177

11641178
if (zv->zv_open_count > 0)
@@ -1171,7 +1185,8 @@ zvol_suspend(const char *name)
11711185
mutex_exit(&zv->zv_state_lock);
11721186

11731187
/* zv_suspend_lock is released in zvol_resume() */
1174-
return (zv);
1188+
*zvp = zv;
1189+
return (0);
11751190
}
11761191

11771192
int

0 commit comments

Comments
 (0)