summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2006-02-11 14:42:23 +0000
committerpjd <pjd@FreeBSD.org>2006-02-11 14:42:23 +0000
commitef806177416ab33073961f577f0a9366966d3f28 (patch)
treeed3f0425d688197ee94e7dfb8ca58eb6ccbf4714
parentab17cb5277cadbb0a9aad15f6c417243fb066cb6 (diff)
downloadFreeBSD-src-ef806177416ab33073961f577f0a9366966d3f28.zip
FreeBSD-src-ef806177416ab33073961f577f0a9366966d3f28.tar.gz
Mark array as CLEAN when there are no write requests in
kern.geom.mirror.idletime seconds. Write, not any requests. Mark array as clean immediatelly on last write close. Prodded by: ru MFC after: 3 days
-rw-r--r--sys/geom/mirror/g_mirror.c155
-rw-r--r--sys/geom/mirror/g_mirror.h2
2 files changed, 54 insertions, 103 deletions
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c
index 4a9c596..f5929a4 100644
--- a/sys/geom/mirror/g_mirror.c
+++ b/sys/geom/mirror/g_mirror.c
@@ -755,15 +755,26 @@ g_mirror_bump_genid(struct g_mirror_softc *sc)
}
}
-static void
-g_mirror_idle(struct g_mirror_softc *sc)
+static int
+g_mirror_idle(struct g_mirror_softc *sc, int from_access)
{
struct g_mirror_disk *disk;
+ int timeout;
- if (sc->sc_provider == NULL || sc->sc_provider->acw == 0)
- return;
+ if (sc->sc_provider == NULL)
+ return (0);
+ if (sc->sc_idle)
+ return (0);
+ if (sc->sc_writes > 0)
+ return (0);
+ if (!from_access && sc->sc_provider->acw > 0) {
+ timeout = g_mirror_idletime - (time_second - sc->sc_last_write);
+ if (timeout > 0)
+ return (timeout);
+ }
sc->sc_idle = 1;
- g_topology_lock();
+ if (!from_access)
+ g_topology_lock();
LIST_FOREACH(disk, &sc->sc_disks, d_next) {
if (disk->d_state != G_MIRROR_DISK_STATE_ACTIVE)
continue;
@@ -772,7 +783,9 @@ g_mirror_idle(struct g_mirror_softc *sc)
disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY;
g_mirror_update_metadata(disk);
}
- g_topology_unlock();
+ if (!from_access)
+ g_topology_unlock();
+ return (0);
}
static void
@@ -781,6 +794,7 @@ g_mirror_unidle(struct g_mirror_softc *sc)
struct g_mirror_disk *disk;
sc->sc_idle = 0;
+ sc->sc_last_write = time_second;
g_topology_lock();
LIST_FOREACH(disk, &sc->sc_disks, d_next) {
if (disk->d_state != G_MIRROR_DISK_STATE_ACTIVE)
@@ -793,30 +807,6 @@ g_mirror_unidle(struct g_mirror_softc *sc)
g_topology_unlock();
}
-/*
- * Return 1 if we should check if mirror is idling.
- */
-static int
-g_mirror_check_idle(struct g_mirror_softc *sc)
-{
- struct g_mirror_disk *disk;
-
- if (sc->sc_idle)
- return (0);
- if (sc->sc_provider != NULL && sc->sc_provider->acw == 0)
- return (0);
- /*
- * Check if there are no in-flight requests.
- */
- LIST_FOREACH(disk, &sc->sc_disks, d_next) {
- if (disk->d_state != G_MIRROR_DISK_STATE_ACTIVE)
- continue;
- if (disk->d_consumer->index > 0)
- return (0);
- }
- return (1);
-}
-
static __inline int
bintime_cmp(struct bintime *bt1, struct bintime *bt2)
{
@@ -864,9 +854,11 @@ g_mirror_regular_request(struct bio *bp)
g_topology_assert_not();
- bp->bio_from->index--;
pbp = bp->bio_parent;
sc = pbp->bio_to->geom->softc;
+ bp->bio_from->index--;
+ if (bp->bio_cmd == BIO_WRITE)
+ sc->sc_writes--;
disk = bp->bio_from->private;
if (disk == NULL) {
g_topology_lock();
@@ -1340,6 +1332,9 @@ g_mirror_register_request(struct bio *bp)
if (sc->sc_idle)
g_mirror_unidle(sc);
+ else
+ sc->sc_last_write = time_second;
+
/*
* Allocate all bios before sending any request, so we can
* return ENOMEM in nice and clean way.
@@ -1392,6 +1387,7 @@ g_mirror_register_request(struct bio *bp)
cp = cbp->bio_caller1;
cbp->bio_caller1 = NULL;
cp->index++;
+ sc->sc_writes++;
g_io_request(cbp, cp);
}
/*
@@ -1475,6 +1471,7 @@ g_mirror_worker(void *arg)
struct g_mirror_event *ep;
struct bio *bp;
u_int nreqs;
+ int timeout;
sc = arg;
mtx_lock_spin(&sched_lock);
@@ -1529,6 +1526,11 @@ g_mirror_worker(void *arg)
continue;
}
/*
+ * Check if we can mark array as CLEAN and if we can't take
+ * how much seconds should we wait.
+ */
+ timeout = g_mirror_idle(sc, 0);
+ /*
* Now I/O requests.
*/
/* Get first request from the queue. */
@@ -1581,29 +1583,9 @@ g_mirror_worker(void *arg)
goto sleep;
}
if (bp == NULL) {
- if (g_mirror_check_idle(sc)) {
- u_int idletime;
-
- idletime = g_mirror_idletime;
- if (idletime == 0)
- idletime = 1;
- idletime *= hz;
- if (msleep(sc, &sc->sc_queue_mtx, PRIBIO | PDROP,
- "m:w1", idletime) == EWOULDBLOCK) {
- G_MIRROR_DEBUG(5, "%s: I'm here 3.",
- __func__);
- /*
- * No I/O requests in 'idletime' seconds,
- * so mark components as clean.
- */
- g_mirror_idle(sc);
- }
- G_MIRROR_DEBUG(5, "%s: I'm here 4.", __func__);
- } else {
- MSLEEP(sc, &sc->sc_queue_mtx, PRIBIO | PDROP,
- "m:w2", 0);
- G_MIRROR_DEBUG(5, "%s: I'm here 5.", __func__);
- }
+ MSLEEP(sc, &sc->sc_queue_mtx, PRIBIO | PDROP, "m:w1",
+ timeout * hz);
+ G_MIRROR_DEBUG(5, "%s: I'm here 4.", __func__);
continue;
}
nreqs++;
@@ -1647,35 +1629,20 @@ sleep:
}
}
-/*
- * Open disk's consumer if needed.
- */
static void
-g_mirror_update_access(struct g_mirror_disk *disk)
+g_mirror_update_idle(struct g_mirror_softc *sc, struct g_mirror_disk *disk)
{
- struct g_provider *pp;
g_topology_assert();
-
- pp = disk->d_softc->sc_provider;
- if (pp == NULL)
- return;
- if (pp->acw > 0) {
- if ((disk->d_flags & G_MIRROR_DISK_FLAG_DIRTY) == 0) {
- G_MIRROR_DEBUG(1,
- "Disk %s (device %s) marked as dirty.",
- g_mirror_get_diskname(disk),
- disk->d_softc->sc_name);
- disk->d_flags |= G_MIRROR_DISK_FLAG_DIRTY;
- }
- } else if (pp->acw == 0) {
- if ((disk->d_flags & G_MIRROR_DISK_FLAG_DIRTY) != 0) {
- G_MIRROR_DEBUG(1,
- "Disk %s (device %s) marked as clean.",
- g_mirror_get_diskname(disk),
- disk->d_softc->sc_name);
- disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY;
- }
+ if (!sc->sc_idle && (disk->d_flags & G_MIRROR_DISK_FLAG_DIRTY) == 0) {
+ G_MIRROR_DEBUG(1, "Disk %s (device %s) marked as dirty.",
+ g_mirror_get_diskname(disk), disk->d_softc->sc_name);
+ disk->d_flags |= G_MIRROR_DISK_FLAG_DIRTY;
+ } else if (sc->sc_idle &&
+ (disk->d_flags & G_MIRROR_DISK_FLAG_DIRTY) != 0) {
+ G_MIRROR_DEBUG(1, "Disk %s (device %s) marked as clean.",
+ g_mirror_get_diskname(disk), disk->d_softc->sc_name);
+ disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY;
}
}
@@ -2196,8 +2163,7 @@ again:
disk->d_state = state;
disk->d_sync.ds_offset = 0;
disk->d_sync.ds_offset_done = 0;
- g_mirror_update_access(disk);
- g_mirror_update_metadata(disk);
+ g_mirror_update_idle(sc, disk);
G_MIRROR_DEBUG(0, "Device %s: provider %s activated.",
sc->sc_name, g_mirror_get_diskname(disk));
break;
@@ -2477,7 +2443,6 @@ static int
g_mirror_access(struct g_provider *pp, int acr, int acw, int ace)
{
struct g_mirror_softc *sc;
- struct g_mirror_disk *disk;
int dcr, dcw, dce;
g_topology_assert();
@@ -2496,26 +2461,8 @@ g_mirror_access(struct g_provider *pp, int acr, int acw, int ace)
else
return (ENXIO);
}
- LIST_FOREACH(disk, &sc->sc_disks, d_next) {
- if (disk->d_state != G_MIRROR_DISK_STATE_ACTIVE)
- continue;
- /*
- * Mark disk as dirty on open and unmark on close.
- */
- if (pp->acw == 0 && dcw > 0) {
- G_MIRROR_DEBUG(1,
- "Disk %s (device %s) marked as dirty.",
- g_mirror_get_diskname(disk), sc->sc_name);
- disk->d_flags |= G_MIRROR_DISK_FLAG_DIRTY;
- g_mirror_update_metadata(disk);
- } else if (pp->acw > 0 && dcw == 0) {
- G_MIRROR_DEBUG(1,
- "Disk %s (device %s) marked as clean.",
- g_mirror_get_diskname(disk), sc->sc_name);
- disk->d_flags &= ~G_MIRROR_DISK_FLAG_DIRTY;
- g_mirror_update_metadata(disk);
- }
- }
+ if (dcw == 0 && !sc->sc_idle)
+ g_mirror_idle(sc, 1);
return (0);
}
@@ -2551,7 +2498,9 @@ g_mirror_create(struct g_class *mp, const struct g_mirror_metadata *md)
sc->sc_ndisks = md->md_all;
sc->sc_flags = md->md_mflags;
sc->sc_bump_id = 0;
- sc->sc_idle = 0;
+ sc->sc_idle = 1;
+ sc->sc_last_write = time_second;
+ sc->sc_writes = 0;
bioq_init(&sc->sc_queue);
mtx_init(&sc->sc_queue_mtx, "gmirror:queue", NULL, MTX_DEF);
LIST_INIT(&sc->sc_disks);
diff --git a/sys/geom/mirror/g_mirror.h b/sys/geom/mirror/g_mirror.h
index 57bee2b..35d84b4 100644
--- a/sys/geom/mirror/g_mirror.h
+++ b/sys/geom/mirror/g_mirror.h
@@ -186,6 +186,8 @@ struct g_mirror_softc {
int sc_bump_id;
struct g_mirror_device_sync sc_sync;
int sc_idle; /* DIRTY flags removed. */
+ time_t sc_last_write;
+ u_int sc_writes;
TAILQ_HEAD(, g_mirror_event) sc_events;
struct mtx sc_events_mtx;
OpenPOWER on IntegriCloud