2 * Copyright (c) 2004, 2005 Lukas Ertl
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
32 #include <sys/errno.h>
33 #include <sys/endian.h>
35 #include <sys/kernel.h>
36 #include <sys/kthread.h>
37 #include <sys/libkern.h>
39 #include <sys/malloc.h>
40 #include <sys/module.h>
41 #include <sys/mutex.h>
43 #include <sys/systm.h>
45 #include <sys/vimage.h>
47 #include <geom/geom.h>
48 #include <geom/vinum/geom_vinum_var.h>
49 #include <geom/vinum/geom_vinum.h>
50 #include <geom/vinum/geom_vinum_share.h>
52 #define GV_LEGACY_I386 0
53 #define GV_LEGACY_AMD64 1
54 #define GV_LEGACY_SPARC64 2
55 #define GV_LEGACY_POWERPC 3
57 static void gv_drive_dead(void *, int);
58 static void gv_drive_worker(void *);
59 static int gv_legacy_header_type(uint8_t *, int);
62 * Here are the "offset (size)" for the various struct gv_hdr fields,
63 * for the legacy i386 (or 32-bit powerpc), legacy amd64 (or sparc64), and
64 * current (cpu & endian agnostic) versions of the on-disk format of the vinum
67 * i386 amd64 current field
68 * -------- -------- -------- -----
69 * 0 ( 8) 0 ( 8) 0 ( 8) magic
70 * 8 ( 4) 8 ( 8) 8 ( 8) config_length
71 * 12 (32) 16 (32) 16 (32) label.sysname
72 * 44 (32) 48 (32) 48 (32) label.name
73 * 76 ( 4) 80 ( 8) 80 ( 8) label.date_of_birth.tv_sec
74 * 80 ( 4) 88 ( 8) 88 ( 8) label.date_of_birth.tv_usec
75 * 84 ( 4) 96 ( 8) 96 ( 8) label.last_update.tv_sec
76 * 88 ( 4) 104 ( 8) 104 ( 8) label.last_update.tv_usec
77 * 92 ( 8) 112 ( 8) 112 ( 8) label.drive_size
78 * ======== ======== ========
79 * 100 120 120 total size
81 * NOTE: i386 and amd64 formats are stored as little-endian; the current
82 * format uses big-endian (network order).
86 /* Checks for legacy format depending on platform. */
88 gv_legacy_header_type(uint8_t *hdr, int bigendian)
91 int arch_32, arch_64, i;
93 /* Set arch according to endianess. */
95 arch_32 = GV_LEGACY_POWERPC;
96 arch_64 = GV_LEGACY_SPARC64;
98 arch_32 = GV_LEGACY_I386;
99 arch_64 = GV_LEGACY_AMD64;
102 /* if non-empty hostname overlaps 64-bit config_length */
103 i32 = (uint32_t *)(hdr + 12);
106 /* check for non-empty hostname */
109 /* check bytes past 32-bit structure */
110 for (i = 100; i < 120; i++)
113 /* check for overlapping timestamp */
114 i32 = (uint32_t *)(hdr + 84);
122 * Read the header while taking magic number into account, and write it to
123 * destination pointer.
126 gv_read_header(struct g_consumer *cp, struct gv_hdr *m_hdr)
128 struct g_provider *pp;
129 uint64_t magic_machdep;
133 #define GV_GET32(endian) \
134 endian##32toh(*((uint32_t *)&d_hdr[off])); \
136 #define GV_GET64(endian) \
137 endian##64toh(*((uint64_t *)&d_hdr[off])); \
140 KASSERT(m_hdr != NULL, ("gv_read_header: null m_hdr"));
141 KASSERT(cp != NULL, ("gv_read_header: null cp"));
143 KASSERT(pp != NULL, ("gv_read_header: null pp"));
145 d_hdr = g_read_data(cp, GV_HDR_OFFSET, pp->sectorsize, NULL);
149 m_hdr->magic = GV_GET64(be);
150 magic_machdep = *((uint64_t *)&d_hdr[0]);
152 * The big endian machines will have a reverse of GV_OLD_MAGIC, so we
153 * need to decide if we are running on a big endian machine as well as
154 * checking the magic against the reverse of GV_OLD_MAGIC.
156 be = (m_hdr->magic == magic_machdep);
157 if (m_hdr->magic == GV_MAGIC) {
158 m_hdr->config_length = GV_GET64(be);
160 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
161 off += GV_HOSTNAME_LEN;
162 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
163 off += GV_MAXDRIVENAME;
164 m_hdr->label.date_of_birth.tv_sec = GV_GET64(be);
165 m_hdr->label.date_of_birth.tv_usec = GV_GET64(be);
166 m_hdr->label.last_update.tv_sec = GV_GET64(be);
167 m_hdr->label.last_update.tv_usec = GV_GET64(be);
168 m_hdr->label.drive_size = GV_GET64(be);
169 } else if (m_hdr->magic != GV_OLD_MAGIC &&
170 m_hdr->magic != le64toh(GV_OLD_MAGIC)) {
171 /* Not a gvinum drive. */
174 } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_SPARC64) {
175 printf("VINUM: detected legacy sparc64 header\n");
176 m_hdr->magic = GV_MAGIC;
177 /* Legacy sparc64 on-disk header */
178 m_hdr->config_length = GV_GET64(be);
179 bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN);
180 off += GV_HOSTNAME_LEN;
181 bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME);
182 off += GV_MAXDRIVENAME;
183 m_hdr->label.date_of_birth.tv_sec = GV_GET64(be);
184 m_hdr->label.date_of_birth.tv_usec = GV_GET64(be);
185 m_hdr->label.last_update.tv_sec = GV_GET64(be);
186 m_hdr->label.last_update.tv_usec = GV_GET64(be);
187 m_hdr->label.drive_size = GV_GET64(be);
188 } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_POWERPC) {
189 printf("VINUM: detected legacy PowerPC header\n");
190 m_hdr->magic = GV_MAGIC;
191 /* legacy 32-bit big endian on-disk header */
192 m_hdr->config_length = GV_GET32(be);
193 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
194 off += GV_HOSTNAME_LEN;
195 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
196 off += GV_MAXDRIVENAME;
197 m_hdr->label.date_of_birth.tv_sec = GV_GET32(be);
198 m_hdr->label.date_of_birth.tv_usec = GV_GET32(be);
199 m_hdr->label.last_update.tv_sec = GV_GET32(be);
200 m_hdr->label.last_update.tv_usec = GV_GET32(be);
201 m_hdr->label.drive_size = GV_GET64(be);
202 } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_I386) {
203 printf("VINUM: detected legacy i386 header\n");
204 m_hdr->magic = GV_MAGIC;
205 /* legacy i386 on-disk header */
206 m_hdr->config_length = GV_GET32(le);
207 bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN);
208 off += GV_HOSTNAME_LEN;
209 bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME);
210 off += GV_MAXDRIVENAME;
211 m_hdr->label.date_of_birth.tv_sec = GV_GET32(le);
212 m_hdr->label.date_of_birth.tv_usec = GV_GET32(le);
213 m_hdr->label.last_update.tv_sec = GV_GET32(le);
214 m_hdr->label.last_update.tv_usec = GV_GET32(le);
215 m_hdr->label.drive_size = GV_GET64(le);
217 printf("VINUM: detected legacy amd64 header\n");
218 m_hdr->magic = GV_MAGIC;
219 /* legacy amd64 on-disk header */
220 m_hdr->config_length = GV_GET64(le);
221 bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN);
222 off += GV_HOSTNAME_LEN;
223 bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME);
224 off += GV_MAXDRIVENAME;
225 m_hdr->label.date_of_birth.tv_sec = GV_GET64(le);
226 m_hdr->label.date_of_birth.tv_usec = GV_GET64(le);
227 m_hdr->label.last_update.tv_sec = GV_GET64(le);
228 m_hdr->label.last_update.tv_usec = GV_GET64(le);
229 m_hdr->label.drive_size = GV_GET64(le);
236 /* Write out the gvinum header. */
238 gv_write_header(struct g_consumer *cp, struct gv_hdr *m_hdr)
240 uint8_t d_hdr[GV_HDR_LEN];
243 #define GV_SET64BE(field) \
245 *((uint64_t *)&d_hdr[off]) = htobe64(field); \
249 KASSERT(m_hdr != NULL, ("gv_write_header: null m_hdr"));
252 memset(d_hdr, 0, GV_HDR_LEN);
253 GV_SET64BE(m_hdr->magic);
254 GV_SET64BE(m_hdr->config_length);
256 bcopy(m_hdr->label.sysname, d_hdr + off, GV_HOSTNAME_LEN);
257 off += GV_HOSTNAME_LEN;
258 bcopy(m_hdr->label.name, d_hdr + off, GV_MAXDRIVENAME);
259 off += GV_MAXDRIVENAME;
260 GV_SET64BE(m_hdr->label.date_of_birth.tv_sec);
261 GV_SET64BE(m_hdr->label.date_of_birth.tv_usec);
262 GV_SET64BE(m_hdr->label.last_update.tv_sec);
263 GV_SET64BE(m_hdr->label.last_update.tv_usec);
264 GV_SET64BE(m_hdr->label.drive_size);
266 ret = g_write_data(cp, GV_HDR_OFFSET, d_hdr, GV_HDR_LEN);
271 gv_config_new_drive(struct gv_drive *d)
274 struct gv_freelist *fl;
276 KASSERT(d != NULL, ("config_new_drive: NULL d"));
278 vhdr = g_malloc(sizeof(*vhdr), M_WAITOK | M_ZERO);
279 vhdr->magic = GV_MAGIC;
280 vhdr->config_length = GV_CFG_LEN;
282 mtx_lock(&hostname_mtx);
283 bcopy(G_hostname, vhdr->label.sysname, GV_HOSTNAME_LEN);
284 mtx_unlock(&hostname_mtx);
285 strncpy(vhdr->label.name, d->name, GV_MAXDRIVENAME);
286 microtime(&vhdr->label.date_of_birth);
290 LIST_INIT(&d->subdisks);
291 LIST_INIT(&d->freelist);
293 fl = g_malloc(sizeof(struct gv_freelist), M_WAITOK | M_ZERO);
294 fl->offset = GV_DATA_START;
296 LIST_INSERT_HEAD(&d->freelist, fl, freelist);
297 d->freelist_entries = 1;
299 d->bqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO);
300 bioq_init(d->bqueue);
301 mtx_init(&d->bqueue_mtx, "gv_drive", NULL, MTX_DEF);
302 kproc_create(gv_drive_worker, d, NULL, 0, 0, "gv_d %s", d->name);
303 d->flags |= GV_DRIVE_THREAD_ACTIVE;
307 gv_save_config_all(struct gv_softc *sc)
313 LIST_FOREACH(d, &sc->drives, drive) {
316 gv_save_config(NULL, d, sc);
320 /* Save the vinum configuration back to disk. */
322 gv_save_config(struct g_consumer *cp, struct gv_drive *d, struct gv_softc *sc)
325 struct g_consumer *cp2;
326 struct gv_hdr *vhdr, *hdr;
332 KASSERT(d != NULL, ("gv_save_config: null d"));
333 KASSERT(sc != NULL, ("gv_save_config: null sc"));
336 * We can't save the config on a drive that isn't up, but drives that
337 * were just created aren't officially up yet, so we check a special
340 if ((d->state != GV_DRIVE_UP) && !(d->flags && GV_DRIVE_NEWBORN))
345 KASSERT(gp != NULL, ("gv_save_config: null gp"));
346 cp2 = LIST_FIRST(&gp->consumer);
347 KASSERT(cp2 != NULL, ("gv_save_config: null cp2"));
351 vhdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);
352 vhdr->magic = GV_MAGIC;
353 vhdr->config_length = GV_CFG_LEN;
357 printf("GEOM_VINUM: drive %s has NULL hdr\n", d->name);
361 microtime(&hdr->label.last_update);
362 bcopy(&hdr->label, &vhdr->label, sizeof(struct gv_label));
364 sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
365 gv_format_config(sc, sb, 1, NULL);
368 error = g_access(cp2, 0, 1, 0);
370 printf("GEOM_VINUM: g_access failed on drive %s, errno %d\n",
379 error = gv_write_header(cp2, vhdr);
381 printf("GEOM_VINUM: writing vhdr failed on drive %s, "
382 "errno %d", d->name, error);
386 error = g_write_data(cp2, GV_CFG_OFFSET, sbuf_data(sb),
389 printf("GEOM_VINUM: writing first config copy failed "
390 "on drive %s, errno %d", d->name, error);
394 error = g_write_data(cp2, GV_CFG_OFFSET + GV_CFG_LEN,
395 sbuf_data(sb), GV_CFG_LEN);
397 printf("GEOM_VINUM: writing second config copy failed "
398 "on drive %s, errno %d", d->name, error);
402 g_access(cp2, 0, -1, 0);
410 /* This resembles g_slice_access(). */
412 gv_drive_access(struct g_provider *pp, int dr, int dw, int de)
415 struct g_consumer *cp;
416 struct g_provider *pp2;
418 struct gv_sd *s, *s2;
422 cp = LIST_FIRST(&gp->consumer);
431 KASSERT(s != NULL, ("gv_drive_access: NULL s"));
433 LIST_FOREACH(s2, &d->subdisks, from_drive) {
436 if (s->drive_offset + s->size <= s2->drive_offset)
438 if (s2->drive_offset + s2->size <= s->drive_offset)
443 KASSERT(s2 != NULL, ("gv_drive_access: NULL s2"));
444 if ((pp->acw + dw) > 0 && pp2->ace > 0)
446 if ((pp->ace + de) > 0 && pp2->acw > 0)
450 error = g_access(cp, dr, dw, de);
455 gv_drive_done(struct bio *bp)
459 /* Put the BIO on the worker queue again. */
460 d = bp->bio_from->geom->softc;
461 bp->bio_cflags |= GV_BIO_DONE;
462 mtx_lock(&d->bqueue_mtx);
463 bioq_insert_tail(d->bqueue, bp);
465 mtx_unlock(&d->bqueue_mtx);
470 gv_drive_start(struct bio *bp)
475 switch (bp->bio_cmd) {
482 g_io_deliver(bp, EOPNOTSUPP);
486 s = bp->bio_to->private;
487 if ((s->state == GV_SD_DOWN) || (s->state == GV_SD_STALE)) {
488 g_io_deliver(bp, ENXIO);
492 d = bp->bio_to->geom->softc;
495 * Put the BIO on the worker queue, where the worker thread will pick
498 mtx_lock(&d->bqueue_mtx);
499 bioq_disksort(d->bqueue, bp);
501 mtx_unlock(&d->bqueue_mtx);
506 gv_drive_worker(void *arg)
508 struct bio *bp, *cbp;
510 struct g_provider *pp;
517 mtx_lock(&d->bqueue_mtx);
519 /* We were signaled to exit. */
520 if (d->flags & GV_DRIVE_THREAD_DIE)
523 /* Take the first BIO from out queue. */
524 bp = bioq_takefirst(d->bqueue);
526 msleep(d, &d->bqueue_mtx, PRIBIO, "-", hz/10);
529 mtx_unlock(&d->bqueue_mtx);
534 /* Completed request. */
535 if (bp->bio_cflags & GV_BIO_DONE) {
536 error = bp->bio_error;
538 /* Deliver the original request. */
541 /* The request had an error, we need to clean up. */
544 gv_set_drive_state(d, GV_DRIVE_DOWN,
545 GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG);
547 g_post_event(gv_drive_dead, d, M_WAITOK, d,
551 /* New request, needs to be sent downwards. */
555 if ((s->state == GV_SD_DOWN) ||
556 (s->state == GV_SD_STALE)) {
557 g_io_deliver(bp, ENXIO);
558 mtx_lock(&d->bqueue_mtx);
561 if (bp->bio_offset > s->size) {
562 g_io_deliver(bp, EINVAL);
563 mtx_lock(&d->bqueue_mtx);
567 cbp = g_clone_bio(bp);
569 g_io_deliver(bp, ENOMEM);
570 mtx_lock(&d->bqueue_mtx);
573 if (cbp->bio_offset + cbp->bio_length > s->size)
574 cbp->bio_length = s->size -
576 cbp->bio_done = gv_drive_done;
577 cbp->bio_offset += s->drive_offset;
578 g_io_request(cbp, LIST_FIRST(&gp->consumer));
581 mtx_lock(&d->bqueue_mtx);
584 while ((bp = bioq_takefirst(d->bqueue)) != NULL) {
585 mtx_unlock(&d->bqueue_mtx);
586 if (bp->bio_cflags & GV_BIO_DONE)
589 g_io_deliver(bp, ENXIO);
590 mtx_lock(&d->bqueue_mtx);
592 mtx_unlock(&d->bqueue_mtx);
593 d->flags |= GV_DRIVE_THREAD_DEAD;
600 gv_drive_orphan(struct g_consumer *cp)
607 g_trace(G_T_TOPOLOGY, "gv_drive_orphan(%s)", gp->name);
610 gv_set_drive_state(d, GV_DRIVE_DOWN,
611 GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG);
612 g_post_event(gv_drive_dead, d, M_WAITOK, d, NULL);
614 g_wither_geom(gp, ENXIO);
617 static struct g_geom *
618 gv_drive_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
620 struct g_geom *gp, *gp2;
621 struct g_consumer *cp;
625 struct gv_freelist *fl;
628 char *buf, errstr[ERRBUFSIZ];
633 g_trace(G_T_TOPOLOGY, "gv_drive_taste(%s, %s)", mp->name, pp->name);
636 /* Find the VINUM class and its associated geom. */
637 gp2 = find_vinum_geom();
642 gp = g_new_geomf(mp, "%s.vinumdrive", pp->name);
643 gp->start = gv_drive_start;
644 gp->orphan = gv_drive_orphan;
645 gp->access = gv_drive_access;
646 gp->start = gv_drive_start;
648 cp = g_new_consumer(gp);
650 error = g_access(cp, 1, 0, 0);
653 g_destroy_consumer(cp);
660 /* Now check if the provided slice is a valid vinum drive. */
662 vhdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO);
663 error = gv_read_header(cp, vhdr);
669 /* A valid vinum drive, let's parse the on-disk information. */
670 buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, NULL);
676 gv_parse_config(sc, buf, 1);
680 * Let's see if this drive is already known in the
683 d = gv_find_drive(sc, vhdr->label.name);
685 /* We already know about this drive. */
687 /* Check if this drive already has a geom. */
688 if (d->geom != NULL) {
693 bcopy(vhdr, d->hdr, sizeof(*vhdr));
696 /* This is a new drive. */
698 d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO);
700 /* Initialize all needed variables. */
701 d->size = pp->mediasize - GV_DATA_START;
704 strncpy(d->name, vhdr->label.name, GV_MAXDRIVENAME);
705 LIST_INIT(&d->subdisks);
706 LIST_INIT(&d->freelist);
708 /* We also need a freelist entry. */
709 fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO);
710 fl->offset = GV_DATA_START;
712 LIST_INSERT_HEAD(&d->freelist, fl, freelist);
713 d->freelist_entries = 1;
715 /* Save it into the main configuration. */
716 LIST_INSERT_HEAD(&sc->drives, d, drive);
720 * Create bio queue, queue mutex and a worker thread, if
723 if (d->bqueue == NULL) {
724 d->bqueue = g_malloc(sizeof(struct bio_queue_head),
726 bioq_init(d->bqueue);
728 if (mtx_initialized(&d->bqueue_mtx) == 0)
729 mtx_init(&d->bqueue_mtx, "gv_drive", NULL, MTX_DEF);
731 if (!(d->flags & GV_DRIVE_THREAD_ACTIVE)) {
732 kproc_create(gv_drive_worker, d, NULL, 0, 0,
734 d->flags |= GV_DRIVE_THREAD_ACTIVE;
737 g_access(cp, -1, 0, 0);
742 strncpy(d->device, pp->name, GV_MAXDRIVENAME);
745 * Find out which subdisks belong to this drive and crosslink
748 LIST_FOREACH(s, &sc->subdisks, sd) {
749 if (!strncmp(s->drive, d->name, GV_MAXDRIVENAME))
750 /* XXX: errors ignored */
751 gv_sd_to_drive(sc, d, s, errstr,
755 /* This drive is now up for sure. */
756 gv_set_drive_state(d, GV_DRIVE_UP, 0);
759 * If there are subdisks on this drive, we need to create
760 * providers for them.
770 g_access(cp, -1, 0, 0);
773 g_destroy_consumer(cp);
779 * Modify the providers for the given drive 'd'. It is assumed that the
780 * subdisk list of 'd' is already correctly set up.
783 gv_drive_modify(struct gv_drive *d)
786 struct g_consumer *cp;
787 struct g_provider *pp, *pp2;
790 KASSERT(d != NULL, ("gv_drive_modify: null d"));
792 KASSERT(gp != NULL, ("gv_drive_modify: null gp"));
793 cp = LIST_FIRST(&gp->consumer);
794 KASSERT(cp != NULL, ("gv_drive_modify: null cp"));
796 KASSERT(pp != NULL, ("gv_drive_modify: null pp"));
800 LIST_FOREACH(s, &d->subdisks, from_drive) {
801 /* This subdisk already has a provider. */
802 if (s->provider != NULL)
804 pp2 = g_new_providerf(gp, "gvinum/sd/%s", s->name);
805 pp2->mediasize = s->size;
806 pp2->sectorsize = pp->sectorsize;
807 g_error_provider(pp2, 0);
814 gv_drive_dead(void *arg, int flag)
817 struct g_consumer *cp;
822 KASSERT(arg != NULL, ("gv_drive_dead: NULL arg"));
824 if (flag == EV_CANCEL)
828 if (d->state != GV_DRIVE_DOWN)
831 g_trace(G_T_TOPOLOGY, "gv_drive_dead(%s)", d->name);
837 LIST_FOREACH(cp, &gp->consumer, consumer) {
838 if (cp->nstart != cp->nend) {
839 printf("GEOM_VINUM: dead drive '%s' has still "
840 "active requests, can't detach consumer\n",
842 g_post_event(gv_drive_dead, d, M_WAITOK, d,
846 if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0)
847 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
850 printf("GEOM_VINUM: lost drive '%s'\n", d->name);
852 LIST_FOREACH(s, &d->subdisks, from_drive) {
856 gv_kill_drive_thread(d);
858 g_wither_geom(gp, ENXIO);
862 gv_drive_destroy_geom(struct gctl_req *req, struct g_class *mp,
867 g_trace(G_T_TOPOLOGY, "gv_drive_destroy_geom: %s", gp->name);
871 gv_kill_drive_thread(d);
873 g_wither_geom(gp, ENXIO);
877 #define VINUMDRIVE_CLASS_NAME "VINUMDRIVE"
879 static struct g_class g_vinum_drive_class = {
880 .name = VINUMDRIVE_CLASS_NAME,
881 .version = G_VERSION,
882 .taste = gv_drive_taste,
883 .destroy_geom = gv_drive_destroy_geom
886 DECLARE_GEOM_CLASS(g_vinum_drive_class, g_vinum_drive);