aboutsummaryrefslogtreecommitdiff
path: root/sys/geom
diff options
context:
space:
mode:
authorMark Johnston <markj@FreeBSD.org>2016-10-20 23:08:40 +0000
committerMark Johnston <markj@FreeBSD.org>2016-10-20 23:08:40 +0000
commit5c2ac5cf2aabe8577b4294d9308f8271a291ecfa (patch)
tree2474212ad884c7071427b73cc69c7afd8962cce8 /sys/geom
parentb450976dc22455c75e0a2ecd9ba665c725bf59c8 (diff)
downloadsrc-5c2ac5cf2aabe8577b4294d9308f8271a291ecfa.tar.gz
src-5c2ac5cf2aabe8577b4294d9308f8271a291ecfa.zip
gmirror: Add a subroutine to free synchronization BIOs.
This addresses a memory leak that occurs upon an I/O error during a mirror synchronization. MFC after: 2 weeks Sponsored by: Dell EMC Isilon
Notes
Notes: svn path=/head/; revision=307692
Diffstat (limited to 'sys/geom')
-rw-r--r--sys/geom/mirror/g_mirror.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c
index 4018f8d6d172..52c007efd1d9 100644
--- a/sys/geom/mirror/g_mirror.c
+++ b/sys/geom/mirror/g_mirror.c
@@ -1276,6 +1276,22 @@ g_mirror_sync_release(struct g_mirror_softc *sc)
}
/*
+ * Free a synchronization request and clear its slot in the array.
+ */
+static void
+g_mirror_sync_request_free(struct g_mirror_disk *disk, struct bio *bp)
+{
+ int i;
+
+ if (disk != NULL && disk->d_sync.ds_bios != NULL) {
+ i = (int)(uintptr_t)bp->bio_caller1;
+ disk->d_sync.ds_bios[i] = NULL;
+ }
+ free(bp->bio_data, M_MIRROR);
+ g_destroy_bio(bp);
+}
+
+/*
* Handle synchronization requests.
* Every synchronization request is two-steps process: first, READ request is
* send to active provider and then WRITE request (with read data) to the provider
@@ -1287,6 +1303,7 @@ g_mirror_sync_request(struct bio *bp)
{
struct g_mirror_softc *sc;
struct g_mirror_disk *disk;
+ struct g_mirror_disk_sync *sync;
bp->bio_from->index--;
sc = bp->bio_from->geom->softc;
@@ -1296,8 +1313,7 @@ g_mirror_sync_request(struct bio *bp)
g_topology_lock();
g_mirror_kill_consumer(sc, bp->bio_from);
g_topology_unlock();
- free(bp->bio_data, M_MIRROR);
- g_destroy_bio(bp);
+ g_mirror_sync_request_free(NULL, bp);
sx_xlock(&sc->sc_lock);
return;
}
@@ -1317,7 +1333,7 @@ g_mirror_sync_request(struct bio *bp)
G_MIRROR_LOGREQ(0, bp,
"Synchronization request failed (error=%d).",
bp->bio_error);
- g_destroy_bio(bp);
+ g_mirror_sync_request_free(disk, bp);
return;
}
G_MIRROR_LOGREQ(3, bp,
@@ -1334,7 +1350,6 @@ g_mirror_sync_request(struct bio *bp)
}
case BIO_WRITE:
{
- struct g_mirror_disk_sync *sync;
off_t offset;
void *data;
int i;
@@ -1346,7 +1361,7 @@ g_mirror_sync_request(struct bio *bp)
G_MIRROR_LOGREQ(0, bp,
"Synchronization request failed (error=%d).",
bp->bio_error);
- g_destroy_bio(bp);
+ g_mirror_sync_request_free(disk, bp);
sc->sc_bump_id |= G_MIRROR_BUMP_GENID;
g_mirror_event_send(disk,
G_MIRROR_DISK_STATE_DISCONNECTED,
@@ -1360,12 +1375,7 @@ g_mirror_sync_request(struct bio *bp)
(sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) {
/* Don't send more synchronization requests. */
sync->ds_inflight--;
- if (sync->ds_bios != NULL) {
- i = (int)(uintptr_t)bp->bio_caller1;
- sync->ds_bios[i] = NULL;
- }
- free(bp->bio_data, M_MIRROR);
- g_destroy_bio(bp);
+ g_mirror_sync_request_free(disk, bp);
if (sync->ds_inflight > 0)
return;
if (sync->ds_consumer == NULL ||