12d1661a5SPawel Jakub Dawidek /*- 22d1661a5SPawel Jakub Dawidek * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 32d1661a5SPawel Jakub Dawidek * All rights reserved. 42d1661a5SPawel Jakub Dawidek * 52d1661a5SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 62d1661a5SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 72d1661a5SPawel Jakub Dawidek * are met: 82d1661a5SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 92d1661a5SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 102d1661a5SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 112d1661a5SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 122d1661a5SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 132d1661a5SPawel Jakub Dawidek * 142d1661a5SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 152d1661a5SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162d1661a5SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172d1661a5SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 182d1661a5SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192d1661a5SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202d1661a5SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212d1661a5SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222d1661a5SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232d1661a5SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242d1661a5SPawel Jakub Dawidek * SUCH DAMAGE. 252d1661a5SPawel Jakub Dawidek */ 262d1661a5SPawel Jakub Dawidek 272d1661a5SPawel Jakub Dawidek #include <sys/cdefs.h> 282d1661a5SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 292d1661a5SPawel Jakub Dawidek 302d1661a5SPawel Jakub Dawidek #include <sys/param.h> 312d1661a5SPawel Jakub Dawidek #include <sys/systm.h> 322d1661a5SPawel Jakub Dawidek #include <sys/kernel.h> 332d1661a5SPawel Jakub Dawidek #include <sys/module.h> 342d1661a5SPawel Jakub Dawidek #include <sys/limits.h> 352d1661a5SPawel Jakub Dawidek #include <sys/lock.h> 362d1661a5SPawel Jakub Dawidek #include <sys/mutex.h> 372d1661a5SPawel Jakub Dawidek #include <sys/bio.h> 382d1661a5SPawel Jakub Dawidek #include <sys/sysctl.h> 392d1661a5SPawel Jakub Dawidek #include <sys/malloc.h> 402d1661a5SPawel Jakub Dawidek #include <sys/bitstring.h> 412d1661a5SPawel Jakub Dawidek #include <vm/uma.h> 422d1661a5SPawel Jakub Dawidek #include <machine/atomic.h> 432d1661a5SPawel Jakub Dawidek #include <geom/geom.h> 442d1661a5SPawel Jakub Dawidek #include <sys/proc.h> 452d1661a5SPawel Jakub Dawidek #include <sys/kthread.h> 462d1661a5SPawel Jakub Dawidek #include <geom/raid3/g_raid3.h> 472d1661a5SPawel Jakub Dawidek 482d1661a5SPawel Jakub Dawidek 492d1661a5SPawel Jakub Dawidek static MALLOC_DEFINE(M_RAID3, "raid3 data", "GEOM_RAID3 Data"); 502d1661a5SPawel Jakub Dawidek 512d1661a5SPawel Jakub Dawidek SYSCTL_DECL(_kern_geom); 522d1661a5SPawel Jakub Dawidek SYSCTL_NODE(_kern_geom, OID_AUTO, raid3, CTLFLAG_RW, 0, "GEOM_RAID3 stuff"); 532d1661a5SPawel Jakub Dawidek u_int g_raid3_debug = 1; 542d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, debug, CTLFLAG_RW, &g_raid3_debug, 0, 552d1661a5SPawel Jakub Dawidek "Debug level"); 562d1661a5SPawel Jakub Dawidek static u_int g_raid3_timeout = 8; 572d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, timeout, CTLFLAG_RW, &g_raid3_timeout, 582d1661a5SPawel Jakub Dawidek 0, "Time to wait on all raid3 components"); 592d1661a5SPawel Jakub Dawidek static u_int g_raid3_reqs_per_sync = 5; 602d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, reqs_per_sync, CTLFLAG_RW, 612d1661a5SPawel Jakub Dawidek &g_raid3_reqs_per_sync, 0, 622d1661a5SPawel Jakub Dawidek "Number of regular I/O requests per synchronization request"); 632d1661a5SPawel Jakub Dawidek static u_int g_raid3_syncs_per_sec = 100; 642d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, syncs_per_sec, CTLFLAG_RW, 652d1661a5SPawel Jakub Dawidek &g_raid3_syncs_per_sec, 0, 662d1661a5SPawel Jakub Dawidek "Number of synchronizations requests per second"); 672d1661a5SPawel Jakub Dawidek 682d1661a5SPawel Jakub Dawidek static u_int g_raid3_n64k = 50; 692d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n64k", &g_raid3_n64k); 702d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n64k, CTLFLAG_RD, &g_raid3_n64k, 0, 712d1661a5SPawel Jakub Dawidek "Maximum number of 64kB allocations"); 722d1661a5SPawel Jakub Dawidek static u_int g_raid3_n16k = 200; 732d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n16k", &g_raid3_n16k); 742d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n16k, CTLFLAG_RD, &g_raid3_n16k, 0, 752d1661a5SPawel Jakub Dawidek "Maximum number of 16kB allocations"); 762d1661a5SPawel Jakub Dawidek static u_int g_raid3_n4k = 1200; 772d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n4k", &g_raid3_n4k); 782d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n4k, CTLFLAG_RD, &g_raid3_n4k, 0, 792d1661a5SPawel Jakub Dawidek "Maximum number of 4kB allocations"); 802d1661a5SPawel Jakub Dawidek 812d1661a5SPawel Jakub Dawidek SYSCTL_NODE(_kern_geom_raid3, OID_AUTO, stat, CTLFLAG_RW, 0, 822d1661a5SPawel Jakub Dawidek "GEOM_RAID3 statistics"); 832d1661a5SPawel Jakub Dawidek static u_int g_raid3_64k_requested = 0; 842d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 64k_requested, CTLFLAG_RD, 852d1661a5SPawel Jakub Dawidek &g_raid3_64k_requested, 0, "Number of requested 64kB allocations"); 862d1661a5SPawel Jakub Dawidek static u_int g_raid3_64k_failed = 0; 872d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 64k_failed, CTLFLAG_RD, 882d1661a5SPawel Jakub Dawidek &g_raid3_64k_failed, 0, "Number of failed 64kB allocations"); 892d1661a5SPawel Jakub Dawidek static u_int g_raid3_16k_requested = 0; 902d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 16k_requested, CTLFLAG_RD, 912d1661a5SPawel Jakub Dawidek &g_raid3_16k_requested, 0, "Number of requested 16kB allocations"); 922d1661a5SPawel Jakub Dawidek static u_int g_raid3_16k_failed = 0; 932d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 16k_failed, CTLFLAG_RD, 942d1661a5SPawel Jakub Dawidek &g_raid3_16k_failed, 0, "Number of failed 16kB allocations"); 952d1661a5SPawel Jakub Dawidek static u_int g_raid3_4k_requested = 0; 962d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 4k_requested, CTLFLAG_RD, 972d1661a5SPawel Jakub Dawidek &g_raid3_4k_requested, 0, "Number of requested 4kB allocations"); 982d1661a5SPawel Jakub Dawidek static u_int g_raid3_4k_failed = 0; 992d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 4k_failed, CTLFLAG_RD, 1002d1661a5SPawel Jakub Dawidek &g_raid3_4k_failed, 0, "Number of failed 4kB allocations"); 1012d1661a5SPawel Jakub Dawidek 1022d1661a5SPawel Jakub Dawidek #define MSLEEP(ident, mtx, priority, wmesg, timeout) do { \ 1032d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, (ident)); \ 1042d1661a5SPawel Jakub Dawidek msleep((ident), (mtx), (priority), (wmesg), (timeout)); \ 1052d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Woken up %p.", __func__, (ident)); \ 1062d1661a5SPawel Jakub Dawidek } while (0) 1072d1661a5SPawel Jakub Dawidek 1082d1661a5SPawel Jakub Dawidek 1092d1661a5SPawel Jakub Dawidek static int g_raid3_destroy_geom(struct gctl_req *req, struct g_class *mp, 1102d1661a5SPawel Jakub Dawidek struct g_geom *gp); 1112d1661a5SPawel Jakub Dawidek static g_taste_t g_raid3_taste; 1122d1661a5SPawel Jakub Dawidek 1132d1661a5SPawel Jakub Dawidek struct g_class g_raid3_class = { 1142d1661a5SPawel Jakub Dawidek .name = G_RAID3_CLASS_NAME, 1152d1661a5SPawel Jakub Dawidek .version = G_VERSION, 1162d1661a5SPawel Jakub Dawidek .ctlreq = g_raid3_config, 1172d1661a5SPawel Jakub Dawidek .taste = g_raid3_taste, 1182d1661a5SPawel Jakub Dawidek .destroy_geom = g_raid3_destroy_geom 1192d1661a5SPawel Jakub Dawidek }; 1202d1661a5SPawel Jakub Dawidek 1212d1661a5SPawel Jakub Dawidek 1222d1661a5SPawel Jakub Dawidek static void g_raid3_destroy_provider(struct g_raid3_softc *sc); 1232d1661a5SPawel Jakub Dawidek static int g_raid3_update_disk(struct g_raid3_disk *disk, u_int state); 1242d1661a5SPawel Jakub Dawidek static void g_raid3_update_device(struct g_raid3_softc *sc, boolean_t force); 1252d1661a5SPawel Jakub Dawidek static void g_raid3_dumpconf(struct sbuf *sb, const char *indent, 1262d1661a5SPawel Jakub Dawidek struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp); 1272d1661a5SPawel Jakub Dawidek static void g_raid3_sync_stop(struct g_raid3_softc *sc, int type); 1282d1661a5SPawel Jakub Dawidek 1292d1661a5SPawel Jakub Dawidek 1302d1661a5SPawel Jakub Dawidek /* 1312d1661a5SPawel Jakub Dawidek * XXX: it should be placed in subr_disk.c. 1322d1661a5SPawel Jakub Dawidek */ 1332d1661a5SPawel Jakub Dawidek static void 1342d1661a5SPawel Jakub Dawidek bioq_insert_head(struct bio_queue_head *head, struct bio *bp) 1352d1661a5SPawel Jakub Dawidek { 1362d1661a5SPawel Jakub Dawidek 1372d1661a5SPawel Jakub Dawidek TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue); 1382d1661a5SPawel Jakub Dawidek } 1392d1661a5SPawel Jakub Dawidek 1402d1661a5SPawel Jakub Dawidek static const char * 1412d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(int state) 1422d1661a5SPawel Jakub Dawidek { 1432d1661a5SPawel Jakub Dawidek 1442d1661a5SPawel Jakub Dawidek switch (state) { 1452d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NODISK: 1462d1661a5SPawel Jakub Dawidek return ("NODISK"); 1472d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NONE: 1482d1661a5SPawel Jakub Dawidek return ("NONE"); 1492d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 1502d1661a5SPawel Jakub Dawidek return ("NEW"); 1512d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 1522d1661a5SPawel Jakub Dawidek return ("ACTIVE"); 1532d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 1542d1661a5SPawel Jakub Dawidek return ("STALE"); 1552d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 1562d1661a5SPawel Jakub Dawidek return ("SYNCHRONIZING"); 1572d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_DISCONNECTED: 1582d1661a5SPawel Jakub Dawidek return ("DISCONNECTED"); 1592d1661a5SPawel Jakub Dawidek default: 1602d1661a5SPawel Jakub Dawidek return ("INVALID"); 1612d1661a5SPawel Jakub Dawidek } 1622d1661a5SPawel Jakub Dawidek } 1632d1661a5SPawel Jakub Dawidek 1642d1661a5SPawel Jakub Dawidek static const char * 1652d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(int state) 1662d1661a5SPawel Jakub Dawidek { 1672d1661a5SPawel Jakub Dawidek 1682d1661a5SPawel Jakub Dawidek switch (state) { 1692d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_STARTING: 1702d1661a5SPawel Jakub Dawidek return ("STARTING"); 1712d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_DEGRADED: 1722d1661a5SPawel Jakub Dawidek return ("DEGRADED"); 1732d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_COMPLETE: 1742d1661a5SPawel Jakub Dawidek return ("COMPLETE"); 1752d1661a5SPawel Jakub Dawidek default: 1762d1661a5SPawel Jakub Dawidek return ("INVALID"); 1772d1661a5SPawel Jakub Dawidek } 1782d1661a5SPawel Jakub Dawidek } 1792d1661a5SPawel Jakub Dawidek 1802d1661a5SPawel Jakub Dawidek const char * 1812d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(struct g_raid3_disk *disk) 1822d1661a5SPawel Jakub Dawidek { 1832d1661a5SPawel Jakub Dawidek 1842d1661a5SPawel Jakub Dawidek if (disk->d_consumer == NULL || disk->d_consumer->provider == NULL) 1852d1661a5SPawel Jakub Dawidek return ("[unknown]"); 1862d1661a5SPawel Jakub Dawidek return (disk->d_name); 1872d1661a5SPawel Jakub Dawidek } 1882d1661a5SPawel Jakub Dawidek 1892d1661a5SPawel Jakub Dawidek #define g_raid3_xor(src1, src2, dst, size) \ 1902d1661a5SPawel Jakub Dawidek _g_raid3_xor((uint64_t *)(src1), (uint64_t *)(src2), \ 1912d1661a5SPawel Jakub Dawidek (uint64_t *)(dst), (size_t)size) 1922d1661a5SPawel Jakub Dawidek static void 1932d1661a5SPawel Jakub Dawidek _g_raid3_xor(uint64_t *src1, uint64_t *src2, uint64_t *dst, size_t size) 1942d1661a5SPawel Jakub Dawidek { 1952d1661a5SPawel Jakub Dawidek 1962d1661a5SPawel Jakub Dawidek KASSERT((size % 128) == 0, ("Invalid size: %zu.", size)); 1972d1661a5SPawel Jakub Dawidek for (; size > 0; size -= 128) { 1982d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 1992d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2002d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2012d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2022d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2032d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2042d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2052d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2062d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2072d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2082d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2092d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2102d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2112d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2122d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2132d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2142d1661a5SPawel Jakub Dawidek } 2152d1661a5SPawel Jakub Dawidek } 2162d1661a5SPawel Jakub Dawidek 2172d1661a5SPawel Jakub Dawidek /* 2182d1661a5SPawel Jakub Dawidek * --- Events handling functions --- 2192d1661a5SPawel Jakub Dawidek * Events in geom_raid3 are used to maintain disks and device status 2202d1661a5SPawel Jakub Dawidek * from one thread to simplify locking. 2212d1661a5SPawel Jakub Dawidek */ 2222d1661a5SPawel Jakub Dawidek static void 2232d1661a5SPawel Jakub Dawidek g_raid3_event_free(struct g_raid3_event *ep) 2242d1661a5SPawel Jakub Dawidek { 2252d1661a5SPawel Jakub Dawidek 2262d1661a5SPawel Jakub Dawidek free(ep, M_RAID3); 2272d1661a5SPawel Jakub Dawidek } 2282d1661a5SPawel Jakub Dawidek 2292d1661a5SPawel Jakub Dawidek int 2302d1661a5SPawel Jakub Dawidek g_raid3_event_send(void *arg, int state, int flags) 2312d1661a5SPawel Jakub Dawidek { 2322d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2332d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 2342d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 2352d1661a5SPawel Jakub Dawidek int error; 2362d1661a5SPawel Jakub Dawidek 2372d1661a5SPawel Jakub Dawidek ep = malloc(sizeof(*ep), M_RAID3, M_WAITOK); 2382d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sending event %p.", __func__, ep); 2392d1661a5SPawel Jakub Dawidek if ((flags & G_RAID3_EVENT_DEVICE) != 0) { 2402d1661a5SPawel Jakub Dawidek disk = NULL; 2412d1661a5SPawel Jakub Dawidek sc = arg; 2422d1661a5SPawel Jakub Dawidek } else { 2432d1661a5SPawel Jakub Dawidek disk = arg; 2442d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 2452d1661a5SPawel Jakub Dawidek } 2462d1661a5SPawel Jakub Dawidek ep->e_disk = disk; 2472d1661a5SPawel Jakub Dawidek ep->e_state = state; 2482d1661a5SPawel Jakub Dawidek ep->e_flags = flags; 2492d1661a5SPawel Jakub Dawidek ep->e_error = 0; 2502d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2512d1661a5SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_events, ep, e_next); 2522d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 2532d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 2542d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 2552d1661a5SPawel Jakub Dawidek wakeup(sc); 2562d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 2572d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 2582d1661a5SPawel Jakub Dawidek if ((flags & G_RAID3_EVENT_DONTWAIT) != 0) 2592d1661a5SPawel Jakub Dawidek return (0); 2602d1661a5SPawel Jakub Dawidek g_topology_assert(); 2612d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, ep); 2622d1661a5SPawel Jakub Dawidek g_topology_unlock(); 2632d1661a5SPawel Jakub Dawidek while ((ep->e_flags & G_RAID3_EVENT_DONE) == 0) { 2642d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2652d1661a5SPawel Jakub Dawidek MSLEEP(ep, &sc->sc_events_mtx, PRIBIO | PDROP, "r3:event", 2662d1661a5SPawel Jakub Dawidek hz * 5); 2672d1661a5SPawel Jakub Dawidek } 2682d1661a5SPawel Jakub Dawidek /* Don't even try to use 'sc' here, because it could be already dead. */ 2692d1661a5SPawel Jakub Dawidek g_topology_lock(); 2702d1661a5SPawel Jakub Dawidek error = ep->e_error; 2712d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 2722d1661a5SPawel Jakub Dawidek return (error); 2732d1661a5SPawel Jakub Dawidek } 2742d1661a5SPawel Jakub Dawidek 2752d1661a5SPawel Jakub Dawidek static struct g_raid3_event * 2762d1661a5SPawel Jakub Dawidek g_raid3_event_get(struct g_raid3_softc *sc) 2772d1661a5SPawel Jakub Dawidek { 2782d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 2792d1661a5SPawel Jakub Dawidek 2802d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2812d1661a5SPawel Jakub Dawidek ep = TAILQ_FIRST(&sc->sc_events); 2822d1661a5SPawel Jakub Dawidek if (ep != NULL) 2832d1661a5SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_events, ep, e_next); 2842d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 2852d1661a5SPawel Jakub Dawidek return (ep); 2862d1661a5SPawel Jakub Dawidek } 2872d1661a5SPawel Jakub Dawidek 2882d1661a5SPawel Jakub Dawidek static void 2892d1661a5SPawel Jakub Dawidek g_raid3_event_cancel(struct g_raid3_disk *disk) 2902d1661a5SPawel Jakub Dawidek { 2912d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2922d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep, *tmpep; 2932d1661a5SPawel Jakub Dawidek 2942d1661a5SPawel Jakub Dawidek g_topology_assert(); 2952d1661a5SPawel Jakub Dawidek 2962d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 2972d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2982d1661a5SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(ep, &sc->sc_events, e_next, tmpep) { 2992d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DEVICE) != 0) 3002d1661a5SPawel Jakub Dawidek continue; 3012d1661a5SPawel Jakub Dawidek if (ep->e_disk != disk) 3022d1661a5SPawel Jakub Dawidek continue; 3032d1661a5SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_events, ep, e_next); 3042d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) 3052d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 3062d1661a5SPawel Jakub Dawidek else { 3072d1661a5SPawel Jakub Dawidek ep->e_error = ECANCELED; 3082d1661a5SPawel Jakub Dawidek wakeup(ep); 3092d1661a5SPawel Jakub Dawidek } 3102d1661a5SPawel Jakub Dawidek } 3112d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 3122d1661a5SPawel Jakub Dawidek } 3132d1661a5SPawel Jakub Dawidek 3142d1661a5SPawel Jakub Dawidek /* 3152d1661a5SPawel Jakub Dawidek * Return the number of disks in the given state. 3162d1661a5SPawel Jakub Dawidek * If state is equal to -1, count all connected disks. 3172d1661a5SPawel Jakub Dawidek */ 3182d1661a5SPawel Jakub Dawidek u_int 3192d1661a5SPawel Jakub Dawidek g_raid3_ndisks(struct g_raid3_softc *sc, int state) 3202d1661a5SPawel Jakub Dawidek { 3212d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 3222d1661a5SPawel Jakub Dawidek u_int n, ndisks = 0; 3232d1661a5SPawel Jakub Dawidek 3242d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 3252d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 3262d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 3272d1661a5SPawel Jakub Dawidek continue; 3282d1661a5SPawel Jakub Dawidek if (state == -1 || disk->d_state == state) 3292d1661a5SPawel Jakub Dawidek ndisks++; 3302d1661a5SPawel Jakub Dawidek } 3312d1661a5SPawel Jakub Dawidek return (ndisks); 3322d1661a5SPawel Jakub Dawidek } 3332d1661a5SPawel Jakub Dawidek 3342d1661a5SPawel Jakub Dawidek static u_int 3352d1661a5SPawel Jakub Dawidek g_raid3_nrequests(struct g_raid3_softc *sc, struct g_consumer *cp) 3362d1661a5SPawel Jakub Dawidek { 3372d1661a5SPawel Jakub Dawidek struct bio *bp; 3382d1661a5SPawel Jakub Dawidek u_int nreqs = 0; 3392d1661a5SPawel Jakub Dawidek 3402d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 3412d1661a5SPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_queue.queue, bio_queue) { 3422d1661a5SPawel Jakub Dawidek if (bp->bio_from == cp) 3432d1661a5SPawel Jakub Dawidek nreqs++; 3442d1661a5SPawel Jakub Dawidek } 3452d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 3462d1661a5SPawel Jakub Dawidek return (nreqs); 3472d1661a5SPawel Jakub Dawidek } 3482d1661a5SPawel Jakub Dawidek 3492d1661a5SPawel Jakub Dawidek static int 3502d1661a5SPawel Jakub Dawidek g_raid3_is_busy(struct g_raid3_softc *sc, struct g_consumer *cp) 3512d1661a5SPawel Jakub Dawidek { 3522d1661a5SPawel Jakub Dawidek 3532d1661a5SPawel Jakub Dawidek if (cp->nstart != cp->nend) { 3542d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, 3552d1661a5SPawel Jakub Dawidek "I/O requests for %s exist, can't destroy it now.", 3562d1661a5SPawel Jakub Dawidek cp->provider->name); 3572d1661a5SPawel Jakub Dawidek return (1); 3582d1661a5SPawel Jakub Dawidek } 3592d1661a5SPawel Jakub Dawidek if (g_raid3_nrequests(sc, cp) > 0) { 3602d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, 3612d1661a5SPawel Jakub Dawidek "I/O requests for %s in queue, can't destroy it now.", 3622d1661a5SPawel Jakub Dawidek cp->provider->name); 3632d1661a5SPawel Jakub Dawidek return (1); 3642d1661a5SPawel Jakub Dawidek } 3652d1661a5SPawel Jakub Dawidek return (0); 3662d1661a5SPawel Jakub Dawidek } 3672d1661a5SPawel Jakub Dawidek 3682d1661a5SPawel Jakub Dawidek static void 3692d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(struct g_raid3_softc *sc, struct g_consumer *cp) 3702d1661a5SPawel Jakub Dawidek { 3712d1661a5SPawel Jakub Dawidek 3722d1661a5SPawel Jakub Dawidek g_topology_assert(); 3732d1661a5SPawel Jakub Dawidek 3742d1661a5SPawel Jakub Dawidek cp->private = NULL; 3752d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 3762d1661a5SPawel Jakub Dawidek return; 3772d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Consumer %s destroyed.", cp->provider->name); 3782d1661a5SPawel Jakub Dawidek g_detach(cp); 3792d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 3802d1661a5SPawel Jakub Dawidek } 3812d1661a5SPawel Jakub Dawidek 3822d1661a5SPawel Jakub Dawidek static int 3832d1661a5SPawel Jakub Dawidek g_raid3_connect_disk(struct g_raid3_disk *disk, struct g_provider *pp) 3842d1661a5SPawel Jakub Dawidek { 3852d1661a5SPawel Jakub Dawidek int error; 3862d1661a5SPawel Jakub Dawidek 3872d1661a5SPawel Jakub Dawidek g_topology_assert(); 3882d1661a5SPawel Jakub Dawidek KASSERT(disk->d_consumer == NULL, 3892d1661a5SPawel Jakub Dawidek ("Disk already connected (device %s).", disk->d_softc->sc_name)); 3902d1661a5SPawel Jakub Dawidek 3912d1661a5SPawel Jakub Dawidek disk->d_consumer = g_new_consumer(disk->d_softc->sc_geom); 3922d1661a5SPawel Jakub Dawidek disk->d_consumer->private = disk; 3932d1661a5SPawel Jakub Dawidek error = g_attach(disk->d_consumer, pp); 3942d1661a5SPawel Jakub Dawidek if (error != 0) 3952d1661a5SPawel Jakub Dawidek return (error); 3962d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Disk %s connected.", g_raid3_get_diskname(disk)); 3972d1661a5SPawel Jakub Dawidek return (0); 3982d1661a5SPawel Jakub Dawidek } 3992d1661a5SPawel Jakub Dawidek 4002d1661a5SPawel Jakub Dawidek static void 4012d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(struct g_raid3_softc *sc, struct g_consumer *cp) 4022d1661a5SPawel Jakub Dawidek { 4032d1661a5SPawel Jakub Dawidek 4042d1661a5SPawel Jakub Dawidek g_topology_assert(); 4052d1661a5SPawel Jakub Dawidek 4062d1661a5SPawel Jakub Dawidek if (cp == NULL) 4072d1661a5SPawel Jakub Dawidek return; 4082d1661a5SPawel Jakub Dawidek if (cp->provider != NULL) { 4092d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Disk %s disconnected.", cp->provider->name); 4102d1661a5SPawel Jakub Dawidek if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) { 4112d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", 4122d1661a5SPawel Jakub Dawidek cp->provider->name, -cp->acr, -cp->acw, -cp->ace, 4132d1661a5SPawel Jakub Dawidek 0); 4142d1661a5SPawel Jakub Dawidek g_access(cp, -cp->acr, -cp->acw, -cp->ace); 4152d1661a5SPawel Jakub Dawidek } 4162d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, cp); 4172d1661a5SPawel Jakub Dawidek } else { 4182d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 4192d1661a5SPawel Jakub Dawidek } 4202d1661a5SPawel Jakub Dawidek } 4212d1661a5SPawel Jakub Dawidek 4222d1661a5SPawel Jakub Dawidek /* 4232d1661a5SPawel Jakub Dawidek * Initialize disk. This means allocate memory, create consumer, attach it 4242d1661a5SPawel Jakub Dawidek * to the provider and open access (r1w1e1) to it. 4252d1661a5SPawel Jakub Dawidek */ 4262d1661a5SPawel Jakub Dawidek static struct g_raid3_disk * 4272d1661a5SPawel Jakub Dawidek g_raid3_init_disk(struct g_raid3_softc *sc, struct g_provider *pp, 4282d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md, int *errorp) 4292d1661a5SPawel Jakub Dawidek { 4302d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 4312d1661a5SPawel Jakub Dawidek int error; 4322d1661a5SPawel Jakub Dawidek 4332d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[md->md_no]; 4342d1661a5SPawel Jakub Dawidek disk->d_softc = sc; 4352d1661a5SPawel Jakub Dawidek error = g_raid3_connect_disk(disk, pp); 4362d1661a5SPawel Jakub Dawidek if (error != 0) 4372d1661a5SPawel Jakub Dawidek goto fail; 4382d1661a5SPawel Jakub Dawidek disk->d_no = md->md_no; 4392d1661a5SPawel Jakub Dawidek disk->d_state = G_RAID3_DISK_STATE_NONE; 4402d1661a5SPawel Jakub Dawidek disk->d_flags = md->md_dflags; 4412d1661a5SPawel Jakub Dawidek if (md->md_provider[0] != '\0') 4422d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_HARDCODED; 4432d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = NULL; 4442d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = md->md_sync_offset; 4452d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = md->md_sync_offset; 4462d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = md->md_syncid; 4472d1661a5SPawel Jakub Dawidek if (errorp != NULL) 4482d1661a5SPawel Jakub Dawidek *errorp = 0; 4492d1661a5SPawel Jakub Dawidek return (disk); 4502d1661a5SPawel Jakub Dawidek fail: 4512d1661a5SPawel Jakub Dawidek if (errorp != NULL) 4522d1661a5SPawel Jakub Dawidek *errorp = error; 4532d1661a5SPawel Jakub Dawidek if (disk != NULL) 4542d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(sc, disk->d_consumer); 4552d1661a5SPawel Jakub Dawidek return (NULL); 4562d1661a5SPawel Jakub Dawidek } 4572d1661a5SPawel Jakub Dawidek 4582d1661a5SPawel Jakub Dawidek static void 4592d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(struct g_raid3_disk *disk) 4602d1661a5SPawel Jakub Dawidek { 4612d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 4622d1661a5SPawel Jakub Dawidek 4632d1661a5SPawel Jakub Dawidek g_topology_assert(); 4642d1661a5SPawel Jakub Dawidek 4652d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 4662d1661a5SPawel Jakub Dawidek return; 4672d1661a5SPawel Jakub Dawidek g_raid3_event_cancel(disk); 4682d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 4692d1661a5SPawel Jakub Dawidek switch (disk->d_state) { 4702d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 4712d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL) 4722d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 1); 4732d1661a5SPawel Jakub Dawidek /* FALLTHROUGH */ 4742d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 4752d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 4762d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 4772d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(sc, disk->d_consumer); 4782d1661a5SPawel Jakub Dawidek disk->d_consumer = NULL; 4792d1661a5SPawel Jakub Dawidek break; 4802d1661a5SPawel Jakub Dawidek default: 4812d1661a5SPawel Jakub Dawidek KASSERT(0 == 1, ("Wrong disk state (%s, %s).", 4822d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 4832d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 4842d1661a5SPawel Jakub Dawidek } 4852d1661a5SPawel Jakub Dawidek disk->d_state = G_RAID3_DISK_STATE_NODISK; 4862d1661a5SPawel Jakub Dawidek } 4872d1661a5SPawel Jakub Dawidek 4882d1661a5SPawel Jakub Dawidek static void 4892d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(struct g_raid3_softc *sc) 4902d1661a5SPawel Jakub Dawidek { 4912d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 4922d1661a5SPawel Jakub Dawidek struct g_geom *gp; 4932d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 4942d1661a5SPawel Jakub Dawidek u_int n; 4952d1661a5SPawel Jakub Dawidek 4962d1661a5SPawel Jakub Dawidek g_topology_assert(); 4972d1661a5SPawel Jakub Dawidek 4982d1661a5SPawel Jakub Dawidek gp = sc->sc_geom; 4992d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) 5002d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(sc); 5012d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) 5022d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(&sc->sc_disks[n]); 5032d1661a5SPawel Jakub Dawidek while ((ep = g_raid3_event_get(sc)) != NULL) { 5042d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) 5052d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 5062d1661a5SPawel Jakub Dawidek else { 5072d1661a5SPawel Jakub Dawidek ep->e_error = ECANCELED; 5082d1661a5SPawel Jakub Dawidek ep->e_flags |= G_RAID3_EVENT_DONE; 5092d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, ep); 5102d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 5112d1661a5SPawel Jakub Dawidek wakeup(ep); 5122d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 5132d1661a5SPawel Jakub Dawidek } 5142d1661a5SPawel Jakub Dawidek } 5152d1661a5SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 5162d1661a5SPawel Jakub Dawidek gp->softc = NULL; 5172d1661a5SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_sync.ds_geom->consumer); 5182d1661a5SPawel Jakub Dawidek if (cp != NULL) 5192d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(sc, cp); 5202d1661a5SPawel Jakub Dawidek sc->sc_sync.ds_geom->softc = NULL; 5212d1661a5SPawel Jakub Dawidek g_wither_geom(sc->sc_sync.ds_geom, ENXIO); 5222d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_64k); 5232d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_16k); 5242d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_4k); 5252d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 5262d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_events_mtx); 5272d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s destroyed.", gp->name); 5282d1661a5SPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 5292d1661a5SPawel Jakub Dawidek } 5302d1661a5SPawel Jakub Dawidek 5312d1661a5SPawel Jakub Dawidek static void 5322d1661a5SPawel Jakub Dawidek g_raid3_orphan(struct g_consumer *cp) 5332d1661a5SPawel Jakub Dawidek { 5342d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 5352d1661a5SPawel Jakub Dawidek 5362d1661a5SPawel Jakub Dawidek g_topology_assert(); 5372d1661a5SPawel Jakub Dawidek 5382d1661a5SPawel Jakub Dawidek disk = cp->private; 5392d1661a5SPawel Jakub Dawidek if (disk == NULL) 5402d1661a5SPawel Jakub Dawidek return; 5412d1661a5SPawel Jakub Dawidek disk->d_softc->sc_bump_syncid = G_RAID3_BUMP_ON_FIRST_WRITE; 5422d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 5432d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 5442d1661a5SPawel Jakub Dawidek } 5452d1661a5SPawel Jakub Dawidek 5462d1661a5SPawel Jakub Dawidek static void 5472d1661a5SPawel Jakub Dawidek g_raid3_spoiled(struct g_consumer *cp) 5482d1661a5SPawel Jakub Dawidek { 5492d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 5502d1661a5SPawel Jakub Dawidek 5512d1661a5SPawel Jakub Dawidek g_topology_assert(); 5522d1661a5SPawel Jakub Dawidek 5532d1661a5SPawel Jakub Dawidek disk = cp->private; 5542d1661a5SPawel Jakub Dawidek if (disk == NULL) 5552d1661a5SPawel Jakub Dawidek return; 5562d1661a5SPawel Jakub Dawidek disk->d_softc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; 5572d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 5582d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 5592d1661a5SPawel Jakub Dawidek } 5602d1661a5SPawel Jakub Dawidek 5612d1661a5SPawel Jakub Dawidek static int 5622d1661a5SPawel Jakub Dawidek g_raid3_write_metadata(struct g_raid3_disk *disk, struct g_raid3_metadata *md) 5632d1661a5SPawel Jakub Dawidek { 5642d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 5652d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 5662d1661a5SPawel Jakub Dawidek off_t offset, length; 5672d1661a5SPawel Jakub Dawidek int close = 0, error = 0; 5682d1661a5SPawel Jakub Dawidek u_char *sector; 5692d1661a5SPawel Jakub Dawidek 5702d1661a5SPawel Jakub Dawidek g_topology_assert(); 5712d1661a5SPawel Jakub Dawidek 5722d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 5732d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 5742d1661a5SPawel Jakub Dawidek KASSERT(cp != NULL, ("NULL consumer (%s).", sc->sc_name)); 5752d1661a5SPawel Jakub Dawidek KASSERT(cp->provider != NULL, ("NULL provider (%s).", sc->sc_name)); 5762d1661a5SPawel Jakub Dawidek length = cp->provider->sectorsize; 5772d1661a5SPawel Jakub Dawidek offset = cp->provider->mediasize - length; 5782d1661a5SPawel Jakub Dawidek sector = malloc((size_t)length, M_RAID3, M_WAITOK | M_ZERO); 5792d1661a5SPawel Jakub Dawidek /* 5802d1661a5SPawel Jakub Dawidek * Open consumer if it wasn't opened and remember to close it. 5812d1661a5SPawel Jakub Dawidek */ 5822d1661a5SPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) == 0) { 5832d1661a5SPawel Jakub Dawidek error = g_access(cp, 0, 1, 1); 5842d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", cp->provider->name, 5852d1661a5SPawel Jakub Dawidek 0, 1, 1, error); 5862d1661a5SPawel Jakub Dawidek if (error == 0) 5872d1661a5SPawel Jakub Dawidek close = 1; 5882d1661a5SPawel Jakub Dawidek #ifdef INVARIANTS 5892d1661a5SPawel Jakub Dawidek } else { 5902d1661a5SPawel Jakub Dawidek KASSERT(cp->acw > 0 && cp->ace > 0, 5912d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 5922d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 5932d1661a5SPawel Jakub Dawidek #endif 5942d1661a5SPawel Jakub Dawidek } 5952d1661a5SPawel Jakub Dawidek if (error == 0) { 5962d1661a5SPawel Jakub Dawidek if (md != NULL) 5972d1661a5SPawel Jakub Dawidek raid3_metadata_encode(md, sector); 5982d1661a5SPawel Jakub Dawidek g_topology_unlock(); 5992d1661a5SPawel Jakub Dawidek error = g_write_data(cp, offset, sector, length); 6002d1661a5SPawel Jakub Dawidek g_topology_lock(); 6012d1661a5SPawel Jakub Dawidek } 6022d1661a5SPawel Jakub Dawidek free(sector, M_RAID3); 6032d1661a5SPawel Jakub Dawidek if (close) { 6042d1661a5SPawel Jakub Dawidek g_access(cp, 0, -1, -1); 6052d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", 6062d1661a5SPawel Jakub Dawidek cp->provider->name, 0, -1, -1, 0); 6072d1661a5SPawel Jakub Dawidek } 6082d1661a5SPawel Jakub Dawidek if (error != 0) { 6092d1661a5SPawel Jakub Dawidek disk->d_softc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; 6102d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 6112d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 6122d1661a5SPawel Jakub Dawidek } 6132d1661a5SPawel Jakub Dawidek return (error); 6142d1661a5SPawel Jakub Dawidek } 6152d1661a5SPawel Jakub Dawidek 6162d1661a5SPawel Jakub Dawidek int 6172d1661a5SPawel Jakub Dawidek g_raid3_clear_metadata(struct g_raid3_disk *disk) 6182d1661a5SPawel Jakub Dawidek { 6192d1661a5SPawel Jakub Dawidek int error; 6202d1661a5SPawel Jakub Dawidek 6212d1661a5SPawel Jakub Dawidek g_topology_assert(); 6222d1661a5SPawel Jakub Dawidek error = g_raid3_write_metadata(disk, NULL); 6232d1661a5SPawel Jakub Dawidek if (error == 0) { 6242d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Metadata on %s cleared.", 6252d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 6262d1661a5SPawel Jakub Dawidek } else { 6272d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 6282d1661a5SPawel Jakub Dawidek "Cannot clear metadata on disk %s (error=%d).", 6292d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), error); 6302d1661a5SPawel Jakub Dawidek } 6312d1661a5SPawel Jakub Dawidek return (error); 6322d1661a5SPawel Jakub Dawidek } 6332d1661a5SPawel Jakub Dawidek 6342d1661a5SPawel Jakub Dawidek void 6352d1661a5SPawel Jakub Dawidek g_raid3_fill_metadata(struct g_raid3_disk *disk, struct g_raid3_metadata *md) 6362d1661a5SPawel Jakub Dawidek { 6372d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 6382d1661a5SPawel Jakub Dawidek 6392d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 6402d1661a5SPawel Jakub Dawidek strlcpy(md->md_magic, G_RAID3_MAGIC, sizeof(md->md_magic)); 6412d1661a5SPawel Jakub Dawidek md->md_version = G_RAID3_VERSION; 6422d1661a5SPawel Jakub Dawidek strlcpy(md->md_name, sc->sc_name, sizeof(md->md_name)); 6432d1661a5SPawel Jakub Dawidek md->md_id = sc->sc_id; 6442d1661a5SPawel Jakub Dawidek md->md_all = sc->sc_ndisks; 6452d1661a5SPawel Jakub Dawidek md->md_mediasize = sc->sc_mediasize; 6462d1661a5SPawel Jakub Dawidek md->md_sectorsize = sc->sc_sectorsize; 6472d1661a5SPawel Jakub Dawidek md->md_mflags = (sc->sc_flags & G_RAID3_DEVICE_FLAG_MASK); 6482d1661a5SPawel Jakub Dawidek md->md_no = disk->d_no; 6492d1661a5SPawel Jakub Dawidek md->md_syncid = disk->d_sync.ds_syncid; 6502d1661a5SPawel Jakub Dawidek md->md_dflags = (disk->d_flags & G_RAID3_DISK_FLAG_MASK); 6512d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 6522d1661a5SPawel Jakub Dawidek md->md_sync_offset = disk->d_sync.ds_offset_done; 6532d1661a5SPawel Jakub Dawidek else 6542d1661a5SPawel Jakub Dawidek md->md_sync_offset = 0; 6552d1661a5SPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_HARDCODED) != 0 && 6562d1661a5SPawel Jakub Dawidek disk->d_consumer != NULL && disk->d_consumer->provider != NULL) { 6572d1661a5SPawel Jakub Dawidek strlcpy(md->md_provider, disk->d_consumer->provider->name, 6582d1661a5SPawel Jakub Dawidek sizeof(md->md_provider)); 6592d1661a5SPawel Jakub Dawidek } else { 6602d1661a5SPawel Jakub Dawidek bzero(md->md_provider, sizeof(md->md_provider)); 6612d1661a5SPawel Jakub Dawidek } 6622d1661a5SPawel Jakub Dawidek } 6632d1661a5SPawel Jakub Dawidek 6642d1661a5SPawel Jakub Dawidek void 6652d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(struct g_raid3_disk *disk) 6662d1661a5SPawel Jakub Dawidek { 6672d1661a5SPawel Jakub Dawidek struct g_raid3_metadata md; 6682d1661a5SPawel Jakub Dawidek int error; 6692d1661a5SPawel Jakub Dawidek 6702d1661a5SPawel Jakub Dawidek g_topology_assert(); 6712d1661a5SPawel Jakub Dawidek g_raid3_fill_metadata(disk, &md); 6722d1661a5SPawel Jakub Dawidek error = g_raid3_write_metadata(disk, &md); 6732d1661a5SPawel Jakub Dawidek if (error == 0) { 6742d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Metadata on %s updated.", 6752d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 6762d1661a5SPawel Jakub Dawidek } else { 6772d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 6782d1661a5SPawel Jakub Dawidek "Cannot update metadata on disk %s (error=%d).", 6792d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), error); 6802d1661a5SPawel Jakub Dawidek } 6812d1661a5SPawel Jakub Dawidek } 6822d1661a5SPawel Jakub Dawidek 6832d1661a5SPawel Jakub Dawidek static void 6842d1661a5SPawel Jakub Dawidek g_raid3_bump_syncid(struct g_raid3_softc *sc) 6852d1661a5SPawel Jakub Dawidek { 6862d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 6872d1661a5SPawel Jakub Dawidek u_int n; 6882d1661a5SPawel Jakub Dawidek 6892d1661a5SPawel Jakub Dawidek g_topology_assert(); 6902d1661a5SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) > 0, 6912d1661a5SPawel Jakub Dawidek ("%s called with no active disks (device=%s).", __func__, 6922d1661a5SPawel Jakub Dawidek sc->sc_name)); 6932d1661a5SPawel Jakub Dawidek 6942d1661a5SPawel Jakub Dawidek sc->sc_syncid++; 6952d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 6962d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 6972d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 6982d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 6992d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = sc->sc_syncid; 7002d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 7012d1661a5SPawel Jakub Dawidek } 7022d1661a5SPawel Jakub Dawidek } 7032d1661a5SPawel Jakub Dawidek } 7042d1661a5SPawel Jakub Dawidek 7052d1661a5SPawel Jakub Dawidek /* 7062d1661a5SPawel Jakub Dawidek * Treat bio_driver1 field in parent bio as list head and field bio_caller1 7072d1661a5SPawel Jakub Dawidek * in child bio as pointer to the next element on the list. 7082d1661a5SPawel Jakub Dawidek */ 7092d1661a5SPawel Jakub Dawidek #define G_RAID3_HEAD_BIO(pbp) (pbp)->bio_driver1 7102d1661a5SPawel Jakub Dawidek 7112d1661a5SPawel Jakub Dawidek #define G_RAID3_NEXT_BIO(cbp) (cbp)->bio_caller1 7122d1661a5SPawel Jakub Dawidek 7132d1661a5SPawel Jakub Dawidek #define G_RAID3_FOREACH_BIO(pbp, bp) \ 7142d1661a5SPawel Jakub Dawidek for ((bp) = G_RAID3_HEAD_BIO(pbp); (bp) != NULL; \ 7152d1661a5SPawel Jakub Dawidek (bp) = G_RAID3_NEXT_BIO(bp)) 7162d1661a5SPawel Jakub Dawidek 7172d1661a5SPawel Jakub Dawidek #define G_RAID3_FOREACH_SAFE_BIO(pbp, bp, tmpbp) \ 7182d1661a5SPawel Jakub Dawidek for ((bp) = G_RAID3_HEAD_BIO(pbp); \ 7192d1661a5SPawel Jakub Dawidek (bp) != NULL && ((tmpbp) = G_RAID3_NEXT_BIO(bp), 1); \ 7202d1661a5SPawel Jakub Dawidek (bp) = (tmpbp)) 7212d1661a5SPawel Jakub Dawidek 7222d1661a5SPawel Jakub Dawidek static void 7232d1661a5SPawel Jakub Dawidek g_raid3_init_bio(struct bio *pbp) 7242d1661a5SPawel Jakub Dawidek { 7252d1661a5SPawel Jakub Dawidek 7262d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = NULL; 7272d1661a5SPawel Jakub Dawidek } 7282d1661a5SPawel Jakub Dawidek 7292d1661a5SPawel Jakub Dawidek static void 7302d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(struct g_raid3_softc *sc, struct bio *cbp) 7312d1661a5SPawel Jakub Dawidek { 7322d1661a5SPawel Jakub Dawidek struct bio *bp, *pbp; 7332d1661a5SPawel Jakub Dawidek size_t size; 7342d1661a5SPawel Jakub Dawidek 7352d1661a5SPawel Jakub Dawidek pbp = cbp->bio_parent; 7362d1661a5SPawel Jakub Dawidek pbp->bio_children--; 7372d1661a5SPawel Jakub Dawidek KASSERT(cbp->bio_data != NULL, ("NULL bio_data")); 7382d1661a5SPawel Jakub Dawidek size = pbp->bio_length / (sc->sc_ndisks - 1); 7392d1661a5SPawel Jakub Dawidek if (size > 16384) 7402d1661a5SPawel Jakub Dawidek uma_zfree(sc->sc_zone_64k, cbp->bio_data); 7412d1661a5SPawel Jakub Dawidek else if (size > 4096) 7422d1661a5SPawel Jakub Dawidek uma_zfree(sc->sc_zone_16k, cbp->bio_data); 7432d1661a5SPawel Jakub Dawidek else 7442d1661a5SPawel Jakub Dawidek uma_zfree(sc->sc_zone_4k, cbp->bio_data); 7452d1661a5SPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == cbp) { 7462d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = G_RAID3_NEXT_BIO(cbp); 7472d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 7482d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 7492d1661a5SPawel Jakub Dawidek } else { 7502d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 7512d1661a5SPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == cbp) 7522d1661a5SPawel Jakub Dawidek break; 7532d1661a5SPawel Jakub Dawidek } 7542d1661a5SPawel Jakub Dawidek KASSERT(bp != NULL, ("NULL bp")); 7552d1661a5SPawel Jakub Dawidek KASSERT(G_RAID3_NEXT_BIO(bp) != NULL, ("NULL bp->bio_driver1")); 7562d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); 7572d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 7582d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 7592d1661a5SPawel Jakub Dawidek } 7602d1661a5SPawel Jakub Dawidek } 7612d1661a5SPawel Jakub Dawidek 7622d1661a5SPawel Jakub Dawidek static struct bio * 7632d1661a5SPawel Jakub Dawidek g_raid3_clone_bio(struct g_raid3_softc *sc, struct bio *pbp) 7642d1661a5SPawel Jakub Dawidek { 7652d1661a5SPawel Jakub Dawidek struct bio *bp, *cbp; 7662d1661a5SPawel Jakub Dawidek size_t size; 7672d1661a5SPawel Jakub Dawidek 7682d1661a5SPawel Jakub Dawidek cbp = g_clone_bio(pbp); 7692d1661a5SPawel Jakub Dawidek if (cbp == NULL) 7702d1661a5SPawel Jakub Dawidek return (NULL); 7712d1661a5SPawel Jakub Dawidek size = pbp->bio_length / (sc->sc_ndisks - 1); 7722d1661a5SPawel Jakub Dawidek if (size > 16384) { 7732d1661a5SPawel Jakub Dawidek cbp->bio_data = uma_zalloc(sc->sc_zone_64k, M_NOWAIT); 7742d1661a5SPawel Jakub Dawidek g_raid3_64k_requested++; 7752d1661a5SPawel Jakub Dawidek } else if (size > 4096) { 7762d1661a5SPawel Jakub Dawidek cbp->bio_data = uma_zalloc(sc->sc_zone_16k, M_NOWAIT); 7772d1661a5SPawel Jakub Dawidek g_raid3_16k_requested++; 7782d1661a5SPawel Jakub Dawidek } else { 7792d1661a5SPawel Jakub Dawidek cbp->bio_data = uma_zalloc(sc->sc_zone_4k, M_NOWAIT); 7802d1661a5SPawel Jakub Dawidek g_raid3_4k_requested++; 7812d1661a5SPawel Jakub Dawidek } 7822d1661a5SPawel Jakub Dawidek if (cbp->bio_data == NULL) { 7832d1661a5SPawel Jakub Dawidek if (size > 16384) 7842d1661a5SPawel Jakub Dawidek g_raid3_64k_failed++; 7852d1661a5SPawel Jakub Dawidek if (size > 4096) 7862d1661a5SPawel Jakub Dawidek g_raid3_16k_failed++; 7872d1661a5SPawel Jakub Dawidek else 7882d1661a5SPawel Jakub Dawidek g_raid3_4k_failed++; 7892d1661a5SPawel Jakub Dawidek pbp->bio_children--; 7902d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 7912d1661a5SPawel Jakub Dawidek return (NULL); 7922d1661a5SPawel Jakub Dawidek } 7932d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 7942d1661a5SPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == NULL) 7952d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = cbp; 7962d1661a5SPawel Jakub Dawidek else { 7972d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 7982d1661a5SPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == NULL) { 7992d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = cbp; 8002d1661a5SPawel Jakub Dawidek break; 8012d1661a5SPawel Jakub Dawidek } 8022d1661a5SPawel Jakub Dawidek } 8032d1661a5SPawel Jakub Dawidek } 8042d1661a5SPawel Jakub Dawidek return (cbp); 8052d1661a5SPawel Jakub Dawidek } 8062d1661a5SPawel Jakub Dawidek 8072d1661a5SPawel Jakub Dawidek static void 8082d1661a5SPawel Jakub Dawidek g_raid3_scatter(struct bio *pbp) 8092d1661a5SPawel Jakub Dawidek { 8102d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 8112d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 8122d1661a5SPawel Jakub Dawidek struct bio *bp, *cbp; 8132d1661a5SPawel Jakub Dawidek off_t atom, cadd, padd, left; 8142d1661a5SPawel Jakub Dawidek 8152d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 8162d1661a5SPawel Jakub Dawidek bp = NULL; 8172d1661a5SPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_NOPARITY) == 0) { 8182d1661a5SPawel Jakub Dawidek /* 8192d1661a5SPawel Jakub Dawidek * Find bio for which we should calculate data. 8202d1661a5SPawel Jakub Dawidek */ 8212d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 8222d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { 8232d1661a5SPawel Jakub Dawidek bp = cbp; 8242d1661a5SPawel Jakub Dawidek break; 8252d1661a5SPawel Jakub Dawidek } 8262d1661a5SPawel Jakub Dawidek } 8272d1661a5SPawel Jakub Dawidek KASSERT(bp != NULL, ("NULL parity bio.")); 8282d1661a5SPawel Jakub Dawidek } 8292d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 8302d1661a5SPawel Jakub Dawidek cadd = padd = 0; 8312d1661a5SPawel Jakub Dawidek for (left = pbp->bio_length; left > 0; left -= sc->sc_sectorsize) { 8322d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 8332d1661a5SPawel Jakub Dawidek if (cbp == bp) 8342d1661a5SPawel Jakub Dawidek continue; 8352d1661a5SPawel Jakub Dawidek bcopy(pbp->bio_data + padd, cbp->bio_data + cadd, atom); 8362d1661a5SPawel Jakub Dawidek padd += atom; 8372d1661a5SPawel Jakub Dawidek } 8382d1661a5SPawel Jakub Dawidek cadd += atom; 8392d1661a5SPawel Jakub Dawidek } 8402d1661a5SPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_NOPARITY) == 0) { 8412d1661a5SPawel Jakub Dawidek struct bio *tmpbp; 8422d1661a5SPawel Jakub Dawidek 8432d1661a5SPawel Jakub Dawidek /* 8442d1661a5SPawel Jakub Dawidek * Calculate parity. 8452d1661a5SPawel Jakub Dawidek */ 8462d1661a5SPawel Jakub Dawidek bzero(bp->bio_data, bp->bio_length); 8472d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_SAFE_BIO(pbp, cbp, tmpbp) { 8482d1661a5SPawel Jakub Dawidek if (cbp == bp) 8492d1661a5SPawel Jakub Dawidek continue; 8502d1661a5SPawel Jakub Dawidek g_raid3_xor(cbp->bio_data, bp->bio_data, bp->bio_data, 8512d1661a5SPawel Jakub Dawidek bp->bio_length); 8522d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_NODISK) != 0) 8532d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 8542d1661a5SPawel Jakub Dawidek } 8552d1661a5SPawel Jakub Dawidek } 8562d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 8572d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 8582d1661a5SPawel Jakub Dawidek 8592d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 8602d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 8612d1661a5SPawel Jakub Dawidek cbp->bio_to = cp->provider; 8622d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Sending request."); 8632d1661a5SPawel Jakub Dawidek KASSERT(cp->acr > 0 && cp->ace > 0, 8642d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 8652d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 8662d1661a5SPawel Jakub Dawidek g_io_request(cbp, cp); 8672d1661a5SPawel Jakub Dawidek } 8682d1661a5SPawel Jakub Dawidek } 8692d1661a5SPawel Jakub Dawidek 8702d1661a5SPawel Jakub Dawidek static void 8712d1661a5SPawel Jakub Dawidek g_raid3_gather(struct bio *pbp) 8722d1661a5SPawel Jakub Dawidek { 8732d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 8742d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 8752d1661a5SPawel Jakub Dawidek struct bio *bp, *cbp; 8762d1661a5SPawel Jakub Dawidek off_t atom, cadd, padd, left; 8772d1661a5SPawel Jakub Dawidek 8782d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 8792d1661a5SPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_DEGRADED) != 0) { 8802d1661a5SPawel Jakub Dawidek /* 8812d1661a5SPawel Jakub Dawidek * Find bio for which we should calculate data. 8822d1661a5SPawel Jakub Dawidek * While going through this path, check if all requests 8832d1661a5SPawel Jakub Dawidek * succeeded, if not, deny whole request. 8842d1661a5SPawel Jakub Dawidek */ 8852d1661a5SPawel Jakub Dawidek bp = NULL; 8862d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 8872d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { 8882d1661a5SPawel Jakub Dawidek KASSERT(bp == NULL, 8892d1661a5SPawel Jakub Dawidek ("More than one parity bio.")); 8902d1661a5SPawel Jakub Dawidek bp = cbp; 8912d1661a5SPawel Jakub Dawidek } 8922d1661a5SPawel Jakub Dawidek if (cbp->bio_error == 0) 8932d1661a5SPawel Jakub Dawidek continue; 8942d1661a5SPawel Jakub Dawidek /* 8952d1661a5SPawel Jakub Dawidek * Found failed request. 8962d1661a5SPawel Jakub Dawidek */ 8972d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 8982d1661a5SPawel Jakub Dawidek pbp->bio_error = cbp->bio_error; 8992d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 9002d1661a5SPawel Jakub Dawidek if (disk != NULL) { 9012d1661a5SPawel Jakub Dawidek /* 9022d1661a5SPawel Jakub Dawidek * Actually this is pointless to bump syncid, 9032d1661a5SPawel Jakub Dawidek * because whole device is fucked up. 9042d1661a5SPawel Jakub Dawidek */ 9052d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; 9062d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 9072d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 9082d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 9092d1661a5SPawel Jakub Dawidek } 9102d1661a5SPawel Jakub Dawidek } 9112d1661a5SPawel Jakub Dawidek KASSERT(bp != NULL, ("NULL parity bio.")); 9122d1661a5SPawel Jakub Dawidek if (pbp->bio_error != 0) { 9132d1661a5SPawel Jakub Dawidek /* 9142d1661a5SPawel Jakub Dawidek * Deny whole request. 9152d1661a5SPawel Jakub Dawidek */ 9162d1661a5SPawel Jakub Dawidek goto finish; 9172d1661a5SPawel Jakub Dawidek } 9182d1661a5SPawel Jakub Dawidek /* 9192d1661a5SPawel Jakub Dawidek * Calculate parity. 9202d1661a5SPawel Jakub Dawidek */ 9212d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 9222d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) 9232d1661a5SPawel Jakub Dawidek continue; 9242d1661a5SPawel Jakub Dawidek g_raid3_xor(cbp->bio_data, bp->bio_data, bp->bio_data, 9252d1661a5SPawel Jakub Dawidek bp->bio_length); 9262d1661a5SPawel Jakub Dawidek } 9272d1661a5SPawel Jakub Dawidek bp->bio_cflags &= ~G_RAID3_BIO_CFLAG_PARITY; 9282d1661a5SPawel Jakub Dawidek } else { 9292d1661a5SPawel Jakub Dawidek /* 9302d1661a5SPawel Jakub Dawidek * If we're in COMPLETE mode, we allow one request to fail, 9312d1661a5SPawel Jakub Dawidek * so if we find one, we're sending it to the parity consumer. 9322d1661a5SPawel Jakub Dawidek * If there are more failed requests, we deny whole request. 9332d1661a5SPawel Jakub Dawidek */ 9342d1661a5SPawel Jakub Dawidek bp = NULL; 9352d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 9362d1661a5SPawel Jakub Dawidek if (cbp->bio_error == 0) 9372d1661a5SPawel Jakub Dawidek continue; 9382d1661a5SPawel Jakub Dawidek /* 9392d1661a5SPawel Jakub Dawidek * Found failed request. 9402d1661a5SPawel Jakub Dawidek */ 9412d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, cbp, "Request failed."); 9422d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 9432d1661a5SPawel Jakub Dawidek if (disk != NULL) { 9442d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; 9452d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 9462d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 9472d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 9482d1661a5SPawel Jakub Dawidek } 9492d1661a5SPawel Jakub Dawidek if (bp == NULL) 9502d1661a5SPawel Jakub Dawidek bp = cbp; 9512d1661a5SPawel Jakub Dawidek else { 9522d1661a5SPawel Jakub Dawidek /* 9532d1661a5SPawel Jakub Dawidek * Next failed request, that's too many. 9542d1661a5SPawel Jakub Dawidek */ 9552d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 9562d1661a5SPawel Jakub Dawidek pbp->bio_error = bp->bio_error; 9572d1661a5SPawel Jakub Dawidek } 9582d1661a5SPawel Jakub Dawidek } 9592d1661a5SPawel Jakub Dawidek if (pbp->bio_error != 0) 9602d1661a5SPawel Jakub Dawidek goto finish; 9612d1661a5SPawel Jakub Dawidek if (bp != NULL) { 9622d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 9632d1661a5SPawel Jakub Dawidek 9642d1661a5SPawel Jakub Dawidek /* 9652d1661a5SPawel Jakub Dawidek * One request failed, so send the same request to 9662d1661a5SPawel Jakub Dawidek * the parity consumer. 9672d1661a5SPawel Jakub Dawidek */ 9682d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 9692d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { 9702d1661a5SPawel Jakub Dawidek pbp->bio_error = bp->bio_error; 9712d1661a5SPawel Jakub Dawidek goto finish; 9722d1661a5SPawel Jakub Dawidek } 9732d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 9742d1661a5SPawel Jakub Dawidek pbp->bio_inbed--; 9752d1661a5SPawel Jakub Dawidek bp->bio_flags &= ~(BIO_DONE | BIO_ERROR); 9762d1661a5SPawel Jakub Dawidek bp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 9772d1661a5SPawel Jakub Dawidek bp->bio_error = 0; 9782d1661a5SPawel Jakub Dawidek bp->bio_completed = 0; 9792d1661a5SPawel Jakub Dawidek bp->bio_children = 0; 9802d1661a5SPawel Jakub Dawidek bp->bio_inbed = 0; 9812d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 9822d1661a5SPawel Jakub Dawidek bp->bio_caller2 = disk; 9832d1661a5SPawel Jakub Dawidek bp->bio_to = cp->provider; 9842d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Sending request (parity)."); 9852d1661a5SPawel Jakub Dawidek KASSERT(cp->acr > 0 && cp->ace > 0, 9862d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 9872d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 9882d1661a5SPawel Jakub Dawidek g_io_request(bp, cp); 9892d1661a5SPawel Jakub Dawidek return; 9902d1661a5SPawel Jakub Dawidek } 9912d1661a5SPawel Jakub Dawidek } 9922d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 9932d1661a5SPawel Jakub Dawidek cadd = padd = 0; 9942d1661a5SPawel Jakub Dawidek for (left = pbp->bio_length; left > 0; left -= sc->sc_sectorsize) { 9952d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 9962d1661a5SPawel Jakub Dawidek bcopy(cbp->bio_data + cadd, pbp->bio_data + padd, atom); 9972d1661a5SPawel Jakub Dawidek pbp->bio_completed += atom; 9982d1661a5SPawel Jakub Dawidek padd += atom; 9992d1661a5SPawel Jakub Dawidek } 10002d1661a5SPawel Jakub Dawidek cadd += atom; 10012d1661a5SPawel Jakub Dawidek } 10022d1661a5SPawel Jakub Dawidek finish: 10032d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 10042d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, pbp, "Request finished."); 10052d1661a5SPawel Jakub Dawidek else 10062d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, pbp, "Request failed."); 10072d1661a5SPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_DEGRADED; 10082d1661a5SPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 10092d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) 10102d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 10112d1661a5SPawel Jakub Dawidek } 10122d1661a5SPawel Jakub Dawidek 10132d1661a5SPawel Jakub Dawidek static void 10142d1661a5SPawel Jakub Dawidek g_raid3_done(struct bio *bp) 10152d1661a5SPawel Jakub Dawidek { 10162d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 10172d1661a5SPawel Jakub Dawidek 10182d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 10192d1661a5SPawel Jakub Dawidek bp->bio_cflags |= G_RAID3_BIO_CFLAG_REGULAR; 10202d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Regular request done (error=%d).", bp->bio_error); 10212d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 10222d1661a5SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 10232d1661a5SPawel Jakub Dawidek wakeup(sc); 10242d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 10252d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 10262d1661a5SPawel Jakub Dawidek } 10272d1661a5SPawel Jakub Dawidek 10282d1661a5SPawel Jakub Dawidek static void 10292d1661a5SPawel Jakub Dawidek g_raid3_regular_request(struct bio *cbp) 10302d1661a5SPawel Jakub Dawidek { 10312d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 10322d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 10332d1661a5SPawel Jakub Dawidek struct bio *pbp; 10342d1661a5SPawel Jakub Dawidek 10352d1661a5SPawel Jakub Dawidek g_topology_assert_not(); 10362d1661a5SPawel Jakub Dawidek 10372d1661a5SPawel Jakub Dawidek pbp = cbp->bio_parent; 10382d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 10392d1661a5SPawel Jakub Dawidek disk = cbp->bio_from->private; 10402d1661a5SPawel Jakub Dawidek if (disk == NULL) { 10412d1661a5SPawel Jakub Dawidek g_topology_lock(); 10422d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, cbp->bio_from); 10432d1661a5SPawel Jakub Dawidek g_topology_unlock(); 10442d1661a5SPawel Jakub Dawidek } 10452d1661a5SPawel Jakub Dawidek 10462d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Request finished."); 10472d1661a5SPawel Jakub Dawidek pbp->bio_inbed++; 10482d1661a5SPawel Jakub Dawidek KASSERT(pbp->bio_inbed <= pbp->bio_children, 10492d1661a5SPawel Jakub Dawidek ("bio_inbed (%u) is bigger than bio_children (%u).", pbp->bio_inbed, 10502d1661a5SPawel Jakub Dawidek pbp->bio_children)); 10512d1661a5SPawel Jakub Dawidek if (pbp->bio_inbed != pbp->bio_children) 10522d1661a5SPawel Jakub Dawidek return; 10532d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 10542d1661a5SPawel Jakub Dawidek case BIO_READ: 10552d1661a5SPawel Jakub Dawidek g_raid3_gather(pbp); 10562d1661a5SPawel Jakub Dawidek break; 10572d1661a5SPawel Jakub Dawidek case BIO_WRITE: 10582d1661a5SPawel Jakub Dawidek case BIO_DELETE: 10592d1661a5SPawel Jakub Dawidek { 10602d1661a5SPawel Jakub Dawidek int error = 0; 10612d1661a5SPawel Jakub Dawidek 10622d1661a5SPawel Jakub Dawidek pbp->bio_completed = pbp->bio_length; 10632d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) { 10642d1661a5SPawel Jakub Dawidek if (cbp->bio_error != 0) { 10652d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 10662d1661a5SPawel Jakub Dawidek if (disk != NULL) { 10672d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = 10682d1661a5SPawel Jakub Dawidek G_RAID3_BUMP_IMMEDIATELY; 10692d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 10702d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 10712d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 10722d1661a5SPawel Jakub Dawidek } 10732d1661a5SPawel Jakub Dawidek if (error == 0) 10742d1661a5SPawel Jakub Dawidek error = cbp->bio_error; 10752d1661a5SPawel Jakub Dawidek else if (pbp->bio_error == 0) { 10762d1661a5SPawel Jakub Dawidek /* 10772d1661a5SPawel Jakub Dawidek * Next failed request, that's too many. 10782d1661a5SPawel Jakub Dawidek */ 10792d1661a5SPawel Jakub Dawidek pbp->bio_error = error; 10802d1661a5SPawel Jakub Dawidek } 10812d1661a5SPawel Jakub Dawidek } 10822d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 10832d1661a5SPawel Jakub Dawidek } 10842d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 10852d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, pbp, "Request finished."); 10862d1661a5SPawel Jakub Dawidek else 10872d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, pbp, "Request failed."); 10882d1661a5SPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_DEGRADED; 10892d1661a5SPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_NOPARITY; 10902d1661a5SPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 10912d1661a5SPawel Jakub Dawidek break; 10922d1661a5SPawel Jakub Dawidek } 10932d1661a5SPawel Jakub Dawidek } 10942d1661a5SPawel Jakub Dawidek } 10952d1661a5SPawel Jakub Dawidek 10962d1661a5SPawel Jakub Dawidek static void 10972d1661a5SPawel Jakub Dawidek g_raid3_sync_done(struct bio *bp) 10982d1661a5SPawel Jakub Dawidek { 10992d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 11002d1661a5SPawel Jakub Dawidek 11012d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request delivered."); 11022d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 11032d1661a5SPawel Jakub Dawidek bp->bio_cflags |= G_RAID3_BIO_CFLAG_SYNC; 11042d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 11052d1661a5SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 11062d1661a5SPawel Jakub Dawidek wakeup(sc); 11072d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 11082d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 11092d1661a5SPawel Jakub Dawidek } 11102d1661a5SPawel Jakub Dawidek 11112d1661a5SPawel Jakub Dawidek static void 11122d1661a5SPawel Jakub Dawidek g_raid3_start(struct bio *bp) 11132d1661a5SPawel Jakub Dawidek { 11142d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 11152d1661a5SPawel Jakub Dawidek 11162d1661a5SPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 11172d1661a5SPawel Jakub Dawidek /* 11182d1661a5SPawel Jakub Dawidek * If sc == NULL or there are no valid disks, provider's error 11192d1661a5SPawel Jakub Dawidek * should be set and g_raid3_start() should not be called at all. 11202d1661a5SPawel Jakub Dawidek */ 11212d1661a5SPawel Jakub Dawidek KASSERT(sc != NULL && (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 11222d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE), 11232d1661a5SPawel Jakub Dawidek ("Provider's error should be set (error=%d)(device=%s).", 11242d1661a5SPawel Jakub Dawidek bp->bio_to->error, bp->bio_to->name)); 11252d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Request received."); 11262d1661a5SPawel Jakub Dawidek 11272d1661a5SPawel Jakub Dawidek switch (bp->bio_cmd) { 11282d1661a5SPawel Jakub Dawidek case BIO_READ: 11292d1661a5SPawel Jakub Dawidek case BIO_WRITE: 11302d1661a5SPawel Jakub Dawidek case BIO_DELETE: 11312d1661a5SPawel Jakub Dawidek break; 11322d1661a5SPawel Jakub Dawidek case BIO_GETATTR: 11332d1661a5SPawel Jakub Dawidek default: 11342d1661a5SPawel Jakub Dawidek g_io_deliver(bp, EOPNOTSUPP); 11352d1661a5SPawel Jakub Dawidek return; 11362d1661a5SPawel Jakub Dawidek } 11372d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 11382d1661a5SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_queue, bp); 11392d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 11402d1661a5SPawel Jakub Dawidek wakeup(sc); 11412d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 11422d1661a5SPawel Jakub Dawidek } 11432d1661a5SPawel Jakub Dawidek 11442d1661a5SPawel Jakub Dawidek /* 11452d1661a5SPawel Jakub Dawidek * Send one synchronization request. 11462d1661a5SPawel Jakub Dawidek */ 11472d1661a5SPawel Jakub Dawidek static void 11482d1661a5SPawel Jakub Dawidek g_raid3_sync_one(struct g_raid3_softc *sc) 11492d1661a5SPawel Jakub Dawidek { 11502d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 11512d1661a5SPawel Jakub Dawidek struct bio *bp; 11522d1661a5SPawel Jakub Dawidek 11532d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 11542d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s).", sc->sc_name, 11552d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state))); 11562d1661a5SPawel Jakub Dawidek disk = sc->sc_syncdisk; 11572d1661a5SPawel Jakub Dawidek KASSERT(disk != NULL, ("No sync disk (%s).", sc->sc_name)); 11582d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 11592d1661a5SPawel Jakub Dawidek ("Disk %s is not marked for synchronization.", 11602d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk))); 11612d1661a5SPawel Jakub Dawidek 11622d1661a5SPawel Jakub Dawidek bp = g_new_bio(); 11632d1661a5SPawel Jakub Dawidek if (bp == NULL) 11642d1661a5SPawel Jakub Dawidek return; 11652d1661a5SPawel Jakub Dawidek bp->bio_parent = NULL; 11662d1661a5SPawel Jakub Dawidek bp->bio_cmd = BIO_READ; 11672d1661a5SPawel Jakub Dawidek bp->bio_offset = disk->d_sync.ds_offset * (sc->sc_ndisks - 1); 11682d1661a5SPawel Jakub Dawidek bp->bio_length = MIN(G_RAID3_MAX_IO_SIZE, 11692d1661a5SPawel Jakub Dawidek sc->sc_mediasize - bp->bio_offset); 11702d1661a5SPawel Jakub Dawidek bp->bio_cflags = 0; 11712d1661a5SPawel Jakub Dawidek bp->bio_done = g_raid3_sync_done; 11722d1661a5SPawel Jakub Dawidek bp->bio_data = disk->d_sync.ds_data; 11732d1661a5SPawel Jakub Dawidek if (bp->bio_data == NULL) { 11742d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 11752d1661a5SPawel Jakub Dawidek return; 11762d1661a5SPawel Jakub Dawidek } 11772d1661a5SPawel Jakub Dawidek bp->bio_cflags = G_RAID3_BIO_CFLAG_REGSYNC; 11782d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset += bp->bio_length / (sc->sc_ndisks - 1); 11792d1661a5SPawel Jakub Dawidek bp->bio_to = sc->sc_provider; 11802d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Sending synchronization request."); 11812d1661a5SPawel Jakub Dawidek g_io_request(bp, disk->d_sync.ds_consumer); 11822d1661a5SPawel Jakub Dawidek } 11832d1661a5SPawel Jakub Dawidek 11842d1661a5SPawel Jakub Dawidek static void 11852d1661a5SPawel Jakub Dawidek g_raid3_sync_request(struct bio *bp) 11862d1661a5SPawel Jakub Dawidek { 11872d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 11882d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 11892d1661a5SPawel Jakub Dawidek 11902d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 11912d1661a5SPawel Jakub Dawidek disk = bp->bio_from->private; 11922d1661a5SPawel Jakub Dawidek if (disk == NULL) { 11932d1661a5SPawel Jakub Dawidek g_topology_lock(); 11942d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, bp->bio_from); 11952d1661a5SPawel Jakub Dawidek g_topology_unlock(); 11962d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 11972d1661a5SPawel Jakub Dawidek return; 11982d1661a5SPawel Jakub Dawidek } 11992d1661a5SPawel Jakub Dawidek 12002d1661a5SPawel Jakub Dawidek /* 12012d1661a5SPawel Jakub Dawidek * Synchronization request. 12022d1661a5SPawel Jakub Dawidek */ 12032d1661a5SPawel Jakub Dawidek switch (bp->bio_cmd) { 12042d1661a5SPawel Jakub Dawidek case BIO_READ: 12052d1661a5SPawel Jakub Dawidek { 12062d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 12072d1661a5SPawel Jakub Dawidek u_char *dst, *src; 12082d1661a5SPawel Jakub Dawidek off_t left; 12092d1661a5SPawel Jakub Dawidek u_int atom; 12102d1661a5SPawel Jakub Dawidek 12112d1661a5SPawel Jakub Dawidek if (bp->bio_error != 0) { 12122d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, bp, 12132d1661a5SPawel Jakub Dawidek "Synchronization request failed (error=%d).", 12142d1661a5SPawel Jakub Dawidek bp->bio_error); 12152d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 12162d1661a5SPawel Jakub Dawidek return; 12172d1661a5SPawel Jakub Dawidek } 12182d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request finished."); 12192d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 12202d1661a5SPawel Jakub Dawidek dst = src = bp->bio_data; 12212d1661a5SPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) { 12222d1661a5SPawel Jakub Dawidek u_int n; 12232d1661a5SPawel Jakub Dawidek 12242d1661a5SPawel Jakub Dawidek /* Parity component. */ 12252d1661a5SPawel Jakub Dawidek for (left = bp->bio_length; left > 0; 12262d1661a5SPawel Jakub Dawidek left -= sc->sc_sectorsize) { 12272d1661a5SPawel Jakub Dawidek bcopy(src, dst, atom); 12282d1661a5SPawel Jakub Dawidek src += atom; 12292d1661a5SPawel Jakub Dawidek for (n = 1; n < sc->sc_ndisks - 1; n++) { 12302d1661a5SPawel Jakub Dawidek g_raid3_xor(src, dst, dst, atom); 12312d1661a5SPawel Jakub Dawidek src += atom; 12322d1661a5SPawel Jakub Dawidek } 12332d1661a5SPawel Jakub Dawidek dst += atom; 12342d1661a5SPawel Jakub Dawidek } 12352d1661a5SPawel Jakub Dawidek } else { 12362d1661a5SPawel Jakub Dawidek /* Regular component. */ 12372d1661a5SPawel Jakub Dawidek src += atom * disk->d_no; 12382d1661a5SPawel Jakub Dawidek for (left = bp->bio_length; left > 0; 12392d1661a5SPawel Jakub Dawidek left -= sc->sc_sectorsize) { 12402d1661a5SPawel Jakub Dawidek bcopy(src, dst, atom); 12412d1661a5SPawel Jakub Dawidek src += sc->sc_sectorsize; 12422d1661a5SPawel Jakub Dawidek dst += atom; 12432d1661a5SPawel Jakub Dawidek } 12442d1661a5SPawel Jakub Dawidek } 12452d1661a5SPawel Jakub Dawidek bp->bio_offset /= sc->sc_ndisks - 1; 12462d1661a5SPawel Jakub Dawidek bp->bio_length /= sc->sc_ndisks - 1; 12472d1661a5SPawel Jakub Dawidek bp->bio_cmd = BIO_WRITE; 12482d1661a5SPawel Jakub Dawidek bp->bio_cflags = 0; 12492d1661a5SPawel Jakub Dawidek bp->bio_children = bp->bio_inbed = 0; 12502d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 12512d1661a5SPawel Jakub Dawidek KASSERT(cp->acr == 0 && cp->acw == 1 && cp->ace == 1, 12522d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 12532d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 12542d1661a5SPawel Jakub Dawidek g_io_request(bp, cp); 12552d1661a5SPawel Jakub Dawidek return; 12562d1661a5SPawel Jakub Dawidek } 12572d1661a5SPawel Jakub Dawidek case BIO_WRITE: 12582d1661a5SPawel Jakub Dawidek if (bp->bio_error != 0) { 12592d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, bp, 12602d1661a5SPawel Jakub Dawidek "Synchronization request failed (error=%d).", 12612d1661a5SPawel Jakub Dawidek bp->bio_error); 12622d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 12632d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; 12642d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 12652d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 12662d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 12672d1661a5SPawel Jakub Dawidek return; 12682d1661a5SPawel Jakub Dawidek } 12692d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request finished."); 12702d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = bp->bio_offset + bp->bio_length; 12712d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 12722d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_offset_done == 12732d1661a5SPawel Jakub Dawidek sc->sc_provider->mediasize / (sc->sc_ndisks - 1)) { 12742d1661a5SPawel Jakub Dawidek /* 12752d1661a5SPawel Jakub Dawidek * Disk up-to-date, activate it. 12762d1661a5SPawel Jakub Dawidek */ 12772d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_ACTIVE, 12782d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 12792d1661a5SPawel Jakub Dawidek return; 12802d1661a5SPawel Jakub Dawidek } else if ((disk->d_sync.ds_offset_done % 12812d1661a5SPawel Jakub Dawidek (G_RAID3_MAX_IO_SIZE * 100)) == 0) { 12822d1661a5SPawel Jakub Dawidek /* 12832d1661a5SPawel Jakub Dawidek * Update offset_done on every 100 blocks. 12842d1661a5SPawel Jakub Dawidek * XXX: This should be configurable. 12852d1661a5SPawel Jakub Dawidek */ 12862d1661a5SPawel Jakub Dawidek g_topology_lock(); 12872d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 12882d1661a5SPawel Jakub Dawidek g_topology_unlock(); 12892d1661a5SPawel Jakub Dawidek } 12902d1661a5SPawel Jakub Dawidek return; 12912d1661a5SPawel Jakub Dawidek default: 12922d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Invalid command here: %u (device=%s)", 12932d1661a5SPawel Jakub Dawidek bp->bio_cmd, sc->sc_name)); 12942d1661a5SPawel Jakub Dawidek break; 12952d1661a5SPawel Jakub Dawidek } 12962d1661a5SPawel Jakub Dawidek } 12972d1661a5SPawel Jakub Dawidek 12982d1661a5SPawel Jakub Dawidek static int 12992d1661a5SPawel Jakub Dawidek g_raid3_register_request(struct bio *pbp) 13002d1661a5SPawel Jakub Dawidek { 13012d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 13022d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 13032d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 13042d1661a5SPawel Jakub Dawidek struct bio *cbp; 13052d1661a5SPawel Jakub Dawidek off_t offset, length; 13062d1661a5SPawel Jakub Dawidek u_int n, ndisks; 13072d1661a5SPawel Jakub Dawidek 13082d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 13092d1661a5SPawel Jakub Dawidek if ((pbp->bio_cflags & G_RAID3_BIO_CFLAG_REGSYNC) != 0 && 13102d1661a5SPawel Jakub Dawidek sc->sc_syncdisk == NULL) { 13112d1661a5SPawel Jakub Dawidek g_io_deliver(pbp, EIO); 13122d1661a5SPawel Jakub Dawidek return (0); 13132d1661a5SPawel Jakub Dawidek } 13142d1661a5SPawel Jakub Dawidek g_raid3_init_bio(pbp); 13152d1661a5SPawel Jakub Dawidek length = pbp->bio_length / (sc->sc_ndisks - 1); 13162d1661a5SPawel Jakub Dawidek offset = pbp->bio_offset / (sc->sc_ndisks - 1); 13172d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 13182d1661a5SPawel Jakub Dawidek case BIO_READ: 13192d1661a5SPawel Jakub Dawidek ndisks = sc->sc_ndisks - 1; 13202d1661a5SPawel Jakub Dawidek break; 13212d1661a5SPawel Jakub Dawidek case BIO_WRITE: 13222d1661a5SPawel Jakub Dawidek case BIO_DELETE: 13232d1661a5SPawel Jakub Dawidek ndisks = sc->sc_ndisks; 13242d1661a5SPawel Jakub Dawidek break; 13252d1661a5SPawel Jakub Dawidek } 13262d1661a5SPawel Jakub Dawidek for (n = 0; n < ndisks; n++) { 13272d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 13282d1661a5SPawel Jakub Dawidek cbp = g_raid3_clone_bio(sc, pbp); 13292d1661a5SPawel Jakub Dawidek if (cbp == NULL) { 13302d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) 13312d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 13322d1661a5SPawel Jakub Dawidek return (ENOMEM); 13332d1661a5SPawel Jakub Dawidek } 13342d1661a5SPawel Jakub Dawidek cbp->bio_offset = offset; 13352d1661a5SPawel Jakub Dawidek cbp->bio_length = length; 13362d1661a5SPawel Jakub Dawidek cbp->bio_done = g_raid3_done; 13372d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 13382d1661a5SPawel Jakub Dawidek case BIO_READ: 13392d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { 13402d1661a5SPawel Jakub Dawidek /* 13412d1661a5SPawel Jakub Dawidek * Replace invalid component with the parity 13422d1661a5SPawel Jakub Dawidek * component. 13432d1661a5SPawel Jakub Dawidek */ 13442d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 13452d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 13462d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 13472d1661a5SPawel Jakub Dawidek } 13482d1661a5SPawel Jakub Dawidek break; 13492d1661a5SPawel Jakub Dawidek case BIO_WRITE: 13502d1661a5SPawel Jakub Dawidek case BIO_DELETE: 13512d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 13522d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 13532d1661a5SPawel Jakub Dawidek if (n == ndisks - 1) { 13542d1661a5SPawel Jakub Dawidek /* 13552d1661a5SPawel Jakub Dawidek * Active parity component, mark it as such. 13562d1661a5SPawel Jakub Dawidek */ 13572d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= 13582d1661a5SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_PARITY; 13592d1661a5SPawel Jakub Dawidek } 13602d1661a5SPawel Jakub Dawidek } else { 13612d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 13622d1661a5SPawel Jakub Dawidek if (n == ndisks - 1) { 13632d1661a5SPawel Jakub Dawidek /* 13642d1661a5SPawel Jakub Dawidek * Parity component is not connected, 13652d1661a5SPawel Jakub Dawidek * so destroy its request. 13662d1661a5SPawel Jakub Dawidek */ 13672d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= 13682d1661a5SPawel Jakub Dawidek G_RAID3_BIO_PFLAG_NOPARITY; 13692d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 13702d1661a5SPawel Jakub Dawidek cbp = NULL; 13712d1661a5SPawel Jakub Dawidek } else { 13722d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= 13732d1661a5SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_NODISK; 13742d1661a5SPawel Jakub Dawidek disk = NULL; 13752d1661a5SPawel Jakub Dawidek } 13762d1661a5SPawel Jakub Dawidek } 13772d1661a5SPawel Jakub Dawidek break; 13782d1661a5SPawel Jakub Dawidek } 13792d1661a5SPawel Jakub Dawidek if (cbp != NULL) 13802d1661a5SPawel Jakub Dawidek cbp->bio_caller2 = disk; 13812d1661a5SPawel Jakub Dawidek } 13822d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 13832d1661a5SPawel Jakub Dawidek case BIO_READ: 13842d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 13852d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 13862d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 13872d1661a5SPawel Jakub Dawidek cbp->bio_to = cp->provider; 13882d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Sending request."); 13892d1661a5SPawel Jakub Dawidek KASSERT(cp->acr > 0 && cp->ace > 0, 13902d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", 13912d1661a5SPawel Jakub Dawidek cp->provider->name, cp->acr, cp->acw, cp->ace)); 13922d1661a5SPawel Jakub Dawidek g_io_request(cbp, cp); 13932d1661a5SPawel Jakub Dawidek } 13942d1661a5SPawel Jakub Dawidek break; 13952d1661a5SPawel Jakub Dawidek case BIO_WRITE: 13962d1661a5SPawel Jakub Dawidek case BIO_DELETE: 13972d1661a5SPawel Jakub Dawidek /* 13982d1661a5SPawel Jakub Dawidek * Bump syncid on first write. 13992d1661a5SPawel Jakub Dawidek */ 14002d1661a5SPawel Jakub Dawidek if (sc->sc_bump_syncid == G_RAID3_BUMP_ON_FIRST_WRITE) { 14012d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = 0; 14022d1661a5SPawel Jakub Dawidek g_topology_lock(); 14032d1661a5SPawel Jakub Dawidek g_raid3_bump_syncid(sc); 14042d1661a5SPawel Jakub Dawidek g_topology_unlock(); 14052d1661a5SPawel Jakub Dawidek } 14062d1661a5SPawel Jakub Dawidek g_raid3_scatter(pbp); 14072d1661a5SPawel Jakub Dawidek break; 14082d1661a5SPawel Jakub Dawidek } 14092d1661a5SPawel Jakub Dawidek return (0); 14102d1661a5SPawel Jakub Dawidek } 14112d1661a5SPawel Jakub Dawidek 14122d1661a5SPawel Jakub Dawidek static int 14132d1661a5SPawel Jakub Dawidek g_raid3_can_destroy(struct g_raid3_softc *sc) 14142d1661a5SPawel Jakub Dawidek { 14152d1661a5SPawel Jakub Dawidek struct g_geom *gp; 14162d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 14172d1661a5SPawel Jakub Dawidek 14182d1661a5SPawel Jakub Dawidek g_topology_assert(); 14192d1661a5SPawel Jakub Dawidek gp = sc->sc_geom; 14202d1661a5SPawel Jakub Dawidek LIST_FOREACH(cp, &gp->consumer, consumer) { 14212d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 14222d1661a5SPawel Jakub Dawidek return (0); 14232d1661a5SPawel Jakub Dawidek } 14242d1661a5SPawel Jakub Dawidek gp = sc->sc_sync.ds_geom; 14252d1661a5SPawel Jakub Dawidek LIST_FOREACH(cp, &gp->consumer, consumer) { 14262d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 14272d1661a5SPawel Jakub Dawidek return (0); 14282d1661a5SPawel Jakub Dawidek } 14292d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "No I/O requests for %s, it can be destroyed.", 14302d1661a5SPawel Jakub Dawidek sc->sc_name); 14312d1661a5SPawel Jakub Dawidek return (1); 14322d1661a5SPawel Jakub Dawidek } 14332d1661a5SPawel Jakub Dawidek 14342d1661a5SPawel Jakub Dawidek static int 14352d1661a5SPawel Jakub Dawidek g_raid3_try_destroy(struct g_raid3_softc *sc) 14362d1661a5SPawel Jakub Dawidek { 14372d1661a5SPawel Jakub Dawidek 14382d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_WAIT) != 0) { 14392d1661a5SPawel Jakub Dawidek g_topology_lock(); 14402d1661a5SPawel Jakub Dawidek if (!g_raid3_can_destroy(sc)) { 14412d1661a5SPawel Jakub Dawidek g_topology_unlock(); 14422d1661a5SPawel Jakub Dawidek return (0); 14432d1661a5SPawel Jakub Dawidek } 14442d1661a5SPawel Jakub Dawidek g_topology_unlock(); 14452d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, 14462d1661a5SPawel Jakub Dawidek &sc->sc_worker); 14472d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_worker); 14482d1661a5SPawel Jakub Dawidek sc->sc_worker = NULL; 14492d1661a5SPawel Jakub Dawidek } else { 14502d1661a5SPawel Jakub Dawidek g_topology_lock(); 14512d1661a5SPawel Jakub Dawidek if (!g_raid3_can_destroy(sc)) { 14522d1661a5SPawel Jakub Dawidek g_topology_unlock(); 14532d1661a5SPawel Jakub Dawidek return (0); 14542d1661a5SPawel Jakub Dawidek } 14552d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(sc); 14562d1661a5SPawel Jakub Dawidek g_topology_unlock(); 14572d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 14582d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 14592d1661a5SPawel Jakub Dawidek } 14602d1661a5SPawel Jakub Dawidek return (1); 14612d1661a5SPawel Jakub Dawidek } 14622d1661a5SPawel Jakub Dawidek 14632d1661a5SPawel Jakub Dawidek /* 14642d1661a5SPawel Jakub Dawidek * Worker thread. 14652d1661a5SPawel Jakub Dawidek */ 14662d1661a5SPawel Jakub Dawidek static void 14672d1661a5SPawel Jakub Dawidek g_raid3_worker(void *arg) 14682d1661a5SPawel Jakub Dawidek { 14692d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 14702d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 14712d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 14722d1661a5SPawel Jakub Dawidek struct bio *bp; 14732d1661a5SPawel Jakub Dawidek u_int nreqs; 14742d1661a5SPawel Jakub Dawidek 14752d1661a5SPawel Jakub Dawidek sc = arg; 14762d1661a5SPawel Jakub Dawidek curthread->td_base_pri = PRIBIO; 14772d1661a5SPawel Jakub Dawidek 14782d1661a5SPawel Jakub Dawidek nreqs = 0; 14792d1661a5SPawel Jakub Dawidek for (;;) { 14802d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: Let's see...", __func__); 14812d1661a5SPawel Jakub Dawidek /* 14822d1661a5SPawel Jakub Dawidek * First take a look at events. 14832d1661a5SPawel Jakub Dawidek * This is important to handle events before any I/O requests. 14842d1661a5SPawel Jakub Dawidek */ 14852d1661a5SPawel Jakub Dawidek ep = g_raid3_event_get(sc); 14862d1661a5SPawel Jakub Dawidek if (ep != NULL) { 14872d1661a5SPawel Jakub Dawidek g_topology_lock(); 14882d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DEVICE) != 0) { 14892d1661a5SPawel Jakub Dawidek /* Update only device status. */ 14902d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, 14912d1661a5SPawel Jakub Dawidek "Running event for device %s.", 14922d1661a5SPawel Jakub Dawidek sc->sc_name); 14932d1661a5SPawel Jakub Dawidek ep->e_error = 0; 14942d1661a5SPawel Jakub Dawidek g_raid3_update_device(sc, 1); 14952d1661a5SPawel Jakub Dawidek } else { 14962d1661a5SPawel Jakub Dawidek /* Update disk status. */ 14972d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "Running event for disk %s.", 14982d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(ep->e_disk)); 14992d1661a5SPawel Jakub Dawidek ep->e_error = g_raid3_update_disk(ep->e_disk, 15002d1661a5SPawel Jakub Dawidek ep->e_state); 15012d1661a5SPawel Jakub Dawidek if (ep->e_error == 0) 15022d1661a5SPawel Jakub Dawidek g_raid3_update_device(sc, 0); 15032d1661a5SPawel Jakub Dawidek } 15042d1661a5SPawel Jakub Dawidek g_topology_unlock(); 15052d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) { 15062d1661a5SPawel Jakub Dawidek KASSERT(ep->e_error == 0, 15072d1661a5SPawel Jakub Dawidek ("Error cannot be handled.")); 15082d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 15092d1661a5SPawel Jakub Dawidek } else { 15102d1661a5SPawel Jakub Dawidek ep->e_flags |= G_RAID3_EVENT_DONE; 15112d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, 15122d1661a5SPawel Jakub Dawidek ep); 15132d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 15142d1661a5SPawel Jakub Dawidek wakeup(ep); 15152d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 15162d1661a5SPawel Jakub Dawidek } 15172d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 15182d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 15192d1661a5SPawel Jakub Dawidek if (g_raid3_try_destroy(sc)) 15202d1661a5SPawel Jakub Dawidek kthread_exit(0); 15212d1661a5SPawel Jakub Dawidek } 15222d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 1.", __func__); 15232d1661a5SPawel Jakub Dawidek continue; 15242d1661a5SPawel Jakub Dawidek } 15252d1661a5SPawel Jakub Dawidek /* 15262d1661a5SPawel Jakub Dawidek * Now I/O requests. 15272d1661a5SPawel Jakub Dawidek */ 15282d1661a5SPawel Jakub Dawidek /* Get first request from the queue. */ 15292d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 15302d1661a5SPawel Jakub Dawidek bp = bioq_first(&sc->sc_queue); 15312d1661a5SPawel Jakub Dawidek if (bp == NULL) { 15322d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 15332d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 15342d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 15352d1661a5SPawel Jakub Dawidek if (g_raid3_try_destroy(sc)) 15362d1661a5SPawel Jakub Dawidek kthread_exit(0); 15372d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 15382d1661a5SPawel Jakub Dawidek } 15392d1661a5SPawel Jakub Dawidek } 15402d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL && 15412d1661a5SPawel Jakub Dawidek (bp == NULL || nreqs > g_raid3_reqs_per_sync)) { 15422d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 15432d1661a5SPawel Jakub Dawidek /* 15442d1661a5SPawel Jakub Dawidek * It is time for synchronization... 15452d1661a5SPawel Jakub Dawidek */ 15462d1661a5SPawel Jakub Dawidek nreqs = 0; 15472d1661a5SPawel Jakub Dawidek disk = sc->sc_syncdisk; 15482d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_offset < 15492d1661a5SPawel Jakub Dawidek sc->sc_provider->mediasize / (sc->sc_ndisks - 1) && 15502d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset == 15512d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done) { 15522d1661a5SPawel Jakub Dawidek g_raid3_sync_one(sc); 15532d1661a5SPawel Jakub Dawidek } 15542d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 2.", __func__); 15552d1661a5SPawel Jakub Dawidek goto sleep; 15562d1661a5SPawel Jakub Dawidek } 15572d1661a5SPawel Jakub Dawidek if (bp == NULL) { 15582d1661a5SPawel Jakub Dawidek MSLEEP(sc, &sc->sc_queue_mtx, PRIBIO | PDROP, "r3:w1", 0); 15592d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 3.", __func__); 15602d1661a5SPawel Jakub Dawidek continue; 15612d1661a5SPawel Jakub Dawidek } 15622d1661a5SPawel Jakub Dawidek nreqs++; 15632d1661a5SPawel Jakub Dawidek bioq_remove(&sc->sc_queue, bp); 15642d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 15652d1661a5SPawel Jakub Dawidek 15662d1661a5SPawel Jakub Dawidek if ((bp->bio_cflags & G_RAID3_BIO_CFLAG_REGULAR) != 0) { 15672d1661a5SPawel Jakub Dawidek g_raid3_regular_request(bp); 15682d1661a5SPawel Jakub Dawidek } else if ((bp->bio_cflags & G_RAID3_BIO_CFLAG_SYNC) != 0) { 15692d1661a5SPawel Jakub Dawidek u_int timeout, sps; 15702d1661a5SPawel Jakub Dawidek 15712d1661a5SPawel Jakub Dawidek g_raid3_sync_request(bp); 15722d1661a5SPawel Jakub Dawidek sleep: 15732d1661a5SPawel Jakub Dawidek sps = atomic_load_acq_int(&g_raid3_syncs_per_sec); 15742d1661a5SPawel Jakub Dawidek if (sps == 0) { 15752d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 5.", __func__); 15762d1661a5SPawel Jakub Dawidek continue; 15772d1661a5SPawel Jakub Dawidek } 15782d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 15792d1661a5SPawel Jakub Dawidek if (bioq_first(&sc->sc_queue) != NULL) { 15802d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 15812d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 4.", __func__); 15822d1661a5SPawel Jakub Dawidek continue; 15832d1661a5SPawel Jakub Dawidek } 15842d1661a5SPawel Jakub Dawidek timeout = hz / sps; 15852d1661a5SPawel Jakub Dawidek if (timeout == 0) 15862d1661a5SPawel Jakub Dawidek timeout = 1; 15872d1661a5SPawel Jakub Dawidek MSLEEP(sc, &sc->sc_queue_mtx, PRIBIO | PDROP, "r3:w2", 15882d1661a5SPawel Jakub Dawidek timeout); 15892d1661a5SPawel Jakub Dawidek } else { 15902d1661a5SPawel Jakub Dawidek if (g_raid3_register_request(bp) != 0) { 15912d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 15922d1661a5SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_queue, bp); 15932d1661a5SPawel Jakub Dawidek MSLEEP(&sc->sc_queue, &sc->sc_queue_mtx, 15942d1661a5SPawel Jakub Dawidek PRIBIO | PDROP, "r3:lowmem", hz / 10); 15952d1661a5SPawel Jakub Dawidek } 15962d1661a5SPawel Jakub Dawidek } 15972d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 6.", __func__); 15982d1661a5SPawel Jakub Dawidek } 15992d1661a5SPawel Jakub Dawidek } 16002d1661a5SPawel Jakub Dawidek 16012d1661a5SPawel Jakub Dawidek /* 16022d1661a5SPawel Jakub Dawidek * Open disk's consumer if needed. 16032d1661a5SPawel Jakub Dawidek */ 16042d1661a5SPawel Jakub Dawidek static void 16052d1661a5SPawel Jakub Dawidek g_raid3_update_access(struct g_raid3_disk *disk) 16062d1661a5SPawel Jakub Dawidek { 16072d1661a5SPawel Jakub Dawidek struct g_provider *pp; 16082d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 16092d1661a5SPawel Jakub Dawidek int acr, acw, ace, cpw, error; 16102d1661a5SPawel Jakub Dawidek 16112d1661a5SPawel Jakub Dawidek g_topology_assert(); 16122d1661a5SPawel Jakub Dawidek 16132d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 16142d1661a5SPawel Jakub Dawidek pp = disk->d_softc->sc_provider; 16152d1661a5SPawel Jakub Dawidek if (pp == NULL) { 16162d1661a5SPawel Jakub Dawidek acr = -cp->acr; 16172d1661a5SPawel Jakub Dawidek acw = -cp->acw; 16182d1661a5SPawel Jakub Dawidek ace = -cp->ace; 16192d1661a5SPawel Jakub Dawidek } else { 16202d1661a5SPawel Jakub Dawidek acr = pp->acr - cp->acr; 16212d1661a5SPawel Jakub Dawidek acw = pp->acw - cp->acw; 16222d1661a5SPawel Jakub Dawidek ace = pp->ace - cp->ace; 16232d1661a5SPawel Jakub Dawidek /* Grab an extra "exclusive" bit. */ 16242d1661a5SPawel Jakub Dawidek if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) 16252d1661a5SPawel Jakub Dawidek ace++; 16262d1661a5SPawel Jakub Dawidek } 16272d1661a5SPawel Jakub Dawidek if (acr == 0 && acw == 0 && ace == 0) 16282d1661a5SPawel Jakub Dawidek return; 16292d1661a5SPawel Jakub Dawidek cpw = cp->acw; 16302d1661a5SPawel Jakub Dawidek error = g_access(cp, acr, acw, ace); 16312d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", cp->provider->name, acr, 16322d1661a5SPawel Jakub Dawidek acw, ace, error); 16332d1661a5SPawel Jakub Dawidek if (error != 0) { 16342d1661a5SPawel Jakub Dawidek disk->d_softc->sc_bump_syncid = G_RAID3_BUMP_ON_FIRST_WRITE; 16352d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 16362d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 16372d1661a5SPawel Jakub Dawidek return; 16382d1661a5SPawel Jakub Dawidek } 16392d1661a5SPawel Jakub Dawidek if (cpw == 0 && cp->acw > 0) { 16402d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as dirty.", 16412d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), disk->d_softc->sc_name); 16422d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 16432d1661a5SPawel Jakub Dawidek } else if (cpw > 0 && cp->acw == 0) { 16442d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as clean.", 16452d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), disk->d_softc->sc_name); 16462d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 16472d1661a5SPawel Jakub Dawidek } 16482d1661a5SPawel Jakub Dawidek } 16492d1661a5SPawel Jakub Dawidek 16502d1661a5SPawel Jakub Dawidek static void 16512d1661a5SPawel Jakub Dawidek g_raid3_sync_start(struct g_raid3_softc *sc) 16522d1661a5SPawel Jakub Dawidek { 16532d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 16542d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 16552d1661a5SPawel Jakub Dawidek int error; 16562d1661a5SPawel Jakub Dawidek u_int n; 16572d1661a5SPawel Jakub Dawidek 16582d1661a5SPawel Jakub Dawidek g_topology_assert(); 16592d1661a5SPawel Jakub Dawidek 16602d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 16612d1661a5SPawel Jakub Dawidek ("Device not in DEGRADED state (%s, %u).", sc->sc_name, 16622d1661a5SPawel Jakub Dawidek sc->sc_state)); 16632d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_syncdisk == NULL, ("Syncdisk is not NULL (%s, %u).", 16642d1661a5SPawel Jakub Dawidek sc->sc_name, sc->sc_state)); 16652d1661a5SPawel Jakub Dawidek disk = NULL; 16662d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 16672d1661a5SPawel Jakub Dawidek if (sc->sc_disks[n].d_state != G_RAID3_DISK_STATE_SYNCHRONIZING) 16682d1661a5SPawel Jakub Dawidek continue; 16692d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 16702d1661a5SPawel Jakub Dawidek break; 16712d1661a5SPawel Jakub Dawidek } 16722d1661a5SPawel Jakub Dawidek if (disk == NULL) 16732d1661a5SPawel Jakub Dawidek return; 16742d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 16752d1661a5SPawel Jakub Dawidek KASSERT(cp->acr == 0 && cp->acw == 0 && cp->ace == 0, 16762d1661a5SPawel Jakub Dawidek ("Consumer %s already opened.", cp->provider->name)); 16772d1661a5SPawel Jakub Dawidek 16782d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s.", sc->sc_name, 16792d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 16802d1661a5SPawel Jakub Dawidek error = g_access(cp, 0, 1, 1); 16812d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", cp->provider->name, 0, 1, 16822d1661a5SPawel Jakub Dawidek 1, error); 16832d1661a5SPawel Jakub Dawidek if (error != 0) { 16842d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 16852d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 16862d1661a5SPawel Jakub Dawidek return; 16872d1661a5SPawel Jakub Dawidek } 16882d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 16892d1661a5SPawel Jakub Dawidek KASSERT(disk->d_sync.ds_consumer == NULL, 16902d1661a5SPawel Jakub Dawidek ("Sync consumer already exists (device=%s, disk=%s).", 16912d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk))); 16922d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = g_new_consumer(sc->sc_sync.ds_geom); 16932d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer->private = disk; 16942d1661a5SPawel Jakub Dawidek error = g_attach(disk->d_sync.ds_consumer, disk->d_softc->sc_provider); 16952d1661a5SPawel Jakub Dawidek KASSERT(error == 0, ("Cannot attach to %s (error=%d).", 16962d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, error)); 16972d1661a5SPawel Jakub Dawidek error = g_access(disk->d_sync.ds_consumer, 1, 0, 0); 16982d1661a5SPawel Jakub Dawidek KASSERT(error == 0, ("Cannot open %s (error=%d).", 16992d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, error)); 17002d1661a5SPawel Jakub Dawidek disk->d_sync.ds_data = malloc(G_RAID3_MAX_IO_SIZE, M_RAID3, M_WAITOK); 17012d1661a5SPawel Jakub Dawidek sc->sc_syncdisk = disk; 17022d1661a5SPawel Jakub Dawidek } 17032d1661a5SPawel Jakub Dawidek 17042d1661a5SPawel Jakub Dawidek /* 17052d1661a5SPawel Jakub Dawidek * Stop synchronization process. 17062d1661a5SPawel Jakub Dawidek * type: 0 - synchronization finished 17072d1661a5SPawel Jakub Dawidek * 1 - synchronization stopped 17082d1661a5SPawel Jakub Dawidek */ 17092d1661a5SPawel Jakub Dawidek static void 17102d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(struct g_raid3_softc *sc, int type) 17112d1661a5SPawel Jakub Dawidek { 17122d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 17132d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 17142d1661a5SPawel Jakub Dawidek 17152d1661a5SPawel Jakub Dawidek g_topology_assert(); 17162d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 17172d1661a5SPawel Jakub Dawidek ("Device not in DEGRADED state (%s, %u).", sc->sc_name, 17182d1661a5SPawel Jakub Dawidek sc->sc_state)); 17192d1661a5SPawel Jakub Dawidek disk = sc->sc_syncdisk; 17202d1661a5SPawel Jakub Dawidek sc->sc_syncdisk = NULL; 17212d1661a5SPawel Jakub Dawidek KASSERT(disk != NULL, ("No disk was synchronized (%s).", sc->sc_name)); 17222d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 17232d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 17242d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 17252d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_consumer == NULL) 17262d1661a5SPawel Jakub Dawidek return; 17272d1661a5SPawel Jakub Dawidek 17282d1661a5SPawel Jakub Dawidek if (type == 0) { 17292d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s finished.", 17302d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, g_raid3_get_diskname(disk)); 17312d1661a5SPawel Jakub Dawidek } else /* if (type == 1) */ { 17322d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s stopped.", 17332d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, g_raid3_get_diskname(disk)); 17342d1661a5SPawel Jakub Dawidek } 17352d1661a5SPawel Jakub Dawidek cp = disk->d_sync.ds_consumer; 17362d1661a5SPawel Jakub Dawidek g_access(cp, -1, 0, 0); 17372d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(disk->d_softc, cp); 17382d1661a5SPawel Jakub Dawidek free(disk->d_sync.ds_data, M_RAID3); 17392d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = NULL; 17402d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 17412d1661a5SPawel Jakub Dawidek KASSERT(cp->acr == 0 && cp->acw == 1 && cp->ace == 1, 17422d1661a5SPawel Jakub Dawidek ("Consumer %s not opened.", cp->provider->name)); 17432d1661a5SPawel Jakub Dawidek g_access(cp, 0, -1, -1); 17442d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", cp->provider->name, 0, -1, 17452d1661a5SPawel Jakub Dawidek -1, 0); 17462d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 17472d1661a5SPawel Jakub Dawidek } 17482d1661a5SPawel Jakub Dawidek 17492d1661a5SPawel Jakub Dawidek static void 17502d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(struct g_raid3_softc *sc) 17512d1661a5SPawel Jakub Dawidek { 17522d1661a5SPawel Jakub Dawidek struct g_provider *pp; 17532d1661a5SPawel Jakub Dawidek 17542d1661a5SPawel Jakub Dawidek g_topology_assert(); 17552d1661a5SPawel Jakub Dawidek 17562d1661a5SPawel Jakub Dawidek pp = g_new_providerf(sc->sc_geom, "raid3/%s", sc->sc_name); 17572d1661a5SPawel Jakub Dawidek pp->mediasize = sc->sc_mediasize; 17582d1661a5SPawel Jakub Dawidek pp->sectorsize = sc->sc_sectorsize; 17592d1661a5SPawel Jakub Dawidek sc->sc_provider = pp; 17602d1661a5SPawel Jakub Dawidek g_error_provider(pp, 0); 17612d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s launched.", sc->sc_name, 17622d1661a5SPawel Jakub Dawidek pp->name); 17632d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED) 17642d1661a5SPawel Jakub Dawidek g_raid3_sync_start(sc); 17652d1661a5SPawel Jakub Dawidek } 17662d1661a5SPawel Jakub Dawidek 17672d1661a5SPawel Jakub Dawidek static void 17682d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(struct g_raid3_softc *sc) 17692d1661a5SPawel Jakub Dawidek { 17702d1661a5SPawel Jakub Dawidek struct bio *bp; 17712d1661a5SPawel Jakub Dawidek 17722d1661a5SPawel Jakub Dawidek g_topology_assert(); 17732d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_provider != NULL, ("NULL provider (device=%s).", 17742d1661a5SPawel Jakub Dawidek sc->sc_name)); 17752d1661a5SPawel Jakub Dawidek 17762d1661a5SPawel Jakub Dawidek g_error_provider(sc->sc_provider, ENXIO); 17772d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 17782d1661a5SPawel Jakub Dawidek while ((bp = bioq_first(&sc->sc_queue)) != NULL) { 17792d1661a5SPawel Jakub Dawidek bioq_remove(&sc->sc_queue, bp); 17802d1661a5SPawel Jakub Dawidek g_io_deliver(bp, ENXIO); 17812d1661a5SPawel Jakub Dawidek } 17822d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 17832d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s destroyed.", sc->sc_name, 17842d1661a5SPawel Jakub Dawidek sc->sc_provider->name); 17852d1661a5SPawel Jakub Dawidek sc->sc_provider->flags |= G_PF_WITHER; 17862d1661a5SPawel Jakub Dawidek g_orphan_provider(sc->sc_provider, ENXIO); 17872d1661a5SPawel Jakub Dawidek sc->sc_provider = NULL; 17882d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL) 17892d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 1); 17902d1661a5SPawel Jakub Dawidek } 17912d1661a5SPawel Jakub Dawidek 17922d1661a5SPawel Jakub Dawidek static void 17932d1661a5SPawel Jakub Dawidek g_raid3_go(void *arg) 17942d1661a5SPawel Jakub Dawidek { 17952d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 17962d1661a5SPawel Jakub Dawidek 17972d1661a5SPawel Jakub Dawidek sc = arg; 17982d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Force device %s start due to timeout.", sc->sc_name); 17992d1661a5SPawel Jakub Dawidek g_raid3_event_send(sc, 0, 18002d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT | G_RAID3_EVENT_DEVICE); 18012d1661a5SPawel Jakub Dawidek } 18022d1661a5SPawel Jakub Dawidek 18032d1661a5SPawel Jakub Dawidek static u_int 18042d1661a5SPawel Jakub Dawidek g_raid3_determine_state(struct g_raid3_disk *disk) 18052d1661a5SPawel Jakub Dawidek { 18062d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 18072d1661a5SPawel Jakub Dawidek u_int state; 18082d1661a5SPawel Jakub Dawidek 18092d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 18102d1661a5SPawel Jakub Dawidek if (sc->sc_syncid == disk->d_sync.ds_syncid) { 18112d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 18122d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING) == 0) { 18132d1661a5SPawel Jakub Dawidek /* Disk does not need synchronization. */ 18142d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_ACTIVE; 18152d1661a5SPawel Jakub Dawidek } else { 18162d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 18172d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_NOAUTOSYNC) == 0 || 18182d1661a5SPawel Jakub Dawidek (disk->d_flags & 18192d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_FORCE_SYNC) != 0) { 18202d1661a5SPawel Jakub Dawidek /* 18212d1661a5SPawel Jakub Dawidek * We can start synchronization from 18222d1661a5SPawel Jakub Dawidek * the stored offset. 18232d1661a5SPawel Jakub Dawidek */ 18242d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_SYNCHRONIZING; 18252d1661a5SPawel Jakub Dawidek } else { 18262d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_STALE; 18272d1661a5SPawel Jakub Dawidek } 18282d1661a5SPawel Jakub Dawidek } 18292d1661a5SPawel Jakub Dawidek } else if (disk->d_sync.ds_syncid < sc->sc_syncid) { 18302d1661a5SPawel Jakub Dawidek /* 18312d1661a5SPawel Jakub Dawidek * Reset all synchronization data for this disk, 18322d1661a5SPawel Jakub Dawidek * because if it even was synchronized, it was 18332d1661a5SPawel Jakub Dawidek * synchronized to disks with different syncid. 18342d1661a5SPawel Jakub Dawidek */ 18352d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_SYNCHRONIZING; 18362d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = 0; 18372d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = 0; 18382d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = sc->sc_syncid; 18392d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) == 0 || 18402d1661a5SPawel Jakub Dawidek (disk->d_flags & G_RAID3_DISK_FLAG_FORCE_SYNC) != 0) { 18412d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_SYNCHRONIZING; 18422d1661a5SPawel Jakub Dawidek } else { 18432d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_STALE; 18442d1661a5SPawel Jakub Dawidek } 18452d1661a5SPawel Jakub Dawidek } else /* if (sc->sc_syncid < disk->d_sync.ds_syncid) */ { 18462d1661a5SPawel Jakub Dawidek /* 18472d1661a5SPawel Jakub Dawidek * Not good, NOT GOOD! 18482d1661a5SPawel Jakub Dawidek * It means that device was started on stale disks 18492d1661a5SPawel Jakub Dawidek * and more fresh disk just arrive. 18502d1661a5SPawel Jakub Dawidek * If there were writes, device is fucked up, sorry. 18512d1661a5SPawel Jakub Dawidek * I think the best choice here is don't touch 18522d1661a5SPawel Jakub Dawidek * this disk and inform the user laudly. 18532d1661a5SPawel Jakub Dawidek */ 18542d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s was started before the freshest " 18552d1661a5SPawel Jakub Dawidek "disk (%s) arrives!! It will not be connected to the " 18562d1661a5SPawel Jakub Dawidek "running device.", sc->sc_name, 18572d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 18582d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 18592d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_NONE; 18602d1661a5SPawel Jakub Dawidek /* Return immediately, because disk was destroyed. */ 18612d1661a5SPawel Jakub Dawidek return (state); 18622d1661a5SPawel Jakub Dawidek } 18632d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "State for %s disk: %s.", 18642d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), g_raid3_disk_state2str(state)); 18652d1661a5SPawel Jakub Dawidek return (state); 18662d1661a5SPawel Jakub Dawidek } 18672d1661a5SPawel Jakub Dawidek 18682d1661a5SPawel Jakub Dawidek /* 18692d1661a5SPawel Jakub Dawidek * Update device state. 18702d1661a5SPawel Jakub Dawidek */ 18712d1661a5SPawel Jakub Dawidek static void 18722d1661a5SPawel Jakub Dawidek g_raid3_update_device(struct g_raid3_softc *sc, boolean_t force) 18732d1661a5SPawel Jakub Dawidek { 18742d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 18752d1661a5SPawel Jakub Dawidek u_int state; 18762d1661a5SPawel Jakub Dawidek 18772d1661a5SPawel Jakub Dawidek g_topology_assert(); 18782d1661a5SPawel Jakub Dawidek 18792d1661a5SPawel Jakub Dawidek switch (sc->sc_state) { 18802d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_STARTING: 18812d1661a5SPawel Jakub Dawidek { 18822d1661a5SPawel Jakub Dawidek u_int n, ndirty, ndisks, syncid; 18832d1661a5SPawel Jakub Dawidek 18842d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_provider == NULL, 18852d1661a5SPawel Jakub Dawidek ("Non-NULL provider in STARTING state (%s).", sc->sc_name)); 18862d1661a5SPawel Jakub Dawidek /* 18872d1661a5SPawel Jakub Dawidek * Are we ready? We are, if all disks are connected or 18882d1661a5SPawel Jakub Dawidek * one disk is missing and 'force' is true. 18892d1661a5SPawel Jakub Dawidek */ 18902d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, -1) + force == sc->sc_ndisks) { 18912d1661a5SPawel Jakub Dawidek if (!force) 18922d1661a5SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 18932d1661a5SPawel Jakub Dawidek } else { 18942d1661a5SPawel Jakub Dawidek if (force) { 18952d1661a5SPawel Jakub Dawidek /* 18962d1661a5SPawel Jakub Dawidek * Timeout expired, so destroy device. 18972d1661a5SPawel Jakub Dawidek */ 18982d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 18992d1661a5SPawel Jakub Dawidek } 19002d1661a5SPawel Jakub Dawidek return; 19012d1661a5SPawel Jakub Dawidek } 19022d1661a5SPawel Jakub Dawidek 19032d1661a5SPawel Jakub Dawidek /* 19042d1661a5SPawel Jakub Dawidek * There must be at least 'sc->sc_ndisks - 1' components 19052d1661a5SPawel Jakub Dawidek * with the same syncid and without SYNCHRONIZING flag. 19062d1661a5SPawel Jakub Dawidek */ 19072d1661a5SPawel Jakub Dawidek 19082d1661a5SPawel Jakub Dawidek /* 19092d1661a5SPawel Jakub Dawidek * Find the biggest syncid, number of valid components and 19102d1661a5SPawel Jakub Dawidek * number of dirty components. 19112d1661a5SPawel Jakub Dawidek */ 19122d1661a5SPawel Jakub Dawidek ndirty = ndisks = syncid = 0; 19132d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 19142d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 19152d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 19162d1661a5SPawel Jakub Dawidek continue; 19172d1661a5SPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) != 0) 19182d1661a5SPawel Jakub Dawidek ndirty++; 19192d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_syncid > syncid) { 19202d1661a5SPawel Jakub Dawidek syncid = disk->d_sync.ds_syncid; 19212d1661a5SPawel Jakub Dawidek ndisks = 0; 19222d1661a5SPawel Jakub Dawidek } else if (disk->d_sync.ds_syncid < syncid) { 19232d1661a5SPawel Jakub Dawidek continue; 19242d1661a5SPawel Jakub Dawidek } 19252d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 19262d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING) != 0) { 19272d1661a5SPawel Jakub Dawidek continue; 19282d1661a5SPawel Jakub Dawidek } 19292d1661a5SPawel Jakub Dawidek ndisks++; 19302d1661a5SPawel Jakub Dawidek } 19312d1661a5SPawel Jakub Dawidek /* 19322d1661a5SPawel Jakub Dawidek * Do we have enough valid components? 19332d1661a5SPawel Jakub Dawidek */ 19342d1661a5SPawel Jakub Dawidek if (ndisks + 1 < sc->sc_ndisks) { 19352d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 19362d1661a5SPawel Jakub Dawidek "Device %s is broken, too few valid components.", 19372d1661a5SPawel Jakub Dawidek sc->sc_name); 19382d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 19392d1661a5SPawel Jakub Dawidek return; 19402d1661a5SPawel Jakub Dawidek } 19412d1661a5SPawel Jakub Dawidek /* 19422d1661a5SPawel Jakub Dawidek * If there is one DIRTY component and all disks are present, 19432d1661a5SPawel Jakub Dawidek * mark it for synchronization. If there is more than one DIRTY 19442d1661a5SPawel Jakub Dawidek * component, mark parity component for synchronization. 19452d1661a5SPawel Jakub Dawidek */ 19462d1661a5SPawel Jakub Dawidek if (ndisks == sc->sc_ndisks && ndirty == 1) { 19472d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 19482d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 19492d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 19502d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_DIRTY) == 0) { 19512d1661a5SPawel Jakub Dawidek continue; 19522d1661a5SPawel Jakub Dawidek } 19532d1661a5SPawel Jakub Dawidek disk->d_flags |= 19542d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING; 19552d1661a5SPawel Jakub Dawidek } 19562d1661a5SPawel Jakub Dawidek } else if (ndisks == sc->sc_ndisks && ndirty > 1) { 19572d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 19582d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_SYNCHRONIZING; 19592d1661a5SPawel Jakub Dawidek } 19602d1661a5SPawel Jakub Dawidek 19612d1661a5SPawel Jakub Dawidek sc->sc_syncid = syncid; 19622d1661a5SPawel Jakub Dawidek if (force) { 19632d1661a5SPawel Jakub Dawidek /* Remember to bump syncid on first write. */ 19642d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = G_RAID3_BUMP_ON_FIRST_WRITE; 19652d1661a5SPawel Jakub Dawidek } 19662d1661a5SPawel Jakub Dawidek if (ndisks == sc->sc_ndisks) 19672d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_COMPLETE; 19682d1661a5SPawel Jakub Dawidek else /* if (ndisks == sc->sc_ndisks - 1) */ 19692d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_DEGRADED; 19702d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s state changed from %s to %s.", 19712d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 19722d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 19732d1661a5SPawel Jakub Dawidek sc->sc_state = state; 19742d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 19752d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 19762d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 19772d1661a5SPawel Jakub Dawidek continue; 19782d1661a5SPawel Jakub Dawidek state = g_raid3_determine_state(disk); 19792d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, state, G_RAID3_EVENT_DONTWAIT); 19802d1661a5SPawel Jakub Dawidek if (state == G_RAID3_DISK_STATE_STALE) { 19812d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = 19822d1661a5SPawel Jakub Dawidek G_RAID3_BUMP_ON_FIRST_WRITE; 19832d1661a5SPawel Jakub Dawidek } 19842d1661a5SPawel Jakub Dawidek } 19852d1661a5SPawel Jakub Dawidek break; 19862d1661a5SPawel Jakub Dawidek } 19872d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_DEGRADED: 19882d1661a5SPawel Jakub Dawidek /* 19892d1661a5SPawel Jakub Dawidek * Bump syncid here, if we need to do it immediately. 19902d1661a5SPawel Jakub Dawidek */ 19912d1661a5SPawel Jakub Dawidek if (sc->sc_bump_syncid == G_RAID3_BUMP_IMMEDIATELY) { 19922d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = 0; 19932d1661a5SPawel Jakub Dawidek g_raid3_bump_syncid(sc); 19942d1661a5SPawel Jakub Dawidek } 19952d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NEW) > 0) 19962d1661a5SPawel Jakub Dawidek return; 19972d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 19982d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1) { 19992d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) 20002d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(sc); 20012d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 20022d1661a5SPawel Jakub Dawidek return; 20032d1661a5SPawel Jakub Dawidek } 20042d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) == 20052d1661a5SPawel Jakub Dawidek sc->sc_ndisks) { 20062d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_COMPLETE; 20072d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 20082d1661a5SPawel Jakub Dawidek "Device %s state changed from %s to %s.", 20092d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 20102d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 20112d1661a5SPawel Jakub Dawidek sc->sc_state = state; 20122d1661a5SPawel Jakub Dawidek } 20132d1661a5SPawel Jakub Dawidek if (sc->sc_provider == NULL) 20142d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(sc); 20152d1661a5SPawel Jakub Dawidek break; 20162d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_COMPLETE: 20172d1661a5SPawel Jakub Dawidek /* 20182d1661a5SPawel Jakub Dawidek * Bump syncid here, if we need to do it immediately. 20192d1661a5SPawel Jakub Dawidek */ 20202d1661a5SPawel Jakub Dawidek if (sc->sc_bump_syncid == G_RAID3_BUMP_IMMEDIATELY) { 20212d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = 0; 20222d1661a5SPawel Jakub Dawidek g_raid3_bump_syncid(sc); 20232d1661a5SPawel Jakub Dawidek } 20242d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NEW) > 0) 20252d1661a5SPawel Jakub Dawidek return; 20262d1661a5SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) >= 20272d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1, 20282d1661a5SPawel Jakub Dawidek ("Too few ACTIVE components in COMPLETE state (device %s).", 20292d1661a5SPawel Jakub Dawidek sc->sc_name)); 20302d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) == 20312d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1) { 20322d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_DEGRADED; 20332d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 20342d1661a5SPawel Jakub Dawidek "Device %s state changed from %s to %s.", 20352d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 20362d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 20372d1661a5SPawel Jakub Dawidek sc->sc_state = state; 20382d1661a5SPawel Jakub Dawidek } 20392d1661a5SPawel Jakub Dawidek if (sc->sc_provider == NULL) 20402d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(sc); 20412d1661a5SPawel Jakub Dawidek break; 20422d1661a5SPawel Jakub Dawidek default: 20432d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Wrong device state (%s, %s).", sc->sc_name, 20442d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state))); 20452d1661a5SPawel Jakub Dawidek break; 20462d1661a5SPawel Jakub Dawidek } 20472d1661a5SPawel Jakub Dawidek } 20482d1661a5SPawel Jakub Dawidek 20492d1661a5SPawel Jakub Dawidek /* 20502d1661a5SPawel Jakub Dawidek * Update disk state and device state if needed. 20512d1661a5SPawel Jakub Dawidek */ 20522d1661a5SPawel Jakub Dawidek #define DISK_STATE_CHANGED() G_RAID3_DEBUG(1, \ 20532d1661a5SPawel Jakub Dawidek "Disk %s state changed from %s to %s (device %s).", \ 20542d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), \ 20552d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state), \ 20562d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(state), sc->sc_name) 20572d1661a5SPawel Jakub Dawidek static int 20582d1661a5SPawel Jakub Dawidek g_raid3_update_disk(struct g_raid3_disk *disk, u_int state) 20592d1661a5SPawel Jakub Dawidek { 20602d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 20612d1661a5SPawel Jakub Dawidek 20622d1661a5SPawel Jakub Dawidek g_topology_assert(); 20632d1661a5SPawel Jakub Dawidek 20642d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 20652d1661a5SPawel Jakub Dawidek again: 20662d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "Changing disk %s state from %s to %s.", 20672d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), g_raid3_disk_state2str(disk->d_state), 20682d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(state)); 20692d1661a5SPawel Jakub Dawidek switch (state) { 20702d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 20712d1661a5SPawel Jakub Dawidek /* 20722d1661a5SPawel Jakub Dawidek * Possible scenarios: 20732d1661a5SPawel Jakub Dawidek * 1. New disk arrive. 20742d1661a5SPawel Jakub Dawidek */ 20752d1661a5SPawel Jakub Dawidek /* Previous state should be NONE. */ 20762d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NONE, 20772d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 20782d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 20792d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 20802d1661a5SPawel Jakub Dawidek 20812d1661a5SPawel Jakub Dawidek disk->d_state = state; 20822d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s detected.", 20832d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 20842d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_STARTING) 20852d1661a5SPawel Jakub Dawidek break; 20862d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 20872d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 20882d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 20892d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 20902d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 20912d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 20922d1661a5SPawel Jakub Dawidek state = g_raid3_determine_state(disk); 20932d1661a5SPawel Jakub Dawidek if (state != G_RAID3_DISK_STATE_NONE) 20942d1661a5SPawel Jakub Dawidek goto again; 20952d1661a5SPawel Jakub Dawidek break; 20962d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 20972d1661a5SPawel Jakub Dawidek /* 20982d1661a5SPawel Jakub Dawidek * Possible scenarios: 20992d1661a5SPawel Jakub Dawidek * 1. New disk does not need synchronization. 21002d1661a5SPawel Jakub Dawidek * 2. Synchronization process finished successfully. 21012d1661a5SPawel Jakub Dawidek */ 21022d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 21032d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 21042d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 21052d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 21062d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 21072d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21082d1661a5SPawel Jakub Dawidek /* Previous state should be NEW or SYNCHRONIZING. */ 21092d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW || 21102d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 21112d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 21122d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21132d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 21142d1661a5SPawel Jakub Dawidek 21152d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NEW) 21162d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 21172d1661a5SPawel Jakub Dawidek else if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 21182d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_SYNCHRONIZING; 21192d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 21202d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 0); 21212d1661a5SPawel Jakub Dawidek } 21222d1661a5SPawel Jakub Dawidek disk->d_state = state; 21232d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = 0; 21242d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = 0; 21252d1661a5SPawel Jakub Dawidek g_raid3_update_access(disk); 21262d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 21272d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s activated.", 21282d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 21292d1661a5SPawel Jakub Dawidek break; 21302d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 21312d1661a5SPawel Jakub Dawidek /* 21322d1661a5SPawel Jakub Dawidek * Possible scenarios: 21332d1661a5SPawel Jakub Dawidek * 1. Stale disk was connected. 21342d1661a5SPawel Jakub Dawidek */ 21352d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 21362d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 21372d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 21382d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21392d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 21402d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 21412d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 21422d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 21432d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 21442d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21452d1661a5SPawel Jakub Dawidek /* 21462d1661a5SPawel Jakub Dawidek * STALE state is only possible if device is marked 21472d1661a5SPawel Jakub Dawidek * NOAUTOSYNC. 21482d1661a5SPawel Jakub Dawidek */ 21492d1661a5SPawel Jakub Dawidek KASSERT((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0, 21502d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 21512d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 21522d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 21532d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21542d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 21552d1661a5SPawel Jakub Dawidek 21562d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 21572d1661a5SPawel Jakub Dawidek disk->d_state = state; 21582d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 21592d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s is stale.", 21602d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 21612d1661a5SPawel Jakub Dawidek break; 21622d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 21632d1661a5SPawel Jakub Dawidek /* 21642d1661a5SPawel Jakub Dawidek * Possible scenarios: 21652d1661a5SPawel Jakub Dawidek * 1. Disk which needs synchronization was connected. 21662d1661a5SPawel Jakub Dawidek */ 21672d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 21682d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 21692d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 21702d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21712d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 21722d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 21732d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 21742d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 21752d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 21762d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21772d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 21782d1661a5SPawel Jakub Dawidek 21792d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NEW) 21802d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 21812d1661a5SPawel Jakub Dawidek disk->d_state = state; 21822d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) { 21832d1661a5SPawel Jakub Dawidek g_raid3_sync_start(sc); 21842d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 21852d1661a5SPawel Jakub Dawidek } 21862d1661a5SPawel Jakub Dawidek break; 21872d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_DISCONNECTED: 21882d1661a5SPawel Jakub Dawidek /* 21892d1661a5SPawel Jakub Dawidek * Possible scenarios: 21902d1661a5SPawel Jakub Dawidek * 1. Device wasn't running yet, but disk disappear. 21912d1661a5SPawel Jakub Dawidek * 2. Disk was active and disapppear. 21922d1661a5SPawel Jakub Dawidek * 3. Disk disappear during synchronization process. 21932d1661a5SPawel Jakub Dawidek */ 21942d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 21952d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 21962d1661a5SPawel Jakub Dawidek /* 21972d1661a5SPawel Jakub Dawidek * Previous state should be ACTIVE, STALE or 21982d1661a5SPawel Jakub Dawidek * SYNCHRONIZING. 21992d1661a5SPawel Jakub Dawidek */ 22002d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 22012d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_STALE || 22022d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 22032d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", 22042d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 22052d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 22062d1661a5SPawel Jakub Dawidek } else if (sc->sc_state == G_RAID3_DEVICE_STATE_STARTING) { 22072d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 22082d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 22092d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", 22102d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 22112d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 22122d1661a5SPawel Jakub Dawidek /* 22132d1661a5SPawel Jakub Dawidek * Reset bumping syncid if disk disappeared in STARTING 22142d1661a5SPawel Jakub Dawidek * state. 22152d1661a5SPawel Jakub Dawidek */ 22162d1661a5SPawel Jakub Dawidek if (sc->sc_bump_syncid == G_RAID3_BUMP_ON_FIRST_WRITE) 22172d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = 0; 22182d1661a5SPawel Jakub Dawidek #ifdef INVARIANTS 22192d1661a5SPawel Jakub Dawidek } else { 22202d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Wrong device state (%s, %s, %s, %s).", 22212d1661a5SPawel Jakub Dawidek sc->sc_name, 22222d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 22232d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 22242d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 22252d1661a5SPawel Jakub Dawidek #endif 22262d1661a5SPawel Jakub Dawidek } 22272d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 22282d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s disconnected.", 22292d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 22302d1661a5SPawel Jakub Dawidek 22312d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 22322d1661a5SPawel Jakub Dawidek break; 22332d1661a5SPawel Jakub Dawidek default: 22342d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Unknown state (%u).", state)); 22352d1661a5SPawel Jakub Dawidek break; 22362d1661a5SPawel Jakub Dawidek } 22372d1661a5SPawel Jakub Dawidek return (0); 22382d1661a5SPawel Jakub Dawidek } 22392d1661a5SPawel Jakub Dawidek #undef DISK_STATE_CHANGED 22402d1661a5SPawel Jakub Dawidek 22412d1661a5SPawel Jakub Dawidek static int 22422d1661a5SPawel Jakub Dawidek g_raid3_read_metadata(struct g_consumer *cp, struct g_raid3_metadata *md) 22432d1661a5SPawel Jakub Dawidek { 22442d1661a5SPawel Jakub Dawidek struct g_provider *pp; 22452d1661a5SPawel Jakub Dawidek u_char *buf; 22462d1661a5SPawel Jakub Dawidek int error; 22472d1661a5SPawel Jakub Dawidek 22482d1661a5SPawel Jakub Dawidek g_topology_assert(); 22492d1661a5SPawel Jakub Dawidek 22502d1661a5SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 22512d1661a5SPawel Jakub Dawidek if (error != 0) 22522d1661a5SPawel Jakub Dawidek return (error); 22532d1661a5SPawel Jakub Dawidek pp = cp->provider; 22542d1661a5SPawel Jakub Dawidek g_topology_unlock(); 22552d1661a5SPawel Jakub Dawidek /* Metadata are stored on last sector. */ 22562d1661a5SPawel Jakub Dawidek buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 22572d1661a5SPawel Jakub Dawidek &error); 22582d1661a5SPawel Jakub Dawidek g_topology_lock(); 22592d1661a5SPawel Jakub Dawidek if (buf == NULL) { 22602d1661a5SPawel Jakub Dawidek g_access(cp, -1, 0, 0); 22612d1661a5SPawel Jakub Dawidek return (error); 22622d1661a5SPawel Jakub Dawidek } 22632d1661a5SPawel Jakub Dawidek if (error != 0) { 22642d1661a5SPawel Jakub Dawidek g_access(cp, -1, 0, 0); 22652d1661a5SPawel Jakub Dawidek g_free(buf); 22662d1661a5SPawel Jakub Dawidek return (error); 22672d1661a5SPawel Jakub Dawidek } 22682d1661a5SPawel Jakub Dawidek error = g_access(cp, -1, 0, 0); 22692d1661a5SPawel Jakub Dawidek KASSERT(error == 0, ("Cannot decrease access count for %s.", pp->name)); 22702d1661a5SPawel Jakub Dawidek 22712d1661a5SPawel Jakub Dawidek /* Decode metadata. */ 22722d1661a5SPawel Jakub Dawidek error = raid3_metadata_decode(buf, md); 22732d1661a5SPawel Jakub Dawidek g_free(buf); 22742d1661a5SPawel Jakub Dawidek if (strcmp(md->md_magic, G_RAID3_MAGIC) != 0) 22752d1661a5SPawel Jakub Dawidek return (EINVAL); 22762d1661a5SPawel Jakub Dawidek if (error != 0) { 22772d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "MD5 metadata hash mismatch for provider %s.", 22782d1661a5SPawel Jakub Dawidek cp->provider->name); 22792d1661a5SPawel Jakub Dawidek return (error); 22802d1661a5SPawel Jakub Dawidek } 22812d1661a5SPawel Jakub Dawidek 22822d1661a5SPawel Jakub Dawidek return (0); 22832d1661a5SPawel Jakub Dawidek } 22842d1661a5SPawel Jakub Dawidek 22852d1661a5SPawel Jakub Dawidek static int 22862d1661a5SPawel Jakub Dawidek g_raid3_check_metadata(struct g_raid3_softc *sc, struct g_provider *pp, 22872d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md) 22882d1661a5SPawel Jakub Dawidek { 22892d1661a5SPawel Jakub Dawidek 22902d1661a5SPawel Jakub Dawidek if (md->md_no >= sc->sc_ndisks) { 22912d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Invalid disk %s number (no=%u), skipping.", 22922d1661a5SPawel Jakub Dawidek pp->name, md->md_no); 22932d1661a5SPawel Jakub Dawidek return (EINVAL); 22942d1661a5SPawel Jakub Dawidek } 22952d1661a5SPawel Jakub Dawidek if (sc->sc_disks[md->md_no].d_state != G_RAID3_DISK_STATE_NODISK) { 22962d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (no=%u) already exists, skipping.", 22972d1661a5SPawel Jakub Dawidek pp->name, md->md_no); 22982d1661a5SPawel Jakub Dawidek return (EEXIST); 22992d1661a5SPawel Jakub Dawidek } 23002d1661a5SPawel Jakub Dawidek if (md->md_all != sc->sc_ndisks) { 23012d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23022d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 23032d1661a5SPawel Jakub Dawidek "md_all", pp->name, sc->sc_name); 23042d1661a5SPawel Jakub Dawidek return (EINVAL); 23052d1661a5SPawel Jakub Dawidek } 23062d1661a5SPawel Jakub Dawidek if (md->md_mediasize != sc->sc_mediasize) { 23072d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23082d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 23092d1661a5SPawel Jakub Dawidek "md_mediasize", pp->name, sc->sc_name); 23102d1661a5SPawel Jakub Dawidek return (EINVAL); 23112d1661a5SPawel Jakub Dawidek } 23122d1661a5SPawel Jakub Dawidek if ((md->md_mediasize % (sc->sc_ndisks - 1)) != 0) { 23132d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23142d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 23152d1661a5SPawel Jakub Dawidek "md_mediasize", pp->name, sc->sc_name); 23162d1661a5SPawel Jakub Dawidek return (EINVAL); 23172d1661a5SPawel Jakub Dawidek } 23182d1661a5SPawel Jakub Dawidek if ((sc->sc_mediasize / (sc->sc_ndisks - 1)) > pp->mediasize) { 23192d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23202d1661a5SPawel Jakub Dawidek "Invalid size of disk %s (device %s), skipping.", pp->name, 23212d1661a5SPawel Jakub Dawidek sc->sc_name); 23222d1661a5SPawel Jakub Dawidek return (EINVAL); 23232d1661a5SPawel Jakub Dawidek } 23242d1661a5SPawel Jakub Dawidek if ((md->md_sectorsize / pp->sectorsize) < sc->sc_ndisks - 1) { 23252d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23262d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 23272d1661a5SPawel Jakub Dawidek "md_sectorsize", pp->name, sc->sc_name); 23282d1661a5SPawel Jakub Dawidek return (EINVAL); 23292d1661a5SPawel Jakub Dawidek } 23302d1661a5SPawel Jakub Dawidek if (md->md_sectorsize != sc->sc_sectorsize) { 23312d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23322d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 23332d1661a5SPawel Jakub Dawidek "md_sectorsize", pp->name, sc->sc_name); 23342d1661a5SPawel Jakub Dawidek return (EINVAL); 23352d1661a5SPawel Jakub Dawidek } 23362d1661a5SPawel Jakub Dawidek if ((sc->sc_sectorsize % pp->sectorsize) != 0) { 23372d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23382d1661a5SPawel Jakub Dawidek "Invalid sector size of disk %s (device %s), skipping.", 23392d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 23402d1661a5SPawel Jakub Dawidek return (EINVAL); 23412d1661a5SPawel Jakub Dawidek } 23422d1661a5SPawel Jakub Dawidek if ((md->md_mflags & ~G_RAID3_DEVICE_FLAG_MASK) != 0) { 23432d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23442d1661a5SPawel Jakub Dawidek "Invalid device flags on disk %s (device %s), skipping.", 23452d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 23462d1661a5SPawel Jakub Dawidek return (EINVAL); 23472d1661a5SPawel Jakub Dawidek } 23482d1661a5SPawel Jakub Dawidek if ((md->md_dflags & ~G_RAID3_DISK_FLAG_MASK) != 0) { 23492d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23502d1661a5SPawel Jakub Dawidek "Invalid disk flags on disk %s (device %s), skipping.", 23512d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 23522d1661a5SPawel Jakub Dawidek return (EINVAL); 23532d1661a5SPawel Jakub Dawidek } 23542d1661a5SPawel Jakub Dawidek return (0); 23552d1661a5SPawel Jakub Dawidek } 23562d1661a5SPawel Jakub Dawidek 23572d1661a5SPawel Jakub Dawidek static int 23582d1661a5SPawel Jakub Dawidek g_raid3_add_disk(struct g_raid3_softc *sc, struct g_provider *pp, 23592d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md) 23602d1661a5SPawel Jakub Dawidek { 23612d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 23622d1661a5SPawel Jakub Dawidek int error; 23632d1661a5SPawel Jakub Dawidek 23642d1661a5SPawel Jakub Dawidek g_topology_assert(); 23652d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Adding disk %s.", pp->name); 23662d1661a5SPawel Jakub Dawidek 23672d1661a5SPawel Jakub Dawidek error = g_raid3_check_metadata(sc, pp, md); 23682d1661a5SPawel Jakub Dawidek if (error != 0) 23692d1661a5SPawel Jakub Dawidek return (error); 23702d1661a5SPawel Jakub Dawidek disk = g_raid3_init_disk(sc, pp, md, &error); 23712d1661a5SPawel Jakub Dawidek if (disk == NULL) 23722d1661a5SPawel Jakub Dawidek return (error); 23732d1661a5SPawel Jakub Dawidek error = g_raid3_event_send(disk, G_RAID3_DISK_STATE_NEW, 23742d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_WAIT); 23752d1661a5SPawel Jakub Dawidek return (error); 23762d1661a5SPawel Jakub Dawidek } 23772d1661a5SPawel Jakub Dawidek 23782d1661a5SPawel Jakub Dawidek static int 23792d1661a5SPawel Jakub Dawidek g_raid3_access(struct g_provider *pp, int acr, int acw, int ace) 23802d1661a5SPawel Jakub Dawidek { 23812d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 23822d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 23832d1661a5SPawel Jakub Dawidek int dcr, dcw, dce, err, error; 23842d1661a5SPawel Jakub Dawidek u_int n; 23852d1661a5SPawel Jakub Dawidek 23862d1661a5SPawel Jakub Dawidek g_topology_assert(); 23872d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access request for %s: r%dw%de%d.", pp->name, acr, 23882d1661a5SPawel Jakub Dawidek acw, ace); 23892d1661a5SPawel Jakub Dawidek 23902d1661a5SPawel Jakub Dawidek dcr = pp->acr + acr; 23912d1661a5SPawel Jakub Dawidek dcw = pp->acw + acw; 23922d1661a5SPawel Jakub Dawidek dce = pp->ace + ace; 23932d1661a5SPawel Jakub Dawidek 23942d1661a5SPawel Jakub Dawidek /* On first open, grab an extra "exclusive" bit */ 23952d1661a5SPawel Jakub Dawidek if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) 23962d1661a5SPawel Jakub Dawidek ace++; 23972d1661a5SPawel Jakub Dawidek /* ... and let go of it on last close */ 23982d1661a5SPawel Jakub Dawidek if (dcr == 0 && dcw == 0 && dce == 0) 23992d1661a5SPawel Jakub Dawidek ace--; 24002d1661a5SPawel Jakub Dawidek 24012d1661a5SPawel Jakub Dawidek sc = pp->geom->softc; 24022d1661a5SPawel Jakub Dawidek if (sc == NULL || 24032d1661a5SPawel Jakub Dawidek g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks - 1) { 24042d1661a5SPawel Jakub Dawidek if (acr <= 0 && acw <= 0 && ace <= 0) 24052d1661a5SPawel Jakub Dawidek return (0); 24062d1661a5SPawel Jakub Dawidek else 24072d1661a5SPawel Jakub Dawidek return (ENXIO); 24082d1661a5SPawel Jakub Dawidek } 24092d1661a5SPawel Jakub Dawidek error = ENXIO; 24102d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 24112d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 24122d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) 24132d1661a5SPawel Jakub Dawidek continue; 24142d1661a5SPawel Jakub Dawidek err = g_access(disk->d_consumer, acr, acw, ace); 24152d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", 24162d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), acr, acw, ace, err); 24172d1661a5SPawel Jakub Dawidek if (err == 0) { 24182d1661a5SPawel Jakub Dawidek /* 24192d1661a5SPawel Jakub Dawidek * Mark disk as dirty on open and unmark on close. 24202d1661a5SPawel Jakub Dawidek */ 24212d1661a5SPawel Jakub Dawidek if (pp->acw == 0 && dcw > 0) { 24222d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 24232d1661a5SPawel Jakub Dawidek "Disk %s (device %s) marked as dirty.", 24242d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 24252d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 24262d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 24272d1661a5SPawel Jakub Dawidek } else if (pp->acw > 0 && dcw == 0) { 24282d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 24292d1661a5SPawel Jakub Dawidek "Disk %s (device %s) marked as clean.", 24302d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 24312d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 24322d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 24332d1661a5SPawel Jakub Dawidek } 24342d1661a5SPawel Jakub Dawidek error = 0; 24352d1661a5SPawel Jakub Dawidek } else { 24362d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = G_RAID3_BUMP_ON_FIRST_WRITE; 24372d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 24382d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 24392d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 24402d1661a5SPawel Jakub Dawidek } 24412d1661a5SPawel Jakub Dawidek } 24422d1661a5SPawel Jakub Dawidek return (error); 24432d1661a5SPawel Jakub Dawidek } 24442d1661a5SPawel Jakub Dawidek 24452d1661a5SPawel Jakub Dawidek static struct g_geom * 24462d1661a5SPawel Jakub Dawidek g_raid3_create(struct g_class *mp, const struct g_raid3_metadata *md) 24472d1661a5SPawel Jakub Dawidek { 24482d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 24492d1661a5SPawel Jakub Dawidek struct g_geom *gp; 24502d1661a5SPawel Jakub Dawidek int error, timeout; 24512d1661a5SPawel Jakub Dawidek u_int n; 24522d1661a5SPawel Jakub Dawidek 24532d1661a5SPawel Jakub Dawidek g_topology_assert(); 24542d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Creating device %s (id=%u).", md->md_name, md->md_id); 24552d1661a5SPawel Jakub Dawidek 24562d1661a5SPawel Jakub Dawidek /* One disk is minimum. */ 24572d1661a5SPawel Jakub Dawidek if (md->md_all < 1) 24582d1661a5SPawel Jakub Dawidek return (NULL); 24592d1661a5SPawel Jakub Dawidek /* 24602d1661a5SPawel Jakub Dawidek * Action geom. 24612d1661a5SPawel Jakub Dawidek */ 24622d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "%s", md->md_name); 24632d1661a5SPawel Jakub Dawidek sc = malloc(sizeof(*sc), M_RAID3, M_WAITOK | M_ZERO); 24642d1661a5SPawel Jakub Dawidek sc->sc_disks = malloc(sizeof(struct g_raid3_disk) * md->md_all, M_RAID3, 24652d1661a5SPawel Jakub Dawidek M_WAITOK | M_ZERO); 24662d1661a5SPawel Jakub Dawidek gp->start = g_raid3_start; 24672d1661a5SPawel Jakub Dawidek gp->spoiled = g_raid3_spoiled; 24682d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_orphan; 24692d1661a5SPawel Jakub Dawidek gp->access = g_raid3_access; 24702d1661a5SPawel Jakub Dawidek gp->dumpconf = g_raid3_dumpconf; 24712d1661a5SPawel Jakub Dawidek 24722d1661a5SPawel Jakub Dawidek sc->sc_id = md->md_id; 24732d1661a5SPawel Jakub Dawidek sc->sc_mediasize = md->md_mediasize; 24742d1661a5SPawel Jakub Dawidek sc->sc_sectorsize = md->md_sectorsize; 24752d1661a5SPawel Jakub Dawidek sc->sc_ndisks = md->md_all; 24762d1661a5SPawel Jakub Dawidek sc->sc_flags = md->md_mflags; 24772d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = 0; 24782d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) 24792d1661a5SPawel Jakub Dawidek sc->sc_disks[n].d_state = G_RAID3_DISK_STATE_NODISK; 24802d1661a5SPawel Jakub Dawidek bioq_init(&sc->sc_queue); 24812d1661a5SPawel Jakub Dawidek mtx_init(&sc->sc_queue_mtx, "graid3:queue", NULL, MTX_DEF); 24822d1661a5SPawel Jakub Dawidek TAILQ_INIT(&sc->sc_events); 24832d1661a5SPawel Jakub Dawidek mtx_init(&sc->sc_events_mtx, "graid3:events", NULL, MTX_DEF); 24842d1661a5SPawel Jakub Dawidek callout_init(&sc->sc_callout, CALLOUT_MPSAFE); 24852d1661a5SPawel Jakub Dawidek sc->sc_state = G_RAID3_DEVICE_STATE_STARTING; 24862d1661a5SPawel Jakub Dawidek gp->softc = sc; 24872d1661a5SPawel Jakub Dawidek sc->sc_geom = gp; 24882d1661a5SPawel Jakub Dawidek sc->sc_provider = NULL; 24892d1661a5SPawel Jakub Dawidek /* 24902d1661a5SPawel Jakub Dawidek * Synchronization geom. 24912d1661a5SPawel Jakub Dawidek */ 24922d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "%s.sync", md->md_name); 24932d1661a5SPawel Jakub Dawidek gp->softc = sc; 24942d1661a5SPawel Jakub Dawidek gp->spoiled = g_raid3_spoiled; 24952d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_orphan; 24962d1661a5SPawel Jakub Dawidek sc->sc_sync.ds_geom = gp; 24972d1661a5SPawel Jakub Dawidek sc->sc_zone_64k = uma_zcreate("gr3:64k", 65536, NULL, NULL, NULL, NULL, 24982d1661a5SPawel Jakub Dawidek UMA_ALIGN_PTR, 0); 24992d1661a5SPawel Jakub Dawidek uma_zone_set_max(sc->sc_zone_64k, g_raid3_n64k); 25002d1661a5SPawel Jakub Dawidek sc->sc_zone_16k = uma_zcreate("gr3:16k", 16384, NULL, NULL, NULL, NULL, 25012d1661a5SPawel Jakub Dawidek UMA_ALIGN_PTR, 0); 25022d1661a5SPawel Jakub Dawidek uma_zone_set_max(sc->sc_zone_64k, g_raid3_n16k); 25032d1661a5SPawel Jakub Dawidek sc->sc_zone_4k = uma_zcreate("gr3:4k", 4096, NULL, NULL, NULL, NULL, 25042d1661a5SPawel Jakub Dawidek UMA_ALIGN_PTR, 0); 25052d1661a5SPawel Jakub Dawidek uma_zone_set_max(sc->sc_zone_4k, g_raid3_n4k); 25062d1661a5SPawel Jakub Dawidek error = kthread_create(g_raid3_worker, sc, &sc->sc_worker, 0, 0, 25072d1661a5SPawel Jakub Dawidek "g_raid3 %s", md->md_name); 25082d1661a5SPawel Jakub Dawidek if (error != 0) { 25092d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Cannot create kernel thread for %s.", 25102d1661a5SPawel Jakub Dawidek sc->sc_name); 25112d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_64k); 25122d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_16k); 25132d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_4k); 25142d1661a5SPawel Jakub Dawidek g_destroy_geom(sc->sc_sync.ds_geom); 25152d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_events_mtx); 25162d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 25172d1661a5SPawel Jakub Dawidek g_destroy_geom(sc->sc_geom); 25182d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 25192d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 25202d1661a5SPawel Jakub Dawidek return (NULL); 25212d1661a5SPawel Jakub Dawidek } 25222d1661a5SPawel Jakub Dawidek 25232d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id); 25242d1661a5SPawel Jakub Dawidek 25252d1661a5SPawel Jakub Dawidek /* 25262d1661a5SPawel Jakub Dawidek * Run timeout. 25272d1661a5SPawel Jakub Dawidek */ 25282d1661a5SPawel Jakub Dawidek timeout = atomic_load_acq_int(&g_raid3_timeout); 25292d1661a5SPawel Jakub Dawidek callout_reset(&sc->sc_callout, timeout * hz, g_raid3_go, sc); 25302d1661a5SPawel Jakub Dawidek return (sc->sc_geom); 25312d1661a5SPawel Jakub Dawidek } 25322d1661a5SPawel Jakub Dawidek 25332d1661a5SPawel Jakub Dawidek int 25342d1661a5SPawel Jakub Dawidek g_raid3_destroy(struct g_raid3_softc *sc, boolean_t force) 25352d1661a5SPawel Jakub Dawidek { 25362d1661a5SPawel Jakub Dawidek struct g_provider *pp; 25372d1661a5SPawel Jakub Dawidek 25382d1661a5SPawel Jakub Dawidek g_topology_assert(); 25392d1661a5SPawel Jakub Dawidek 25402d1661a5SPawel Jakub Dawidek if (sc == NULL) 25412d1661a5SPawel Jakub Dawidek return (ENXIO); 25422d1661a5SPawel Jakub Dawidek pp = sc->sc_provider; 25432d1661a5SPawel Jakub Dawidek if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 25442d1661a5SPawel Jakub Dawidek if (force) { 25452d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s is still open, so it " 25462d1661a5SPawel Jakub Dawidek "can't be definitely removed.", pp->name); 25472d1661a5SPawel Jakub Dawidek } else { 25482d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 25492d1661a5SPawel Jakub Dawidek "Device %s is still open (r%dw%de%d).", pp->name, 25502d1661a5SPawel Jakub Dawidek pp->acr, pp->acw, pp->ace); 25512d1661a5SPawel Jakub Dawidek return (EBUSY); 25522d1661a5SPawel Jakub Dawidek } 25532d1661a5SPawel Jakub Dawidek } 25542d1661a5SPawel Jakub Dawidek 25552d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 25562d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_WAIT; 25572d1661a5SPawel Jakub Dawidek g_topology_unlock(); 25582d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 25592d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 25602d1661a5SPawel Jakub Dawidek wakeup(sc); 25612d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 25622d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 25632d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, &sc->sc_worker); 25642d1661a5SPawel Jakub Dawidek while (sc->sc_worker != NULL) 25652d1661a5SPawel Jakub Dawidek tsleep(&sc->sc_worker, PRIBIO, "r3:destroy", hz / 5); 25662d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Woken up %p.", __func__, &sc->sc_worker); 25672d1661a5SPawel Jakub Dawidek g_topology_lock(); 25682d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(sc); 25692d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 25702d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 25712d1661a5SPawel Jakub Dawidek return (0); 25722d1661a5SPawel Jakub Dawidek } 25732d1661a5SPawel Jakub Dawidek 25742d1661a5SPawel Jakub Dawidek static void 25752d1661a5SPawel Jakub Dawidek g_raid3_taste_orphan(struct g_consumer *cp) 25762d1661a5SPawel Jakub Dawidek { 25772d1661a5SPawel Jakub Dawidek 25782d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("%s called while tasting %s.", __func__, 25792d1661a5SPawel Jakub Dawidek cp->provider->name)); 25802d1661a5SPawel Jakub Dawidek } 25812d1661a5SPawel Jakub Dawidek 25822d1661a5SPawel Jakub Dawidek static struct g_geom * 25832d1661a5SPawel Jakub Dawidek g_raid3_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 25842d1661a5SPawel Jakub Dawidek { 25852d1661a5SPawel Jakub Dawidek struct g_raid3_metadata md; 25862d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 25872d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 25882d1661a5SPawel Jakub Dawidek struct g_geom *gp; 25892d1661a5SPawel Jakub Dawidek int error; 25902d1661a5SPawel Jakub Dawidek 25912d1661a5SPawel Jakub Dawidek g_topology_assert(); 25922d1661a5SPawel Jakub Dawidek g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 25932d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Tasting %s.", pp->name); 25942d1661a5SPawel Jakub Dawidek 25952d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "raid3:taste"); 25962d1661a5SPawel Jakub Dawidek /* This orphan function should be never called. */ 25972d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_taste_orphan; 25982d1661a5SPawel Jakub Dawidek cp = g_new_consumer(gp); 25992d1661a5SPawel Jakub Dawidek g_attach(cp, pp); 26002d1661a5SPawel Jakub Dawidek error = g_raid3_read_metadata(cp, &md); 26012d1661a5SPawel Jakub Dawidek g_detach(cp); 26022d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 26032d1661a5SPawel Jakub Dawidek g_destroy_geom(gp); 26042d1661a5SPawel Jakub Dawidek if (error != 0) 26052d1661a5SPawel Jakub Dawidek return (NULL); 26062d1661a5SPawel Jakub Dawidek gp = NULL; 26072d1661a5SPawel Jakub Dawidek 26082d1661a5SPawel Jakub Dawidek if (md.md_version > G_RAID3_VERSION) { 26092d1661a5SPawel Jakub Dawidek printf("geom_raid3.ko module is too old to handle %s.\n", 26102d1661a5SPawel Jakub Dawidek pp->name); 26112d1661a5SPawel Jakub Dawidek return (NULL); 26122d1661a5SPawel Jakub Dawidek } 26132d1661a5SPawel Jakub Dawidek if (md.md_provider[0] != '\0' && strcmp(md.md_provider, pp->name) != 0) 26142d1661a5SPawel Jakub Dawidek return (NULL); 26152d1661a5SPawel Jakub Dawidek if (g_raid3_debug >= 2) 26162d1661a5SPawel Jakub Dawidek raid3_metadata_dump(&md); 26172d1661a5SPawel Jakub Dawidek 26182d1661a5SPawel Jakub Dawidek /* 26192d1661a5SPawel Jakub Dawidek * Let's check if device already exists. 26202d1661a5SPawel Jakub Dawidek */ 26212d1661a5SPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 26222d1661a5SPawel Jakub Dawidek sc = gp->softc; 26232d1661a5SPawel Jakub Dawidek if (sc == NULL) 26242d1661a5SPawel Jakub Dawidek continue; 26252d1661a5SPawel Jakub Dawidek if (sc->sc_sync.ds_geom == gp) 26262d1661a5SPawel Jakub Dawidek continue; 26272d1661a5SPawel Jakub Dawidek if (strcmp(md.md_name, sc->sc_name) != 0) 26282d1661a5SPawel Jakub Dawidek continue; 26292d1661a5SPawel Jakub Dawidek if (md.md_id != sc->sc_id) { 26302d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s already configured.", 26312d1661a5SPawel Jakub Dawidek sc->sc_name); 26322d1661a5SPawel Jakub Dawidek return (NULL); 26332d1661a5SPawel Jakub Dawidek } 26342d1661a5SPawel Jakub Dawidek break; 26352d1661a5SPawel Jakub Dawidek } 26362d1661a5SPawel Jakub Dawidek if (gp == NULL) { 26372d1661a5SPawel Jakub Dawidek gp = g_raid3_create(mp, &md); 26382d1661a5SPawel Jakub Dawidek if (gp == NULL) { 26392d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot create device %s.", 26402d1661a5SPawel Jakub Dawidek md.md_name); 26412d1661a5SPawel Jakub Dawidek return (NULL); 26422d1661a5SPawel Jakub Dawidek } 26432d1661a5SPawel Jakub Dawidek sc = gp->softc; 26442d1661a5SPawel Jakub Dawidek } 26452d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 26462d1661a5SPawel Jakub Dawidek error = g_raid3_add_disk(sc, pp, &md); 26472d1661a5SPawel Jakub Dawidek if (error != 0) { 26482d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot add disk %s to %s (error=%d).", 26492d1661a5SPawel Jakub Dawidek pp->name, gp->name, error); 26502d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NODISK) == 26512d1661a5SPawel Jakub Dawidek sc->sc_ndisks) { 26522d1661a5SPawel Jakub Dawidek g_raid3_destroy(sc, 1); 26532d1661a5SPawel Jakub Dawidek } 26542d1661a5SPawel Jakub Dawidek return (NULL); 26552d1661a5SPawel Jakub Dawidek } 26562d1661a5SPawel Jakub Dawidek return (gp); 26572d1661a5SPawel Jakub Dawidek } 26582d1661a5SPawel Jakub Dawidek 26592d1661a5SPawel Jakub Dawidek static int 26602d1661a5SPawel Jakub Dawidek g_raid3_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused, 26612d1661a5SPawel Jakub Dawidek struct g_geom *gp) 26622d1661a5SPawel Jakub Dawidek { 26632d1661a5SPawel Jakub Dawidek 26642d1661a5SPawel Jakub Dawidek return (g_raid3_destroy(gp->softc, 0)); 26652d1661a5SPawel Jakub Dawidek } 26662d1661a5SPawel Jakub Dawidek 26672d1661a5SPawel Jakub Dawidek static void 26682d1661a5SPawel Jakub Dawidek g_raid3_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 26692d1661a5SPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 26702d1661a5SPawel Jakub Dawidek { 26712d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 26722d1661a5SPawel Jakub Dawidek 26732d1661a5SPawel Jakub Dawidek g_topology_assert(); 26742d1661a5SPawel Jakub Dawidek 26752d1661a5SPawel Jakub Dawidek sc = gp->softc; 26762d1661a5SPawel Jakub Dawidek if (sc == NULL) 26772d1661a5SPawel Jakub Dawidek return; 26782d1661a5SPawel Jakub Dawidek /* Skip synchronization geom. */ 26792d1661a5SPawel Jakub Dawidek if (gp == sc->sc_sync.ds_geom) 26802d1661a5SPawel Jakub Dawidek return; 26812d1661a5SPawel Jakub Dawidek if (pp != NULL) { 26822d1661a5SPawel Jakub Dawidek /* Nothing here. */ 26832d1661a5SPawel Jakub Dawidek } else if (cp != NULL) { 26842d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 26852d1661a5SPawel Jakub Dawidek 26862d1661a5SPawel Jakub Dawidek disk = cp->private; 26872d1661a5SPawel Jakub Dawidek if (disk == NULL) 26882d1661a5SPawel Jakub Dawidek return; 26892d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Type>", indent); 26902d1661a5SPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) 26912d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "PARITY"); 26922d1661a5SPawel Jakub Dawidek else 26932d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "DATA"); 26942d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Type>\n"); 26952d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Number>%u</Number>\n", indent, 26962d1661a5SPawel Jakub Dawidek (u_int)disk->d_no); 26972d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 26982d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Synchronized>", indent); 26992d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_offset_done == 0) 27002d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "0%%"); 27012d1661a5SPawel Jakub Dawidek else { 27022d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%u%%", 27032d1661a5SPawel Jakub Dawidek (u_int)((disk->d_sync.ds_offset_done * 100) / 27042d1661a5SPawel Jakub Dawidek (sc->sc_provider->mediasize / 27052d1661a5SPawel Jakub Dawidek (sc->sc_ndisks - 1)))); 27062d1661a5SPawel Jakub Dawidek } 27072d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Synchronized>\n"); 27082d1661a5SPawel Jakub Dawidek } 27092d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, 27102d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid); 27112d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Flags>", indent); 27122d1661a5SPawel Jakub Dawidek if (disk->d_flags == 0) 27132d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "NONE"); 27142d1661a5SPawel Jakub Dawidek else { 27152d1661a5SPawel Jakub Dawidek int first = 1; 27162d1661a5SPawel Jakub Dawidek 27172d1661a5SPawel Jakub Dawidek #define ADD_FLAG(flag, name) do { \ 27182d1661a5SPawel Jakub Dawidek if ((disk->d_flags & (flag)) != 0) { \ 27192d1661a5SPawel Jakub Dawidek if (!first) \ 27202d1661a5SPawel Jakub Dawidek sbuf_printf(sb, ", "); \ 27212d1661a5SPawel Jakub Dawidek else \ 27222d1661a5SPawel Jakub Dawidek first = 0; \ 27232d1661a5SPawel Jakub Dawidek sbuf_printf(sb, name); \ 27242d1661a5SPawel Jakub Dawidek } \ 27252d1661a5SPawel Jakub Dawidek } while (0) 27262d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_DIRTY, "DIRTY"); 27272d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_HARDCODED, "HARDCODED"); 27282d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_SYNCHRONIZING, 27292d1661a5SPawel Jakub Dawidek "SYNCHRONIZING"); 27302d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_FORCE_SYNC, "FORCE_SYNC"); 27312d1661a5SPawel Jakub Dawidek #undef ADD_FLAG 27322d1661a5SPawel Jakub Dawidek } 27332d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Flags>\n"); 27342d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<State>%s</State>\n", indent, 27352d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state)); 27362d1661a5SPawel Jakub Dawidek } else { 27372d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id); 27382d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, sc->sc_syncid); 27392d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Flags>", indent); 27402d1661a5SPawel Jakub Dawidek if (sc->sc_flags == 0) 27412d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "NONE"); 27422d1661a5SPawel Jakub Dawidek else { 27432d1661a5SPawel Jakub Dawidek int first = 1; 27442d1661a5SPawel Jakub Dawidek 27452d1661a5SPawel Jakub Dawidek #define ADD_FLAG(flag, name) do { \ 27462d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & (flag)) != 0) { \ 27472d1661a5SPawel Jakub Dawidek if (!first) \ 27482d1661a5SPawel Jakub Dawidek sbuf_printf(sb, ", "); \ 27492d1661a5SPawel Jakub Dawidek else \ 27502d1661a5SPawel Jakub Dawidek first = 0; \ 27512d1661a5SPawel Jakub Dawidek sbuf_printf(sb, name); \ 27522d1661a5SPawel Jakub Dawidek } \ 27532d1661a5SPawel Jakub Dawidek } while (0) 27542d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DEVICE_FLAG_NOAUTOSYNC, "NOAUTOSYNC"); 27552d1661a5SPawel Jakub Dawidek #undef ADD_FLAG 27562d1661a5SPawel Jakub Dawidek } 27572d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Flags>\n"); 27582d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Components>%u</Components>\n", indent, 27592d1661a5SPawel Jakub Dawidek sc->sc_ndisks); 27602d1661a5SPawel Jakub Dawidek } 27612d1661a5SPawel Jakub Dawidek } 27622d1661a5SPawel Jakub Dawidek 27632d1661a5SPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_raid3_class, g_raid3); 2764