FreeBSD: add kqfilter support for zvol cdev

The only event hooked up is NOTE_ATTRIB, which is triggered when the
device is resized.

Reviewed-by: Ryan Moeller <ryan@iXsystems.com>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Signed-off-by: Rob Wing <rew@FreeBSD.org>
Closes #13773
This commit is contained in:
Rob Wing 2022-02-01 20:00:57 -09:00 committed by Brian Behlendorf
parent 9d0887402b
commit 983096a1b4

View File

@ -92,6 +92,7 @@
#include <sys/zio_checksum.h>
#include <sys/zil_impl.h>
#include <sys/filio.h>
#include <sys/freebsd_event.h>
#include <geom/geom.h>
#include <sys/zvol.h>
@ -123,6 +124,7 @@ struct zvol_state_os {
struct zvol_state_dev {
struct cdev *zsd_cdev;
uint64_t zsd_sync_cnt;
struct selinfo zsd_selinfo;
} _zso_dev;
/* volmode=geom */
@ -167,6 +169,7 @@ static d_ioctl_t zvol_cdev_ioctl;
static d_read_t zvol_cdev_read;
static d_write_t zvol_cdev_write;
static d_strategy_t zvol_geom_bio_strategy;
static d_kqfilter_t zvol_cdev_kqfilter;
static struct cdevsw zvol_cdevsw = {
.d_name = "zvol",
@ -178,6 +181,16 @@ static struct cdevsw zvol_cdevsw = {
.d_read = zvol_cdev_read,
.d_write = zvol_cdev_write,
.d_strategy = zvol_geom_bio_strategy,
.d_kqfilter = zvol_cdev_kqfilter,
};
static void zvol_filter_detach(struct knote *kn);
static int zvol_filter_vnode(struct knote *kn, long hint);
static struct filterops zvol_filterops_vnode = {
.f_isfd = 1,
.f_detach = zvol_filter_detach,
.f_event = zvol_filter_vnode,
};
extern uint_t zfs_geom_probe_vdev_key;
@ -601,6 +614,49 @@ zvol_geom_bio_getattr(struct bio *bp)
return (1);
}
static void
zvol_filter_detach(struct knote *kn)
{
zvol_state_t *zv;
struct zvol_state_dev *zsd;
zv = kn->kn_hook;
zsd = &zv->zv_zso->zso_dev;
knlist_remove(&zsd->zsd_selinfo.si_note, kn, 0);
}
static int
zvol_filter_vnode(struct knote *kn, long hint)
{
kn->kn_fflags |= kn->kn_sfflags & hint;
return (kn->kn_fflags != 0);
}
static int
zvol_cdev_kqfilter(struct cdev *dev, struct knote *kn)
{
zvol_state_t *zv;
struct zvol_state_dev *zsd;
zv = dev->si_drv2;
zsd = &zv->zv_zso->zso_dev;
if (kn->kn_filter != EVFILT_VNODE)
return (EINVAL);
/* XXX: extend support for other NOTE_* events */
if (kn->kn_sfflags != NOTE_ATTRIB)
return (EINVAL);
kn->kn_fop = &zvol_filterops_vnode;
kn->kn_hook = zv;
knlist_add(&zsd->zsd_selinfo.si_note, kn, 0);
return (0);
}
static void
zvol_geom_bio_strategy(struct bio *bp)
{
@ -1306,6 +1362,8 @@ zvol_os_free(zvol_state_t *zv)
if (dev != NULL) {
ASSERT3P(dev->si_drv2, ==, NULL);
destroy_dev(dev);
knlist_clear(&zsd->zsd_selinfo.si_note, 0);
knlist_destroy(&zsd->zsd_selinfo.si_note);
}
}
@ -1409,6 +1467,8 @@ zvol_os_create_minor(const char *name)
dev->si_iosize_max = MAXPHYS;
#endif
zsd->zsd_cdev = dev;
knlist_init_sx(&zsd->zsd_selinfo.si_note,
&zv->zv_state_lock);
}
}
(void) strlcpy(zv->zv_name, name, MAXPATHLEN);
@ -1515,6 +1575,10 @@ zvol_os_update_volsize(zvol_state_t *zv, uint64_t volsize)
g_resize_provider(pp, zv->zv_volsize);
g_topology_unlock();
} else if (zv->zv_volmode == ZFS_VOLMODE_DEV) {
struct zvol_state_dev *zsd = &zv->zv_zso->zso_dev;
KNOTE_UNLOCKED(&zsd->zsd_selinfo.si_note, NOTE_ATTRIB);
}
return (0);
}