[Midnightbsd-cvs] src [9978] trunk/sys/geom/mirror: sync
laffer1 at midnightbsd.org
laffer1 at midnightbsd.org
Sat May 26 11:30:06 EDT 2018
Revision: 9978
http://svnweb.midnightbsd.org/src/?rev=9978
Author: laffer1
Date: 2018-05-26 11:30:05 -0400 (Sat, 26 May 2018)
Log Message:
-----------
sync
Modified Paths:
--------------
trunk/sys/geom/mirror/g_mirror.c
trunk/sys/geom/mirror/g_mirror.h
trunk/sys/geom/mirror/g_mirror_ctl.c
Modified: trunk/sys/geom/mirror/g_mirror.c
===================================================================
--- trunk/sys/geom/mirror/g_mirror.c 2018-05-26 15:29:30 UTC (rev 9977)
+++ trunk/sys/geom/mirror/g_mirror.c 2018-05-26 15:30:05 UTC (rev 9978)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd at FreeBSD.org>
* All rights reserved.
@@ -25,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/geom/mirror/g_mirror.c,v 1.93.2.3 2010/09/19 19:43:05 mav Exp $");
+__FBSDID("$FreeBSD: stable/10/sys/geom/mirror/g_mirror.c 324589 2017-10-13 09:14:05Z avg $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -84,11 +85,12 @@
static eventhandler_tag g_mirror_post_sync = NULL;
static int g_mirror_shutdown = 0;
-static int g_mirror_destroy_geom(struct gctl_req *req, struct g_class *mp,
- struct g_geom *gp);
+static g_ctl_destroy_geom_t g_mirror_destroy_geom;
static g_taste_t g_mirror_taste;
-static void g_mirror_init(struct g_class *mp);
-static void g_mirror_fini(struct g_class *mp);
+static g_init_t g_mirror_init;
+static g_fini_t g_mirror_fini;
+static g_provgone_t g_mirror_providergone;
+static g_resize_t g_mirror_resize;
struct g_class g_mirror_class = {
.name = G_MIRROR_CLASS_NAME,
@@ -97,7 +99,9 @@
.taste = g_mirror_taste,
.destroy_geom = g_mirror_destroy_geom,
.init = g_mirror_init,
- .fini = g_mirror_fini
+ .fini = g_mirror_fini,
+ .providergone = g_mirror_providergone,
+ .resize = g_mirror_resize
};
@@ -394,6 +398,7 @@
g_topology_lock();
cp = g_new_consumer(disk->d_softc->sc_geom);
+ cp->flags |= G_CF_DIRECT_RECEIVE;
error = g_attach(cp, pp);
if (error != 0) {
g_destroy_consumer(cp);
@@ -510,6 +515,26 @@
}
static void
+g_mirror_free_device(struct g_mirror_softc *sc)
+{
+
+ mtx_destroy(&sc->sc_queue_mtx);
+ mtx_destroy(&sc->sc_events_mtx);
+ mtx_destroy(&sc->sc_done_mtx);
+ sx_destroy(&sc->sc_lock);
+ free(sc, M_MIRROR);
+}
+
+static void
+g_mirror_providergone(struct g_provider *pp)
+{
+ struct g_mirror_softc *sc = pp->private;
+
+ if ((--sc->sc_refcnt) == 0)
+ g_mirror_free_device(sc);
+}
+
+static void
g_mirror_destroy_device(struct g_mirror_softc *sc)
{
struct g_mirror_disk *disk;
@@ -551,11 +576,10 @@
g_wither_geom(sc->sc_sync.ds_geom, ENXIO);
G_MIRROR_DEBUG(0, "Device %s destroyed.", gp->name);
g_wither_geom(gp, ENXIO);
+ sx_xunlock(&sc->sc_lock);
+ if ((--sc->sc_refcnt) == 0)
+ g_mirror_free_device(sc);
g_topology_unlock();
- mtx_destroy(&sc->sc_queue_mtx);
- mtx_destroy(&sc->sc_events_mtx);
- sx_xunlock(&sc->sc_lock);
- sx_destroy(&sc->sc_lock);
}
static void
@@ -638,9 +662,18 @@
length = cp->provider->sectorsize;
offset = cp->provider->mediasize - length;
sector = malloc((size_t)length, M_MIRROR, M_WAITOK | M_ZERO);
- if (md != NULL)
- mirror_metadata_encode(md, sector);
- error = g_write_data(cp, offset, sector, length);
+ if (md != NULL &&
+ (sc->sc_flags & G_MIRROR_DEVICE_FLAG_WIPE) == 0) {
+ /*
+ * Handle the case, when the size of parent provider reduced.
+ */
+ if (offset < md->md_mediasize)
+ error = ENOSPC;
+ else
+ mirror_metadata_encode(md, sector);
+ }
+ if (error == 0)
+ error = g_write_data(cp, offset, sector, length);
free(sector, M_MIRROR);
if (error != 0) {
if ((disk->d_flags & G_MIRROR_DISK_FLAG_BROKEN) == 0) {
@@ -737,7 +770,8 @@
sc = disk->d_softc;
sx_assert(&sc->sc_lock, SX_LOCKED);
- g_mirror_fill_metadata(sc, disk, &md);
+ if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_WIPE) == 0)
+ g_mirror_fill_metadata(sc, disk, &md);
error = g_mirror_write_metadata(disk, &md);
if (error == 0) {
G_MIRROR_DEBUG(2, "Metadata on %s updated.",
@@ -852,6 +886,27 @@
}
static void
+g_mirror_flush_done(struct bio *bp)
+{
+ struct g_mirror_softc *sc;
+ struct bio *pbp;
+
+ pbp = bp->bio_parent;
+ sc = pbp->bio_to->private;
+ mtx_lock(&sc->sc_done_mtx);
+ if (pbp->bio_error == 0)
+ pbp->bio_error = bp->bio_error;
+ pbp->bio_completed += bp->bio_completed;
+ pbp->bio_inbed++;
+ if (pbp->bio_children == pbp->bio_inbed) {
+ mtx_unlock(&sc->sc_done_mtx);
+ g_io_deliver(pbp, pbp->bio_error);
+ } else
+ mtx_unlock(&sc->sc_done_mtx);
+ g_destroy_bio(bp);
+}
+
+static void
g_mirror_done(struct bio *bp)
{
struct g_mirror_softc *sc;
@@ -859,7 +914,7 @@
sc = bp->bio_from->geom->softc;
bp->bio_cflags = G_MIRROR_BIO_FLAG_REGULAR;
mtx_lock(&sc->sc_queue_mtx);
- bioq_disksort(&sc->sc_queue, bp);
+ bioq_insert_tail(&sc->sc_queue, bp);
mtx_unlock(&sc->sc_queue_mtx);
wakeup(sc);
}
@@ -874,7 +929,7 @@
g_topology_assert_not();
pbp = bp->bio_parent;
- sc = pbp->bio_to->geom->softc;
+ sc = pbp->bio_to->private;
bp->bio_from->index--;
if (bp->bio_cmd == BIO_WRITE)
sc->sc_writes--;
@@ -921,7 +976,13 @@
if (g_mirror_disconnect_on_failure &&
g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) > 1)
{
- sc->sc_bump_id |= G_MIRROR_BUMP_GENID;
+ if (bp->bio_error == ENXIO &&
+ bp->bio_cmd == BIO_READ)
+ sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID;
+ else if (bp->bio_error == ENXIO)
+ sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID_NOW;
+ else
+ sc->sc_bump_id |= G_MIRROR_BUMP_GENID;
g_mirror_event_send(disk,
G_MIRROR_DISK_STATE_DISCONNECTED,
G_MIRROR_EVENT_DONTWAIT);
@@ -946,7 +1007,7 @@
else {
pbp->bio_error = 0;
mtx_lock(&sc->sc_queue_mtx);
- bioq_disksort(&sc->sc_queue, pbp);
+ bioq_insert_tail(&sc->sc_queue, pbp);
mtx_unlock(&sc->sc_queue_mtx);
G_MIRROR_DEBUG(4, "%s: Waking up %p.", __func__, sc);
wakeup(sc);
@@ -986,12 +1047,29 @@
sc = bp->bio_from->geom->softc;
bp->bio_cflags = G_MIRROR_BIO_FLAG_SYNC;
mtx_lock(&sc->sc_queue_mtx);
- bioq_disksort(&sc->sc_queue, bp);
+ bioq_insert_tail(&sc->sc_queue, bp);
mtx_unlock(&sc->sc_queue_mtx);
wakeup(sc);
}
static void
+g_mirror_candelete(struct bio *bp)
+{
+ struct g_mirror_softc *sc;
+ struct g_mirror_disk *disk;
+ int *val;
+
+ sc = bp->bio_to->private;
+ LIST_FOREACH(disk, &sc->sc_disks, d_next) {
+ if (disk->d_flags & G_MIRROR_DISK_FLAG_CANDELETE)
+ break;
+ }
+ val = (int *)bp->bio_data;
+ *val = (disk != NULL);
+ g_io_deliver(bp, 0);
+}
+
+static void
g_mirror_kernel_dump(struct bio *bp)
{
struct g_mirror_softc *sc;
@@ -1006,7 +1084,7 @@
* we will not be able to read the dump after the reboot if it will be
* connected and synchronized later. Can we do something better?
*/
- sc = bp->bio_to->geom->softc;
+ sc = bp->bio_to->private;
disk = LIST_FIRST(&sc->sc_disks);
gkd = (struct g_kerneldump *)bp->bio_data;
@@ -1037,11 +1115,8 @@
continue;
cbp = g_clone_bio(bp);
if (cbp == NULL) {
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL)
g_destroy_bio(cbp);
- }
if (bp->bio_error == 0)
bp->bio_error = ENOMEM;
g_io_deliver(bp, bp->bio_error);
@@ -1048,12 +1123,11 @@
return;
}
bioq_insert_tail(&queue, cbp);
- cbp->bio_done = g_std_done;
+ cbp->bio_done = g_mirror_flush_done;
cbp->bio_caller1 = disk;
cbp->bio_to = disk->d_consumer->provider;
}
- for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL) {
G_MIRROR_LOGREQ(3, cbp, "Sending request.");
disk = cbp->bio_caller1;
cbp->bio_caller1 = NULL;
@@ -1070,7 +1144,7 @@
{
struct g_mirror_softc *sc;
- sc = bp->bio_to->geom->softc;
+ sc = bp->bio_to->private;
/*
* If sc == NULL or there are no valid disks, provider's error
* should be set and g_mirror_start() should not be called at all.
@@ -1089,9 +1163,10 @@
g_mirror_flush(sc, bp);
return;
case BIO_GETATTR:
- if (g_handleattr_int(bp, "GEOM::candelete", 1))
+ if (!strcmp(bp->bio_attribute, "GEOM::candelete")) {
+ g_mirror_candelete(bp);
return;
- else if (strcmp("GEOM::kerneldump", bp->bio_attribute) == 0) {
+ } else if (strcmp("GEOM::kerneldump", bp->bio_attribute) == 0) {
g_mirror_kernel_dump(bp);
return;
}
@@ -1101,7 +1176,7 @@
return;
}
mtx_lock(&sc->sc_queue_mtx);
- bioq_disksort(&sc->sc_queue, bp);
+ bioq_insert_tail(&sc->sc_queue, bp);
mtx_unlock(&sc->sc_queue_mtx);
G_MIRROR_DEBUG(4, "%s: Waking up %p.", __func__, sc);
wakeup(sc);
@@ -1117,7 +1192,7 @@
struct g_mirror_disk *disk;
struct bio *sbp;
off_t rstart, rend, sstart, send;
- int i;
+ u_int i;
if (sc->sc_sync.ds_ndisks == 0)
return (0);
@@ -1304,7 +1379,7 @@
}
G_MIRROR_LOGREQ(3, bp, "Synchronization request finished.");
sync = &disk->d_sync;
- if (sync->ds_offset == sc->sc_mediasize ||
+ if (sync->ds_offset >= sc->sc_mediasize ||
sync->ds_consumer == NULL ||
(sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
/* Don't send more synchronization requests. */
@@ -1538,11 +1613,8 @@
continue;
cbp = g_clone_bio(bp);
if (cbp == NULL) {
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL)
g_destroy_bio(cbp);
- }
if (bp->bio_error == 0)
bp->bio_error = ENOMEM;
g_io_deliver(bp, bp->bio_error);
@@ -1561,8 +1633,7 @@
offset += cbp->bio_length;
data += cbp->bio_length;
}
- for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL) {
G_MIRROR_LOGREQ(3, cbp, "Sending request.");
disk = cbp->bio_caller1;
cbp->bio_caller1 = NULL;
@@ -1580,7 +1651,7 @@
{
struct g_mirror_softc *sc;
- sc = bp->bio_to->geom->softc;
+ sc = bp->bio_to->private;
switch (bp->bio_cmd) {
case BIO_READ:
switch (sc->sc_balance) {
@@ -1643,11 +1714,8 @@
continue;
cbp = g_clone_bio(bp);
if (cbp == NULL) {
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ while ((cbp = bioq_takefirst(&queue)) != NULL)
g_destroy_bio(cbp);
- }
if (bp->bio_error == 0)
bp->bio_error = ENOMEM;
g_io_deliver(bp, bp->bio_error);
@@ -1662,9 +1730,11 @@
("Consumer %s not opened (r%dw%de%d).",
cp->provider->name, cp->acr, cp->acw, cp->ace));
}
- for (cbp = bioq_first(&queue); cbp != NULL;
- cbp = bioq_first(&queue)) {
- bioq_remove(&queue, cbp);
+ if (bioq_first(&queue) == NULL) {
+ g_io_deliver(bp, EOPNOTSUPP);
+ return;
+ }
+ while ((cbp = bioq_takefirst(&queue)) != NULL) {
G_MIRROR_LOGREQ(3, cbp, "Sending request.");
cp = cbp->bio_caller1;
cbp->bio_caller1 = NULL;
@@ -1747,7 +1817,6 @@
} else {
g_topology_unlock();
g_mirror_destroy_device(sc);
- free(sc, M_MIRROR);
}
return (1);
}
@@ -1827,7 +1896,7 @@
*/
/* Get first request from the queue. */
mtx_lock(&sc->sc_queue_mtx);
- bp = bioq_first(&sc->sc_queue);
+ bp = bioq_takefirst(&sc->sc_queue);
if (bp == NULL) {
if ((sc->sc_flags &
G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
@@ -1855,7 +1924,6 @@
G_MIRROR_DEBUG(5, "%s: I'm here 4.", __func__);
continue;
}
- bioq_remove(&sc->sc_queue, bp);
mtx_unlock(&sc->sc_queue_mtx);
if (bp->bio_from->geom == sc->sc_sync.ds_geom &&
@@ -1920,6 +1988,7 @@
sx_xunlock(&sc->sc_lock);
g_topology_lock();
cp = g_new_consumer(sc->sc_sync.ds_geom);
+ cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
error = g_attach(cp, sc->sc_provider);
KASSERT(error == 0,
("Cannot attach to %s (error=%d).", sc->sc_name, error));
@@ -2028,23 +2097,39 @@
g_mirror_launch_provider(struct g_mirror_softc *sc)
{
struct g_mirror_disk *disk;
- struct g_provider *pp;
+ struct g_provider *pp, *dp;
sx_assert(&sc->sc_lock, SX_LOCKED);
g_topology_lock();
pp = g_new_providerf(sc->sc_geom, "mirror/%s", sc->sc_name);
+ pp->flags |= G_PF_DIRECT_RECEIVE;
pp->mediasize = sc->sc_mediasize;
pp->sectorsize = sc->sc_sectorsize;
pp->stripesize = 0;
pp->stripeoffset = 0;
+
+ /* Splitting of unmapped BIO's could work but isn't implemented now */
+ if (sc->sc_balance != G_MIRROR_BALANCE_SPLIT)
+ pp->flags |= G_PF_ACCEPT_UNMAPPED;
+
LIST_FOREACH(disk, &sc->sc_disks, d_next) {
- if (disk->d_consumer && disk->d_consumer->provider &&
- disk->d_consumer->provider->stripesize > pp->stripesize) {
- pp->stripesize = disk->d_consumer->provider->stripesize;
- pp->stripeoffset = disk->d_consumer->provider->stripeoffset;
+ if (disk->d_consumer && disk->d_consumer->provider) {
+ dp = disk->d_consumer->provider;
+ if (dp->stripesize > pp->stripesize) {
+ pp->stripesize = dp->stripesize;
+ pp->stripeoffset = dp->stripeoffset;
+ }
+ /* A provider underneath us doesn't support unmapped */
+ if ((dp->flags & G_PF_ACCEPT_UNMAPPED) == 0) {
+ G_MIRROR_DEBUG(0, "Cancelling unmapped "
+ "because of %s.", dp->name);
+ pp->flags &= ~G_PF_ACCEPT_UNMAPPED;
+ }
}
}
+ pp->private = sc;
+ sc->sc_refcnt++;
sc->sc_provider = pp;
g_error_provider(pp, 0);
g_topology_unlock();
@@ -2069,17 +2154,26 @@
g_topology_lock();
g_error_provider(sc->sc_provider, ENXIO);
mtx_lock(&sc->sc_queue_mtx);
- while ((bp = bioq_first(&sc->sc_queue)) != NULL) {
- bioq_remove(&sc->sc_queue, bp);
- g_io_deliver(bp, ENXIO);
+ while ((bp = bioq_takefirst(&sc->sc_queue)) != NULL) {
+ /*
+ * Abort any pending I/O that wasn't generated by us.
+ * Synchronization requests and requests destined for individual
+ * mirror components can be destroyed immediately.
+ */
+ if (bp->bio_to == sc->sc_provider &&
+ bp->bio_from->geom != sc->sc_sync.ds_geom) {
+ g_io_deliver(bp, ENXIO);
+ } else {
+ if ((bp->bio_cflags & G_MIRROR_BIO_FLAG_SYNC) != 0)
+ free(bp->bio_data, M_MIRROR);
+ g_destroy_bio(bp);
+ }
}
mtx_unlock(&sc->sc_queue_mtx);
- G_MIRROR_DEBUG(0, "Device %s: provider %s destroyed.", sc->sc_name,
- sc->sc_provider->name);
- sc->sc_provider->flags |= G_PF_WITHER;
- g_orphan_provider(sc->sc_provider, ENXIO);
+ g_wither_provider(sc->sc_provider, ENXIO);
+ sc->sc_provider = NULL;
+ G_MIRROR_DEBUG(0, "Device %s: provider destroyed.", sc->sc_name);
g_topology_unlock();
- sc->sc_provider = NULL;
LIST_FOREACH(disk, &sc->sc_disks, d_next) {
if (disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING)
g_mirror_sync_stop(disk, 1);
@@ -2393,6 +2487,10 @@
sc->sc_bump_id &= ~G_MIRROR_BUMP_GENID;
g_mirror_bump_genid(sc);
}
+ if ((sc->sc_bump_id & G_MIRROR_BUMP_SYNCID_NOW) != 0) {
+ sc->sc_bump_id &= ~G_MIRROR_BUMP_SYNCID_NOW;
+ g_mirror_bump_syncid(sc);
+ }
break;
default:
KASSERT(1 == 0, ("Wrong device state (%s, %s).",
@@ -2600,8 +2698,12 @@
int error;
error = g_mirror_clear_metadata(disk);
- if (error != 0)
- return (error);
+ if (error != 0) {
+ G_MIRROR_DEBUG(0,
+ "Device %s: failed to clear metadata on %s: %d.",
+ sc->sc_name, g_mirror_get_diskname(disk), error);
+ break;
+ }
DISK_STATE_CHANGED();
G_MIRROR_DEBUG(0, "Device %s: provider %s destroyed.",
sc->sc_name, g_mirror_get_diskname(disk));
@@ -2694,6 +2796,7 @@
"md_balance", pp->name, sc->sc_name);
return (EINVAL);
}
+#if 0
if (md->md_mediasize != sc->sc_mediasize) {
G_MIRROR_DEBUG(1,
"Invalid '%s' field on disk %s (device %s), skipping.",
@@ -2700,6 +2803,7 @@
"md_mediasize", pp->name, sc->sc_name);
return (EINVAL);
}
+#endif
if (sc->sc_mediasize > pp->mediasize) {
G_MIRROR_DEBUG(1,
"Invalid size of disk %s (device %s), skipping.", pp->name,
@@ -2787,7 +2891,8 @@
G_MIRROR_DEBUG(1, "Destroying %s (delayed).", sc->sc_name);
error = g_mirror_destroy(sc, G_MIRROR_DESTROY_SOFT);
if (error != 0) {
- G_MIRROR_DEBUG(0, "Cannot destroy %s.", sc->sc_name);
+ G_MIRROR_DEBUG(0, "Cannot destroy %s (error=%d).",
+ sc->sc_name, error);
sx_xunlock(&sc->sc_lock);
}
g_topology_lock();
@@ -2797,41 +2902,30 @@
g_mirror_access(struct g_provider *pp, int acr, int acw, int ace)
{
struct g_mirror_softc *sc;
- int dcr, dcw, dce, error = 0;
+ int error = 0;
g_topology_assert();
G_MIRROR_DEBUG(2, "Access request for %s: r%dw%de%d.", pp->name, acr,
acw, ace);
- sc = pp->geom->softc;
- if (sc == NULL && acr <= 0 && acw <= 0 && ace <= 0)
- return (0);
+ sc = pp->private;
KASSERT(sc != NULL, ("NULL softc (provider=%s).", pp->name));
- dcr = pp->acr + acr;
- dcw = pp->acw + acw;
- dce = pp->ace + ace;
-
g_topology_unlock();
sx_xlock(&sc->sc_lock);
if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0 ||
+ (sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROYING) != 0 ||
LIST_EMPTY(&sc->sc_disks)) {
if (acr > 0 || acw > 0 || ace > 0)
error = ENXIO;
goto end;
}
- if (dcw == 0)
- g_mirror_idle(sc, dcw);
- if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROYING) != 0) {
- if (acr > 0 || acw > 0 || ace > 0) {
- error = ENXIO;
- goto end;
- }
- if (dcr == 0 && dcw == 0 && dce == 0) {
- g_post_event(g_mirror_destroy_delayed, sc, M_WAITOK,
- sc, NULL);
- }
- }
+ sc->sc_provider_open += acr + acw + ace;
+ if (pp->acw + acw == 0)
+ g_mirror_idle(sc, 0);
+ if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROYING) != 0 &&
+ sc->sc_provider_open == 0)
+ g_post_event(g_mirror_destroy_delayed, sc, M_WAITOK, sc, NULL);
end:
sx_xunlock(&sc->sc_lock);
g_topology_lock();
@@ -2873,6 +2967,7 @@
sc->sc_idle = 1;
sc->sc_last_write = time_uptime;
sc->sc_writes = 0;
+ sc->sc_refcnt = 1;
sx_init(&sc->sc_lock, "gmirror:lock");
bioq_init(&sc->sc_queue);
mtx_init(&sc->sc_queue_mtx, "gmirror:queue", NULL, MTX_DEF);
@@ -2882,11 +2977,13 @@
LIST_INIT(&sc->sc_disks);
TAILQ_INIT(&sc->sc_events);
mtx_init(&sc->sc_events_mtx, "gmirror:events", NULL, MTX_DEF);
- callout_init(&sc->sc_callout, CALLOUT_MPSAFE);
+ callout_init(&sc->sc_callout, 1);
+ mtx_init(&sc->sc_done_mtx, "gmirror:done", NULL, MTX_DEF);
sc->sc_state = G_MIRROR_DEVICE_STATE_STARTING;
gp->softc = sc;
sc->sc_geom = gp;
sc->sc_provider = NULL;
+ sc->sc_provider_open = 0;
/*
* Synchronization geom.
*/
@@ -2901,11 +2998,8 @@
G_MIRROR_DEBUG(1, "Cannot create kernel thread for %s.",
sc->sc_name);
g_destroy_geom(sc->sc_sync.ds_geom);
- mtx_destroy(&sc->sc_events_mtx);
- mtx_destroy(&sc->sc_queue_mtx);
- sx_destroy(&sc->sc_lock);
g_destroy_geom(sc->sc_geom);
- free(sc, M_MIRROR);
+ g_mirror_free_device(sc);
return (NULL);
}
@@ -2926,25 +3020,21 @@
g_mirror_destroy(struct g_mirror_softc *sc, int how)
{
struct g_mirror_disk *disk;
- struct g_provider *pp;
g_topology_assert_not();
- if (sc == NULL)
- return (ENXIO);
sx_assert(&sc->sc_lock, SX_XLOCKED);
- pp = sc->sc_provider;
- if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
+ if (sc->sc_provider_open != 0) {
switch (how) {
case G_MIRROR_DESTROY_SOFT:
G_MIRROR_DEBUG(1,
- "Device %s is still open (r%dw%de%d).", pp->name,
- pp->acr, pp->acw, pp->ace);
+ "Device %s is still open (%d).", sc->sc_name,
+ sc->sc_provider_open);
return (EBUSY);
case G_MIRROR_DESTROY_DELAYED:
G_MIRROR_DEBUG(1,
"Device %s will be destroyed on last close.",
- pp->name);
+ sc->sc_name);
LIST_FOREACH(disk, &sc->sc_disks, d_next) {
if (disk->d_state ==
G_MIRROR_DISK_STATE_SYNCHRONIZING) {
@@ -2955,7 +3045,7 @@
return (EBUSY);
case G_MIRROR_DESTROY_HARD:
G_MIRROR_DEBUG(1, "Device %s is still open, so it "
- "can't be definitely removed.", pp->name);
+ "can't be definitely removed.", sc->sc_name);
}
}
@@ -2981,7 +3071,6 @@
G_MIRROR_DEBUG(4, "%s: Woken up %p.", __func__, &sc->sc_worker);
sx_xlock(&sc->sc_lock);
g_mirror_destroy_device(sc);
- free(sc, M_MIRROR);
return (0);
}
@@ -3090,6 +3179,22 @@
return (gp);
}
+static void
+g_mirror_resize(struct g_consumer *cp)
+{
+ struct g_mirror_disk *disk;
+
+ g_topology_assert();
+ g_trace(G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name);
+
+ disk = cp->private;
+ if (disk == NULL)
+ return;
+ g_topology_unlock();
+ g_mirror_update_metadata(disk);
+ g_topology_lock();
+}
+
static int
g_mirror_destroy_geom(struct gctl_req *req __unused,
struct g_class *mp __unused, struct g_geom *gp)
Modified: trunk/sys/geom/mirror/g_mirror.h
===================================================================
--- trunk/sys/geom/mirror/g_mirror.h 2018-05-26 15:29:30 UTC (rev 9977)
+++ trunk/sys/geom/mirror/g_mirror.h 2018-05-26 15:30:05 UTC (rev 9978)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd at FreeBSD.org>
* All rights reserved.
@@ -23,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD: src/sys/geom/mirror/g_mirror.h,v 1.24.2.1 2009/12/08 23:34:34 mav Exp $
+ * $FreeBSD: stable/10/sys/geom/mirror/g_mirror.h 324589 2017-10-13 09:14:05Z avg $
*/
#ifndef _G_MIRROR_H_
@@ -160,14 +161,17 @@
#define G_MIRROR_DEVICE_FLAG_WAIT 0x0200000000000000ULL
#define G_MIRROR_DEVICE_FLAG_DESTROYING 0x0400000000000000ULL
#define G_MIRROR_DEVICE_FLAG_TASTING 0x0800000000000000ULL
+#define G_MIRROR_DEVICE_FLAG_WIPE 0x1000000000000000ULL
#define G_MIRROR_DEVICE_STATE_STARTING 0
#define G_MIRROR_DEVICE_STATE_RUNNING 1
/* Bump syncid on first write. */
-#define G_MIRROR_BUMP_SYNCID 0x1
+#define G_MIRROR_BUMP_SYNCID 0x1
/* Bump genid immediately. */
-#define G_MIRROR_BUMP_GENID 0x2
+#define G_MIRROR_BUMP_GENID 0x2
+/* Bump syncid immediately. */
+#define G_MIRROR_BUMP_SYNCID_NOW 0x4
struct g_mirror_softc {
u_int sc_state; /* Device state. */
uint32_t sc_slice; /* Slice size. */
@@ -178,6 +182,7 @@
struct g_geom *sc_geom;
struct g_provider *sc_provider;
+ int sc_provider_open;
uint32_t sc_id; /* Mirror unique ID. */
@@ -205,6 +210,7 @@
int sc_idle; /* DIRTY flags removed. */
time_t sc_last_write;
u_int sc_writes;
+ u_int sc_refcnt; /* Number of softc references */
TAILQ_HEAD(, g_mirror_event) sc_events;
struct mtx sc_events_mtx;
@@ -212,6 +218,8 @@
struct callout sc_callout;
struct root_hold_token *sc_rootmount;
+
+ struct mtx sc_done_mtx;
};
#define sc_name sc_geom->name
Modified: trunk/sys/geom/mirror/g_mirror_ctl.c
===================================================================
--- trunk/sys/geom/mirror/g_mirror_ctl.c 2018-05-26 15:29:30 UTC (rev 9977)
+++ trunk/sys/geom/mirror/g_mirror_ctl.c 2018-05-26 15:30:05 UTC (rev 9978)
@@ -1,3 +1,4 @@
+/* $MidnightBSD$ */
/*-
* Copyright (c) 2004-2009 Pawel Jakub Dawidek <pjd at FreeBSD.org>
* All rights reserved.
@@ -25,12 +26,13 @@
*/
#include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/sys/geom/mirror/g_mirror_ctl.c,v 1.18.2.1 2011/09/29 18:42:44 mav Exp $");
+__FBSDID("$FreeBSD: stable/10/sys/geom/mirror/g_mirror_ctl.c 307666 2016-10-20 09:06:39Z mav $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/limits.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/bio.h>
@@ -40,6 +42,7 @@
#include <vm/uma.h>
#include <machine/atomic.h>
#include <geom/geom.h>
+#include <geom/geom_int.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <geom/mirror/g_mirror.h>
@@ -617,6 +620,74 @@
}
static void
+g_mirror_ctl_resize(struct gctl_req *req, struct g_class *mp)
+{
+ struct g_mirror_softc *sc;
+ struct g_mirror_disk *disk;
+ uint64_t mediasize;
+ const char *name, *s;
+ char *x;
+ int *nargs;
+
+ nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
+ if (nargs == NULL) {
+ gctl_error(req, "No '%s' argument.", "nargs");
+ return;
+ }
+ if (*nargs != 1) {
+ gctl_error(req, "Missing device.");
+ return;
+ }
+ name = gctl_get_asciiparam(req, "arg0");
+ if (name == NULL) {
+ gctl_error(req, "No 'arg%u' argument.", 0);
+ return;
+ }
+ s = gctl_get_asciiparam(req, "size");
+ if (s == NULL) {
+ gctl_error(req, "No '%s' argument.", "size");
+ return;
+ }
+ mediasize = strtouq(s, &x, 0);
+ if (*x != '\0' || mediasize == 0) {
+ gctl_error(req, "Invalid '%s' argument.", "size");
+ return;
+ }
+ sc = g_mirror_find_device(mp, name);
+ if (sc == NULL) {
+ gctl_error(req, "No such device: %s.", name);
+ return;
+ }
+ /* Deny shrinking of an opened provider */
+ if ((g_debugflags & 16) == 0 && sc->sc_provider_open > 0) {
+ if (sc->sc_mediasize > mediasize) {
+ gctl_error(req, "Device %s is busy.",
+ sc->sc_provider->name);
+ sx_xunlock(&sc->sc_lock);
+ return;
+ }
+ }
+ LIST_FOREACH(disk, &sc->sc_disks, d_next) {
+ if (mediasize > disk->d_consumer->provider->mediasize -
+ disk->d_consumer->provider->sectorsize) {
+ gctl_error(req, "Provider %s is too small.",
+ disk->d_name);
+ sx_xunlock(&sc->sc_lock);
+ return;
+ }
+ }
+ /* Update the size. */
+ sc->sc_mediasize = mediasize;
+ LIST_FOREACH(disk, &sc->sc_disks, d_next) {
+ g_mirror_update_metadata(disk);
+ }
+ g_topology_lock();
+ g_resize_provider(sc->sc_provider, mediasize);
+ g_topology_unlock();
+ sx_xunlock(&sc->sc_lock);
+}
+
+static void
g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp)
{
struct g_mirror_softc *sc;
@@ -624,7 +695,7 @@
const char *name;
char param[16];
int *nargs;
- u_int i;
+ u_int i, active;
nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
if (nargs == NULL) {
@@ -645,6 +716,7 @@
gctl_error(req, "No such device: %s.", name);
return;
}
+ active = g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE);
for (i = 1; i < (u_int)*nargs; i++) {
snprintf(param, sizeof(param), "arg%u", i);
name = gctl_get_asciiparam(req, param);
@@ -657,6 +729,16 @@
gctl_error(req, "No such provider: %s.", name);
continue;
}
+ if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE) {
+ if (active > 1)
+ active--;
+ else {
+ gctl_error(req, "%s: Can't deactivate the "
+ "last ACTIVE component %s.",
+ sc->sc_geom->name, name);
+ continue;
+ }
+ }
disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE;
disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC;
g_mirror_update_metadata(disk);
@@ -715,7 +797,7 @@
}
static void
-g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp)
+g_mirror_ctl_stop(struct gctl_req *req, struct g_class *mp, int wipe)
{
struct g_mirror_softc *sc;
int *force, *nargs, error;
@@ -756,10 +838,14 @@
return;
}
g_cancel_event(sc);
+ if (wipe)
+ sc->sc_flags |= G_MIRROR_DEVICE_FLAG_WIPE;
error = g_mirror_destroy(sc, how);
if (error != 0) {
gctl_error(req, "Cannot destroy device %s (error=%d).",
sc->sc_geom->name, error);
+ if (wipe)
+ sc->sc_flags &= ~G_MIRROR_DEVICE_FLAG_WIPE;
sx_xunlock(&sc->sc_lock);
return;
}
@@ -793,12 +879,16 @@
g_mirror_ctl_insert(req, mp);
else if (strcmp(verb, "remove") == 0)
g_mirror_ctl_remove(req, mp);
+ else if (strcmp(verb, "resize") == 0)
+ g_mirror_ctl_resize(req, mp);
else if (strcmp(verb, "deactivate") == 0)
g_mirror_ctl_deactivate(req, mp);
else if (strcmp(verb, "forget") == 0)
g_mirror_ctl_forget(req, mp);
else if (strcmp(verb, "stop") == 0)
- g_mirror_ctl_stop(req, mp);
+ g_mirror_ctl_stop(req, mp, 0);
+ else if (strcmp(verb, "destroy") == 0)
+ g_mirror_ctl_stop(req, mp, 1);
else
gctl_error(req, "Unknown verb.");
g_topology_lock();
More information about the Midnightbsd-cvs
mailing list