xref: /titanic_52/usr/src/uts/common/fs/arcflush/arcflush.c (revision 4d40e39c66a331aefef24083480939f0e78a9045)
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
73 _init()
74 {
75 	int error = mod_install(&modlinkage);
76 	return (error);
77 }
78 
79 int
80 _fini()
81 {
82 	int error;
83 
84 	error = mod_remove(&modlinkage);
85 	return (error);
86 }
87 
88 int
89 _info(struct modinfo *modinfop)
90 {
91 	int error;
92 
93 	error = mod_info(&modlinkage, modinfop);
94 	return error;
95 }
96 
97 static int
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
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
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
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
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
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