Index: sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c =================================================================== --- sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c +++ sys/contrib/openzfs/module/os/freebsd/zfs/zvol_os.c @@ -123,6 +123,7 @@ struct zvol_state_dev { struct cdev *zsd_cdev; uint64_t zsd_sync_cnt; + struct selinfo zsd_selinfo; } _zso_dev; /* volmode=geom */ @@ -167,6 +168,7 @@ 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 +180,16 @@ .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; @@ -592,6 +604,49 @@ 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; + + switch (kn->kn_filter) { + case EVFILT_VNODE: + kn->kn_fop = &zvol_filterops_vnode; + break; + default: + return (EINVAL); + } + + kn->kn_hook = zv; + knlist_add(&zsd->zsd_selinfo.si_note, kn, 0); + + return (0); +} + static void zvol_geom_bio_strategy(struct bio *bp) { @@ -1281,6 +1336,9 @@ struct zvol_state_dev *zsd = &zv->zv_zso->zso_dev; struct cdev *dev = zsd->zsd_cdev; + knlist_clear(&zsd->zsd_selinfo.si_note, 0); + knlist_destroy(&zsd->zsd_selinfo.si_note); + if (dev != NULL) { ASSERT3P(dev->si_drv2, ==, NULL); destroy_dev(dev); @@ -1387,6 +1445,7 @@ 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); @@ -1491,6 +1550,10 @@ 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); }