xref: /freebsd/sys/geom/geom_ctl.c (revision 6780ab54325a71e7e70112b11657973edde8655e)
1 /*-
2  * Copyright (c) 2002 Poul-Henning Kamp
3  * Copyright (c) 2002 Networks Associates Technology, Inc.
4  * All rights reserved.
5  *
6  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7  * and NAI Labs, the Security Research Division of Network Associates, Inc.
8  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9  * DARPA CHATS research program.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The names of the authors may not be used to endorse or promote
20  *    products derived from this software without specific prior written
21  *    permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $FreeBSD$
36  */
37 
38 #include "opt_geom.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/sysctl.h>
44 #include <sys/bio.h>
45 #include <sys/conf.h>
46 #include <sys/disk.h>
47 #include <sys/malloc.h>
48 #include <sys/sysctl.h>
49 #include <sys/stdint.h>
50 
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53 #include <geom/geom.h>
54 #include <geom/geom_int.h>
55 
56 static g_access_t g_ctl_access;
57 static g_start_t g_ctl_start;
58 static void g_ctl_init(void);
59 static d_ioctl_t g_ctl_ioctl;
60 
61 struct g_class g_ctl_class = {
62 	"GEOMCTL",
63 	NULL,
64 	NULL,
65 	G_CLASS_INITIALIZER
66 };
67 
68 DECLARE_GEOM_CLASS_INIT(g_ctl_class, g_ctl, g_ctl_init);
69 
70 /*
71  * We cannot do create our geom.ctl geom/provider in g_ctl_init() because
72  * the event thread has to finish adding our class first and that doesn't
73  * happen until later.  We know however, that the events are processed in
74  * FIFO order, so scheduling g_ctl_init2() with g_call_me() is safe.
75  */
76 
77 static void
78 g_ctl_init2(void *p __unused)
79 {
80 	struct g_geom *gp;
81 	struct g_provider *pp;
82 
83 	g_topology_assert();
84 	gp = g_new_geomf(&g_ctl_class, "geom.ctl");
85 	gp->start = g_ctl_start;
86 	gp->access = g_ctl_access;
87 	pp = g_new_providerf(gp, "%s", gp->name);
88 	pp->sectorsize = 512;
89 	g_error_provider(pp, 0);
90 }
91 
92 static void
93 g_ctl_init(void)
94 {
95 	mtx_unlock(&Giant);
96 	g_add_class(&g_ctl_class);
97 	g_call_me(g_ctl_init2, NULL);
98 	mtx_lock(&Giant);
99 }
100 
101 /*
102  * We allow any kind of access.  Access control is handled at the devfs
103  * level.
104  */
105 
106 static int
107 g_ctl_access(struct g_provider *pp, int r, int w, int e)
108 {
109 	int error;
110 
111 	g_trace(G_T_ACCESS, "g_ctl_access(%s, %d, %d, %d)",
112 	    pp->name, r, w, e);
113 
114 	g_topology_assert();
115 	error = 0;
116 	return (error);
117 }
118 
119 static void
120 g_ctl_start(struct bio *bp)
121 {
122 	struct g_ioctl *gio;
123 	int error;
124 
125 	switch(bp->bio_cmd) {
126 	case BIO_DELETE:
127 	case BIO_READ:
128 	case BIO_WRITE:
129 		error = EOPNOTSUPP;
130 		break;
131 	case BIO_GETATTR:
132 	case BIO_SETATTR:
133 		if (strcmp(bp->bio_attribute, "GEOM::ioctl") ||
134 		    bp->bio_length != sizeof *gio) {
135 			error = EOPNOTSUPP;
136 			break;
137 		}
138 		gio = (struct g_ioctl *)bp->bio_data;
139 		gio->func = g_ctl_ioctl;
140 		error = EDIRIOCTL;
141 		break;
142 	default:
143 		error = EOPNOTSUPP;
144 		break;
145 	}
146 	g_io_deliver(bp, error);
147 	return;
148 }
149 
150 /*
151  * All the stuff above is really just needed to get to the stuff below
152  */
153 
154 static int
155 g_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
156 {
157 	struct geomconfiggeom *gcp;
158 	struct g_configargs ga;
159 	int error;
160 
161 	error = 0;
162 	bzero(&ga, sizeof ga);
163 	gcp = (struct geomconfiggeom *)data;
164 	ga.class = g_idclass(&gcp->class);
165 	if (ga.class == NULL)
166 		return (EINVAL);
167 	if (ga.class->config == NULL)
168 		return (EOPNOTSUPP);
169 	ga.geom = g_idgeom(&gcp->geom);
170 	ga.provider = g_idprovider(&gcp->provider);
171 	ga.len = gcp->len;
172 	if (gcp->len > 64 * 1024)
173 		return (EINVAL);
174 	else if (gcp->len == 0) {
175 		ga.ptr = NULL;
176 	} else {
177 		ga.ptr = g_malloc(gcp->len, 0);
178 		error = copyin(gcp->ptr, ga.ptr, gcp->len);
179 		if (error) {
180 			g_free(ga.ptr);
181 			return (error);
182 		}
183 	}
184 	ga.flag = gcp->flag;
185 	error = ga.class->config(&ga);
186 	if (gcp->len != 0)
187 		copyout(ga.ptr, gcp->ptr, gcp->len);	/* Ignore error */
188 	gcp->class.u.id = (uintptr_t)ga.class;
189 	gcp->class.len = 0;
190 	gcp->geom.u.id = (uintptr_t)ga.geom;
191 	gcp->geom.len = 0;
192 	gcp->provider.u.id = (uintptr_t)ga.provider;
193 	gcp->provider.len = 0;
194 	return(error);
195 }
196 
197 static int
198 g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
199 {
200 	int error;
201 
202 	DROP_GIANT();
203 	g_topology_lock();
204 	switch(cmd) {
205 	case GEOMCONFIGGEOM:
206 		error = g_ctl_ioctl_configgeom(dev, cmd, data, fflag, td);
207 		break;
208 	default:
209 		error = ENOTTY;
210 		break;
211 	}
212 	g_topology_unlock();
213 	PICKUP_GIANT();
214 	return (error);
215 
216 }
217