Deleted Added
full compact
geom_disk.c (248516) geom_disk.c (248694)
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
36#include <sys/cdefs.h>
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
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/sys/geom/geom_disk.c 248516 2013-03-19 14:49:15Z kib $");
37__FBSDID("$FreeBSD: head/sys/geom/geom_disk.c 248694 2013-03-25 05:45:24Z mav $");
38
39#include "opt_geom.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/kernel.h>
44#include <sys/sysctl.h>
45#include <sys/bio.h>
46#include <sys/ctype.h>
47#include <sys/fcntl.h>
48#include <sys/malloc.h>
49#include <sys/sbuf.h>
50#include <sys/sysctl.h>
51#include <sys/devicestat.h>
52#include <machine/md_var.h>
53
54#include <sys/lock.h>
55#include <sys/mutex.h>
56#include <geom/geom.h>
57#include <geom/geom_disk.h>
58#include <geom/geom_int.h>
59
60#include <dev/led/led.h>
61
62struct g_disk_softc {
38
39#include "opt_geom.h"
40
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/kernel.h>
44#include <sys/sysctl.h>
45#include <sys/bio.h>
46#include <sys/ctype.h>
47#include <sys/fcntl.h>
48#include <sys/malloc.h>
49#include <sys/sbuf.h>
50#include <sys/sysctl.h>
51#include <sys/devicestat.h>
52#include <machine/md_var.h>
53
54#include <sys/lock.h>
55#include <sys/mutex.h>
56#include <geom/geom.h>
57#include <geom/geom_disk.h>
58#include <geom/geom_int.h>
59
60#include <dev/led/led.h>
61
62struct g_disk_softc {
63 struct mtx done_mtx;
63 struct disk *dp;
64 struct sysctl_ctx_list sysctl_ctx;
65 struct sysctl_oid *sysctl_tree;
66 char led[64];
67 uint32_t state;
68};
69
64 struct disk *dp;
65 struct sysctl_ctx_list sysctl_ctx;
66 struct sysctl_oid *sysctl_tree;
67 char led[64];
68 uint32_t state;
69};
70
70static struct mtx g_disk_done_mtx;
71
72static g_access_t g_disk_access;
71static g_access_t g_disk_access;
73static g_init_t g_disk_init;
74static g_fini_t g_disk_fini;
75static g_start_t g_disk_start;
76static g_ioctl_t g_disk_ioctl;
77static g_dumpconf_t g_disk_dumpconf;
78static g_provgone_t g_disk_providergone;
79
80static struct g_class g_disk_class = {
81 .name = "DISK",
82 .version = G_VERSION,
72static g_start_t g_disk_start;
73static g_ioctl_t g_disk_ioctl;
74static g_dumpconf_t g_disk_dumpconf;
75static g_provgone_t g_disk_providergone;
76
77static struct g_class g_disk_class = {
78 .name = "DISK",
79 .version = G_VERSION,
83 .init = g_disk_init,
84 .fini = g_disk_fini,
85 .start = g_disk_start,
86 .access = g_disk_access,
87 .ioctl = g_disk_ioctl,
88 .providergone = g_disk_providergone,
89 .dumpconf = g_disk_dumpconf,
90};
91
92SYSCTL_DECL(_kern_geom);
93static SYSCTL_NODE(_kern_geom, OID_AUTO, disk, CTLFLAG_RW, 0,
94 "GEOM_DISK stuff");
95
80 .start = g_disk_start,
81 .access = g_disk_access,
82 .ioctl = g_disk_ioctl,
83 .providergone = g_disk_providergone,
84 .dumpconf = g_disk_dumpconf,
85};
86
87SYSCTL_DECL(_kern_geom);
88static SYSCTL_NODE(_kern_geom, OID_AUTO, disk, CTLFLAG_RW, 0,
89 "GEOM_DISK stuff");
90
96static void
97g_disk_init(struct g_class *mp __unused)
98{
99
100 mtx_init(&g_disk_done_mtx, "g_disk_done", NULL, MTX_DEF);
101}
102
103static void
104g_disk_fini(struct g_class *mp __unused)
105{
106
107 mtx_destroy(&g_disk_done_mtx);
108}
109
110DECLARE_GEOM_CLASS(g_disk_class, g_disk);
111
112static void __inline
113g_disk_lock_giant(struct disk *dp)
114{
115
116 if (dp->d_flags & DISKFLAG_NEEDSGIANT)
117 mtx_lock(&Giant);
118}
119
120static void __inline
121g_disk_unlock_giant(struct disk *dp)
122{
123
124 if (dp->d_flags & DISKFLAG_NEEDSGIANT)
125 mtx_unlock(&Giant);
126}
127
128static int
129g_disk_access(struct g_provider *pp, int r, int w, int e)
130{
131 struct disk *dp;
132 struct g_disk_softc *sc;
133 int error;
134
135 g_trace(G_T_ACCESS, "g_disk_access(%s, %d, %d, %d)",
136 pp->name, r, w, e);
137 g_topology_assert();
91DECLARE_GEOM_CLASS(g_disk_class, g_disk);
92
93static void __inline
94g_disk_lock_giant(struct disk *dp)
95{
96
97 if (dp->d_flags & DISKFLAG_NEEDSGIANT)
98 mtx_lock(&Giant);
99}
100
101static void __inline
102g_disk_unlock_giant(struct disk *dp)
103{
104
105 if (dp->d_flags & DISKFLAG_NEEDSGIANT)
106 mtx_unlock(&Giant);
107}
108
109static int
110g_disk_access(struct g_provider *pp, int r, int w, int e)
111{
112 struct disk *dp;
113 struct g_disk_softc *sc;
114 int error;
115
116 g_trace(G_T_ACCESS, "g_disk_access(%s, %d, %d, %d)",
117 pp->name, r, w, e);
118 g_topology_assert();
138 sc = pp->geom->softc;
119 sc = pp->private;
139 if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
140 /*
141 * Allow decreasing access count even if disk is not
142 * avaliable anymore.
143 */
144 if (r <= 0 && w <= 0 && e <= 0)
145 return (0);
146 return (ENXIO);
147 }
148 r += pp->acr;
149 w += pp->acw;
150 e += pp->ace;
151 error = 0;
152 if ((pp->acr + pp->acw + pp->ace) == 0 && (r + w + e) > 0) {
153 if (dp->d_open != NULL) {
154 g_disk_lock_giant(dp);
155 error = dp->d_open(dp);
156 if (bootverbose && error != 0)
157 printf("Opened disk %s -> %d\n",
158 pp->name, error);
159 g_disk_unlock_giant(dp);
160 }
161 pp->mediasize = dp->d_mediasize;
162 pp->sectorsize = dp->d_sectorsize;
163 pp->stripeoffset = dp->d_stripeoffset;
164 pp->stripesize = dp->d_stripesize;
165 dp->d_flags |= DISKFLAG_OPEN;
166 if (dp->d_maxsize == 0) {
167 printf("WARNING: Disk drive %s%d has no d_maxsize\n",
168 dp->d_name, dp->d_unit);
169 dp->d_maxsize = DFLTPHYS;
170 }
171 } else if ((pp->acr + pp->acw + pp->ace) > 0 && (r + w + e) == 0) {
172 if (dp->d_close != NULL) {
173 g_disk_lock_giant(dp);
174 error = dp->d_close(dp);
175 if (error != 0)
176 printf("Closed disk %s -> %d\n",
177 pp->name, error);
178 g_disk_unlock_giant(dp);
179 }
180 sc->state = G_STATE_ACTIVE;
181 if (sc->led[0] != 0)
182 led_set(sc->led, "0");
183 dp->d_flags &= ~DISKFLAG_OPEN;
184 }
185 return (error);
186}
187
188static void
189g_disk_kerneldump(struct bio *bp, struct disk *dp)
190{
191 struct g_kerneldump *gkd;
192 struct g_geom *gp;
193
194 gkd = (struct g_kerneldump*)bp->bio_data;
195 gp = bp->bio_to->geom;
196 g_trace(G_T_TOPOLOGY, "g_disk_kernedump(%s, %jd, %jd)",
197 gp->name, (intmax_t)gkd->offset, (intmax_t)gkd->length);
198 if (dp->d_dump == NULL) {
199 g_io_deliver(bp, ENODEV);
200 return;
201 }
202 gkd->di.dumper = dp->d_dump;
203 gkd->di.priv = dp;
204 gkd->di.blocksize = dp->d_sectorsize;
205 gkd->di.maxiosize = dp->d_maxsize;
206 gkd->di.mediaoffset = gkd->offset;
207 if ((gkd->offset + gkd->length) > dp->d_mediasize)
208 gkd->length = dp->d_mediasize - gkd->offset;
209 gkd->di.mediasize = gkd->length;
210 g_io_deliver(bp, 0);
211}
212
213static void
214g_disk_setstate(struct bio *bp, struct g_disk_softc *sc)
215{
216 const char *cmd;
217
218 memcpy(&sc->state, bp->bio_data, sizeof(sc->state));
219 if (sc->led[0] != 0) {
220 switch (sc->state) {
221 case G_STATE_FAILED:
222 cmd = "1";
223 break;
224 case G_STATE_REBUILD:
225 cmd = "f5";
226 break;
227 case G_STATE_RESYNC:
228 cmd = "f1";
229 break;
230 default:
231 cmd = "0";
232 break;
233 }
234 led_set(sc->led, cmd);
235 }
236 g_io_deliver(bp, 0);
237}
238
239static void
240g_disk_done(struct bio *bp)
241{
242 struct bio *bp2;
120 if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
121 /*
122 * Allow decreasing access count even if disk is not
123 * avaliable anymore.
124 */
125 if (r <= 0 && w <= 0 && e <= 0)
126 return (0);
127 return (ENXIO);
128 }
129 r += pp->acr;
130 w += pp->acw;
131 e += pp->ace;
132 error = 0;
133 if ((pp->acr + pp->acw + pp->ace) == 0 && (r + w + e) > 0) {
134 if (dp->d_open != NULL) {
135 g_disk_lock_giant(dp);
136 error = dp->d_open(dp);
137 if (bootverbose && error != 0)
138 printf("Opened disk %s -> %d\n",
139 pp->name, error);
140 g_disk_unlock_giant(dp);
141 }
142 pp->mediasize = dp->d_mediasize;
143 pp->sectorsize = dp->d_sectorsize;
144 pp->stripeoffset = dp->d_stripeoffset;
145 pp->stripesize = dp->d_stripesize;
146 dp->d_flags |= DISKFLAG_OPEN;
147 if (dp->d_maxsize == 0) {
148 printf("WARNING: Disk drive %s%d has no d_maxsize\n",
149 dp->d_name, dp->d_unit);
150 dp->d_maxsize = DFLTPHYS;
151 }
152 } else if ((pp->acr + pp->acw + pp->ace) > 0 && (r + w + e) == 0) {
153 if (dp->d_close != NULL) {
154 g_disk_lock_giant(dp);
155 error = dp->d_close(dp);
156 if (error != 0)
157 printf("Closed disk %s -> %d\n",
158 pp->name, error);
159 g_disk_unlock_giant(dp);
160 }
161 sc->state = G_STATE_ACTIVE;
162 if (sc->led[0] != 0)
163 led_set(sc->led, "0");
164 dp->d_flags &= ~DISKFLAG_OPEN;
165 }
166 return (error);
167}
168
169static void
170g_disk_kerneldump(struct bio *bp, struct disk *dp)
171{
172 struct g_kerneldump *gkd;
173 struct g_geom *gp;
174
175 gkd = (struct g_kerneldump*)bp->bio_data;
176 gp = bp->bio_to->geom;
177 g_trace(G_T_TOPOLOGY, "g_disk_kernedump(%s, %jd, %jd)",
178 gp->name, (intmax_t)gkd->offset, (intmax_t)gkd->length);
179 if (dp->d_dump == NULL) {
180 g_io_deliver(bp, ENODEV);
181 return;
182 }
183 gkd->di.dumper = dp->d_dump;
184 gkd->di.priv = dp;
185 gkd->di.blocksize = dp->d_sectorsize;
186 gkd->di.maxiosize = dp->d_maxsize;
187 gkd->di.mediaoffset = gkd->offset;
188 if ((gkd->offset + gkd->length) > dp->d_mediasize)
189 gkd->length = dp->d_mediasize - gkd->offset;
190 gkd->di.mediasize = gkd->length;
191 g_io_deliver(bp, 0);
192}
193
194static void
195g_disk_setstate(struct bio *bp, struct g_disk_softc *sc)
196{
197 const char *cmd;
198
199 memcpy(&sc->state, bp->bio_data, sizeof(sc->state));
200 if (sc->led[0] != 0) {
201 switch (sc->state) {
202 case G_STATE_FAILED:
203 cmd = "1";
204 break;
205 case G_STATE_REBUILD:
206 cmd = "f5";
207 break;
208 case G_STATE_RESYNC:
209 cmd = "f1";
210 break;
211 default:
212 cmd = "0";
213 break;
214 }
215 led_set(sc->led, cmd);
216 }
217 g_io_deliver(bp, 0);
218}
219
220static void
221g_disk_done(struct bio *bp)
222{
223 struct bio *bp2;
243 struct disk *dp;
244 struct g_disk_softc *sc;
245
246 /* See "notes" for why we need a mutex here */
247 /* XXX: will witness accept a mix of Giant/unGiant drivers here ? */
224 struct g_disk_softc *sc;
225
226 /* See "notes" for why we need a mutex here */
227 /* XXX: will witness accept a mix of Giant/unGiant drivers here ? */
248 mtx_lock(&g_disk_done_mtx);
249 bp->bio_completed = bp->bio_length - bp->bio_resid;
250
251 bp2 = bp->bio_parent;
228 bp2 = bp->bio_parent;
229 sc = bp2->bio_to->private;
230 bp->bio_completed = bp->bio_length - bp->bio_resid;
231 mtx_lock(&sc->done_mtx);
252 if (bp2->bio_error == 0)
253 bp2->bio_error = bp->bio_error;
254 bp2->bio_completed += bp->bio_completed;
232 if (bp2->bio_error == 0)
233 bp2->bio_error = bp->bio_error;
234 bp2->bio_completed += bp->bio_completed;
255 if ((bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) != 0 &&
256 (sc = bp2->bio_to->geom->softc) != NULL &&
257 (dp = sc->dp) != NULL) {
258 devstat_end_transaction_bio(dp->d_devstat, bp);
259 }
235 if ((bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) != 0)
236 devstat_end_transaction_bio(sc->dp->d_devstat, bp);
260 g_destroy_bio(bp);
261 bp2->bio_inbed++;
262 if (bp2->bio_children == bp2->bio_inbed) {
263 bp2->bio_resid = bp2->bio_bcount - bp2->bio_completed;
264 g_io_deliver(bp2, bp2->bio_error);
265 }
237 g_destroy_bio(bp);
238 bp2->bio_inbed++;
239 if (bp2->bio_children == bp2->bio_inbed) {
240 bp2->bio_resid = bp2->bio_bcount - bp2->bio_completed;
241 g_io_deliver(bp2, bp2->bio_error);
242 }
266 mtx_unlock(&g_disk_done_mtx);
243 mtx_unlock(&sc->done_mtx);
267}
268
269static int
270g_disk_ioctl(struct g_provider *pp, u_long cmd, void * data, int fflag, struct thread *td)
271{
244}
245
246static int
247g_disk_ioctl(struct g_provider *pp, u_long cmd, void * data, int fflag, struct thread *td)
248{
272 struct g_geom *gp;
273 struct disk *dp;
274 struct g_disk_softc *sc;
275 int error;
276
249 struct disk *dp;
250 struct g_disk_softc *sc;
251 int error;
252
277 gp = pp->geom;
278 sc = gp->softc;
253 sc = pp->private;
279 dp = sc->dp;
280
281 if (dp->d_ioctl == NULL)
282 return (ENOIOCTL);
283 g_disk_lock_giant(dp);
284 error = dp->d_ioctl(dp, cmd, data, fflag, td);
285 g_disk_unlock_giant(dp);
286 return (error);
287}
288
289static void
290g_disk_start(struct bio *bp)
291{
292 struct bio *bp2, *bp3;
293 struct disk *dp;
294 struct g_disk_softc *sc;
295 int error;
296 off_t off;
297
254 dp = sc->dp;
255
256 if (dp->d_ioctl == NULL)
257 return (ENOIOCTL);
258 g_disk_lock_giant(dp);
259 error = dp->d_ioctl(dp, cmd, data, fflag, td);
260 g_disk_unlock_giant(dp);
261 return (error);
262}
263
264static void
265g_disk_start(struct bio *bp)
266{
267 struct bio *bp2, *bp3;
268 struct disk *dp;
269 struct g_disk_softc *sc;
270 int error;
271 off_t off;
272
298 sc = bp->bio_to->geom->softc;
273 sc = bp->bio_to->private;
299 if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
300 g_io_deliver(bp, ENXIO);
301 return;
302 }
303 error = EJUSTRETURN;
304 switch(bp->bio_cmd) {
305 case BIO_DELETE:
306 if (!(dp->d_flags & DISKFLAG_CANDELETE)) {
307 error = EOPNOTSUPP;
308 break;
309 }
310 /* fall-through */
311 case BIO_READ:
312 case BIO_WRITE:
313 off = 0;
314 bp3 = NULL;
315 bp2 = g_clone_bio(bp);
316 if (bp2 == NULL) {
317 error = ENOMEM;
318 break;
319 }
320 do {
321 bp2->bio_offset += off;
322 bp2->bio_length -= off;
323 if ((bp->bio_flags & BIO_UNMAPPED) == 0) {
324 bp2->bio_data += off;
325 } else {
326 KASSERT((dp->d_flags & DISKFLAG_UNMAPPED_BIO)
327 != 0,
328 ("unmapped bio not supported by disk %s",
329 dp->d_name));
330 bp2->bio_ma += off / PAGE_SIZE;
331 bp2->bio_ma_offset += off;
332 bp2->bio_ma_offset %= PAGE_SIZE;
333 bp2->bio_ma_n -= off / PAGE_SIZE;
334 }
335 if (bp2->bio_length > dp->d_maxsize) {
336 /*
337 * XXX: If we have a stripesize we should really
338 * use it here.
339 */
340 bp2->bio_length = dp->d_maxsize;
341 if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
342 bp2->bio_ma_n = howmany(
343 bp2->bio_ma_offset +
344 bp2->bio_length, PAGE_SIZE);
345 }
346 off += dp->d_maxsize;
347 /*
348 * To avoid a race, we need to grab the next bio
349 * before we schedule this one. See "notes".
350 */
351 bp3 = g_clone_bio(bp);
352 if (bp3 == NULL)
353 bp->bio_error = ENOMEM;
354 }
355 bp2->bio_done = g_disk_done;
356 bp2->bio_pblkno = bp2->bio_offset / dp->d_sectorsize;
357 bp2->bio_bcount = bp2->bio_length;
358 bp2->bio_disk = dp;
359 devstat_start_transaction_bio(dp->d_devstat, bp2);
360 g_disk_lock_giant(dp);
361 dp->d_strategy(bp2);
362 g_disk_unlock_giant(dp);
363 bp2 = bp3;
364 bp3 = NULL;
365 } while (bp2 != NULL);
366 break;
367 case BIO_GETATTR:
368 /* Give the driver a chance to override */
369 if (dp->d_getattr != NULL) {
370 if (bp->bio_disk == NULL)
371 bp->bio_disk = dp;
372 error = dp->d_getattr(bp);
373 if (error != -1)
374 break;
375 error = EJUSTRETURN;
376 }
377 if (g_handleattr_int(bp, "GEOM::candelete",
378 (dp->d_flags & DISKFLAG_CANDELETE) != 0))
379 break;
380 else if (g_handleattr_int(bp, "GEOM::fwsectors",
381 dp->d_fwsectors))
382 break;
383 else if (g_handleattr_int(bp, "GEOM::fwheads", dp->d_fwheads))
384 break;
385 else if (g_handleattr_off_t(bp, "GEOM::frontstuff", 0))
386 break;
387 else if (g_handleattr_str(bp, "GEOM::ident", dp->d_ident))
388 break;
389 else if (g_handleattr(bp, "GEOM::hba_vendor",
390 &dp->d_hba_vendor, 2))
391 break;
392 else if (g_handleattr(bp, "GEOM::hba_device",
393 &dp->d_hba_device, 2))
394 break;
395 else if (g_handleattr(bp, "GEOM::hba_subvendor",
396 &dp->d_hba_subvendor, 2))
397 break;
398 else if (g_handleattr(bp, "GEOM::hba_subdevice",
399 &dp->d_hba_subdevice, 2))
400 break;
401 else if (!strcmp(bp->bio_attribute, "GEOM::kerneldump"))
402 g_disk_kerneldump(bp, dp);
403 else if (!strcmp(bp->bio_attribute, "GEOM::setstate"))
404 g_disk_setstate(bp, sc);
405 else
406 error = ENOIOCTL;
407 break;
408 case BIO_FLUSH:
409 g_trace(G_T_BIO, "g_disk_flushcache(%s)",
410 bp->bio_to->name);
411 if (!(dp->d_flags & DISKFLAG_CANFLUSHCACHE)) {
412 error = EOPNOTSUPP;
413 break;
414 }
415 bp2 = g_clone_bio(bp);
416 if (bp2 == NULL) {
417 g_io_deliver(bp, ENOMEM);
418 return;
419 }
420 bp2->bio_done = g_disk_done;
421 bp2->bio_disk = dp;
422 g_disk_lock_giant(dp);
423 dp->d_strategy(bp2);
424 g_disk_unlock_giant(dp);
425 break;
426 default:
427 error = EOPNOTSUPP;
428 break;
429 }
430 if (error != EJUSTRETURN)
431 g_io_deliver(bp, error);
432 return;
433}
434
435static void
436g_disk_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
437{
438 struct disk *dp;
439 struct g_disk_softc *sc;
440
441 sc = gp->softc;
442 if (sc == NULL || (dp = sc->dp) == NULL)
443 return;
444 if (indent == NULL) {
445 sbuf_printf(sb, " hd %u", dp->d_fwheads);
446 sbuf_printf(sb, " sc %u", dp->d_fwsectors);
447 return;
448 }
449 if (pp != NULL) {
450 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n",
451 indent, dp->d_fwheads);
452 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n",
453 indent, dp->d_fwsectors);
454 sbuf_printf(sb, "%s<ident>%s</ident>\n", indent, dp->d_ident);
455 sbuf_printf(sb, "%s<descr>%s</descr>\n", indent, dp->d_descr);
456 }
457}
458
459static void
460g_disk_resize(void *ptr, int flag)
461{
462 struct disk *dp;
463 struct g_geom *gp;
464 struct g_provider *pp;
465
466 if (flag == EV_CANCEL)
467 return;
468 g_topology_assert();
469
470 dp = ptr;
471 gp = dp->d_geom;
472
473 if (dp->d_destroyed || gp == NULL)
474 return;
475
476 LIST_FOREACH(pp, &gp->provider, provider) {
477 if (pp->sectorsize != 0 &&
478 pp->sectorsize != dp->d_sectorsize)
479 g_wither_provider(pp, ENXIO);
480 else
481 g_resize_provider(pp, dp->d_mediasize);
482 }
483}
484
485static void
486g_disk_create(void *arg, int flag)
487{
488 struct g_geom *gp;
489 struct g_provider *pp;
490 struct disk *dp;
491 struct g_disk_softc *sc;
492 char tmpstr[80];
493
494 if (flag == EV_CANCEL)
495 return;
496 g_topology_assert();
497 dp = arg;
498 sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
274 if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
275 g_io_deliver(bp, ENXIO);
276 return;
277 }
278 error = EJUSTRETURN;
279 switch(bp->bio_cmd) {
280 case BIO_DELETE:
281 if (!(dp->d_flags & DISKFLAG_CANDELETE)) {
282 error = EOPNOTSUPP;
283 break;
284 }
285 /* fall-through */
286 case BIO_READ:
287 case BIO_WRITE:
288 off = 0;
289 bp3 = NULL;
290 bp2 = g_clone_bio(bp);
291 if (bp2 == NULL) {
292 error = ENOMEM;
293 break;
294 }
295 do {
296 bp2->bio_offset += off;
297 bp2->bio_length -= off;
298 if ((bp->bio_flags & BIO_UNMAPPED) == 0) {
299 bp2->bio_data += off;
300 } else {
301 KASSERT((dp->d_flags & DISKFLAG_UNMAPPED_BIO)
302 != 0,
303 ("unmapped bio not supported by disk %s",
304 dp->d_name));
305 bp2->bio_ma += off / PAGE_SIZE;
306 bp2->bio_ma_offset += off;
307 bp2->bio_ma_offset %= PAGE_SIZE;
308 bp2->bio_ma_n -= off / PAGE_SIZE;
309 }
310 if (bp2->bio_length > dp->d_maxsize) {
311 /*
312 * XXX: If we have a stripesize we should really
313 * use it here.
314 */
315 bp2->bio_length = dp->d_maxsize;
316 if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
317 bp2->bio_ma_n = howmany(
318 bp2->bio_ma_offset +
319 bp2->bio_length, PAGE_SIZE);
320 }
321 off += dp->d_maxsize;
322 /*
323 * To avoid a race, we need to grab the next bio
324 * before we schedule this one. See "notes".
325 */
326 bp3 = g_clone_bio(bp);
327 if (bp3 == NULL)
328 bp->bio_error = ENOMEM;
329 }
330 bp2->bio_done = g_disk_done;
331 bp2->bio_pblkno = bp2->bio_offset / dp->d_sectorsize;
332 bp2->bio_bcount = bp2->bio_length;
333 bp2->bio_disk = dp;
334 devstat_start_transaction_bio(dp->d_devstat, bp2);
335 g_disk_lock_giant(dp);
336 dp->d_strategy(bp2);
337 g_disk_unlock_giant(dp);
338 bp2 = bp3;
339 bp3 = NULL;
340 } while (bp2 != NULL);
341 break;
342 case BIO_GETATTR:
343 /* Give the driver a chance to override */
344 if (dp->d_getattr != NULL) {
345 if (bp->bio_disk == NULL)
346 bp->bio_disk = dp;
347 error = dp->d_getattr(bp);
348 if (error != -1)
349 break;
350 error = EJUSTRETURN;
351 }
352 if (g_handleattr_int(bp, "GEOM::candelete",
353 (dp->d_flags & DISKFLAG_CANDELETE) != 0))
354 break;
355 else if (g_handleattr_int(bp, "GEOM::fwsectors",
356 dp->d_fwsectors))
357 break;
358 else if (g_handleattr_int(bp, "GEOM::fwheads", dp->d_fwheads))
359 break;
360 else if (g_handleattr_off_t(bp, "GEOM::frontstuff", 0))
361 break;
362 else if (g_handleattr_str(bp, "GEOM::ident", dp->d_ident))
363 break;
364 else if (g_handleattr(bp, "GEOM::hba_vendor",
365 &dp->d_hba_vendor, 2))
366 break;
367 else if (g_handleattr(bp, "GEOM::hba_device",
368 &dp->d_hba_device, 2))
369 break;
370 else if (g_handleattr(bp, "GEOM::hba_subvendor",
371 &dp->d_hba_subvendor, 2))
372 break;
373 else if (g_handleattr(bp, "GEOM::hba_subdevice",
374 &dp->d_hba_subdevice, 2))
375 break;
376 else if (!strcmp(bp->bio_attribute, "GEOM::kerneldump"))
377 g_disk_kerneldump(bp, dp);
378 else if (!strcmp(bp->bio_attribute, "GEOM::setstate"))
379 g_disk_setstate(bp, sc);
380 else
381 error = ENOIOCTL;
382 break;
383 case BIO_FLUSH:
384 g_trace(G_T_BIO, "g_disk_flushcache(%s)",
385 bp->bio_to->name);
386 if (!(dp->d_flags & DISKFLAG_CANFLUSHCACHE)) {
387 error = EOPNOTSUPP;
388 break;
389 }
390 bp2 = g_clone_bio(bp);
391 if (bp2 == NULL) {
392 g_io_deliver(bp, ENOMEM);
393 return;
394 }
395 bp2->bio_done = g_disk_done;
396 bp2->bio_disk = dp;
397 g_disk_lock_giant(dp);
398 dp->d_strategy(bp2);
399 g_disk_unlock_giant(dp);
400 break;
401 default:
402 error = EOPNOTSUPP;
403 break;
404 }
405 if (error != EJUSTRETURN)
406 g_io_deliver(bp, error);
407 return;
408}
409
410static void
411g_disk_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
412{
413 struct disk *dp;
414 struct g_disk_softc *sc;
415
416 sc = gp->softc;
417 if (sc == NULL || (dp = sc->dp) == NULL)
418 return;
419 if (indent == NULL) {
420 sbuf_printf(sb, " hd %u", dp->d_fwheads);
421 sbuf_printf(sb, " sc %u", dp->d_fwsectors);
422 return;
423 }
424 if (pp != NULL) {
425 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n",
426 indent, dp->d_fwheads);
427 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n",
428 indent, dp->d_fwsectors);
429 sbuf_printf(sb, "%s<ident>%s</ident>\n", indent, dp->d_ident);
430 sbuf_printf(sb, "%s<descr>%s</descr>\n", indent, dp->d_descr);
431 }
432}
433
434static void
435g_disk_resize(void *ptr, int flag)
436{
437 struct disk *dp;
438 struct g_geom *gp;
439 struct g_provider *pp;
440
441 if (flag == EV_CANCEL)
442 return;
443 g_topology_assert();
444
445 dp = ptr;
446 gp = dp->d_geom;
447
448 if (dp->d_destroyed || gp == NULL)
449 return;
450
451 LIST_FOREACH(pp, &gp->provider, provider) {
452 if (pp->sectorsize != 0 &&
453 pp->sectorsize != dp->d_sectorsize)
454 g_wither_provider(pp, ENXIO);
455 else
456 g_resize_provider(pp, dp->d_mediasize);
457 }
458}
459
460static void
461g_disk_create(void *arg, int flag)
462{
463 struct g_geom *gp;
464 struct g_provider *pp;
465 struct disk *dp;
466 struct g_disk_softc *sc;
467 char tmpstr[80];
468
469 if (flag == EV_CANCEL)
470 return;
471 g_topology_assert();
472 dp = arg;
473 sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
474 mtx_init(&sc->done_mtx, "g_disk_done", NULL, MTX_DEF);
499 sc->dp = dp;
500 gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit);
501 gp->softc = sc;
502 pp = g_new_providerf(gp, "%s", gp->name);
503 pp->mediasize = dp->d_mediasize;
504 pp->sectorsize = dp->d_sectorsize;
505 pp->stripeoffset = dp->d_stripeoffset;
506 pp->stripesize = dp->d_stripesize;
507 if ((dp->d_flags & DISKFLAG_UNMAPPED_BIO) != 0)
508 pp->flags |= G_PF_ACCEPT_UNMAPPED;
509 if (bootverbose)
510 printf("GEOM: new disk %s\n", gp->name);
511 sysctl_ctx_init(&sc->sysctl_ctx);
512 snprintf(tmpstr, sizeof(tmpstr), "GEOM disk %s", gp->name);
513 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
514 SYSCTL_STATIC_CHILDREN(_kern_geom_disk), OID_AUTO, gp->name,
515 CTLFLAG_RD, 0, tmpstr);
516 if (sc->sysctl_tree != NULL) {
517 snprintf(tmpstr, sizeof(tmpstr),
518 "kern.geom.disk.%s.led", gp->name);
519 TUNABLE_STR_FETCH(tmpstr, sc->led, sizeof(sc->led));
520 SYSCTL_ADD_STRING(&sc->sysctl_ctx,
521 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "led",
522 CTLFLAG_RW | CTLFLAG_TUN, sc->led, sizeof(sc->led),
523 "LED name");
524 }
525 pp->private = sc;
526 dp->d_geom = gp;
527 g_error_provider(pp, 0);
528}
529
530/*
531 * We get this callback after all of the consumers have gone away, and just
532 * before the provider is freed. If the disk driver provided a d_gone
533 * callback, let them know that it is okay to free resources -- they won't
534 * be getting any more accesses from GEOM.
535 */
536static void
537g_disk_providergone(struct g_provider *pp)
538{
539 struct disk *dp;
540 struct g_disk_softc *sc;
541
475 sc->dp = dp;
476 gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit);
477 gp->softc = sc;
478 pp = g_new_providerf(gp, "%s", gp->name);
479 pp->mediasize = dp->d_mediasize;
480 pp->sectorsize = dp->d_sectorsize;
481 pp->stripeoffset = dp->d_stripeoffset;
482 pp->stripesize = dp->d_stripesize;
483 if ((dp->d_flags & DISKFLAG_UNMAPPED_BIO) != 0)
484 pp->flags |= G_PF_ACCEPT_UNMAPPED;
485 if (bootverbose)
486 printf("GEOM: new disk %s\n", gp->name);
487 sysctl_ctx_init(&sc->sysctl_ctx);
488 snprintf(tmpstr, sizeof(tmpstr), "GEOM disk %s", gp->name);
489 sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
490 SYSCTL_STATIC_CHILDREN(_kern_geom_disk), OID_AUTO, gp->name,
491 CTLFLAG_RD, 0, tmpstr);
492 if (sc->sysctl_tree != NULL) {
493 snprintf(tmpstr, sizeof(tmpstr),
494 "kern.geom.disk.%s.led", gp->name);
495 TUNABLE_STR_FETCH(tmpstr, sc->led, sizeof(sc->led));
496 SYSCTL_ADD_STRING(&sc->sysctl_ctx,
497 SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "led",
498 CTLFLAG_RW | CTLFLAG_TUN, sc->led, sizeof(sc->led),
499 "LED name");
500 }
501 pp->private = sc;
502 dp->d_geom = gp;
503 g_error_provider(pp, 0);
504}
505
506/*
507 * We get this callback after all of the consumers have gone away, and just
508 * before the provider is freed. If the disk driver provided a d_gone
509 * callback, let them know that it is okay to free resources -- they won't
510 * be getting any more accesses from GEOM.
511 */
512static void
513g_disk_providergone(struct g_provider *pp)
514{
515 struct disk *dp;
516 struct g_disk_softc *sc;
517
542 sc = (struct g_disk_softc *)pp->geom->softc;
543
544 /*
545 * If the softc is already NULL, then we've probably been through
546 * g_disk_destroy already; there is nothing for us to do anyway.
547 */
548 if (sc == NULL)
549 return;
550
518 sc = (struct g_disk_softc *)pp->private;
551 dp = sc->dp;
519 dp = sc->dp;
552
553 if (dp->d_gone != NULL)
520 if (dp != NULL && dp->d_gone != NULL)
554 dp->d_gone(dp);
521 dp->d_gone(dp);
522 if (sc->sysctl_tree != NULL) {
523 sysctl_ctx_free(&sc->sysctl_ctx);
524 sc->sysctl_tree = NULL;
525 }
526 if (sc->led[0] != 0) {
527 led_set(sc->led, "0");
528 sc->led[0] = 0;
529 }
530 pp->private = NULL;
531 pp->geom->softc = NULL;
532 mtx_destroy(&sc->done_mtx);
533 g_free(sc);
555}
556
557static void
558g_disk_destroy(void *ptr, int flag)
559{
560 struct disk *dp;
561 struct g_geom *gp;
562 struct g_disk_softc *sc;
563
564 g_topology_assert();
565 dp = ptr;
566 gp = dp->d_geom;
567 if (gp != NULL) {
568 sc = gp->softc;
534}
535
536static void
537g_disk_destroy(void *ptr, int flag)
538{
539 struct disk *dp;
540 struct g_geom *gp;
541 struct g_disk_softc *sc;
542
543 g_topology_assert();
544 dp = ptr;
545 gp = dp->d_geom;
546 if (gp != NULL) {
547 sc = gp->softc;
569 if (sc->sysctl_tree != NULL) {
570 sysctl_ctx_free(&sc->sysctl_ctx);
571 sc->sysctl_tree = NULL;
572 }
573 if (sc->led[0] != 0) {
574 led_set(sc->led, "0");
575 sc->led[0] = 0;
576 }
577 g_free(sc);
578 gp->softc = NULL;
548 if (sc != NULL)
549 sc->dp = NULL;
550 dp->d_geom = NULL;
579 g_wither_geom(gp, ENXIO);
580 }
581 g_free(dp);
582}
583
584/*
585 * We only allow printable characters in disk ident,
586 * the rest is converted to 'x<HH>'.
587 */
588static void
589g_disk_ident_adjust(char *ident, size_t size)
590{
591 char *p, tmp[4], newid[DISK_IDENT_SIZE];
592
593 newid[0] = '\0';
594 for (p = ident; *p != '\0'; p++) {
595 if (isprint(*p)) {
596 tmp[0] = *p;
597 tmp[1] = '\0';
598 } else {
599 snprintf(tmp, sizeof(tmp), "x%02hhx",
600 *(unsigned char *)p);
601 }
602 if (strlcat(newid, tmp, sizeof(newid)) >= sizeof(newid))
603 break;
604 }
605 bzero(ident, size);
606 strlcpy(ident, newid, size);
607}
608
609struct disk *
610disk_alloc(void)
611{
612
613 return (g_malloc(sizeof(struct disk), M_WAITOK | M_ZERO));
614}
615
616void
617disk_create(struct disk *dp, int version)
618{
619
620 if (version != DISK_VERSION_02) {
621 printf("WARNING: Attempt to add disk %s%d %s",
622 dp->d_name, dp->d_unit,
623 " using incompatible ABI version of disk(9)\n");
624 printf("WARNING: Ignoring disk %s%d\n",
625 dp->d_name, dp->d_unit);
626 return;
627 }
628 KASSERT(dp->d_strategy != NULL, ("disk_create need d_strategy"));
629 KASSERT(dp->d_name != NULL, ("disk_create need d_name"));
630 KASSERT(*dp->d_name != 0, ("disk_create need d_name"));
631 KASSERT(strlen(dp->d_name) < SPECNAMELEN - 4, ("disk name too long"));
632 if (dp->d_devstat == NULL)
633 dp->d_devstat = devstat_new_entry(dp->d_name, dp->d_unit,
634 dp->d_sectorsize, DEVSTAT_ALL_SUPPORTED,
635 DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
636 dp->d_geom = NULL;
637 g_disk_ident_adjust(dp->d_ident, sizeof(dp->d_ident));
638 g_post_event(g_disk_create, dp, M_WAITOK, dp, NULL);
639}
640
641void
642disk_destroy(struct disk *dp)
643{
644
645 g_cancel_event(dp);
646 dp->d_destroyed = 1;
647 if (dp->d_devstat != NULL)
648 devstat_remove_entry(dp->d_devstat);
649 g_post_event(g_disk_destroy, dp, M_WAITOK, NULL);
650}
651
652void
653disk_gone(struct disk *dp)
654{
655 struct g_geom *gp;
656 struct g_provider *pp;
657
658 gp = dp->d_geom;
659 if (gp != NULL) {
660 pp = LIST_FIRST(&gp->provider);
661 if (pp != NULL) {
662 KASSERT(LIST_NEXT(pp, provider) == NULL,
663 ("geom %p has more than one provider", gp));
664 g_wither_provider(pp, ENXIO);
665 }
666 }
667}
668
669void
670disk_attr_changed(struct disk *dp, const char *attr, int flag)
671{
672 struct g_geom *gp;
673 struct g_provider *pp;
674
675 gp = dp->d_geom;
676 if (gp != NULL)
677 LIST_FOREACH(pp, &gp->provider, provider)
678 (void)g_attr_changed(pp, attr, flag);
679}
680
681void
682disk_media_changed(struct disk *dp, int flag)
683{
684 struct g_geom *gp;
685 struct g_provider *pp;
686
687 gp = dp->d_geom;
688 if (gp != NULL) {
689 LIST_FOREACH(pp, &gp->provider, provider)
690 g_media_changed(pp, flag);
691 }
692}
693
694void
695disk_media_gone(struct disk *dp, int flag)
696{
697 struct g_geom *gp;
698 struct g_provider *pp;
699
700 gp = dp->d_geom;
701 if (gp != NULL) {
702 LIST_FOREACH(pp, &gp->provider, provider)
703 g_media_gone(pp, flag);
704 }
705}
706
707int
708disk_resize(struct disk *dp, int flag)
709{
710
711 if (dp->d_destroyed || dp->d_geom == NULL)
712 return (0);
713
714 return (g_post_event(g_disk_resize, dp, flag, NULL));
715}
716
717static void
718g_kern_disks(void *p, int flag __unused)
719{
720 struct sbuf *sb;
721 struct g_geom *gp;
722 char *sp;
723
724 sb = p;
725 sp = "";
726 g_topology_assert();
727 LIST_FOREACH(gp, &g_disk_class.geom, geom) {
728 sbuf_printf(sb, "%s%s", sp, gp->name);
729 sp = " ";
730 }
731 sbuf_finish(sb);
732}
733
734static int
735sysctl_disks(SYSCTL_HANDLER_ARGS)
736{
737 int error;
738 struct sbuf *sb;
739
740 sb = sbuf_new_auto();
741 g_waitfor_event(g_kern_disks, sb, M_WAITOK, NULL);
742 error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
743 sbuf_delete(sb);
744 return error;
745}
746
747SYSCTL_PROC(_kern, OID_AUTO, disks,
748 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
749 sysctl_disks, "A", "names of available disks");
551 g_wither_geom(gp, ENXIO);
552 }
553 g_free(dp);
554}
555
556/*
557 * We only allow printable characters in disk ident,
558 * the rest is converted to 'x<HH>'.
559 */
560static void
561g_disk_ident_adjust(char *ident, size_t size)
562{
563 char *p, tmp[4], newid[DISK_IDENT_SIZE];
564
565 newid[0] = '\0';
566 for (p = ident; *p != '\0'; p++) {
567 if (isprint(*p)) {
568 tmp[0] = *p;
569 tmp[1] = '\0';
570 } else {
571 snprintf(tmp, sizeof(tmp), "x%02hhx",
572 *(unsigned char *)p);
573 }
574 if (strlcat(newid, tmp, sizeof(newid)) >= sizeof(newid))
575 break;
576 }
577 bzero(ident, size);
578 strlcpy(ident, newid, size);
579}
580
581struct disk *
582disk_alloc(void)
583{
584
585 return (g_malloc(sizeof(struct disk), M_WAITOK | M_ZERO));
586}
587
588void
589disk_create(struct disk *dp, int version)
590{
591
592 if (version != DISK_VERSION_02) {
593 printf("WARNING: Attempt to add disk %s%d %s",
594 dp->d_name, dp->d_unit,
595 " using incompatible ABI version of disk(9)\n");
596 printf("WARNING: Ignoring disk %s%d\n",
597 dp->d_name, dp->d_unit);
598 return;
599 }
600 KASSERT(dp->d_strategy != NULL, ("disk_create need d_strategy"));
601 KASSERT(dp->d_name != NULL, ("disk_create need d_name"));
602 KASSERT(*dp->d_name != 0, ("disk_create need d_name"));
603 KASSERT(strlen(dp->d_name) < SPECNAMELEN - 4, ("disk name too long"));
604 if (dp->d_devstat == NULL)
605 dp->d_devstat = devstat_new_entry(dp->d_name, dp->d_unit,
606 dp->d_sectorsize, DEVSTAT_ALL_SUPPORTED,
607 DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
608 dp->d_geom = NULL;
609 g_disk_ident_adjust(dp->d_ident, sizeof(dp->d_ident));
610 g_post_event(g_disk_create, dp, M_WAITOK, dp, NULL);
611}
612
613void
614disk_destroy(struct disk *dp)
615{
616
617 g_cancel_event(dp);
618 dp->d_destroyed = 1;
619 if (dp->d_devstat != NULL)
620 devstat_remove_entry(dp->d_devstat);
621 g_post_event(g_disk_destroy, dp, M_WAITOK, NULL);
622}
623
624void
625disk_gone(struct disk *dp)
626{
627 struct g_geom *gp;
628 struct g_provider *pp;
629
630 gp = dp->d_geom;
631 if (gp != NULL) {
632 pp = LIST_FIRST(&gp->provider);
633 if (pp != NULL) {
634 KASSERT(LIST_NEXT(pp, provider) == NULL,
635 ("geom %p has more than one provider", gp));
636 g_wither_provider(pp, ENXIO);
637 }
638 }
639}
640
641void
642disk_attr_changed(struct disk *dp, const char *attr, int flag)
643{
644 struct g_geom *gp;
645 struct g_provider *pp;
646
647 gp = dp->d_geom;
648 if (gp != NULL)
649 LIST_FOREACH(pp, &gp->provider, provider)
650 (void)g_attr_changed(pp, attr, flag);
651}
652
653void
654disk_media_changed(struct disk *dp, int flag)
655{
656 struct g_geom *gp;
657 struct g_provider *pp;
658
659 gp = dp->d_geom;
660 if (gp != NULL) {
661 LIST_FOREACH(pp, &gp->provider, provider)
662 g_media_changed(pp, flag);
663 }
664}
665
666void
667disk_media_gone(struct disk *dp, int flag)
668{
669 struct g_geom *gp;
670 struct g_provider *pp;
671
672 gp = dp->d_geom;
673 if (gp != NULL) {
674 LIST_FOREACH(pp, &gp->provider, provider)
675 g_media_gone(pp, flag);
676 }
677}
678
679int
680disk_resize(struct disk *dp, int flag)
681{
682
683 if (dp->d_destroyed || dp->d_geom == NULL)
684 return (0);
685
686 return (g_post_event(g_disk_resize, dp, flag, NULL));
687}
688
689static void
690g_kern_disks(void *p, int flag __unused)
691{
692 struct sbuf *sb;
693 struct g_geom *gp;
694 char *sp;
695
696 sb = p;
697 sp = "";
698 g_topology_assert();
699 LIST_FOREACH(gp, &g_disk_class.geom, geom) {
700 sbuf_printf(sb, "%s%s", sp, gp->name);
701 sp = " ";
702 }
703 sbuf_finish(sb);
704}
705
706static int
707sysctl_disks(SYSCTL_HANDLER_ARGS)
708{
709 int error;
710 struct sbuf *sb;
711
712 sb = sbuf_new_auto();
713 g_waitfor_event(g_kern_disks, sb, M_WAITOK, NULL);
714 error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
715 sbuf_delete(sb);
716 return error;
717}
718
719SYSCTL_PROC(_kern, OID_AUTO, disks,
720 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
721 sysctl_disks, "A", "names of available disks");