Release onexit/events with any missed zfsdev_state

Linux and FreeBSD will most likely never see this issue.
On macOS when kext is unloaded, but zed is still connected, zed
will be issued ENODEV. As the cdevsw is released, the kernel
will not have zfsdev_release() called to release minor/onexit/events,
and it "leaks". This ensures it is cleaned up before unload.

Changed the for loop from zsprev, to zsnext style, for less
code duplication.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Jorgen Lundman <lundman@lundman.net>
Closes #10700
This commit is contained in:
Jorgen Lundman 2020-08-14 07:03:23 +09:00 committed by GitHub
parent f67f5832ec
commit faa296c73c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 12 additions and 7 deletions

View File

@ -201,6 +201,8 @@ zfsdev_close(void *data)
zfs_onexit_destroy(zs->zs_onexit);
zfs_zevent_destroy(zs->zs_zevent);
mutex_exit(&zfsdev_state_lock);
zs->zs_onexit = NULL;
zs->zs_zevent = NULL;
}
static int

View File

@ -148,6 +148,8 @@ zfsdev_state_destroy(struct file *filp)
zs->zs_minor = -1;
zfs_onexit_destroy(zs->zs_onexit);
zfs_zevent_destroy(zs->zs_zevent);
zs->zs_onexit = NULL;
zs->zs_zevent = NULL;
return (0);
}

View File

@ -7609,19 +7609,20 @@ out:
void
zfs_kmod_fini(void)
{
zfsdev_state_t *zs, *zsprev = NULL;
zfsdev_state_t *zs, *zsnext = NULL;
zfsdev_detach();
mutex_destroy(&zfsdev_state_lock);
for (zs = zfsdev_state_list; zs != NULL; zs = zs->zs_next) {
if (zsprev)
kmem_free(zsprev, sizeof (zfsdev_state_t));
zsprev = zs;
for (zs = zfsdev_state_list; zs != NULL; zs = zsnext) {
zsnext = zs->zs_next;
if (zs->zs_onexit)
zfs_onexit_destroy(zs->zs_onexit);
if (zs->zs_zevent)
zfs_zevent_destroy(zs->zs_zevent);
kmem_free(zs, sizeof (zfsdev_state_t));
}
if (zsprev)
kmem_free(zsprev, sizeof (zfsdev_state_t));
zfs_fini();
spa_fini();