1 #include <sys/modctl.h>
2 #include <sys/ddi.h>
3 #include <sys/sunddi.h>
4 #include <sys/devops.h>
5 #include <sys/conf.h>
6 #include <sys/cpuvar.h>
7 #include <sys/kobj.h>
8 #include <sys/spa.h>
9 #include <sys/arc.h>
10 #include <sys/vfs.h>
11 #include <sys/dnlc.h>
12
13 static dev_info_t *arcflushdevi;
14
15 #define FTAG ((char *)(uintptr_t)__func__)
16
17 static int arcflushioctl(dev_t dev, int cmd, intptr_t arg, int mode,
18 cred_t *credp, int *rvalp);
19 static int arcflushclose(dev_t dev, int flag, int otyp, cred_t *crepd);
20 static int arcflushopen(dev_t *devp, int flag, int otyp, cred_t *credp);
21
22 static struct cb_ops arcflush_cb_ops = {
23 arcflushopen, /* open */
24 arcflushclose, /* close */
25 nodev, /* strategy */
26 nodev, /* print */
27 nodev, /* dump */
28 nodev, /* read */
29 nodev, /* write */
30 arcflushioctl, /* ioctl */
31 nodev, /* devmap */
32 nodev, /* mmap */
33 nodev, /* segmap */
34 nochpoll, /* poll */
35 ddi_prop_op, /* prop_op */
36 (struct streamtab *)0, /* streamtab */
37 D_NEW | D_64BIT | D_MP, /* flags */
38 CB_REV,
39 nodev,
40 nodev
41 };
42
43 static int arcflushattach(dev_info_t *, ddi_attach_cmd_t);
44 static int arcflushdetach(dev_info_t *, ddi_detach_cmd_t);
45 static int arcflushinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
46
47 static struct dev_ops arcflush_ops = {
48 DEVO_REV, /* devo_rev */
49 0, /* refcnt */
50 arcflushinfo, /* info */
51 nulldev, /* identify */
52 nulldev, /* probe */
53 arcflushattach, /* attach */
54 arcflushdetach, /* detach */
55 nodev, /* reset */
56 &arcflush_cb_ops, /* driver operations */
57 (struct bus_ops *)NULL, /* bus operations */
58 NULL /* power */
59 };
60
61 static struct modldrv modldrv = {
62 &mod_driverops, /* type of module - a driver */
63 "arcflush driver",
64 &arcflush_ops,
65 };
66
67 static struct modlinkage modlinkage = {
68 MODREV_1,
69 { (void *)&modldrv, NULL }
70 };
71
72 int
_init()73 _init()
74 {
75 int error = mod_install(&modlinkage);
76 return (error);
77 }
78
79 int
_fini()80 _fini()
81 {
82 int error;
83
84 error = mod_remove(&modlinkage);
85 return (error);
86 }
87
88 int
_info(struct modinfo * modinfop)89 _info(struct modinfo *modinfop)
90 {
91 int error;
92
93 error = mod_info(&modlinkage, modinfop);
94 return error;
95 }
96
97 static int
arcflushclose(dev_t dev,int flag,int otyp,cred_t * crepd)98 arcflushclose(dev_t dev, int flag, int otyp, cred_t *crepd)
99 {
100 if (otyp != OTYP_CHR)
101 return (EINVAL);
102
103 return (0);
104 }
105
106 static int
arcflushopen(dev_t * devp,int flag,int otyp,cred_t * credp)107 arcflushopen(dev_t *devp, int flag, int otyp, cred_t *credp)
108 {
109 if (otyp != OTYP_CHR)
110 return (EINVAL);
111 if (drv_priv(credp) != 0)
112 return (EPERM);
113
114 return (0);
115 }
116
117 static int
arcflushioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)118 arcflushioctl(dev_t dev, int cmd, intptr_t arg, int mode,
119 cred_t *credp, int *rvalp)
120 {
121 spa_t *spa;
122 int ret;
123 char name[MAXPATHLEN + 1];
124 vfs_t *vfsp;
125
126 if (ddi_copyin((void *)arg, name, MAXPATHLEN, mode) != 0)
127 return EFAULT;
128 name[MAXPATHLEN] = 0;
129
130 switch (cmd) {
131 case 0xf10053:
132 ret = spa_open(name, &spa, FTAG);
133 if (ret != 0)
134 return (ret);
135 arc_flush(spa, FALSE);
136 spa_close(spa, FTAG);
137 break;
138 case 0xf10054:
139 vfsp = vfs_mntpoint2vfsp(name);
140 if (vfsp == NULL)
141 return (EINVAL);
142 dnlc_purge_vfsp(vfsp, 0);
143 break;
144 default:
145 return ENOTTY;
146 }
147
148 return (0);
149 }
150
151 /*ARGSUSED*/
152 static int
arcflushattach(dev_info_t * devi,ddi_attach_cmd_t cmd)153 arcflushattach(dev_info_t *devi, ddi_attach_cmd_t cmd)
154 {
155 if (cmd != DDI_ATTACH) {
156 return (DDI_FAILURE);
157 }
158
159 if (ddi_create_minor_node(devi, "arcflush", S_IFCHR, 0, DDI_PSEUDO, 0)
160 == DDI_FAILURE) {
161 cmn_err(CE_NOTE, "arcflushattach fail: "
162 "ddi_create_minor_node\n");
163 return (DDI_FAILURE);
164 }
165 ddi_report_dev(devi);
166
167 arcflushdevi = devi;
168
169 return (DDI_SUCCESS);
170 }
171
172 static int
arcflushdetach(dev_info_t * devi,ddi_detach_cmd_t cmd)173 arcflushdetach(dev_info_t *devi, ddi_detach_cmd_t cmd)
174 {
175 if (cmd != DDI_DETACH) {
176 return (DDI_FAILURE);
177 }
178
179 arcflushdevi = NULL;
180
181 ddi_prop_remove_all(devi);
182 ddi_remove_minor_node(devi, NULL);
183
184 return (DDI_SUCCESS);
185 }
186
187 /* ARGSUSED */
188 static int
arcflushinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)189 arcflushinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
190 {
191 int error;
192 switch (infocmd) {
193 case DDI_INFO_DEVT2DEVINFO:
194 *result = (void *)arcflushdevi;
195 error = DDI_SUCCESS;
196 break;
197 case DDI_INFO_DEVT2INSTANCE:
198 *result = (void *)0;
199 error = DDI_SUCCESS;
200 break;
201 default:
202 error = DDI_FAILURE;
203 }
204 return (error);
205 }
206