#include #include #include #include #include #include #include #include #include #include #include static dev_info_t *arcflushdevi; #define FTAG ((char *)(uintptr_t)__func__) static int arcflushioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp); static int arcflushclose(dev_t dev, int flag, int otyp, cred_t *crepd); static int arcflushopen(dev_t *devp, int flag, int otyp, cred_t *credp); static struct cb_ops arcflush_cb_ops = { arcflushopen, /* open */ arcflushclose, /* close */ nodev, /* strategy */ nodev, /* print */ nodev, /* dump */ nodev, /* read */ nodev, /* write */ arcflushioctl, /* ioctl */ nodev, /* devmap */ nodev, /* mmap */ nodev, /* segmap */ nochpoll, /* poll */ ddi_prop_op, /* prop_op */ (struct streamtab *)0, /* streamtab */ D_NEW | D_64BIT | D_MP, /* flags */ CB_REV, nodev, nodev }; static int arcflushattach(dev_info_t *, ddi_attach_cmd_t); static int arcflushdetach(dev_info_t *, ddi_detach_cmd_t); static int arcflushinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); static struct dev_ops arcflush_ops = { DEVO_REV, /* devo_rev */ 0, /* refcnt */ arcflushinfo, /* info */ nulldev, /* identify */ nulldev, /* probe */ arcflushattach, /* attach */ arcflushdetach, /* detach */ nodev, /* reset */ &arcflush_cb_ops, /* driver operations */ (struct bus_ops *)NULL, /* bus operations */ NULL /* power */ }; static struct modldrv modldrv = { &mod_driverops, /* type of module - a driver */ "arcflush driver", &arcflush_ops, }; static struct modlinkage modlinkage = { MODREV_1, { (void *)&modldrv, NULL } }; int _init() { int error = mod_install(&modlinkage); return (error); } int _fini() { int error; error = mod_remove(&modlinkage); return (error); } int _info(struct modinfo *modinfop) { int error; error = mod_info(&modlinkage, modinfop); return error; } static int arcflushclose(dev_t dev, int flag, int otyp, cred_t *crepd) { if (otyp != OTYP_CHR) return (EINVAL); return (0); } static int arcflushopen(dev_t *devp, int flag, int otyp, cred_t *credp) { if (otyp != OTYP_CHR) return (EINVAL); if (drv_priv(credp) != 0) return (EPERM); return (0); } static int arcflushioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) { spa_t *spa; int ret; char name[MAXPATHLEN + 1]; vfs_t *vfsp; if (ddi_copyin((void *)arg, name, MAXPATHLEN, mode) != 0) return EFAULT; name[MAXPATHLEN] = 0; switch (cmd) { case 0xf10053: ret = spa_open(name, &spa, FTAG); if (ret != 0) return (ret); arc_flush(spa, FALSE); spa_close(spa, FTAG); break; case 0xf10054: vfsp = vfs_mntpoint2vfsp(name); if (vfsp == NULL) return (EINVAL); dnlc_purge_vfsp(vfsp, 0); break; default: return ENOTTY; } return (0); } /*ARGSUSED*/ static int arcflushattach(dev_info_t *devi, ddi_attach_cmd_t cmd) { if (cmd != DDI_ATTACH) { return (DDI_FAILURE); } if (ddi_create_minor_node(devi, "arcflush", S_IFCHR, 0, DDI_PSEUDO, 0) == DDI_FAILURE) { cmn_err(CE_NOTE, "arcflushattach fail: " "ddi_create_minor_node\n"); return (DDI_FAILURE); } ddi_report_dev(devi); arcflushdevi = devi; return (DDI_SUCCESS); } static int arcflushdetach(dev_info_t *devi, ddi_detach_cmd_t cmd) { if (cmd != DDI_DETACH) { return (DDI_FAILURE); } arcflushdevi = NULL; ddi_prop_remove_all(devi); ddi_remove_minor_node(devi, NULL); return (DDI_SUCCESS); } /* ARGSUSED */ static int arcflushinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) { int error; switch (infocmd) { case DDI_INFO_DEVT2DEVINFO: *result = (void *)arcflushdevi; error = DDI_SUCCESS; break; case DDI_INFO_DEVT2INSTANCE: *result = (void *)0; error = DDI_SUCCESS; break; default: error = DDI_FAILURE; } return (error); }