12d1661a5SPawel Jakub Dawidek /*- 20218292cSPawel Jakub Dawidek * Copyright (c) 2004-2005 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> 409da3072cSPawel Jakub Dawidek #include <sys/eventhandler.h> 412d1661a5SPawel Jakub Dawidek #include <vm/uma.h> 422d1661a5SPawel Jakub Dawidek #include <geom/geom.h> 432d1661a5SPawel Jakub Dawidek #include <sys/proc.h> 442d1661a5SPawel Jakub Dawidek #include <sys/kthread.h> 4563710c4dSJohn Baldwin #include <sys/sched.h> 462d1661a5SPawel Jakub Dawidek #include <geom/raid3/g_raid3.h> 472d1661a5SPawel Jakub Dawidek 482d1661a5SPawel Jakub Dawidek 495bb84bc8SRobert Watson 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"); 53809a9dc6SPawel Jakub Dawidek u_int g_raid3_debug = 0; 546d7b8aecSPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.debug", &g_raid3_debug); 552d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, debug, CTLFLAG_RW, &g_raid3_debug, 0, 562d1661a5SPawel Jakub Dawidek "Debug level"); 57e5e7825cSPawel Jakub Dawidek static u_int g_raid3_timeout = 4; 584d006a98SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.timeout", &g_raid3_timeout); 592d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, timeout, CTLFLAG_RW, &g_raid3_timeout, 602d1661a5SPawel Jakub Dawidek 0, "Time to wait on all raid3 components"); 614d006a98SPawel Jakub Dawidek static u_int g_raid3_idletime = 5; 624d006a98SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.idletime", &g_raid3_idletime); 634d006a98SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, idletime, CTLFLAG_RW, 644d006a98SPawel Jakub Dawidek &g_raid3_idletime, 0, "Mark components as clean when idling"); 652d1661a5SPawel Jakub Dawidek static u_int g_raid3_reqs_per_sync = 5; 662d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, reqs_per_sync, CTLFLAG_RW, 672d1661a5SPawel Jakub Dawidek &g_raid3_reqs_per_sync, 0, 682d1661a5SPawel Jakub Dawidek "Number of regular I/O requests per synchronization request"); 6943756685SPawel Jakub Dawidek static u_int g_raid3_syncs_per_sec = 1000; 702d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, syncs_per_sec, CTLFLAG_RW, 712d1661a5SPawel Jakub Dawidek &g_raid3_syncs_per_sec, 0, 722d1661a5SPawel Jakub Dawidek "Number of synchronizations requests per second"); 733aae74ecSPawel Jakub Dawidek static u_int g_raid3_disconnect_on_failure = 1; 7467cae8aaSPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.disconnect_on_failure", 7567cae8aaSPawel Jakub Dawidek &g_raid3_disconnect_on_failure); 763aae74ecSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, disconnect_on_failure, CTLFLAG_RW, 773aae74ecSPawel Jakub Dawidek &g_raid3_disconnect_on_failure, 0, "Disconnect component on I/O failure."); 782d1661a5SPawel Jakub Dawidek 792d1661a5SPawel Jakub Dawidek static u_int g_raid3_n64k = 50; 802d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n64k", &g_raid3_n64k); 812d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n64k, CTLFLAG_RD, &g_raid3_n64k, 0, 822d1661a5SPawel Jakub Dawidek "Maximum number of 64kB allocations"); 832d1661a5SPawel Jakub Dawidek static u_int g_raid3_n16k = 200; 842d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n16k", &g_raid3_n16k); 852d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n16k, CTLFLAG_RD, &g_raid3_n16k, 0, 862d1661a5SPawel Jakub Dawidek "Maximum number of 16kB allocations"); 872d1661a5SPawel Jakub Dawidek static u_int g_raid3_n4k = 1200; 882d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n4k", &g_raid3_n4k); 892d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n4k, CTLFLAG_RD, &g_raid3_n4k, 0, 902d1661a5SPawel Jakub Dawidek "Maximum number of 4kB allocations"); 912d1661a5SPawel Jakub Dawidek 922d1661a5SPawel Jakub Dawidek SYSCTL_NODE(_kern_geom_raid3, OID_AUTO, stat, CTLFLAG_RW, 0, 932d1661a5SPawel Jakub Dawidek "GEOM_RAID3 statistics"); 94dba915cfSPawel Jakub Dawidek static u_int g_raid3_parity_mismatch = 0; 95dba915cfSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, parity_mismatch, CTLFLAG_RD, 96dba915cfSPawel Jakub Dawidek &g_raid3_parity_mismatch, 0, "Number of failures in VERIFY mode"); 972d1661a5SPawel Jakub Dawidek static u_int g_raid3_64k_requested = 0; 982d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 64k_requested, CTLFLAG_RD, 992d1661a5SPawel Jakub Dawidek &g_raid3_64k_requested, 0, "Number of requested 64kB allocations"); 1002d1661a5SPawel Jakub Dawidek static u_int g_raid3_64k_failed = 0; 1012d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 64k_failed, CTLFLAG_RD, 1022d1661a5SPawel Jakub Dawidek &g_raid3_64k_failed, 0, "Number of failed 64kB allocations"); 1032d1661a5SPawel Jakub Dawidek static u_int g_raid3_16k_requested = 0; 1042d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 16k_requested, CTLFLAG_RD, 1052d1661a5SPawel Jakub Dawidek &g_raid3_16k_requested, 0, "Number of requested 16kB allocations"); 1062d1661a5SPawel Jakub Dawidek static u_int g_raid3_16k_failed = 0; 1072d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 16k_failed, CTLFLAG_RD, 1082d1661a5SPawel Jakub Dawidek &g_raid3_16k_failed, 0, "Number of failed 16kB allocations"); 1092d1661a5SPawel Jakub Dawidek static u_int g_raid3_4k_requested = 0; 1102d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 4k_requested, CTLFLAG_RD, 1112d1661a5SPawel Jakub Dawidek &g_raid3_4k_requested, 0, "Number of requested 4kB allocations"); 1122d1661a5SPawel Jakub Dawidek static u_int g_raid3_4k_failed = 0; 1132d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 4k_failed, CTLFLAG_RD, 1142d1661a5SPawel Jakub Dawidek &g_raid3_4k_failed, 0, "Number of failed 4kB allocations"); 1152d1661a5SPawel Jakub Dawidek 1162d1661a5SPawel Jakub Dawidek #define MSLEEP(ident, mtx, priority, wmesg, timeout) do { \ 1172d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, (ident)); \ 1182d1661a5SPawel Jakub Dawidek msleep((ident), (mtx), (priority), (wmesg), (timeout)); \ 1192d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Woken up %p.", __func__, (ident)); \ 1202d1661a5SPawel Jakub Dawidek } while (0) 1212d1661a5SPawel Jakub Dawidek 1229da3072cSPawel Jakub Dawidek static eventhandler_tag g_raid3_ehtag = NULL; 1232d1661a5SPawel Jakub Dawidek 1242d1661a5SPawel Jakub Dawidek static int g_raid3_destroy_geom(struct gctl_req *req, struct g_class *mp, 1252d1661a5SPawel Jakub Dawidek struct g_geom *gp); 1262d1661a5SPawel Jakub Dawidek static g_taste_t g_raid3_taste; 1279da3072cSPawel Jakub Dawidek static void g_raid3_init(struct g_class *mp); 1289da3072cSPawel Jakub Dawidek static void g_raid3_fini(struct g_class *mp); 1292d1661a5SPawel Jakub Dawidek 1302d1661a5SPawel Jakub Dawidek struct g_class g_raid3_class = { 1312d1661a5SPawel Jakub Dawidek .name = G_RAID3_CLASS_NAME, 1322d1661a5SPawel Jakub Dawidek .version = G_VERSION, 1332d1661a5SPawel Jakub Dawidek .ctlreq = g_raid3_config, 1342d1661a5SPawel Jakub Dawidek .taste = g_raid3_taste, 1359da3072cSPawel Jakub Dawidek .destroy_geom = g_raid3_destroy_geom, 1369da3072cSPawel Jakub Dawidek .init = g_raid3_init, 1379da3072cSPawel Jakub Dawidek .fini = g_raid3_fini 1382d1661a5SPawel Jakub Dawidek }; 1392d1661a5SPawel Jakub Dawidek 1402d1661a5SPawel Jakub Dawidek 1412d1661a5SPawel Jakub Dawidek static void g_raid3_destroy_provider(struct g_raid3_softc *sc); 142d97d5ee9SPawel Jakub Dawidek static int g_raid3_update_disk(struct g_raid3_disk *disk, u_int state); 143d97d5ee9SPawel Jakub Dawidek static void g_raid3_update_device(struct g_raid3_softc *sc, boolean_t force); 1442d1661a5SPawel Jakub Dawidek static void g_raid3_dumpconf(struct sbuf *sb, const char *indent, 1452d1661a5SPawel Jakub Dawidek struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp); 1462d1661a5SPawel Jakub Dawidek static void g_raid3_sync_stop(struct g_raid3_softc *sc, int type); 1472d1661a5SPawel Jakub Dawidek 1482d1661a5SPawel Jakub Dawidek 1492d1661a5SPawel Jakub Dawidek static const char * 1502d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(int state) 1512d1661a5SPawel Jakub Dawidek { 1522d1661a5SPawel Jakub Dawidek 1532d1661a5SPawel Jakub Dawidek switch (state) { 1542d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NODISK: 1552d1661a5SPawel Jakub Dawidek return ("NODISK"); 1562d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NONE: 1572d1661a5SPawel Jakub Dawidek return ("NONE"); 1582d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 1592d1661a5SPawel Jakub Dawidek return ("NEW"); 1602d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 1612d1661a5SPawel Jakub Dawidek return ("ACTIVE"); 1622d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 1632d1661a5SPawel Jakub Dawidek return ("STALE"); 1642d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 1652d1661a5SPawel Jakub Dawidek return ("SYNCHRONIZING"); 1662d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_DISCONNECTED: 1672d1661a5SPawel Jakub Dawidek return ("DISCONNECTED"); 1682d1661a5SPawel Jakub Dawidek default: 1692d1661a5SPawel Jakub Dawidek return ("INVALID"); 1702d1661a5SPawel Jakub Dawidek } 1712d1661a5SPawel Jakub Dawidek } 1722d1661a5SPawel Jakub Dawidek 1732d1661a5SPawel Jakub Dawidek static const char * 1742d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(int state) 1752d1661a5SPawel Jakub Dawidek { 1762d1661a5SPawel Jakub Dawidek 1772d1661a5SPawel Jakub Dawidek switch (state) { 1782d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_STARTING: 1792d1661a5SPawel Jakub Dawidek return ("STARTING"); 1802d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_DEGRADED: 1812d1661a5SPawel Jakub Dawidek return ("DEGRADED"); 1822d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_COMPLETE: 1832d1661a5SPawel Jakub Dawidek return ("COMPLETE"); 1842d1661a5SPawel Jakub Dawidek default: 1852d1661a5SPawel Jakub Dawidek return ("INVALID"); 1862d1661a5SPawel Jakub Dawidek } 1872d1661a5SPawel Jakub Dawidek } 1882d1661a5SPawel Jakub Dawidek 1892d1661a5SPawel Jakub Dawidek const char * 1902d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(struct g_raid3_disk *disk) 1912d1661a5SPawel Jakub Dawidek { 1922d1661a5SPawel Jakub Dawidek 1932d1661a5SPawel Jakub Dawidek if (disk->d_consumer == NULL || disk->d_consumer->provider == NULL) 1942d1661a5SPawel Jakub Dawidek return ("[unknown]"); 1952d1661a5SPawel Jakub Dawidek return (disk->d_name); 1962d1661a5SPawel Jakub Dawidek } 1972d1661a5SPawel Jakub Dawidek 1982d1661a5SPawel Jakub Dawidek #define g_raid3_xor(src1, src2, dst, size) \ 1992d1661a5SPawel Jakub Dawidek _g_raid3_xor((uint64_t *)(src1), (uint64_t *)(src2), \ 2002d1661a5SPawel Jakub Dawidek (uint64_t *)(dst), (size_t)size) 2012d1661a5SPawel Jakub Dawidek static void 2022d1661a5SPawel Jakub Dawidek _g_raid3_xor(uint64_t *src1, uint64_t *src2, uint64_t *dst, size_t size) 2032d1661a5SPawel Jakub Dawidek { 2042d1661a5SPawel Jakub Dawidek 2052d1661a5SPawel Jakub Dawidek KASSERT((size % 128) == 0, ("Invalid size: %zu.", size)); 2062d1661a5SPawel Jakub Dawidek for (; size > 0; size -= 128) { 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 *dst++ = (*src1++) ^ (*src2++); 2152d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2162d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2172d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2182d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2192d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2202d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2212d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2222d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2232d1661a5SPawel Jakub Dawidek } 2242d1661a5SPawel Jakub Dawidek } 2252d1661a5SPawel Jakub Dawidek 226dba915cfSPawel Jakub Dawidek static int 227dba915cfSPawel Jakub Dawidek g_raid3_is_zero(struct bio *bp) 228dba915cfSPawel Jakub Dawidek { 229dba915cfSPawel Jakub Dawidek static const uint64_t zeros[] = { 230dba915cfSPawel Jakub Dawidek 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 231dba915cfSPawel Jakub Dawidek }; 232dba915cfSPawel Jakub Dawidek u_char *addr; 233dba915cfSPawel Jakub Dawidek ssize_t size; 234dba915cfSPawel Jakub Dawidek 235dba915cfSPawel Jakub Dawidek size = bp->bio_length; 236dba915cfSPawel Jakub Dawidek addr = (u_char *)bp->bio_data; 237dba915cfSPawel Jakub Dawidek for (; size > 0; size -= sizeof(zeros), addr += sizeof(zeros)) { 238dba915cfSPawel Jakub Dawidek if (bcmp(addr, zeros, sizeof(zeros)) != 0) 239dba915cfSPawel Jakub Dawidek return (0); 240dba915cfSPawel Jakub Dawidek } 241dba915cfSPawel Jakub Dawidek return (1); 242dba915cfSPawel Jakub Dawidek } 243dba915cfSPawel Jakub Dawidek 2442d1661a5SPawel Jakub Dawidek /* 2452d1661a5SPawel Jakub Dawidek * --- Events handling functions --- 2462d1661a5SPawel Jakub Dawidek * Events in geom_raid3 are used to maintain disks and device status 2472d1661a5SPawel Jakub Dawidek * from one thread to simplify locking. 2482d1661a5SPawel Jakub Dawidek */ 2492d1661a5SPawel Jakub Dawidek static void 2502d1661a5SPawel Jakub Dawidek g_raid3_event_free(struct g_raid3_event *ep) 2512d1661a5SPawel Jakub Dawidek { 2522d1661a5SPawel Jakub Dawidek 2532d1661a5SPawel Jakub Dawidek free(ep, M_RAID3); 2542d1661a5SPawel Jakub Dawidek } 2552d1661a5SPawel Jakub Dawidek 2562d1661a5SPawel Jakub Dawidek int 2572d1661a5SPawel Jakub Dawidek g_raid3_event_send(void *arg, int state, int flags) 2582d1661a5SPawel Jakub Dawidek { 2592d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2602d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 2612d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 2622d1661a5SPawel Jakub Dawidek int error; 2632d1661a5SPawel Jakub Dawidek 2642d1661a5SPawel Jakub Dawidek ep = malloc(sizeof(*ep), M_RAID3, M_WAITOK); 2652d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sending event %p.", __func__, ep); 2662d1661a5SPawel Jakub Dawidek if ((flags & G_RAID3_EVENT_DEVICE) != 0) { 2672d1661a5SPawel Jakub Dawidek disk = NULL; 2682d1661a5SPawel Jakub Dawidek sc = arg; 2692d1661a5SPawel Jakub Dawidek } else { 2702d1661a5SPawel Jakub Dawidek disk = arg; 2712d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 2722d1661a5SPawel Jakub Dawidek } 2732d1661a5SPawel Jakub Dawidek ep->e_disk = disk; 2742d1661a5SPawel Jakub Dawidek ep->e_state = state; 2752d1661a5SPawel Jakub Dawidek ep->e_flags = flags; 2762d1661a5SPawel Jakub Dawidek ep->e_error = 0; 2772d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2782d1661a5SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_events, ep, e_next); 2792d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 2802d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 2812d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 2822d1661a5SPawel Jakub Dawidek wakeup(sc); 2832d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 2842d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 2852d1661a5SPawel Jakub Dawidek if ((flags & G_RAID3_EVENT_DONTWAIT) != 0) 2862d1661a5SPawel Jakub Dawidek return (0); 2872d1661a5SPawel Jakub Dawidek g_topology_assert(); 2882d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, ep); 2892d1661a5SPawel Jakub Dawidek g_topology_unlock(); 2902d1661a5SPawel Jakub Dawidek while ((ep->e_flags & G_RAID3_EVENT_DONE) == 0) { 2912d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2922d1661a5SPawel Jakub Dawidek MSLEEP(ep, &sc->sc_events_mtx, PRIBIO | PDROP, "r3:event", 2932d1661a5SPawel Jakub Dawidek hz * 5); 2942d1661a5SPawel Jakub Dawidek } 2952d1661a5SPawel Jakub Dawidek /* Don't even try to use 'sc' here, because it could be already dead. */ 2962d1661a5SPawel Jakub Dawidek g_topology_lock(); 2972d1661a5SPawel Jakub Dawidek error = ep->e_error; 2982d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 2992d1661a5SPawel Jakub Dawidek return (error); 3002d1661a5SPawel Jakub Dawidek } 3012d1661a5SPawel Jakub Dawidek 3022d1661a5SPawel Jakub Dawidek static struct g_raid3_event * 3032d1661a5SPawel Jakub Dawidek g_raid3_event_get(struct g_raid3_softc *sc) 3042d1661a5SPawel Jakub Dawidek { 3052d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 3062d1661a5SPawel Jakub Dawidek 3072d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 3082d1661a5SPawel Jakub Dawidek ep = TAILQ_FIRST(&sc->sc_events); 3092d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 3102d1661a5SPawel Jakub Dawidek return (ep); 3112d1661a5SPawel Jakub Dawidek } 3122d1661a5SPawel Jakub Dawidek 3132d1661a5SPawel Jakub Dawidek static void 314d97d5ee9SPawel Jakub Dawidek g_raid3_event_remove(struct g_raid3_softc *sc, struct g_raid3_event *ep) 315d97d5ee9SPawel Jakub Dawidek { 316d97d5ee9SPawel Jakub Dawidek 317d97d5ee9SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 318d97d5ee9SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_events, ep, e_next); 319d97d5ee9SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 320d97d5ee9SPawel Jakub Dawidek } 321d97d5ee9SPawel Jakub Dawidek 322d97d5ee9SPawel Jakub Dawidek static void 3232d1661a5SPawel Jakub Dawidek g_raid3_event_cancel(struct g_raid3_disk *disk) 3242d1661a5SPawel Jakub Dawidek { 3252d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 3262d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep, *tmpep; 3272d1661a5SPawel Jakub Dawidek 3282d1661a5SPawel Jakub Dawidek g_topology_assert(); 3292d1661a5SPawel Jakub Dawidek 3302d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 3312d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 3322d1661a5SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(ep, &sc->sc_events, e_next, tmpep) { 3332d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DEVICE) != 0) 3342d1661a5SPawel Jakub Dawidek continue; 3352d1661a5SPawel Jakub Dawidek if (ep->e_disk != disk) 3362d1661a5SPawel Jakub Dawidek continue; 3372d1661a5SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_events, ep, e_next); 3382d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) 3392d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 3402d1661a5SPawel Jakub Dawidek else { 3412d1661a5SPawel Jakub Dawidek ep->e_error = ECANCELED; 3422d1661a5SPawel Jakub Dawidek wakeup(ep); 3432d1661a5SPawel Jakub Dawidek } 3442d1661a5SPawel Jakub Dawidek } 3452d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 3462d1661a5SPawel Jakub Dawidek } 3472d1661a5SPawel Jakub Dawidek 3482d1661a5SPawel Jakub Dawidek /* 3492d1661a5SPawel Jakub Dawidek * Return the number of disks in the given state. 3502d1661a5SPawel Jakub Dawidek * If state is equal to -1, count all connected disks. 3512d1661a5SPawel Jakub Dawidek */ 3522d1661a5SPawel Jakub Dawidek u_int 3532d1661a5SPawel Jakub Dawidek g_raid3_ndisks(struct g_raid3_softc *sc, int state) 3542d1661a5SPawel Jakub Dawidek { 3552d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 356fa6a7837SDavid E. O'Brien u_int n, ndisks; 3572d1661a5SPawel Jakub Dawidek 358fa6a7837SDavid E. O'Brien for (n = ndisks = 0; n < sc->sc_ndisks; n++) { 3592d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 3602d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 3612d1661a5SPawel Jakub Dawidek continue; 3622d1661a5SPawel Jakub Dawidek if (state == -1 || disk->d_state == state) 3632d1661a5SPawel Jakub Dawidek ndisks++; 3642d1661a5SPawel Jakub Dawidek } 3652d1661a5SPawel Jakub Dawidek return (ndisks); 3662d1661a5SPawel Jakub Dawidek } 3672d1661a5SPawel Jakub Dawidek 3682d1661a5SPawel Jakub Dawidek static u_int 3692d1661a5SPawel Jakub Dawidek g_raid3_nrequests(struct g_raid3_softc *sc, struct g_consumer *cp) 3702d1661a5SPawel Jakub Dawidek { 3712d1661a5SPawel Jakub Dawidek struct bio *bp; 3722d1661a5SPawel Jakub Dawidek u_int nreqs = 0; 3732d1661a5SPawel Jakub Dawidek 3742d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 3752d1661a5SPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_queue.queue, bio_queue) { 3762d1661a5SPawel Jakub Dawidek if (bp->bio_from == cp) 3772d1661a5SPawel Jakub Dawidek nreqs++; 3782d1661a5SPawel Jakub Dawidek } 3792d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 3802d1661a5SPawel Jakub Dawidek return (nreqs); 3812d1661a5SPawel Jakub Dawidek } 3822d1661a5SPawel Jakub Dawidek 3832d1661a5SPawel Jakub Dawidek static int 3842d1661a5SPawel Jakub Dawidek g_raid3_is_busy(struct g_raid3_softc *sc, struct g_consumer *cp) 3852d1661a5SPawel Jakub Dawidek { 3862d1661a5SPawel Jakub Dawidek 38779e61493SPawel Jakub Dawidek if (cp->index > 0) { 3882d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, 3892d1661a5SPawel Jakub Dawidek "I/O requests for %s exist, can't destroy it now.", 3902d1661a5SPawel Jakub Dawidek cp->provider->name); 3912d1661a5SPawel Jakub Dawidek return (1); 3922d1661a5SPawel Jakub Dawidek } 3932d1661a5SPawel Jakub Dawidek if (g_raid3_nrequests(sc, cp) > 0) { 3942d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, 3952d1661a5SPawel Jakub Dawidek "I/O requests for %s in queue, can't destroy it now.", 3962d1661a5SPawel Jakub Dawidek cp->provider->name); 3972d1661a5SPawel Jakub Dawidek return (1); 3982d1661a5SPawel Jakub Dawidek } 3992d1661a5SPawel Jakub Dawidek return (0); 4002d1661a5SPawel Jakub Dawidek } 4012d1661a5SPawel Jakub Dawidek 4022d1661a5SPawel Jakub Dawidek static void 403d97d5ee9SPawel Jakub Dawidek g_raid3_destroy_consumer(void *arg, int flags __unused) 404d97d5ee9SPawel Jakub Dawidek { 405d97d5ee9SPawel Jakub Dawidek struct g_consumer *cp; 406d97d5ee9SPawel Jakub Dawidek 407d97d5ee9SPawel Jakub Dawidek cp = arg; 408d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Consumer %s destroyed.", cp->provider->name); 409d97d5ee9SPawel Jakub Dawidek g_detach(cp); 410d97d5ee9SPawel Jakub Dawidek g_destroy_consumer(cp); 411d97d5ee9SPawel Jakub Dawidek } 412d97d5ee9SPawel Jakub Dawidek 413d97d5ee9SPawel Jakub Dawidek static void 4142d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(struct g_raid3_softc *sc, struct g_consumer *cp) 4152d1661a5SPawel Jakub Dawidek { 416d97d5ee9SPawel Jakub Dawidek struct g_provider *pp; 417d97d5ee9SPawel Jakub Dawidek int retaste_wait; 4182d1661a5SPawel Jakub Dawidek 4192d1661a5SPawel Jakub Dawidek g_topology_assert(); 4202d1661a5SPawel Jakub Dawidek 4212d1661a5SPawel Jakub Dawidek cp->private = NULL; 4222d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 4232d1661a5SPawel Jakub Dawidek return; 4242d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Consumer %s destroyed.", cp->provider->name); 425d97d5ee9SPawel Jakub Dawidek pp = cp->provider; 426d97d5ee9SPawel Jakub Dawidek retaste_wait = 0; 427d97d5ee9SPawel Jakub Dawidek if (cp->acw == 1) { 428d97d5ee9SPawel Jakub Dawidek if ((pp->geom->flags & G_GEOM_WITHER) == 0) 429d97d5ee9SPawel Jakub Dawidek retaste_wait = 1; 430d97d5ee9SPawel Jakub Dawidek } 431d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", pp->name, -cp->acr, 432d97d5ee9SPawel Jakub Dawidek -cp->acw, -cp->ace, 0); 433d97d5ee9SPawel Jakub Dawidek if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 434d97d5ee9SPawel Jakub Dawidek g_access(cp, -cp->acr, -cp->acw, -cp->ace); 435d97d5ee9SPawel Jakub Dawidek if (retaste_wait) { 436d97d5ee9SPawel Jakub Dawidek /* 437d97d5ee9SPawel Jakub Dawidek * After retaste event was send (inside g_access()), we can send 438d97d5ee9SPawel Jakub Dawidek * event to detach and destroy consumer. 439d97d5ee9SPawel Jakub Dawidek * A class, which has consumer to the given provider connected 440d97d5ee9SPawel Jakub Dawidek * will not receive retaste event for the provider. 441d97d5ee9SPawel Jakub Dawidek * This is the way how I ignore retaste events when I close 442d97d5ee9SPawel Jakub Dawidek * consumers opened for write: I detach and destroy consumer 443d97d5ee9SPawel Jakub Dawidek * after retaste event is sent. 444d97d5ee9SPawel Jakub Dawidek */ 445d97d5ee9SPawel Jakub Dawidek g_post_event(g_raid3_destroy_consumer, cp, M_WAITOK, NULL); 446d97d5ee9SPawel Jakub Dawidek return; 447d97d5ee9SPawel Jakub Dawidek } 448d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Consumer %s destroyed.", pp->name); 4492d1661a5SPawel Jakub Dawidek g_detach(cp); 4502d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 4512d1661a5SPawel Jakub Dawidek } 4522d1661a5SPawel Jakub Dawidek 4532d1661a5SPawel Jakub Dawidek static int 4542d1661a5SPawel Jakub Dawidek g_raid3_connect_disk(struct g_raid3_disk *disk, struct g_provider *pp) 4552d1661a5SPawel Jakub Dawidek { 45634cb1517SPawel Jakub Dawidek struct g_consumer *cp; 4572d1661a5SPawel Jakub Dawidek int error; 4582d1661a5SPawel Jakub Dawidek 4592d1661a5SPawel Jakub Dawidek g_topology_assert(); 4602d1661a5SPawel Jakub Dawidek KASSERT(disk->d_consumer == NULL, 4612d1661a5SPawel Jakub Dawidek ("Disk already connected (device %s).", disk->d_softc->sc_name)); 4622d1661a5SPawel Jakub Dawidek 46334cb1517SPawel Jakub Dawidek cp = g_new_consumer(disk->d_softc->sc_geom); 46434cb1517SPawel Jakub Dawidek error = g_attach(cp, pp); 465d97d5ee9SPawel Jakub Dawidek if (error != 0) { 46634cb1517SPawel Jakub Dawidek g_destroy_consumer(cp); 46734cb1517SPawel Jakub Dawidek return (error); 46834cb1517SPawel Jakub Dawidek } 46934cb1517SPawel Jakub Dawidek error = g_access(cp, 1, 1, 1); 47034cb1517SPawel Jakub Dawidek if (error != 0) { 47134cb1517SPawel Jakub Dawidek g_detach(cp); 47234cb1517SPawel Jakub Dawidek g_destroy_consumer(cp); 473d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot open consumer %s (error=%d).", 474d97d5ee9SPawel Jakub Dawidek pp->name, error); 475d97d5ee9SPawel Jakub Dawidek return (error); 476d97d5ee9SPawel Jakub Dawidek } 47734cb1517SPawel Jakub Dawidek disk->d_consumer = cp; 47834cb1517SPawel Jakub Dawidek disk->d_consumer->private = disk; 47934cb1517SPawel Jakub Dawidek disk->d_consumer->index = 0; 4802d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Disk %s connected.", g_raid3_get_diskname(disk)); 4812d1661a5SPawel Jakub Dawidek return (0); 4822d1661a5SPawel Jakub Dawidek } 4832d1661a5SPawel Jakub Dawidek 4842d1661a5SPawel Jakub Dawidek static void 4852d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(struct g_raid3_softc *sc, struct g_consumer *cp) 4862d1661a5SPawel Jakub Dawidek { 4872d1661a5SPawel Jakub Dawidek 4882d1661a5SPawel Jakub Dawidek g_topology_assert(); 4892d1661a5SPawel Jakub Dawidek 4902d1661a5SPawel Jakub Dawidek if (cp == NULL) 4912d1661a5SPawel Jakub Dawidek return; 492d97d5ee9SPawel Jakub Dawidek if (cp->provider != NULL) 4932d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, cp); 494d97d5ee9SPawel Jakub Dawidek else 4952d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 4962d1661a5SPawel Jakub Dawidek } 4972d1661a5SPawel Jakub Dawidek 4982d1661a5SPawel Jakub Dawidek /* 4992d1661a5SPawel Jakub Dawidek * Initialize disk. This means allocate memory, create consumer, attach it 5002d1661a5SPawel Jakub Dawidek * to the provider and open access (r1w1e1) to it. 5012d1661a5SPawel Jakub Dawidek */ 5022d1661a5SPawel Jakub Dawidek static struct g_raid3_disk * 5032d1661a5SPawel Jakub Dawidek g_raid3_init_disk(struct g_raid3_softc *sc, struct g_provider *pp, 5042d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md, int *errorp) 5052d1661a5SPawel Jakub Dawidek { 5062d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 5072d1661a5SPawel Jakub Dawidek int error; 5082d1661a5SPawel Jakub Dawidek 5092d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[md->md_no]; 5102d1661a5SPawel Jakub Dawidek error = g_raid3_connect_disk(disk, pp); 51134cb1517SPawel Jakub Dawidek if (error != 0) { 51234cb1517SPawel Jakub Dawidek if (errorp != NULL) 51334cb1517SPawel Jakub Dawidek *errorp = error; 51434cb1517SPawel Jakub Dawidek return (NULL); 51534cb1517SPawel Jakub Dawidek } 5162d1661a5SPawel Jakub Dawidek disk->d_state = G_RAID3_DISK_STATE_NONE; 5172d1661a5SPawel Jakub Dawidek disk->d_flags = md->md_dflags; 5182d1661a5SPawel Jakub Dawidek if (md->md_provider[0] != '\0') 5192d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_HARDCODED; 5202d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = NULL; 5212d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = md->md_sync_offset; 5222d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = md->md_sync_offset; 523d2fb9c62SPawel Jakub Dawidek disk->d_sync.ds_resync = -1; 524a245a548SPawel Jakub Dawidek disk->d_genid = md->md_genid; 5252d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = md->md_syncid; 5262d1661a5SPawel Jakub Dawidek if (errorp != NULL) 5272d1661a5SPawel Jakub Dawidek *errorp = 0; 5282d1661a5SPawel Jakub Dawidek return (disk); 5292d1661a5SPawel Jakub Dawidek } 5302d1661a5SPawel Jakub Dawidek 5312d1661a5SPawel Jakub Dawidek static void 5322d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(struct g_raid3_disk *disk) 5332d1661a5SPawel Jakub Dawidek { 5342d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 5352d1661a5SPawel Jakub Dawidek 5362d1661a5SPawel Jakub Dawidek g_topology_assert(); 5372d1661a5SPawel Jakub Dawidek 5382d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 5392d1661a5SPawel Jakub Dawidek return; 5402d1661a5SPawel Jakub Dawidek g_raid3_event_cancel(disk); 5412d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 5422d1661a5SPawel Jakub Dawidek switch (disk->d_state) { 5432d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 5442d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL) 5452d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 1); 5462d1661a5SPawel Jakub Dawidek /* FALLTHROUGH */ 5472d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 5482d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 5492d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 5502d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(sc, disk->d_consumer); 5512d1661a5SPawel Jakub Dawidek disk->d_consumer = NULL; 5522d1661a5SPawel Jakub Dawidek break; 5532d1661a5SPawel Jakub Dawidek default: 5542d1661a5SPawel Jakub Dawidek KASSERT(0 == 1, ("Wrong disk state (%s, %s).", 5552d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 5562d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 5572d1661a5SPawel Jakub Dawidek } 5582d1661a5SPawel Jakub Dawidek disk->d_state = G_RAID3_DISK_STATE_NODISK; 5592d1661a5SPawel Jakub Dawidek } 5602d1661a5SPawel Jakub Dawidek 5612d1661a5SPawel Jakub Dawidek static void 5622d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(struct g_raid3_softc *sc) 5632d1661a5SPawel Jakub Dawidek { 5642d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 5659da3072cSPawel Jakub Dawidek struct g_raid3_disk *disk; 5662d1661a5SPawel Jakub Dawidek struct g_geom *gp; 5672d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 5682d1661a5SPawel Jakub Dawidek u_int n; 5692d1661a5SPawel Jakub Dawidek 5702d1661a5SPawel Jakub Dawidek g_topology_assert(); 5712d1661a5SPawel Jakub Dawidek 5722d1661a5SPawel Jakub Dawidek gp = sc->sc_geom; 5732d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) 5742d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(sc); 5759da3072cSPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 5769da3072cSPawel Jakub Dawidek disk = &sc->sc_disks[n]; 577d97d5ee9SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 5789da3072cSPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 5799da3072cSPawel Jakub Dawidek g_raid3_update_metadata(disk); 5809da3072cSPawel Jakub Dawidek g_raid3_destroy_disk(disk); 5819da3072cSPawel Jakub Dawidek } 582d97d5ee9SPawel Jakub Dawidek } 5832d1661a5SPawel Jakub Dawidek while ((ep = g_raid3_event_get(sc)) != NULL) { 584d97d5ee9SPawel Jakub Dawidek g_raid3_event_remove(sc, ep); 5852d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) 5862d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 5872d1661a5SPawel Jakub Dawidek else { 5882d1661a5SPawel Jakub Dawidek ep->e_error = ECANCELED; 5892d1661a5SPawel Jakub Dawidek ep->e_flags |= G_RAID3_EVENT_DONE; 5902d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, ep); 5912d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 5922d1661a5SPawel Jakub Dawidek wakeup(ep); 5932d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 5942d1661a5SPawel Jakub Dawidek } 5952d1661a5SPawel Jakub Dawidek } 5962d1661a5SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 5972d1661a5SPawel Jakub Dawidek gp->softc = NULL; 5982d1661a5SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_sync.ds_geom->consumer); 5992d1661a5SPawel Jakub Dawidek if (cp != NULL) 6002d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(sc, cp); 6012d1661a5SPawel Jakub Dawidek sc->sc_sync.ds_geom->softc = NULL; 6022d1661a5SPawel Jakub Dawidek g_wither_geom(sc->sc_sync.ds_geom, ENXIO); 6032d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_64k); 6042d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_16k); 6052d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_4k); 6062d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 6072d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_events_mtx); 6082d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s destroyed.", gp->name); 6092d1661a5SPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 6102d1661a5SPawel Jakub Dawidek } 6112d1661a5SPawel Jakub Dawidek 6122d1661a5SPawel Jakub Dawidek static void 6132d1661a5SPawel Jakub Dawidek g_raid3_orphan(struct g_consumer *cp) 6142d1661a5SPawel Jakub Dawidek { 6152d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 6162d1661a5SPawel Jakub Dawidek 6172d1661a5SPawel Jakub Dawidek g_topology_assert(); 6182d1661a5SPawel Jakub Dawidek 6192d1661a5SPawel Jakub Dawidek disk = cp->private; 6202d1661a5SPawel Jakub Dawidek if (disk == NULL) 6212d1661a5SPawel Jakub Dawidek return; 622ea973705SPawel Jakub Dawidek disk->d_softc->sc_bump_id = G_RAID3_BUMP_SYNCID; 6232d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 6242d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 6252d1661a5SPawel Jakub Dawidek } 6262d1661a5SPawel Jakub Dawidek 6272d1661a5SPawel Jakub Dawidek static int 6282d1661a5SPawel Jakub Dawidek g_raid3_write_metadata(struct g_raid3_disk *disk, struct g_raid3_metadata *md) 6292d1661a5SPawel Jakub Dawidek { 6302d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 6312d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 6322d1661a5SPawel Jakub Dawidek off_t offset, length; 6332d1661a5SPawel Jakub Dawidek u_char *sector; 634d97d5ee9SPawel Jakub Dawidek int error = 0; 6352d1661a5SPawel Jakub Dawidek 6362d1661a5SPawel Jakub Dawidek g_topology_assert(); 6372d1661a5SPawel Jakub Dawidek 6382d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 6392d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 6402d1661a5SPawel Jakub Dawidek KASSERT(cp != NULL, ("NULL consumer (%s).", sc->sc_name)); 6412d1661a5SPawel Jakub Dawidek KASSERT(cp->provider != NULL, ("NULL provider (%s).", sc->sc_name)); 642d97d5ee9SPawel Jakub Dawidek KASSERT(cp->acr == 1 && cp->acw == 1 && cp->ace == 1, 643d97d5ee9SPawel Jakub Dawidek ("Consumer %s closed? (r%dw%de%d).", cp->provider->name, cp->acr, 644d97d5ee9SPawel Jakub Dawidek cp->acw, cp->ace)); 6452d1661a5SPawel Jakub Dawidek length = cp->provider->sectorsize; 6462d1661a5SPawel Jakub Dawidek offset = cp->provider->mediasize - length; 6472d1661a5SPawel Jakub Dawidek sector = malloc((size_t)length, M_RAID3, M_WAITOK | M_ZERO); 6482d1661a5SPawel Jakub Dawidek if (md != NULL) 6492d1661a5SPawel Jakub Dawidek raid3_metadata_encode(md, sector); 6502d1661a5SPawel Jakub Dawidek g_topology_unlock(); 6512d1661a5SPawel Jakub Dawidek error = g_write_data(cp, offset, sector, length); 6522d1661a5SPawel Jakub Dawidek g_topology_lock(); 6532d1661a5SPawel Jakub Dawidek free(sector, M_RAID3); 6542d1661a5SPawel Jakub Dawidek if (error != 0) { 6553aae74ecSPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_BROKEN) == 0) { 6563aae74ecSPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot write metadata on %s " 6573aae74ecSPawel Jakub Dawidek "(device=%s, error=%d).", 6583aae74ecSPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name, error); 6593aae74ecSPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_BROKEN; 6603aae74ecSPawel Jakub Dawidek } else { 6613aae74ecSPawel Jakub Dawidek G_RAID3_DEBUG(1, "Cannot write metadata on %s " 6623aae74ecSPawel Jakub Dawidek "(device=%s, error=%d).", 6633aae74ecSPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name, error); 6643aae74ecSPawel Jakub Dawidek } 6653aae74ecSPawel Jakub Dawidek if (g_raid3_disconnect_on_failure && 6663aae74ecSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 6673aae74ecSPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 6683aae74ecSPawel Jakub Dawidek g_raid3_event_send(disk, 6693aae74ecSPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 6702d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 6712d1661a5SPawel Jakub Dawidek } 6723aae74ecSPawel Jakub Dawidek } 6732d1661a5SPawel Jakub Dawidek return (error); 6742d1661a5SPawel Jakub Dawidek } 6752d1661a5SPawel Jakub Dawidek 6762d1661a5SPawel Jakub Dawidek int 6772d1661a5SPawel Jakub Dawidek g_raid3_clear_metadata(struct g_raid3_disk *disk) 6782d1661a5SPawel Jakub Dawidek { 6792d1661a5SPawel Jakub Dawidek int error; 6802d1661a5SPawel Jakub Dawidek 6812d1661a5SPawel Jakub Dawidek g_topology_assert(); 6822d1661a5SPawel Jakub Dawidek error = g_raid3_write_metadata(disk, NULL); 6832d1661a5SPawel Jakub Dawidek if (error == 0) { 6842d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Metadata on %s cleared.", 6852d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 6862d1661a5SPawel Jakub Dawidek } else { 6872d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 6882d1661a5SPawel Jakub Dawidek "Cannot clear metadata on disk %s (error=%d).", 6892d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), error); 6902d1661a5SPawel Jakub Dawidek } 6912d1661a5SPawel Jakub Dawidek return (error); 6922d1661a5SPawel Jakub Dawidek } 6932d1661a5SPawel Jakub Dawidek 6942d1661a5SPawel Jakub Dawidek void 6952d1661a5SPawel Jakub Dawidek g_raid3_fill_metadata(struct g_raid3_disk *disk, struct g_raid3_metadata *md) 6962d1661a5SPawel Jakub Dawidek { 6972d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 698e6890985SPawel Jakub Dawidek struct g_provider *pp; 6992d1661a5SPawel Jakub Dawidek 7002d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 7012d1661a5SPawel Jakub Dawidek strlcpy(md->md_magic, G_RAID3_MAGIC, sizeof(md->md_magic)); 7022d1661a5SPawel Jakub Dawidek md->md_version = G_RAID3_VERSION; 7032d1661a5SPawel Jakub Dawidek strlcpy(md->md_name, sc->sc_name, sizeof(md->md_name)); 7042d1661a5SPawel Jakub Dawidek md->md_id = sc->sc_id; 7052d1661a5SPawel Jakub Dawidek md->md_all = sc->sc_ndisks; 706a245a548SPawel Jakub Dawidek md->md_genid = sc->sc_genid; 7072d1661a5SPawel Jakub Dawidek md->md_mediasize = sc->sc_mediasize; 7082d1661a5SPawel Jakub Dawidek md->md_sectorsize = sc->sc_sectorsize; 7092d1661a5SPawel Jakub Dawidek md->md_mflags = (sc->sc_flags & G_RAID3_DEVICE_FLAG_MASK); 7102d1661a5SPawel Jakub Dawidek md->md_no = disk->d_no; 7112d1661a5SPawel Jakub Dawidek md->md_syncid = disk->d_sync.ds_syncid; 7122d1661a5SPawel Jakub Dawidek md->md_dflags = (disk->d_flags & G_RAID3_DISK_FLAG_MASK); 7132d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 7142d1661a5SPawel Jakub Dawidek md->md_sync_offset = disk->d_sync.ds_offset_done; 7152d1661a5SPawel Jakub Dawidek else 7162d1661a5SPawel Jakub Dawidek md->md_sync_offset = 0; 717e6890985SPawel Jakub Dawidek if (disk->d_consumer != NULL && disk->d_consumer->provider != NULL) 718e6890985SPawel Jakub Dawidek pp = disk->d_consumer->provider; 719e6890985SPawel Jakub Dawidek else 720e6890985SPawel Jakub Dawidek pp = NULL; 721e6890985SPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_HARDCODED) != 0 && pp != NULL) 722e6890985SPawel Jakub Dawidek strlcpy(md->md_provider, pp->name, sizeof(md->md_provider)); 723e6890985SPawel Jakub Dawidek else 7242d1661a5SPawel Jakub Dawidek bzero(md->md_provider, sizeof(md->md_provider)); 725e6890985SPawel Jakub Dawidek if (pp != NULL) 726e6890985SPawel Jakub Dawidek md->md_provsize = pp->mediasize; 727e6890985SPawel Jakub Dawidek else 728e6890985SPawel Jakub Dawidek md->md_provsize = 0; 7292d1661a5SPawel Jakub Dawidek } 7302d1661a5SPawel Jakub Dawidek 7312d1661a5SPawel Jakub Dawidek void 7322d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(struct g_raid3_disk *disk) 7332d1661a5SPawel Jakub Dawidek { 7342d1661a5SPawel Jakub Dawidek struct g_raid3_metadata md; 7352d1661a5SPawel Jakub Dawidek int error; 7362d1661a5SPawel Jakub Dawidek 7372d1661a5SPawel Jakub Dawidek g_topology_assert(); 7382d1661a5SPawel Jakub Dawidek g_raid3_fill_metadata(disk, &md); 7392d1661a5SPawel Jakub Dawidek error = g_raid3_write_metadata(disk, &md); 7402d1661a5SPawel Jakub Dawidek if (error == 0) { 7412d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Metadata on %s updated.", 7422d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 7432d1661a5SPawel Jakub Dawidek } else { 7442d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 7452d1661a5SPawel Jakub Dawidek "Cannot update metadata on disk %s (error=%d).", 7462d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), error); 7472d1661a5SPawel Jakub Dawidek } 7482d1661a5SPawel Jakub Dawidek } 7492d1661a5SPawel Jakub Dawidek 7502d1661a5SPawel Jakub Dawidek static void 751d97d5ee9SPawel Jakub Dawidek g_raid3_bump_syncid(struct g_raid3_softc *sc) 7522d1661a5SPawel Jakub Dawidek { 7532d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 7542d1661a5SPawel Jakub Dawidek u_int n; 7552d1661a5SPawel Jakub Dawidek 7562d1661a5SPawel Jakub Dawidek g_topology_assert(); 7572d1661a5SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) > 0, 7582d1661a5SPawel Jakub Dawidek ("%s called with no active disks (device=%s).", __func__, 7592d1661a5SPawel Jakub Dawidek sc->sc_name)); 7602d1661a5SPawel Jakub Dawidek 7612d1661a5SPawel Jakub Dawidek sc->sc_syncid++; 762a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s: syncid bumped to %u.", sc->sc_name, 763a245a548SPawel Jakub Dawidek sc->sc_syncid); 7642d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 7652d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 7662d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 7672d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 7682d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = sc->sc_syncid; 7692d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 7702d1661a5SPawel Jakub Dawidek } 7712d1661a5SPawel Jakub Dawidek } 7722d1661a5SPawel Jakub Dawidek } 7732d1661a5SPawel Jakub Dawidek 7744d006a98SPawel Jakub Dawidek static void 775a245a548SPawel Jakub Dawidek g_raid3_bump_genid(struct g_raid3_softc *sc) 776a245a548SPawel Jakub Dawidek { 777a245a548SPawel Jakub Dawidek struct g_raid3_disk *disk; 778a245a548SPawel Jakub Dawidek u_int n; 779a245a548SPawel Jakub Dawidek 780a245a548SPawel Jakub Dawidek g_topology_assert(); 781a245a548SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) > 0, 782a245a548SPawel Jakub Dawidek ("%s called with no active disks (device=%s).", __func__, 783a245a548SPawel Jakub Dawidek sc->sc_name)); 784a245a548SPawel Jakub Dawidek 785a245a548SPawel Jakub Dawidek sc->sc_genid++; 786a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s: genid bumped to %u.", sc->sc_name, 787a245a548SPawel Jakub Dawidek sc->sc_genid); 788a245a548SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 789a245a548SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 790a245a548SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 791a245a548SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 792a245a548SPawel Jakub Dawidek disk->d_genid = sc->sc_genid; 793a245a548SPawel Jakub Dawidek g_raid3_update_metadata(disk); 794a245a548SPawel Jakub Dawidek } 795a245a548SPawel Jakub Dawidek } 796a245a548SPawel Jakub Dawidek } 797a245a548SPawel Jakub Dawidek 7980962f942SPawel Jakub Dawidek static int 7990962f942SPawel Jakub Dawidek g_raid3_idle(struct g_raid3_softc *sc, int from_access) 8004d006a98SPawel Jakub Dawidek { 8014d006a98SPawel Jakub Dawidek struct g_raid3_disk *disk; 8024d006a98SPawel Jakub Dawidek u_int i; 8030962f942SPawel Jakub Dawidek int timeout; 8044d006a98SPawel Jakub Dawidek 8050962f942SPawel Jakub Dawidek if (sc->sc_provider == NULL) 8060962f942SPawel Jakub Dawidek return (0); 8070962f942SPawel Jakub Dawidek if (sc->sc_idle) 8080962f942SPawel Jakub Dawidek return (0); 8090962f942SPawel Jakub Dawidek if (sc->sc_writes > 0) 8100962f942SPawel Jakub Dawidek return (0); 8110962f942SPawel Jakub Dawidek if (!from_access && sc->sc_provider->acw > 0) { 81201f1f41cSPawel Jakub Dawidek timeout = g_raid3_idletime - (time_uptime - sc->sc_last_write); 8130962f942SPawel Jakub Dawidek if (timeout > 0) 8140962f942SPawel Jakub Dawidek return (timeout); 8150962f942SPawel Jakub Dawidek } 8164d006a98SPawel Jakub Dawidek sc->sc_idle = 1; 8170962f942SPawel Jakub Dawidek if (!from_access) 8184d006a98SPawel Jakub Dawidek g_topology_lock(); 8194d006a98SPawel Jakub Dawidek for (i = 0; i < sc->sc_ndisks; i++) { 8204d006a98SPawel Jakub Dawidek disk = &sc->sc_disks[i]; 8214d006a98SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) 8224d006a98SPawel Jakub Dawidek continue; 8234d006a98SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as clean.", 8244d006a98SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 8254d006a98SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 8264d006a98SPawel Jakub Dawidek g_raid3_update_metadata(disk); 8274d006a98SPawel Jakub Dawidek } 8280962f942SPawel Jakub Dawidek if (!from_access) 8294d006a98SPawel Jakub Dawidek g_topology_unlock(); 8300962f942SPawel Jakub Dawidek return (0); 8314d006a98SPawel Jakub Dawidek } 8324d006a98SPawel Jakub Dawidek 8334d006a98SPawel Jakub Dawidek static void 8344d006a98SPawel Jakub Dawidek g_raid3_unidle(struct g_raid3_softc *sc) 8354d006a98SPawel Jakub Dawidek { 8364d006a98SPawel Jakub Dawidek struct g_raid3_disk *disk; 8374d006a98SPawel Jakub Dawidek u_int i; 8384d006a98SPawel Jakub Dawidek 8394d006a98SPawel Jakub Dawidek sc->sc_idle = 0; 84001f1f41cSPawel Jakub Dawidek sc->sc_last_write = time_uptime; 8414d006a98SPawel Jakub Dawidek g_topology_lock(); 8424d006a98SPawel Jakub Dawidek for (i = 0; i < sc->sc_ndisks; i++) { 8434d006a98SPawel Jakub Dawidek disk = &sc->sc_disks[i]; 8444d006a98SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) 8454d006a98SPawel Jakub Dawidek continue; 8464d006a98SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as dirty.", 8474d006a98SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 8484d006a98SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 8494d006a98SPawel Jakub Dawidek g_raid3_update_metadata(disk); 8504d006a98SPawel Jakub Dawidek } 8514d006a98SPawel Jakub Dawidek g_topology_unlock(); 8524d006a98SPawel Jakub Dawidek } 8534d006a98SPawel Jakub Dawidek 8542d1661a5SPawel Jakub Dawidek /* 8552d1661a5SPawel Jakub Dawidek * Treat bio_driver1 field in parent bio as list head and field bio_caller1 8562d1661a5SPawel Jakub Dawidek * in child bio as pointer to the next element on the list. 8572d1661a5SPawel Jakub Dawidek */ 8582d1661a5SPawel Jakub Dawidek #define G_RAID3_HEAD_BIO(pbp) (pbp)->bio_driver1 8592d1661a5SPawel Jakub Dawidek 8602d1661a5SPawel Jakub Dawidek #define G_RAID3_NEXT_BIO(cbp) (cbp)->bio_caller1 8612d1661a5SPawel Jakub Dawidek 8622d1661a5SPawel Jakub Dawidek #define G_RAID3_FOREACH_BIO(pbp, bp) \ 8632d1661a5SPawel Jakub Dawidek for ((bp) = G_RAID3_HEAD_BIO(pbp); (bp) != NULL; \ 8642d1661a5SPawel Jakub Dawidek (bp) = G_RAID3_NEXT_BIO(bp)) 8652d1661a5SPawel Jakub Dawidek 8662d1661a5SPawel Jakub Dawidek #define G_RAID3_FOREACH_SAFE_BIO(pbp, bp, tmpbp) \ 8672d1661a5SPawel Jakub Dawidek for ((bp) = G_RAID3_HEAD_BIO(pbp); \ 8682d1661a5SPawel Jakub Dawidek (bp) != NULL && ((tmpbp) = G_RAID3_NEXT_BIO(bp), 1); \ 8692d1661a5SPawel Jakub Dawidek (bp) = (tmpbp)) 8702d1661a5SPawel Jakub Dawidek 8712d1661a5SPawel Jakub Dawidek static void 8722d1661a5SPawel Jakub Dawidek g_raid3_init_bio(struct bio *pbp) 8732d1661a5SPawel Jakub Dawidek { 8742d1661a5SPawel Jakub Dawidek 8752d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = NULL; 8762d1661a5SPawel Jakub Dawidek } 8772d1661a5SPawel Jakub Dawidek 8782d1661a5SPawel Jakub Dawidek static void 879dba915cfSPawel Jakub Dawidek g_raid3_remove_bio(struct bio *cbp) 880dba915cfSPawel Jakub Dawidek { 881dba915cfSPawel Jakub Dawidek struct bio *pbp, *bp; 882dba915cfSPawel Jakub Dawidek 883dba915cfSPawel Jakub Dawidek pbp = cbp->bio_parent; 884dba915cfSPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == cbp) 885dba915cfSPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = G_RAID3_NEXT_BIO(cbp); 886dba915cfSPawel Jakub Dawidek else { 887dba915cfSPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 888dba915cfSPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == cbp) { 889dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); 890dba915cfSPawel Jakub Dawidek break; 891dba915cfSPawel Jakub Dawidek } 892dba915cfSPawel Jakub Dawidek } 893dba915cfSPawel Jakub Dawidek } 894dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 895dba915cfSPawel Jakub Dawidek } 896dba915cfSPawel Jakub Dawidek 897dba915cfSPawel Jakub Dawidek static void 898dba915cfSPawel Jakub Dawidek g_raid3_replace_bio(struct bio *sbp, struct bio *dbp) 899dba915cfSPawel Jakub Dawidek { 900dba915cfSPawel Jakub Dawidek struct bio *pbp, *bp; 901dba915cfSPawel Jakub Dawidek 902dba915cfSPawel Jakub Dawidek g_raid3_remove_bio(sbp); 903dba915cfSPawel Jakub Dawidek pbp = dbp->bio_parent; 904dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(sbp) = G_RAID3_NEXT_BIO(dbp); 905dba915cfSPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == dbp) 906dba915cfSPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = sbp; 907dba915cfSPawel Jakub Dawidek else { 908dba915cfSPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 909dba915cfSPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == dbp) { 910dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = sbp; 911dba915cfSPawel Jakub Dawidek break; 912dba915cfSPawel Jakub Dawidek } 913dba915cfSPawel Jakub Dawidek } 914dba915cfSPawel Jakub Dawidek } 915dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(dbp) = NULL; 916dba915cfSPawel Jakub Dawidek } 917dba915cfSPawel Jakub Dawidek 918dba915cfSPawel Jakub Dawidek static void 9192d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(struct g_raid3_softc *sc, struct bio *cbp) 9202d1661a5SPawel Jakub Dawidek { 9212d1661a5SPawel Jakub Dawidek struct bio *bp, *pbp; 9222d1661a5SPawel Jakub Dawidek size_t size; 9232d1661a5SPawel Jakub Dawidek 9242d1661a5SPawel Jakub Dawidek pbp = cbp->bio_parent; 9252d1661a5SPawel Jakub Dawidek pbp->bio_children--; 9262d1661a5SPawel Jakub Dawidek KASSERT(cbp->bio_data != NULL, ("NULL bio_data")); 9272d1661a5SPawel Jakub Dawidek size = pbp->bio_length / (sc->sc_ndisks - 1); 9282d1661a5SPawel Jakub Dawidek if (size > 16384) 9292d1661a5SPawel Jakub Dawidek uma_zfree(sc->sc_zone_64k, cbp->bio_data); 9302d1661a5SPawel Jakub Dawidek else if (size > 4096) 9312d1661a5SPawel Jakub Dawidek uma_zfree(sc->sc_zone_16k, cbp->bio_data); 9322d1661a5SPawel Jakub Dawidek else 9332d1661a5SPawel Jakub Dawidek uma_zfree(sc->sc_zone_4k, cbp->bio_data); 9342d1661a5SPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == cbp) { 9352d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = G_RAID3_NEXT_BIO(cbp); 9362d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 9372d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 9382d1661a5SPawel Jakub Dawidek } else { 9392d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 9402d1661a5SPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == cbp) 9412d1661a5SPawel Jakub Dawidek break; 9422d1661a5SPawel Jakub Dawidek } 943dba915cfSPawel Jakub Dawidek if (bp != NULL) { 944dba915cfSPawel Jakub Dawidek KASSERT(G_RAID3_NEXT_BIO(bp) != NULL, 945dba915cfSPawel Jakub Dawidek ("NULL bp->bio_driver1")); 9462d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); 9472d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 948dba915cfSPawel Jakub Dawidek } 9492d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 9502d1661a5SPawel Jakub Dawidek } 9512d1661a5SPawel Jakub Dawidek } 9522d1661a5SPawel Jakub Dawidek 9532d1661a5SPawel Jakub Dawidek static struct bio * 9542d1661a5SPawel Jakub Dawidek g_raid3_clone_bio(struct g_raid3_softc *sc, struct bio *pbp) 9552d1661a5SPawel Jakub Dawidek { 9562d1661a5SPawel Jakub Dawidek struct bio *bp, *cbp; 9572d1661a5SPawel Jakub Dawidek size_t size; 9582d1661a5SPawel Jakub Dawidek 9592d1661a5SPawel Jakub Dawidek cbp = g_clone_bio(pbp); 9602d1661a5SPawel Jakub Dawidek if (cbp == NULL) 9612d1661a5SPawel Jakub Dawidek return (NULL); 9622d1661a5SPawel Jakub Dawidek size = pbp->bio_length / (sc->sc_ndisks - 1); 9632d1661a5SPawel Jakub Dawidek if (size > 16384) { 9642d1661a5SPawel Jakub Dawidek cbp->bio_data = uma_zalloc(sc->sc_zone_64k, M_NOWAIT); 9652d1661a5SPawel Jakub Dawidek g_raid3_64k_requested++; 9662d1661a5SPawel Jakub Dawidek } else if (size > 4096) { 9672d1661a5SPawel Jakub Dawidek cbp->bio_data = uma_zalloc(sc->sc_zone_16k, M_NOWAIT); 9682d1661a5SPawel Jakub Dawidek g_raid3_16k_requested++; 9692d1661a5SPawel Jakub Dawidek } else { 9702d1661a5SPawel Jakub Dawidek cbp->bio_data = uma_zalloc(sc->sc_zone_4k, M_NOWAIT); 9712d1661a5SPawel Jakub Dawidek g_raid3_4k_requested++; 9722d1661a5SPawel Jakub Dawidek } 9732d1661a5SPawel Jakub Dawidek if (cbp->bio_data == NULL) { 9742d1661a5SPawel Jakub Dawidek if (size > 16384) 9752d1661a5SPawel Jakub Dawidek g_raid3_64k_failed++; 976a65a0da2SPawel Jakub Dawidek else if (size > 4096) 9772d1661a5SPawel Jakub Dawidek g_raid3_16k_failed++; 9782d1661a5SPawel Jakub Dawidek else 9792d1661a5SPawel Jakub Dawidek g_raid3_4k_failed++; 9802d1661a5SPawel Jakub Dawidek pbp->bio_children--; 9812d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 9822d1661a5SPawel Jakub Dawidek return (NULL); 9832d1661a5SPawel Jakub Dawidek } 9842d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 9852d1661a5SPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == NULL) 9862d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = cbp; 9872d1661a5SPawel Jakub Dawidek else { 9882d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 9892d1661a5SPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == NULL) { 9902d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = cbp; 9912d1661a5SPawel Jakub Dawidek break; 9922d1661a5SPawel Jakub Dawidek } 9932d1661a5SPawel Jakub Dawidek } 9942d1661a5SPawel Jakub Dawidek } 9952d1661a5SPawel Jakub Dawidek return (cbp); 9962d1661a5SPawel Jakub Dawidek } 9972d1661a5SPawel Jakub Dawidek 9982d1661a5SPawel Jakub Dawidek static void 9992d1661a5SPawel Jakub Dawidek g_raid3_scatter(struct bio *pbp) 10002d1661a5SPawel Jakub Dawidek { 10012d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 10022d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 10032d1661a5SPawel Jakub Dawidek struct bio *bp, *cbp; 10042d1661a5SPawel Jakub Dawidek off_t atom, cadd, padd, left; 10052d1661a5SPawel Jakub Dawidek 10062d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 10072d1661a5SPawel Jakub Dawidek bp = NULL; 10082d1661a5SPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_NOPARITY) == 0) { 10092d1661a5SPawel Jakub Dawidek /* 10102d1661a5SPawel Jakub Dawidek * Find bio for which we should calculate data. 10112d1661a5SPawel Jakub Dawidek */ 10122d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 10132d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { 10142d1661a5SPawel Jakub Dawidek bp = cbp; 10152d1661a5SPawel Jakub Dawidek break; 10162d1661a5SPawel Jakub Dawidek } 10172d1661a5SPawel Jakub Dawidek } 10182d1661a5SPawel Jakub Dawidek KASSERT(bp != NULL, ("NULL parity bio.")); 10192d1661a5SPawel Jakub Dawidek } 10202d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 10212d1661a5SPawel Jakub Dawidek cadd = padd = 0; 10222d1661a5SPawel Jakub Dawidek for (left = pbp->bio_length; left > 0; left -= sc->sc_sectorsize) { 10232d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 10242d1661a5SPawel Jakub Dawidek if (cbp == bp) 10252d1661a5SPawel Jakub Dawidek continue; 10262d1661a5SPawel Jakub Dawidek bcopy(pbp->bio_data + padd, cbp->bio_data + cadd, atom); 10272d1661a5SPawel Jakub Dawidek padd += atom; 10282d1661a5SPawel Jakub Dawidek } 10292d1661a5SPawel Jakub Dawidek cadd += atom; 10302d1661a5SPawel Jakub Dawidek } 10312d1661a5SPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_NOPARITY) == 0) { 10322d1661a5SPawel Jakub Dawidek struct bio *tmpbp; 10332d1661a5SPawel Jakub Dawidek 10342d1661a5SPawel Jakub Dawidek /* 10352d1661a5SPawel Jakub Dawidek * Calculate parity. 10362d1661a5SPawel Jakub Dawidek */ 10372d1661a5SPawel Jakub Dawidek bzero(bp->bio_data, bp->bio_length); 10382d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_SAFE_BIO(pbp, cbp, tmpbp) { 10392d1661a5SPawel Jakub Dawidek if (cbp == bp) 10402d1661a5SPawel Jakub Dawidek continue; 10412d1661a5SPawel Jakub Dawidek g_raid3_xor(cbp->bio_data, bp->bio_data, bp->bio_data, 10422d1661a5SPawel Jakub Dawidek bp->bio_length); 10432d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_NODISK) != 0) 10442d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 10452d1661a5SPawel Jakub Dawidek } 10462d1661a5SPawel Jakub Dawidek } 10472d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 10482d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 10492d1661a5SPawel Jakub Dawidek 10502d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 10512d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 10522d1661a5SPawel Jakub Dawidek cbp->bio_to = cp->provider; 10532d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Sending request."); 1054d97d5ee9SPawel Jakub Dawidek KASSERT(cp->acr == 1 && cp->acw == 1 && cp->ace == 1, 1055d97d5ee9SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 1056d97d5ee9SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 105779e61493SPawel Jakub Dawidek cp->index++; 10580962f942SPawel Jakub Dawidek sc->sc_writes++; 10592d1661a5SPawel Jakub Dawidek g_io_request(cbp, cp); 10602d1661a5SPawel Jakub Dawidek } 10612d1661a5SPawel Jakub Dawidek } 10622d1661a5SPawel Jakub Dawidek 10632d1661a5SPawel Jakub Dawidek static void 10642d1661a5SPawel Jakub Dawidek g_raid3_gather(struct bio *pbp) 10652d1661a5SPawel Jakub Dawidek { 10662d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 10672d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 1068f5a2f7feSPawel Jakub Dawidek struct bio *xbp, *fbp, *cbp; 10692d1661a5SPawel Jakub Dawidek off_t atom, cadd, padd, left; 10702d1661a5SPawel Jakub Dawidek 10712d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 10722d1661a5SPawel Jakub Dawidek /* 1073f5a2f7feSPawel Jakub Dawidek * Find bio for which we have to calculate data. 10742d1661a5SPawel Jakub Dawidek * While going through this path, check if all requests 10752d1661a5SPawel Jakub Dawidek * succeeded, if not, deny whole request. 1076f5a2f7feSPawel Jakub Dawidek * If we're in COMPLETE mode, we allow one request to fail, 1077f5a2f7feSPawel Jakub Dawidek * so if we find one, we're sending it to the parity consumer. 1078f5a2f7feSPawel Jakub Dawidek * If there are more failed requests, we deny whole request. 10792d1661a5SPawel Jakub Dawidek */ 1080f5a2f7feSPawel Jakub Dawidek xbp = fbp = NULL; 10812d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 10822d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { 1083f5a2f7feSPawel Jakub Dawidek KASSERT(xbp == NULL, ("More than one parity bio.")); 1084f5a2f7feSPawel Jakub Dawidek xbp = cbp; 10852d1661a5SPawel Jakub Dawidek } 10862d1661a5SPawel Jakub Dawidek if (cbp->bio_error == 0) 10872d1661a5SPawel Jakub Dawidek continue; 10882d1661a5SPawel Jakub Dawidek /* 10892d1661a5SPawel Jakub Dawidek * Found failed request. 10902d1661a5SPawel Jakub Dawidek */ 1091f5a2f7feSPawel Jakub Dawidek if (fbp == NULL) { 1092f5a2f7feSPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_DEGRADED) != 0) { 10932d1661a5SPawel Jakub Dawidek /* 1094f5a2f7feSPawel Jakub Dawidek * We are already in degraded mode, so we can't 1095f5a2f7feSPawel Jakub Dawidek * accept any failures. 10962d1661a5SPawel Jakub Dawidek */ 1097f5a2f7feSPawel Jakub Dawidek if (pbp->bio_error == 0) 109817fec17eSPawel Jakub Dawidek pbp->bio_error = cbp->bio_error; 10992d1661a5SPawel Jakub Dawidek } else { 1100f5a2f7feSPawel Jakub Dawidek fbp = cbp; 11012d1661a5SPawel Jakub Dawidek } 1102f5a2f7feSPawel Jakub Dawidek } else { 11032d1661a5SPawel Jakub Dawidek /* 11042d1661a5SPawel Jakub Dawidek * Next failed request, that's too many. 11052d1661a5SPawel Jakub Dawidek */ 11062d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 1107f5a2f7feSPawel Jakub Dawidek pbp->bio_error = fbp->bio_error; 11082d1661a5SPawel Jakub Dawidek } 11093aae74ecSPawel Jakub Dawidek disk = cbp->bio_caller2; 11103aae74ecSPawel Jakub Dawidek if (disk == NULL) 11113aae74ecSPawel Jakub Dawidek continue; 11123aae74ecSPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_BROKEN) == 0) { 11133aae74ecSPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_BROKEN; 11143aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(0, cbp, "Request failed (error=%d).", 11153aae74ecSPawel Jakub Dawidek cbp->bio_error); 11163aae74ecSPawel Jakub Dawidek } else { 11173aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(1, cbp, "Request failed (error=%d).", 11183aae74ecSPawel Jakub Dawidek cbp->bio_error); 11193aae74ecSPawel Jakub Dawidek } 11203aae74ecSPawel Jakub Dawidek if (g_raid3_disconnect_on_failure && 11213aae74ecSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 11223aae74ecSPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 11233aae74ecSPawel Jakub Dawidek g_raid3_event_send(disk, 11243aae74ecSPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 11253aae74ecSPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 11263aae74ecSPawel Jakub Dawidek } 11272d1661a5SPawel Jakub Dawidek } 11282d1661a5SPawel Jakub Dawidek if (pbp->bio_error != 0) 11292d1661a5SPawel Jakub Dawidek goto finish; 1130dba915cfSPawel Jakub Dawidek if (fbp != NULL && (pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) { 1131dba915cfSPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_VERIFY; 1132dba915cfSPawel Jakub Dawidek if (xbp != fbp) 1133dba915cfSPawel Jakub Dawidek g_raid3_replace_bio(xbp, fbp); 1134dba915cfSPawel Jakub Dawidek g_raid3_destroy_bio(sc, fbp); 1135dba915cfSPawel Jakub Dawidek } else if (fbp != NULL) { 11362d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 11372d1661a5SPawel Jakub Dawidek 11382d1661a5SPawel Jakub Dawidek /* 11392d1661a5SPawel Jakub Dawidek * One request failed, so send the same request to 11402d1661a5SPawel Jakub Dawidek * the parity consumer. 11412d1661a5SPawel Jakub Dawidek */ 1142f5a2f7feSPawel Jakub Dawidek disk = pbp->bio_driver2; 11432d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { 1144f5a2f7feSPawel Jakub Dawidek pbp->bio_error = fbp->bio_error; 11452d1661a5SPawel Jakub Dawidek goto finish; 11462d1661a5SPawel Jakub Dawidek } 11472d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 11482d1661a5SPawel Jakub Dawidek pbp->bio_inbed--; 1149f5a2f7feSPawel Jakub Dawidek fbp->bio_flags &= ~(BIO_DONE | BIO_ERROR); 1150f5a2f7feSPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) 1151f5a2f7feSPawel Jakub Dawidek fbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 1152f5a2f7feSPawel Jakub Dawidek fbp->bio_error = 0; 1153f5a2f7feSPawel Jakub Dawidek fbp->bio_completed = 0; 1154f5a2f7feSPawel Jakub Dawidek fbp->bio_children = 0; 1155f5a2f7feSPawel Jakub Dawidek fbp->bio_inbed = 0; 11562d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 1157f5a2f7feSPawel Jakub Dawidek fbp->bio_caller2 = disk; 1158f5a2f7feSPawel Jakub Dawidek fbp->bio_to = cp->provider; 1159f5a2f7feSPawel Jakub Dawidek G_RAID3_LOGREQ(3, fbp, "Sending request (recover)."); 1160d97d5ee9SPawel Jakub Dawidek KASSERT(cp->acr == 1 && cp->acw == 1 && cp->ace == 1, 11612d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 11622d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 116379e61493SPawel Jakub Dawidek cp->index++; 1164f5a2f7feSPawel Jakub Dawidek g_io_request(fbp, cp); 11652d1661a5SPawel Jakub Dawidek return; 11662d1661a5SPawel Jakub Dawidek } 1167f5a2f7feSPawel Jakub Dawidek if (xbp != NULL) { 1168f5a2f7feSPawel Jakub Dawidek /* 1169f5a2f7feSPawel Jakub Dawidek * Calculate parity. 1170f5a2f7feSPawel Jakub Dawidek */ 1171f5a2f7feSPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 1172f5a2f7feSPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) 1173f5a2f7feSPawel Jakub Dawidek continue; 1174f5a2f7feSPawel Jakub Dawidek g_raid3_xor(cbp->bio_data, xbp->bio_data, xbp->bio_data, 1175f5a2f7feSPawel Jakub Dawidek xbp->bio_length); 1176f5a2f7feSPawel Jakub Dawidek } 1177f5a2f7feSPawel Jakub Dawidek xbp->bio_cflags &= ~G_RAID3_BIO_CFLAG_PARITY; 1178dba915cfSPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) { 1179dba915cfSPawel Jakub Dawidek if (!g_raid3_is_zero(xbp)) { 1180dba915cfSPawel Jakub Dawidek g_raid3_parity_mismatch++; 1181dba915cfSPawel Jakub Dawidek pbp->bio_error = EIO; 1182dba915cfSPawel Jakub Dawidek goto finish; 1183dba915cfSPawel Jakub Dawidek } 1184dba915cfSPawel Jakub Dawidek g_raid3_destroy_bio(sc, xbp); 1185dba915cfSPawel Jakub Dawidek } 11862d1661a5SPawel Jakub Dawidek } 11872d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 11882d1661a5SPawel Jakub Dawidek cadd = padd = 0; 11892d1661a5SPawel Jakub Dawidek for (left = pbp->bio_length; left > 0; left -= sc->sc_sectorsize) { 11902d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 11912d1661a5SPawel Jakub Dawidek bcopy(cbp->bio_data + cadd, pbp->bio_data + padd, atom); 11922d1661a5SPawel Jakub Dawidek pbp->bio_completed += atom; 11932d1661a5SPawel Jakub Dawidek padd += atom; 11942d1661a5SPawel Jakub Dawidek } 11952d1661a5SPawel Jakub Dawidek cadd += atom; 11962d1661a5SPawel Jakub Dawidek } 11972d1661a5SPawel Jakub Dawidek finish: 11982d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 11992d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, pbp, "Request finished."); 12004cf67afeSPawel Jakub Dawidek else { 12014cf67afeSPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) 12024cf67afeSPawel Jakub Dawidek G_RAID3_LOGREQ(1, pbp, "Verification error."); 12032d1661a5SPawel Jakub Dawidek else 12042d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, pbp, "Request failed."); 12054cf67afeSPawel Jakub Dawidek } 1206dba915cfSPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_MASK; 12072d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) 12082d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 1209290c6161SPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 12102d1661a5SPawel Jakub Dawidek } 12112d1661a5SPawel Jakub Dawidek 12122d1661a5SPawel Jakub Dawidek static void 12132d1661a5SPawel Jakub Dawidek g_raid3_done(struct bio *bp) 12142d1661a5SPawel Jakub Dawidek { 12152d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 12162d1661a5SPawel Jakub Dawidek 12172d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 12182d1661a5SPawel Jakub Dawidek bp->bio_cflags |= G_RAID3_BIO_CFLAG_REGULAR; 12192d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Regular request done (error=%d).", bp->bio_error); 12202d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 12212d1661a5SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 12222d1661a5SPawel Jakub Dawidek wakeup(sc); 12232d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 12242d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 12252d1661a5SPawel Jakub Dawidek } 12262d1661a5SPawel Jakub Dawidek 12272d1661a5SPawel Jakub Dawidek static void 12282d1661a5SPawel Jakub Dawidek g_raid3_regular_request(struct bio *cbp) 12292d1661a5SPawel Jakub Dawidek { 12302d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 12312d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 12322d1661a5SPawel Jakub Dawidek struct bio *pbp; 12332d1661a5SPawel Jakub Dawidek 12342d1661a5SPawel Jakub Dawidek g_topology_assert_not(); 12352d1661a5SPawel Jakub Dawidek 12362d1661a5SPawel Jakub Dawidek pbp = cbp->bio_parent; 12372d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 12380962f942SPawel Jakub Dawidek cbp->bio_from->index--; 12390962f942SPawel Jakub Dawidek if (cbp->bio_cmd == BIO_WRITE) 12400962f942SPawel Jakub Dawidek sc->sc_writes--; 12412d1661a5SPawel Jakub Dawidek disk = cbp->bio_from->private; 12422d1661a5SPawel Jakub Dawidek if (disk == NULL) { 12432d1661a5SPawel Jakub Dawidek g_topology_lock(); 12442d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, cbp->bio_from); 12452d1661a5SPawel Jakub Dawidek g_topology_unlock(); 12462d1661a5SPawel Jakub Dawidek } 12472d1661a5SPawel Jakub Dawidek 12482d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Request finished."); 12492d1661a5SPawel Jakub Dawidek pbp->bio_inbed++; 12502d1661a5SPawel Jakub Dawidek KASSERT(pbp->bio_inbed <= pbp->bio_children, 12512d1661a5SPawel Jakub Dawidek ("bio_inbed (%u) is bigger than bio_children (%u).", pbp->bio_inbed, 12522d1661a5SPawel Jakub Dawidek pbp->bio_children)); 12532d1661a5SPawel Jakub Dawidek if (pbp->bio_inbed != pbp->bio_children) 12542d1661a5SPawel Jakub Dawidek return; 12552d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 12562d1661a5SPawel Jakub Dawidek case BIO_READ: 12572d1661a5SPawel Jakub Dawidek g_raid3_gather(pbp); 12582d1661a5SPawel Jakub Dawidek break; 12592d1661a5SPawel Jakub Dawidek case BIO_WRITE: 12602d1661a5SPawel Jakub Dawidek case BIO_DELETE: 12612d1661a5SPawel Jakub Dawidek { 12622d1661a5SPawel Jakub Dawidek int error = 0; 12632d1661a5SPawel Jakub Dawidek 12642d1661a5SPawel Jakub Dawidek pbp->bio_completed = pbp->bio_length; 12652d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) { 12663aae74ecSPawel Jakub Dawidek if (cbp->bio_error == 0) { 12673aae74ecSPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 12683aae74ecSPawel Jakub Dawidek continue; 12692d1661a5SPawel Jakub Dawidek } 12703aae74ecSPawel Jakub Dawidek 12712d1661a5SPawel Jakub Dawidek if (error == 0) 12722d1661a5SPawel Jakub Dawidek error = cbp->bio_error; 12732d1661a5SPawel Jakub Dawidek else if (pbp->bio_error == 0) { 12742d1661a5SPawel Jakub Dawidek /* 12752d1661a5SPawel Jakub Dawidek * Next failed request, that's too many. 12762d1661a5SPawel Jakub Dawidek */ 12772d1661a5SPawel Jakub Dawidek pbp->bio_error = error; 12782d1661a5SPawel Jakub Dawidek } 12793aae74ecSPawel Jakub Dawidek 12803aae74ecSPawel Jakub Dawidek disk = cbp->bio_caller2; 12813aae74ecSPawel Jakub Dawidek if (disk == NULL) { 12823aae74ecSPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 12833aae74ecSPawel Jakub Dawidek continue; 12843aae74ecSPawel Jakub Dawidek } 12853aae74ecSPawel Jakub Dawidek 12863aae74ecSPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_BROKEN) == 0) { 12873aae74ecSPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_BROKEN; 12883aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(0, cbp, 12893aae74ecSPawel Jakub Dawidek "Request failed (error=%d).", 12903aae74ecSPawel Jakub Dawidek cbp->bio_error); 12913aae74ecSPawel Jakub Dawidek } else { 12923aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(1, cbp, 12933aae74ecSPawel Jakub Dawidek "Request failed (error=%d).", 12943aae74ecSPawel Jakub Dawidek cbp->bio_error); 12953aae74ecSPawel Jakub Dawidek } 12963aae74ecSPawel Jakub Dawidek if (g_raid3_disconnect_on_failure && 12973aae74ecSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 12983aae74ecSPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 12993aae74ecSPawel Jakub Dawidek g_raid3_event_send(disk, 13003aae74ecSPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 13013aae74ecSPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 13022d1661a5SPawel Jakub Dawidek } 13032d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 13042d1661a5SPawel Jakub Dawidek } 13052d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 13062d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, pbp, "Request finished."); 13072d1661a5SPawel Jakub Dawidek else 13082d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, pbp, "Request failed."); 13092d1661a5SPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_DEGRADED; 13102d1661a5SPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_NOPARITY; 13112d1661a5SPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 13122d1661a5SPawel Jakub Dawidek break; 13132d1661a5SPawel Jakub Dawidek } 13142d1661a5SPawel Jakub Dawidek } 13152d1661a5SPawel Jakub Dawidek } 13162d1661a5SPawel Jakub Dawidek 13172d1661a5SPawel Jakub Dawidek static void 13182d1661a5SPawel Jakub Dawidek g_raid3_sync_done(struct bio *bp) 13192d1661a5SPawel Jakub Dawidek { 13202d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 13212d1661a5SPawel Jakub Dawidek 13222d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request delivered."); 13232d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 13242d1661a5SPawel Jakub Dawidek bp->bio_cflags |= G_RAID3_BIO_CFLAG_SYNC; 13252d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 13262d1661a5SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 13272d1661a5SPawel Jakub Dawidek wakeup(sc); 13282d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 13292d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 13302d1661a5SPawel Jakub Dawidek } 13312d1661a5SPawel Jakub Dawidek 13322d1661a5SPawel Jakub Dawidek static void 13332d1661a5SPawel Jakub Dawidek g_raid3_start(struct bio *bp) 13342d1661a5SPawel Jakub Dawidek { 13352d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 13362d1661a5SPawel Jakub Dawidek 13372d1661a5SPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 13382d1661a5SPawel Jakub Dawidek /* 13392d1661a5SPawel Jakub Dawidek * If sc == NULL or there are no valid disks, provider's error 13402d1661a5SPawel Jakub Dawidek * should be set and g_raid3_start() should not be called at all. 13412d1661a5SPawel Jakub Dawidek */ 13422d1661a5SPawel Jakub Dawidek KASSERT(sc != NULL && (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 13432d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE), 13442d1661a5SPawel Jakub Dawidek ("Provider's error should be set (error=%d)(device=%s).", 13452d1661a5SPawel Jakub Dawidek bp->bio_to->error, bp->bio_to->name)); 13462d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Request received."); 13472d1661a5SPawel Jakub Dawidek 13482d1661a5SPawel Jakub Dawidek switch (bp->bio_cmd) { 13492d1661a5SPawel Jakub Dawidek case BIO_READ: 13502d1661a5SPawel Jakub Dawidek case BIO_WRITE: 13512d1661a5SPawel Jakub Dawidek case BIO_DELETE: 13522d1661a5SPawel Jakub Dawidek break; 13532d1661a5SPawel Jakub Dawidek case BIO_GETATTR: 13542d1661a5SPawel Jakub Dawidek default: 13552d1661a5SPawel Jakub Dawidek g_io_deliver(bp, EOPNOTSUPP); 13562d1661a5SPawel Jakub Dawidek return; 13572d1661a5SPawel Jakub Dawidek } 13582d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 13592d1661a5SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_queue, bp); 13602d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 13612d1661a5SPawel Jakub Dawidek wakeup(sc); 13622d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 13632d1661a5SPawel Jakub Dawidek } 13642d1661a5SPawel Jakub Dawidek 13652d1661a5SPawel Jakub Dawidek /* 13662d1661a5SPawel Jakub Dawidek * Send one synchronization request. 13672d1661a5SPawel Jakub Dawidek */ 13682d1661a5SPawel Jakub Dawidek static void 13692d1661a5SPawel Jakub Dawidek g_raid3_sync_one(struct g_raid3_softc *sc) 13702d1661a5SPawel Jakub Dawidek { 13712d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 13722d1661a5SPawel Jakub Dawidek struct bio *bp; 13732d1661a5SPawel Jakub Dawidek 13742d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 13752d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s).", sc->sc_name, 13762d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state))); 13772d1661a5SPawel Jakub Dawidek disk = sc->sc_syncdisk; 13782d1661a5SPawel Jakub Dawidek KASSERT(disk != NULL, ("No sync disk (%s).", sc->sc_name)); 13792d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 13802d1661a5SPawel Jakub Dawidek ("Disk %s is not marked for synchronization.", 13812d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk))); 13822d1661a5SPawel Jakub Dawidek 13832d1661a5SPawel Jakub Dawidek bp = g_new_bio(); 13842d1661a5SPawel Jakub Dawidek if (bp == NULL) 13852d1661a5SPawel Jakub Dawidek return; 13862d1661a5SPawel Jakub Dawidek bp->bio_parent = NULL; 13872d1661a5SPawel Jakub Dawidek bp->bio_cmd = BIO_READ; 13882d1661a5SPawel Jakub Dawidek bp->bio_offset = disk->d_sync.ds_offset * (sc->sc_ndisks - 1); 1389604fce4fSPawel Jakub Dawidek bp->bio_length = MIN(MAXPHYS, sc->sc_mediasize - bp->bio_offset); 13902d1661a5SPawel Jakub Dawidek bp->bio_cflags = 0; 13912d1661a5SPawel Jakub Dawidek bp->bio_done = g_raid3_sync_done; 13922d1661a5SPawel Jakub Dawidek bp->bio_data = disk->d_sync.ds_data; 13932d1661a5SPawel Jakub Dawidek if (bp->bio_data == NULL) { 13942d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 13952d1661a5SPawel Jakub Dawidek return; 13962d1661a5SPawel Jakub Dawidek } 13972d1661a5SPawel Jakub Dawidek bp->bio_cflags = G_RAID3_BIO_CFLAG_REGSYNC; 13982d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset += bp->bio_length / (sc->sc_ndisks - 1); 13992d1661a5SPawel Jakub Dawidek bp->bio_to = sc->sc_provider; 14002d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Sending synchronization request."); 140179e61493SPawel Jakub Dawidek disk->d_sync.ds_consumer->index++; 14022d1661a5SPawel Jakub Dawidek g_io_request(bp, disk->d_sync.ds_consumer); 14032d1661a5SPawel Jakub Dawidek } 14042d1661a5SPawel Jakub Dawidek 14052d1661a5SPawel Jakub Dawidek static void 14062d1661a5SPawel Jakub Dawidek g_raid3_sync_request(struct bio *bp) 14072d1661a5SPawel Jakub Dawidek { 14082d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 14092d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 14102d1661a5SPawel Jakub Dawidek 141179e61493SPawel Jakub Dawidek bp->bio_from->index--; 14122d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 14132d1661a5SPawel Jakub Dawidek disk = bp->bio_from->private; 14142d1661a5SPawel Jakub Dawidek if (disk == NULL) { 14152d1661a5SPawel Jakub Dawidek g_topology_lock(); 14162d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, bp->bio_from); 14172d1661a5SPawel Jakub Dawidek g_topology_unlock(); 14182d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 14192d1661a5SPawel Jakub Dawidek return; 14202d1661a5SPawel Jakub Dawidek } 14212d1661a5SPawel Jakub Dawidek 14222d1661a5SPawel Jakub Dawidek /* 14232d1661a5SPawel Jakub Dawidek * Synchronization request. 14242d1661a5SPawel Jakub Dawidek */ 14252d1661a5SPawel Jakub Dawidek switch (bp->bio_cmd) { 14262d1661a5SPawel Jakub Dawidek case BIO_READ: 14272d1661a5SPawel Jakub Dawidek { 14282d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 14292d1661a5SPawel Jakub Dawidek u_char *dst, *src; 14302d1661a5SPawel Jakub Dawidek off_t left; 14312d1661a5SPawel Jakub Dawidek u_int atom; 14322d1661a5SPawel Jakub Dawidek 14332d1661a5SPawel Jakub Dawidek if (bp->bio_error != 0) { 14342d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, bp, 14352d1661a5SPawel Jakub Dawidek "Synchronization request failed (error=%d).", 14362d1661a5SPawel Jakub Dawidek bp->bio_error); 14372d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 14382d1661a5SPawel Jakub Dawidek return; 14392d1661a5SPawel Jakub Dawidek } 14402d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request finished."); 14412d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 14422d1661a5SPawel Jakub Dawidek dst = src = bp->bio_data; 14432d1661a5SPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) { 14442d1661a5SPawel Jakub Dawidek u_int n; 14452d1661a5SPawel Jakub Dawidek 14462d1661a5SPawel Jakub Dawidek /* Parity component. */ 14472d1661a5SPawel Jakub Dawidek for (left = bp->bio_length; left > 0; 14482d1661a5SPawel Jakub Dawidek left -= sc->sc_sectorsize) { 14492d1661a5SPawel Jakub Dawidek bcopy(src, dst, atom); 14502d1661a5SPawel Jakub Dawidek src += atom; 14512d1661a5SPawel Jakub Dawidek for (n = 1; n < sc->sc_ndisks - 1; n++) { 14522d1661a5SPawel Jakub Dawidek g_raid3_xor(src, dst, dst, atom); 14532d1661a5SPawel Jakub Dawidek src += atom; 14542d1661a5SPawel Jakub Dawidek } 14552d1661a5SPawel Jakub Dawidek dst += atom; 14562d1661a5SPawel Jakub Dawidek } 14572d1661a5SPawel Jakub Dawidek } else { 14582d1661a5SPawel Jakub Dawidek /* Regular component. */ 14592d1661a5SPawel Jakub Dawidek src += atom * disk->d_no; 14602d1661a5SPawel Jakub Dawidek for (left = bp->bio_length; left > 0; 14612d1661a5SPawel Jakub Dawidek left -= sc->sc_sectorsize) { 14622d1661a5SPawel Jakub Dawidek bcopy(src, dst, atom); 14632d1661a5SPawel Jakub Dawidek src += sc->sc_sectorsize; 14642d1661a5SPawel Jakub Dawidek dst += atom; 14652d1661a5SPawel Jakub Dawidek } 14662d1661a5SPawel Jakub Dawidek } 14672d1661a5SPawel Jakub Dawidek bp->bio_offset /= sc->sc_ndisks - 1; 14682d1661a5SPawel Jakub Dawidek bp->bio_length /= sc->sc_ndisks - 1; 14692d1661a5SPawel Jakub Dawidek bp->bio_cmd = BIO_WRITE; 14702d1661a5SPawel Jakub Dawidek bp->bio_cflags = 0; 14712d1661a5SPawel Jakub Dawidek bp->bio_children = bp->bio_inbed = 0; 14722d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 1473d97d5ee9SPawel Jakub Dawidek KASSERT(cp->acr == 1 && cp->acw == 1 && cp->ace == 1, 14742d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 14752d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 147679e61493SPawel Jakub Dawidek cp->index++; 14772d1661a5SPawel Jakub Dawidek g_io_request(bp, cp); 14782d1661a5SPawel Jakub Dawidek return; 14792d1661a5SPawel Jakub Dawidek } 14802d1661a5SPawel Jakub Dawidek case BIO_WRITE: 1481d2fb9c62SPawel Jakub Dawidek { 1482d2fb9c62SPawel Jakub Dawidek struct g_raid3_disk_sync *sync; 1483d2fb9c62SPawel Jakub Dawidek 14842d1661a5SPawel Jakub Dawidek if (bp->bio_error != 0) { 14852d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, bp, 14862d1661a5SPawel Jakub Dawidek "Synchronization request failed (error=%d).", 14872d1661a5SPawel Jakub Dawidek bp->bio_error); 14882d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 1489ea973705SPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 14902d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 14912d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 14922d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 14932d1661a5SPawel Jakub Dawidek return; 14942d1661a5SPawel Jakub Dawidek } 14952d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request finished."); 1496d2fb9c62SPawel Jakub Dawidek sync = &disk->d_sync; 1497d2fb9c62SPawel Jakub Dawidek sync->ds_offset_done = bp->bio_offset + bp->bio_length; 14982d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 1499d2fb9c62SPawel Jakub Dawidek if (sync->ds_resync != -1) 1500d2fb9c62SPawel Jakub Dawidek return; 1501d2fb9c62SPawel Jakub Dawidek if (sync->ds_offset_done == 1502c0d68b6eSPawel Jakub Dawidek sc->sc_mediasize / (sc->sc_ndisks - 1)) { 15032d1661a5SPawel Jakub Dawidek /* 15042d1661a5SPawel Jakub Dawidek * Disk up-to-date, activate it. 15052d1661a5SPawel Jakub Dawidek */ 15062d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_ACTIVE, 15072d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 15082d1661a5SPawel Jakub Dawidek return; 1509604fce4fSPawel Jakub Dawidek } else if (sync->ds_offset_done % (MAXPHYS * 100) == 0) { 15102d1661a5SPawel Jakub Dawidek /* 15112d1661a5SPawel Jakub Dawidek * Update offset_done on every 100 blocks. 15122d1661a5SPawel Jakub Dawidek * XXX: This should be configurable. 15132d1661a5SPawel Jakub Dawidek */ 15142d1661a5SPawel Jakub Dawidek g_topology_lock(); 15152d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 15162d1661a5SPawel Jakub Dawidek g_topology_unlock(); 15172d1661a5SPawel Jakub Dawidek } 15182d1661a5SPawel Jakub Dawidek return; 1519d2fb9c62SPawel Jakub Dawidek } 15202d1661a5SPawel Jakub Dawidek default: 15212d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Invalid command here: %u (device=%s)", 15222d1661a5SPawel Jakub Dawidek bp->bio_cmd, sc->sc_name)); 15232d1661a5SPawel Jakub Dawidek break; 15242d1661a5SPawel Jakub Dawidek } 15252d1661a5SPawel Jakub Dawidek } 15262d1661a5SPawel Jakub Dawidek 15272d1661a5SPawel Jakub Dawidek static int 15282d1661a5SPawel Jakub Dawidek g_raid3_register_request(struct bio *pbp) 15292d1661a5SPawel Jakub Dawidek { 15302d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 15312d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 15322d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 15332d1661a5SPawel Jakub Dawidek struct bio *cbp; 15342d1661a5SPawel Jakub Dawidek off_t offset, length; 1535fa6a7837SDavid E. O'Brien u_int n, ndisks; 1536dba915cfSPawel Jakub Dawidek int round_robin, verify; 15372d1661a5SPawel Jakub Dawidek 1538fa6a7837SDavid E. O'Brien ndisks = 0; 15392d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 15402d1661a5SPawel Jakub Dawidek if ((pbp->bio_cflags & G_RAID3_BIO_CFLAG_REGSYNC) != 0 && 15412d1661a5SPawel Jakub Dawidek sc->sc_syncdisk == NULL) { 15422d1661a5SPawel Jakub Dawidek g_io_deliver(pbp, EIO); 15432d1661a5SPawel Jakub Dawidek return (0); 15442d1661a5SPawel Jakub Dawidek } 15452d1661a5SPawel Jakub Dawidek g_raid3_init_bio(pbp); 15462d1661a5SPawel Jakub Dawidek length = pbp->bio_length / (sc->sc_ndisks - 1); 15472d1661a5SPawel Jakub Dawidek offset = pbp->bio_offset / (sc->sc_ndisks - 1); 1548dba915cfSPawel Jakub Dawidek round_robin = verify = 0; 15492d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 15502d1661a5SPawel Jakub Dawidek case BIO_READ: 1551dba915cfSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 1552dba915cfSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 1553dba915cfSPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_VERIFY; 1554dba915cfSPawel Jakub Dawidek verify = 1; 1555dba915cfSPawel Jakub Dawidek ndisks = sc->sc_ndisks; 1556dba915cfSPawel Jakub Dawidek } else { 1557dba915cfSPawel Jakub Dawidek verify = 0; 15582d1661a5SPawel Jakub Dawidek ndisks = sc->sc_ndisks - 1; 1559dba915cfSPawel Jakub Dawidek } 1560dba915cfSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0 && 1561dba915cfSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 1562dba915cfSPawel Jakub Dawidek round_robin = 1; 1563dba915cfSPawel Jakub Dawidek } else { 1564dba915cfSPawel Jakub Dawidek round_robin = 0; 1565dba915cfSPawel Jakub Dawidek } 1566dba915cfSPawel Jakub Dawidek KASSERT(!round_robin || !verify, 1567dba915cfSPawel Jakub Dawidek ("ROUND-ROBIN and VERIFY are mutually exclusive.")); 1568f5a2f7feSPawel Jakub Dawidek pbp->bio_driver2 = &sc->sc_disks[sc->sc_ndisks - 1]; 15692d1661a5SPawel Jakub Dawidek break; 15702d1661a5SPawel Jakub Dawidek case BIO_WRITE: 15712d1661a5SPawel Jakub Dawidek case BIO_DELETE: 1572d2fb9c62SPawel Jakub Dawidek { 1573d2fb9c62SPawel Jakub Dawidek struct g_raid3_disk_sync *sync; 1574d2fb9c62SPawel Jakub Dawidek 15754d006a98SPawel Jakub Dawidek if (sc->sc_idle) 15764d006a98SPawel Jakub Dawidek g_raid3_unidle(sc); 15770962f942SPawel Jakub Dawidek else 157801f1f41cSPawel Jakub Dawidek sc->sc_last_write = time_uptime; 15794d006a98SPawel Jakub Dawidek 15802d1661a5SPawel Jakub Dawidek ndisks = sc->sc_ndisks; 1581d2fb9c62SPawel Jakub Dawidek 1582d2fb9c62SPawel Jakub Dawidek if (sc->sc_syncdisk == NULL) 15832d1661a5SPawel Jakub Dawidek break; 1584d2fb9c62SPawel Jakub Dawidek sync = &sc->sc_syncdisk->d_sync; 1585d2fb9c62SPawel Jakub Dawidek if (offset >= sync->ds_offset) 1586d2fb9c62SPawel Jakub Dawidek break; 1587d2fb9c62SPawel Jakub Dawidek if (offset + length <= sync->ds_offset_done) 1588d2fb9c62SPawel Jakub Dawidek break; 1589d2fb9c62SPawel Jakub Dawidek if (offset >= sync->ds_resync && sync->ds_resync != -1) 1590d2fb9c62SPawel Jakub Dawidek break; 1591604fce4fSPawel Jakub Dawidek sync->ds_resync = offset - (offset % MAXPHYS); 1592d2fb9c62SPawel Jakub Dawidek break; 1593d2fb9c62SPawel Jakub Dawidek } 15942d1661a5SPawel Jakub Dawidek } 15952d1661a5SPawel Jakub Dawidek for (n = 0; n < ndisks; n++) { 15962d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 15972d1661a5SPawel Jakub Dawidek cbp = g_raid3_clone_bio(sc, pbp); 15982d1661a5SPawel Jakub Dawidek if (cbp == NULL) { 15992d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) 16002d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 1601a65a0da2SPawel Jakub Dawidek /* 1602a65a0da2SPawel Jakub Dawidek * To prevent deadlock, we must run back up 1603a65a0da2SPawel Jakub Dawidek * with the ENOMEM for failed requests of any 1604a65a0da2SPawel Jakub Dawidek * of our consumers. Our own sync requests 1605a65a0da2SPawel Jakub Dawidek * can stick around, as they are finite. 1606a65a0da2SPawel Jakub Dawidek */ 1607a65a0da2SPawel Jakub Dawidek if ((pbp->bio_cflags & 1608a65a0da2SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_REGULAR) != 0) { 1609a65a0da2SPawel Jakub Dawidek g_io_deliver(pbp, ENOMEM); 1610a65a0da2SPawel Jakub Dawidek return (0); 1611a65a0da2SPawel Jakub Dawidek } 16122d1661a5SPawel Jakub Dawidek return (ENOMEM); 16132d1661a5SPawel Jakub Dawidek } 16142d1661a5SPawel Jakub Dawidek cbp->bio_offset = offset; 16152d1661a5SPawel Jakub Dawidek cbp->bio_length = length; 16162d1661a5SPawel Jakub Dawidek cbp->bio_done = g_raid3_done; 16172d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 16182d1661a5SPawel Jakub Dawidek case BIO_READ: 16192d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { 16202d1661a5SPawel Jakub Dawidek /* 16212d1661a5SPawel Jakub Dawidek * Replace invalid component with the parity 16222d1661a5SPawel Jakub Dawidek * component. 16232d1661a5SPawel Jakub Dawidek */ 16242d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 16252d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 16262d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 1627f5a2f7feSPawel Jakub Dawidek } else if (round_robin && 1628f5a2f7feSPawel Jakub Dawidek disk->d_no == sc->sc_round_robin) { 1629f5a2f7feSPawel Jakub Dawidek /* 1630f5a2f7feSPawel Jakub Dawidek * In round-robin mode skip one data component 1631f5a2f7feSPawel Jakub Dawidek * and use parity component when reading. 1632f5a2f7feSPawel Jakub Dawidek */ 1633f5a2f7feSPawel Jakub Dawidek pbp->bio_driver2 = disk; 1634f5a2f7feSPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 1635f5a2f7feSPawel Jakub Dawidek cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 1636f5a2f7feSPawel Jakub Dawidek sc->sc_round_robin++; 1637f5a2f7feSPawel Jakub Dawidek round_robin = 0; 1638dba915cfSPawel Jakub Dawidek } else if (verify && disk->d_no == sc->sc_ndisks - 1) { 1639dba915cfSPawel Jakub Dawidek cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 16402d1661a5SPawel Jakub Dawidek } 16412d1661a5SPawel Jakub Dawidek break; 16422d1661a5SPawel Jakub Dawidek case BIO_WRITE: 16432d1661a5SPawel Jakub Dawidek case BIO_DELETE: 16442d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 16452d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 16462d1661a5SPawel Jakub Dawidek if (n == ndisks - 1) { 16472d1661a5SPawel Jakub Dawidek /* 16482d1661a5SPawel Jakub Dawidek * Active parity component, mark it as such. 16492d1661a5SPawel Jakub Dawidek */ 16502d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= 16512d1661a5SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_PARITY; 16522d1661a5SPawel Jakub Dawidek } 16532d1661a5SPawel Jakub Dawidek } else { 16542d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 16552d1661a5SPawel Jakub Dawidek if (n == ndisks - 1) { 16562d1661a5SPawel Jakub Dawidek /* 16572d1661a5SPawel Jakub Dawidek * Parity component is not connected, 16582d1661a5SPawel Jakub Dawidek * so destroy its request. 16592d1661a5SPawel Jakub Dawidek */ 16602d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= 16612d1661a5SPawel Jakub Dawidek G_RAID3_BIO_PFLAG_NOPARITY; 16622d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 16632d1661a5SPawel Jakub Dawidek cbp = NULL; 16642d1661a5SPawel Jakub Dawidek } else { 16652d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= 16662d1661a5SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_NODISK; 16672d1661a5SPawel Jakub Dawidek disk = NULL; 16682d1661a5SPawel Jakub Dawidek } 16692d1661a5SPawel Jakub Dawidek } 16702d1661a5SPawel Jakub Dawidek break; 16712d1661a5SPawel Jakub Dawidek } 16722d1661a5SPawel Jakub Dawidek if (cbp != NULL) 16732d1661a5SPawel Jakub Dawidek cbp->bio_caller2 = disk; 16742d1661a5SPawel Jakub Dawidek } 16752d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 16762d1661a5SPawel Jakub Dawidek case BIO_READ: 1677f5a2f7feSPawel Jakub Dawidek if (round_robin) { 1678f5a2f7feSPawel Jakub Dawidek /* 1679f5a2f7feSPawel Jakub Dawidek * If we are in round-robin mode and 'round_robin' is 1680f5a2f7feSPawel Jakub Dawidek * still 1, it means, that we skipped parity component 1681f5a2f7feSPawel Jakub Dawidek * for this read and must reset sc_round_robin field. 1682f5a2f7feSPawel Jakub Dawidek */ 1683f5a2f7feSPawel Jakub Dawidek sc->sc_round_robin = 0; 1684f5a2f7feSPawel Jakub Dawidek } 16852d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 16862d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 16872d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 16882d1661a5SPawel Jakub Dawidek cbp->bio_to = cp->provider; 16892d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Sending request."); 1690d97d5ee9SPawel Jakub Dawidek KASSERT(cp->acr == 1 && cp->acw == 1 && cp->ace == 1, 16912d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", 16922d1661a5SPawel Jakub Dawidek cp->provider->name, cp->acr, cp->acw, cp->ace)); 169379e61493SPawel Jakub Dawidek cp->index++; 16942d1661a5SPawel Jakub Dawidek g_io_request(cbp, cp); 16952d1661a5SPawel Jakub Dawidek } 16962d1661a5SPawel Jakub Dawidek break; 16972d1661a5SPawel Jakub Dawidek case BIO_WRITE: 16982d1661a5SPawel Jakub Dawidek case BIO_DELETE: 16992d1661a5SPawel Jakub Dawidek /* 17002d1661a5SPawel Jakub Dawidek * Bump syncid on first write. 17012d1661a5SPawel Jakub Dawidek */ 1702ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_SYNCID) != 0) { 1703a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_SYNCID; 17042d1661a5SPawel Jakub Dawidek g_topology_lock(); 1705d97d5ee9SPawel Jakub Dawidek g_raid3_bump_syncid(sc); 17062d1661a5SPawel Jakub Dawidek g_topology_unlock(); 17072d1661a5SPawel Jakub Dawidek } 17082d1661a5SPawel Jakub Dawidek g_raid3_scatter(pbp); 17092d1661a5SPawel Jakub Dawidek break; 17102d1661a5SPawel Jakub Dawidek } 17112d1661a5SPawel Jakub Dawidek return (0); 17122d1661a5SPawel Jakub Dawidek } 17132d1661a5SPawel Jakub Dawidek 17142d1661a5SPawel Jakub Dawidek static int 17152d1661a5SPawel Jakub Dawidek g_raid3_can_destroy(struct g_raid3_softc *sc) 17162d1661a5SPawel Jakub Dawidek { 17172d1661a5SPawel Jakub Dawidek struct g_geom *gp; 17182d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 17192d1661a5SPawel Jakub Dawidek 17202d1661a5SPawel Jakub Dawidek g_topology_assert(); 17212d1661a5SPawel Jakub Dawidek gp = sc->sc_geom; 17222d1661a5SPawel Jakub Dawidek LIST_FOREACH(cp, &gp->consumer, consumer) { 17232d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 17242d1661a5SPawel Jakub Dawidek return (0); 17252d1661a5SPawel Jakub Dawidek } 17262d1661a5SPawel Jakub Dawidek gp = sc->sc_sync.ds_geom; 17272d1661a5SPawel Jakub Dawidek LIST_FOREACH(cp, &gp->consumer, consumer) { 17282d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 17292d1661a5SPawel Jakub Dawidek return (0); 17302d1661a5SPawel Jakub Dawidek } 17312d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "No I/O requests for %s, it can be destroyed.", 17322d1661a5SPawel Jakub Dawidek sc->sc_name); 17332d1661a5SPawel Jakub Dawidek return (1); 17342d1661a5SPawel Jakub Dawidek } 17352d1661a5SPawel Jakub Dawidek 17362d1661a5SPawel Jakub Dawidek static int 17372d1661a5SPawel Jakub Dawidek g_raid3_try_destroy(struct g_raid3_softc *sc) 17382d1661a5SPawel Jakub Dawidek { 17392d1661a5SPawel Jakub Dawidek 17404ed854e8SPawel Jakub Dawidek if (sc->sc_rootmount != NULL) { 17414ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", __LINE__, 17424ed854e8SPawel Jakub Dawidek sc->sc_rootmount); 17434ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 17444ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 17454ed854e8SPawel Jakub Dawidek } 17464ed854e8SPawel Jakub Dawidek 17472d1661a5SPawel Jakub Dawidek g_topology_lock(); 17482d1661a5SPawel Jakub Dawidek if (!g_raid3_can_destroy(sc)) { 17492d1661a5SPawel Jakub Dawidek g_topology_unlock(); 17502d1661a5SPawel Jakub Dawidek return (0); 17512d1661a5SPawel Jakub Dawidek } 1752a245a548SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_WAIT) != 0) { 17532d1661a5SPawel Jakub Dawidek g_topology_unlock(); 17542d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, 17552d1661a5SPawel Jakub Dawidek &sc->sc_worker); 17562d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_worker); 17572d1661a5SPawel Jakub Dawidek sc->sc_worker = NULL; 17582d1661a5SPawel Jakub Dawidek } else { 17592d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(sc); 17602d1661a5SPawel Jakub Dawidek g_topology_unlock(); 17612d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 17622d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 17632d1661a5SPawel Jakub Dawidek } 17642d1661a5SPawel Jakub Dawidek return (1); 17652d1661a5SPawel Jakub Dawidek } 17662d1661a5SPawel Jakub Dawidek 17672d1661a5SPawel Jakub Dawidek /* 17682d1661a5SPawel Jakub Dawidek * Worker thread. 17692d1661a5SPawel Jakub Dawidek */ 17702d1661a5SPawel Jakub Dawidek static void 17712d1661a5SPawel Jakub Dawidek g_raid3_worker(void *arg) 17722d1661a5SPawel Jakub Dawidek { 17732d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 17742d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 1775d2fb9c62SPawel Jakub Dawidek struct g_raid3_disk_sync *sync; 17762d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 17772d1661a5SPawel Jakub Dawidek struct bio *bp; 17782d1661a5SPawel Jakub Dawidek u_int nreqs; 17790962f942SPawel Jakub Dawidek int timeout; 17802d1661a5SPawel Jakub Dawidek 17812d1661a5SPawel Jakub Dawidek sc = arg; 178263710c4dSJohn Baldwin mtx_lock_spin(&sched_lock); 178363710c4dSJohn Baldwin sched_prio(curthread, PRIBIO); 178463710c4dSJohn Baldwin mtx_unlock_spin(&sched_lock); 17852d1661a5SPawel Jakub Dawidek 17862d1661a5SPawel Jakub Dawidek nreqs = 0; 17872d1661a5SPawel Jakub Dawidek for (;;) { 17882d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: Let's see...", __func__); 17892d1661a5SPawel Jakub Dawidek /* 17902d1661a5SPawel Jakub Dawidek * First take a look at events. 17912d1661a5SPawel Jakub Dawidek * This is important to handle events before any I/O requests. 17922d1661a5SPawel Jakub Dawidek */ 17932d1661a5SPawel Jakub Dawidek ep = g_raid3_event_get(sc); 1794d97d5ee9SPawel Jakub Dawidek if (ep != NULL && g_topology_try_lock()) { 1795d97d5ee9SPawel Jakub Dawidek g_raid3_event_remove(sc, ep); 17962d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DEVICE) != 0) { 17972d1661a5SPawel Jakub Dawidek /* Update only device status. */ 17982d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, 17992d1661a5SPawel Jakub Dawidek "Running event for device %s.", 18002d1661a5SPawel Jakub Dawidek sc->sc_name); 18012d1661a5SPawel Jakub Dawidek ep->e_error = 0; 1802d97d5ee9SPawel Jakub Dawidek g_raid3_update_device(sc, 1); 18032d1661a5SPawel Jakub Dawidek } else { 18042d1661a5SPawel Jakub Dawidek /* Update disk status. */ 18052d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "Running event for disk %s.", 18062d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(ep->e_disk)); 18072d1661a5SPawel Jakub Dawidek ep->e_error = g_raid3_update_disk(ep->e_disk, 1808d97d5ee9SPawel Jakub Dawidek ep->e_state); 18092d1661a5SPawel Jakub Dawidek if (ep->e_error == 0) 1810d97d5ee9SPawel Jakub Dawidek g_raid3_update_device(sc, 0); 18112d1661a5SPawel Jakub Dawidek } 18122d1661a5SPawel Jakub Dawidek g_topology_unlock(); 18132d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) { 18142d1661a5SPawel Jakub Dawidek KASSERT(ep->e_error == 0, 18152d1661a5SPawel Jakub Dawidek ("Error cannot be handled.")); 18162d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 18172d1661a5SPawel Jakub Dawidek } else { 18182d1661a5SPawel Jakub Dawidek ep->e_flags |= G_RAID3_EVENT_DONE; 18192d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, 18202d1661a5SPawel Jakub Dawidek ep); 18212d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 18222d1661a5SPawel Jakub Dawidek wakeup(ep); 18232d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 18242d1661a5SPawel Jakub Dawidek } 18252d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 18262d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 18272d1661a5SPawel Jakub Dawidek if (g_raid3_try_destroy(sc)) 18282d1661a5SPawel Jakub Dawidek kthread_exit(0); 18292d1661a5SPawel Jakub Dawidek } 18302d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 1.", __func__); 18312d1661a5SPawel Jakub Dawidek continue; 18322d1661a5SPawel Jakub Dawidek } 18332d1661a5SPawel Jakub Dawidek /* 18340962f942SPawel Jakub Dawidek * Check if we can mark array as CLEAN and if we can't take 18350962f942SPawel Jakub Dawidek * how much seconds should we wait. 18360962f942SPawel Jakub Dawidek */ 18370962f942SPawel Jakub Dawidek timeout = g_raid3_idle(sc, 0); 18380962f942SPawel Jakub Dawidek /* 18392d1661a5SPawel Jakub Dawidek * Now I/O requests. 18402d1661a5SPawel Jakub Dawidek */ 18412d1661a5SPawel Jakub Dawidek /* Get first request from the queue. */ 18422d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 18432d1661a5SPawel Jakub Dawidek bp = bioq_first(&sc->sc_queue); 18442d1661a5SPawel Jakub Dawidek if (bp == NULL) { 1845d97d5ee9SPawel Jakub Dawidek if (ep != NULL) { 1846d97d5ee9SPawel Jakub Dawidek /* 1847d97d5ee9SPawel Jakub Dawidek * No I/O requests and topology lock was 1848d97d5ee9SPawel Jakub Dawidek * already held? Try again. 1849d97d5ee9SPawel Jakub Dawidek */ 1850d97d5ee9SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 18517f456a7dSPawel Jakub Dawidek tsleep(ep, PRIBIO, "r3:top1", hz / 5); 1852d97d5ee9SPawel Jakub Dawidek continue; 1853d97d5ee9SPawel Jakub Dawidek } 18542d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 18552d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 18562d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 18572d1661a5SPawel Jakub Dawidek if (g_raid3_try_destroy(sc)) 18582d1661a5SPawel Jakub Dawidek kthread_exit(0); 18592d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 18602d1661a5SPawel Jakub Dawidek } 18612d1661a5SPawel Jakub Dawidek } 18622d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL && 18632d1661a5SPawel Jakub Dawidek (bp == NULL || nreqs > g_raid3_reqs_per_sync)) { 18642d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 18652d1661a5SPawel Jakub Dawidek /* 18662d1661a5SPawel Jakub Dawidek * It is time for synchronization... 18672d1661a5SPawel Jakub Dawidek */ 18682d1661a5SPawel Jakub Dawidek nreqs = 0; 18692d1661a5SPawel Jakub Dawidek disk = sc->sc_syncdisk; 1870d2fb9c62SPawel Jakub Dawidek sync = &disk->d_sync; 1871d2fb9c62SPawel Jakub Dawidek if (sync->ds_offset < 1872c0d68b6eSPawel Jakub Dawidek sc->sc_mediasize / (sc->sc_ndisks - 1) && 1873d2fb9c62SPawel Jakub Dawidek sync->ds_offset == sync->ds_offset_done) { 1874d2fb9c62SPawel Jakub Dawidek if (sync->ds_resync != -1) { 1875d2fb9c62SPawel Jakub Dawidek sync->ds_offset = sync->ds_resync; 1876d2fb9c62SPawel Jakub Dawidek sync->ds_offset_done = sync->ds_resync; 1877d2fb9c62SPawel Jakub Dawidek sync->ds_resync = -1; 1878d2fb9c62SPawel Jakub Dawidek } 18792d1661a5SPawel Jakub Dawidek g_raid3_sync_one(sc); 18802d1661a5SPawel Jakub Dawidek } 18812d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 2.", __func__); 18822d1661a5SPawel Jakub Dawidek goto sleep; 18832d1661a5SPawel Jakub Dawidek } 18842d1661a5SPawel Jakub Dawidek if (bp == NULL) { 18850962f942SPawel Jakub Dawidek MSLEEP(sc, &sc->sc_queue_mtx, PRIBIO | PDROP, "r3:w1", 18860962f942SPawel Jakub Dawidek timeout * hz); 18879bb09163SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 4.", __func__); 18882d1661a5SPawel Jakub Dawidek continue; 18892d1661a5SPawel Jakub Dawidek } 18902d1661a5SPawel Jakub Dawidek nreqs++; 18912d1661a5SPawel Jakub Dawidek bioq_remove(&sc->sc_queue, bp); 18922d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 18932d1661a5SPawel Jakub Dawidek 18942d1661a5SPawel Jakub Dawidek if ((bp->bio_cflags & G_RAID3_BIO_CFLAG_REGULAR) != 0) { 18952d1661a5SPawel Jakub Dawidek g_raid3_regular_request(bp); 18962d1661a5SPawel Jakub Dawidek } else if ((bp->bio_cflags & G_RAID3_BIO_CFLAG_SYNC) != 0) { 18972d1661a5SPawel Jakub Dawidek u_int timeout, sps; 18982d1661a5SPawel Jakub Dawidek 18992d1661a5SPawel Jakub Dawidek g_raid3_sync_request(bp); 19002d1661a5SPawel Jakub Dawidek sleep: 19012d1661a5SPawel Jakub Dawidek sps = atomic_load_acq_int(&g_raid3_syncs_per_sec); 19022d1661a5SPawel Jakub Dawidek if (sps == 0) { 1903d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 6.", __func__); 1904d97d5ee9SPawel Jakub Dawidek continue; 1905d97d5ee9SPawel Jakub Dawidek } 1906d97d5ee9SPawel Jakub Dawidek if (ep != NULL) { 1907d97d5ee9SPawel Jakub Dawidek /* 1908d97d5ee9SPawel Jakub Dawidek * We have some pending events, don't sleep now. 1909d97d5ee9SPawel Jakub Dawidek */ 1910d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 7.", __func__); 19117f456a7dSPawel Jakub Dawidek tsleep(ep, PRIBIO, "r3:top2", hz / 5); 19122d1661a5SPawel Jakub Dawidek continue; 19132d1661a5SPawel Jakub Dawidek } 19142d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 19152d1661a5SPawel Jakub Dawidek if (bioq_first(&sc->sc_queue) != NULL) { 19162d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 1917d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 8.", __func__); 19182d1661a5SPawel Jakub Dawidek continue; 19192d1661a5SPawel Jakub Dawidek } 19202d1661a5SPawel Jakub Dawidek timeout = hz / sps; 19212d1661a5SPawel Jakub Dawidek if (timeout == 0) 19222d1661a5SPawel Jakub Dawidek timeout = 1; 19232d1661a5SPawel Jakub Dawidek MSLEEP(sc, &sc->sc_queue_mtx, PRIBIO | PDROP, "r3:w2", 19242d1661a5SPawel Jakub Dawidek timeout); 19252d1661a5SPawel Jakub Dawidek } else { 19262d1661a5SPawel Jakub Dawidek if (g_raid3_register_request(bp) != 0) { 19272d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 19282d1661a5SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_queue, bp); 19292d1661a5SPawel Jakub Dawidek MSLEEP(&sc->sc_queue, &sc->sc_queue_mtx, 19302d1661a5SPawel Jakub Dawidek PRIBIO | PDROP, "r3:lowmem", hz / 10); 19312d1661a5SPawel Jakub Dawidek } 19322d1661a5SPawel Jakub Dawidek } 1933d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 9.", __func__); 19342d1661a5SPawel Jakub Dawidek } 19352d1661a5SPawel Jakub Dawidek } 19362d1661a5SPawel Jakub Dawidek 19372d1661a5SPawel Jakub Dawidek static void 19380962f942SPawel Jakub Dawidek g_raid3_update_idle(struct g_raid3_softc *sc, struct g_raid3_disk *disk) 19392d1661a5SPawel Jakub Dawidek { 19402d1661a5SPawel Jakub Dawidek 19412d1661a5SPawel Jakub Dawidek g_topology_assert(); 19420962f942SPawel Jakub Dawidek if (!sc->sc_idle && (disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) == 0) { 19432d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as dirty.", 19442d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), disk->d_softc->sc_name); 19452d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 19460962f942SPawel Jakub Dawidek } else if (sc->sc_idle && 19470962f942SPawel Jakub Dawidek (disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) != 0) { 19482d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as clean.", 19492d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), disk->d_softc->sc_name); 19502d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 19512d1661a5SPawel Jakub Dawidek } 19522d1661a5SPawel Jakub Dawidek } 19532d1661a5SPawel Jakub Dawidek 19542d1661a5SPawel Jakub Dawidek static void 19552d1661a5SPawel Jakub Dawidek g_raid3_sync_start(struct g_raid3_softc *sc) 19562d1661a5SPawel Jakub Dawidek { 19572d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 19582d1661a5SPawel Jakub Dawidek int error; 19592d1661a5SPawel Jakub Dawidek u_int n; 19602d1661a5SPawel Jakub Dawidek 19612d1661a5SPawel Jakub Dawidek g_topology_assert(); 19622d1661a5SPawel Jakub Dawidek 19632d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 19642d1661a5SPawel Jakub Dawidek ("Device not in DEGRADED state (%s, %u).", sc->sc_name, 19652d1661a5SPawel Jakub Dawidek sc->sc_state)); 19662d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_syncdisk == NULL, ("Syncdisk is not NULL (%s, %u).", 19672d1661a5SPawel Jakub Dawidek sc->sc_name, sc->sc_state)); 19682d1661a5SPawel Jakub Dawidek disk = NULL; 19692d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 19702d1661a5SPawel Jakub Dawidek if (sc->sc_disks[n].d_state != G_RAID3_DISK_STATE_SYNCHRONIZING) 19712d1661a5SPawel Jakub Dawidek continue; 19722d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 19732d1661a5SPawel Jakub Dawidek break; 19742d1661a5SPawel Jakub Dawidek } 19752d1661a5SPawel Jakub Dawidek if (disk == NULL) 19762d1661a5SPawel Jakub Dawidek return; 19772d1661a5SPawel Jakub Dawidek 19782d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s.", sc->sc_name, 19792d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 19802d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 19812d1661a5SPawel Jakub Dawidek KASSERT(disk->d_sync.ds_consumer == NULL, 19822d1661a5SPawel Jakub Dawidek ("Sync consumer already exists (device=%s, disk=%s).", 19832d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk))); 19842d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = g_new_consumer(sc->sc_sync.ds_geom); 19852d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer->private = disk; 198679e61493SPawel Jakub Dawidek disk->d_sync.ds_consumer->index = 0; 19872d1661a5SPawel Jakub Dawidek error = g_attach(disk->d_sync.ds_consumer, disk->d_softc->sc_provider); 19882d1661a5SPawel Jakub Dawidek KASSERT(error == 0, ("Cannot attach to %s (error=%d).", 19892d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, error)); 19902d1661a5SPawel Jakub Dawidek error = g_access(disk->d_sync.ds_consumer, 1, 0, 0); 19912d1661a5SPawel Jakub Dawidek KASSERT(error == 0, ("Cannot open %s (error=%d).", 19922d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, error)); 1993604fce4fSPawel Jakub Dawidek disk->d_sync.ds_data = malloc(MAXPHYS, M_RAID3, M_WAITOK); 19942d1661a5SPawel Jakub Dawidek sc->sc_syncdisk = disk; 19952d1661a5SPawel Jakub Dawidek } 19962d1661a5SPawel Jakub Dawidek 19972d1661a5SPawel Jakub Dawidek /* 19982d1661a5SPawel Jakub Dawidek * Stop synchronization process. 19992d1661a5SPawel Jakub Dawidek * type: 0 - synchronization finished 20002d1661a5SPawel Jakub Dawidek * 1 - synchronization stopped 20012d1661a5SPawel Jakub Dawidek */ 20022d1661a5SPawel Jakub Dawidek static void 20032d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(struct g_raid3_softc *sc, int type) 20042d1661a5SPawel Jakub Dawidek { 20052d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 20062d1661a5SPawel Jakub Dawidek 20072d1661a5SPawel Jakub Dawidek g_topology_assert(); 20082d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 20092d1661a5SPawel Jakub Dawidek ("Device not in DEGRADED state (%s, %u).", sc->sc_name, 20102d1661a5SPawel Jakub Dawidek sc->sc_state)); 20112d1661a5SPawel Jakub Dawidek disk = sc->sc_syncdisk; 20122d1661a5SPawel Jakub Dawidek sc->sc_syncdisk = NULL; 20132d1661a5SPawel Jakub Dawidek KASSERT(disk != NULL, ("No disk was synchronized (%s).", sc->sc_name)); 20142d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 20152d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 20162d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 20172d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_consumer == NULL) 20182d1661a5SPawel Jakub Dawidek return; 20192d1661a5SPawel Jakub Dawidek 20202d1661a5SPawel Jakub Dawidek if (type == 0) { 20212d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s finished.", 20222d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, g_raid3_get_diskname(disk)); 20232d1661a5SPawel Jakub Dawidek } else /* if (type == 1) */ { 20242d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s stopped.", 20252d1661a5SPawel Jakub Dawidek disk->d_softc->sc_name, g_raid3_get_diskname(disk)); 20262d1661a5SPawel Jakub Dawidek } 2027d97d5ee9SPawel Jakub Dawidek g_raid3_kill_consumer(disk->d_softc, disk->d_sync.ds_consumer); 20282d1661a5SPawel Jakub Dawidek free(disk->d_sync.ds_data, M_RAID3); 20292d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = NULL; 20302d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 20312d1661a5SPawel Jakub Dawidek } 20322d1661a5SPawel Jakub Dawidek 20332d1661a5SPawel Jakub Dawidek static void 20342d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(struct g_raid3_softc *sc) 20352d1661a5SPawel Jakub Dawidek { 20362d1661a5SPawel Jakub Dawidek struct g_provider *pp; 20372d1661a5SPawel Jakub Dawidek 20382d1661a5SPawel Jakub Dawidek g_topology_assert(); 20392d1661a5SPawel Jakub Dawidek 20402d1661a5SPawel Jakub Dawidek pp = g_new_providerf(sc->sc_geom, "raid3/%s", sc->sc_name); 20412d1661a5SPawel Jakub Dawidek pp->mediasize = sc->sc_mediasize; 20422d1661a5SPawel Jakub Dawidek pp->sectorsize = sc->sc_sectorsize; 20432d1661a5SPawel Jakub Dawidek sc->sc_provider = pp; 20442d1661a5SPawel Jakub Dawidek g_error_provider(pp, 0); 20452d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s launched.", sc->sc_name, 20462d1661a5SPawel Jakub Dawidek pp->name); 20472d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED) 20482d1661a5SPawel Jakub Dawidek g_raid3_sync_start(sc); 20492d1661a5SPawel Jakub Dawidek } 20502d1661a5SPawel Jakub Dawidek 20512d1661a5SPawel Jakub Dawidek static void 20522d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(struct g_raid3_softc *sc) 20532d1661a5SPawel Jakub Dawidek { 20542d1661a5SPawel Jakub Dawidek struct bio *bp; 20552d1661a5SPawel Jakub Dawidek 20562d1661a5SPawel Jakub Dawidek g_topology_assert(); 20572d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_provider != NULL, ("NULL provider (device=%s).", 20582d1661a5SPawel Jakub Dawidek sc->sc_name)); 20592d1661a5SPawel Jakub Dawidek 20602d1661a5SPawel Jakub Dawidek g_error_provider(sc->sc_provider, ENXIO); 20612d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 20622d1661a5SPawel Jakub Dawidek while ((bp = bioq_first(&sc->sc_queue)) != NULL) { 20632d1661a5SPawel Jakub Dawidek bioq_remove(&sc->sc_queue, bp); 20642d1661a5SPawel Jakub Dawidek g_io_deliver(bp, ENXIO); 20652d1661a5SPawel Jakub Dawidek } 20662d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 20672d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s destroyed.", sc->sc_name, 20682d1661a5SPawel Jakub Dawidek sc->sc_provider->name); 20692d1661a5SPawel Jakub Dawidek sc->sc_provider->flags |= G_PF_WITHER; 20702d1661a5SPawel Jakub Dawidek g_orphan_provider(sc->sc_provider, ENXIO); 20712d1661a5SPawel Jakub Dawidek sc->sc_provider = NULL; 20722d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL) 20732d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 1); 20742d1661a5SPawel Jakub Dawidek } 20752d1661a5SPawel Jakub Dawidek 20762d1661a5SPawel Jakub Dawidek static void 20772d1661a5SPawel Jakub Dawidek g_raid3_go(void *arg) 20782d1661a5SPawel Jakub Dawidek { 20792d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 20802d1661a5SPawel Jakub Dawidek 20812d1661a5SPawel Jakub Dawidek sc = arg; 20822d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Force device %s start due to timeout.", sc->sc_name); 20832d1661a5SPawel Jakub Dawidek g_raid3_event_send(sc, 0, 20842d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT | G_RAID3_EVENT_DEVICE); 20852d1661a5SPawel Jakub Dawidek } 20862d1661a5SPawel Jakub Dawidek 20872d1661a5SPawel Jakub Dawidek static u_int 20882d1661a5SPawel Jakub Dawidek g_raid3_determine_state(struct g_raid3_disk *disk) 20892d1661a5SPawel Jakub Dawidek { 20902d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 20912d1661a5SPawel Jakub Dawidek u_int state; 20922d1661a5SPawel Jakub Dawidek 20932d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 20942d1661a5SPawel Jakub Dawidek if (sc->sc_syncid == disk->d_sync.ds_syncid) { 20952d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 20962d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING) == 0) { 20972d1661a5SPawel Jakub Dawidek /* Disk does not need synchronization. */ 20982d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_ACTIVE; 20992d1661a5SPawel Jakub Dawidek } else { 21002d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 21012d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_NOAUTOSYNC) == 0 || 21022d1661a5SPawel Jakub Dawidek (disk->d_flags & 21032d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_FORCE_SYNC) != 0) { 21042d1661a5SPawel Jakub Dawidek /* 21052d1661a5SPawel Jakub Dawidek * We can start synchronization from 21062d1661a5SPawel Jakub Dawidek * the stored offset. 21072d1661a5SPawel Jakub Dawidek */ 21082d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_SYNCHRONIZING; 21092d1661a5SPawel Jakub Dawidek } else { 21102d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_STALE; 21112d1661a5SPawel Jakub Dawidek } 21122d1661a5SPawel Jakub Dawidek } 21132d1661a5SPawel Jakub Dawidek } else if (disk->d_sync.ds_syncid < sc->sc_syncid) { 21142d1661a5SPawel Jakub Dawidek /* 21152d1661a5SPawel Jakub Dawidek * Reset all synchronization data for this disk, 21162d1661a5SPawel Jakub Dawidek * because if it even was synchronized, it was 21172d1661a5SPawel Jakub Dawidek * synchronized to disks with different syncid. 21182d1661a5SPawel Jakub Dawidek */ 21192d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_SYNCHRONIZING; 21202d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = 0; 21212d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = 0; 21222d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = sc->sc_syncid; 21232d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) == 0 || 21242d1661a5SPawel Jakub Dawidek (disk->d_flags & G_RAID3_DISK_FLAG_FORCE_SYNC) != 0) { 21252d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_SYNCHRONIZING; 21262d1661a5SPawel Jakub Dawidek } else { 21272d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_STALE; 21282d1661a5SPawel Jakub Dawidek } 21292d1661a5SPawel Jakub Dawidek } else /* if (sc->sc_syncid < disk->d_sync.ds_syncid) */ { 21302d1661a5SPawel Jakub Dawidek /* 21312d1661a5SPawel Jakub Dawidek * Not good, NOT GOOD! 21322d1661a5SPawel Jakub Dawidek * It means that device was started on stale disks 21332d1661a5SPawel Jakub Dawidek * and more fresh disk just arrive. 21342d1661a5SPawel Jakub Dawidek * If there were writes, device is fucked up, sorry. 21352d1661a5SPawel Jakub Dawidek * I think the best choice here is don't touch 21362d1661a5SPawel Jakub Dawidek * this disk and inform the user laudly. 21372d1661a5SPawel Jakub Dawidek */ 21382d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s was started before the freshest " 21392d1661a5SPawel Jakub Dawidek "disk (%s) arrives!! It will not be connected to the " 21402d1661a5SPawel Jakub Dawidek "running device.", sc->sc_name, 21412d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 21422d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 21432d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_NONE; 21442d1661a5SPawel Jakub Dawidek /* Return immediately, because disk was destroyed. */ 21452d1661a5SPawel Jakub Dawidek return (state); 21462d1661a5SPawel Jakub Dawidek } 21472d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "State for %s disk: %s.", 21482d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), g_raid3_disk_state2str(state)); 21492d1661a5SPawel Jakub Dawidek return (state); 21502d1661a5SPawel Jakub Dawidek } 21512d1661a5SPawel Jakub Dawidek 21522d1661a5SPawel Jakub Dawidek /* 21532d1661a5SPawel Jakub Dawidek * Update device state. 21542d1661a5SPawel Jakub Dawidek */ 21552d1661a5SPawel Jakub Dawidek static void 2156d97d5ee9SPawel Jakub Dawidek g_raid3_update_device(struct g_raid3_softc *sc, boolean_t force) 21572d1661a5SPawel Jakub Dawidek { 21582d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 21592d1661a5SPawel Jakub Dawidek u_int state; 21602d1661a5SPawel Jakub Dawidek 21612d1661a5SPawel Jakub Dawidek g_topology_assert(); 21622d1661a5SPawel Jakub Dawidek 21632d1661a5SPawel Jakub Dawidek switch (sc->sc_state) { 21642d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_STARTING: 21652d1661a5SPawel Jakub Dawidek { 2166a245a548SPawel Jakub Dawidek u_int n, ndirty, ndisks, genid, syncid; 21672d1661a5SPawel Jakub Dawidek 21682d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_provider == NULL, 21692d1661a5SPawel Jakub Dawidek ("Non-NULL provider in STARTING state (%s).", sc->sc_name)); 21702d1661a5SPawel Jakub Dawidek /* 21712d1661a5SPawel Jakub Dawidek * Are we ready? We are, if all disks are connected or 21722d1661a5SPawel Jakub Dawidek * one disk is missing and 'force' is true. 21732d1661a5SPawel Jakub Dawidek */ 21742d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, -1) + force == sc->sc_ndisks) { 21752d1661a5SPawel Jakub Dawidek if (!force) 21762d1661a5SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 21772d1661a5SPawel Jakub Dawidek } else { 21782d1661a5SPawel Jakub Dawidek if (force) { 21792d1661a5SPawel Jakub Dawidek /* 21802d1661a5SPawel Jakub Dawidek * Timeout expired, so destroy device. 21812d1661a5SPawel Jakub Dawidek */ 21822d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 21834ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", 21844ed854e8SPawel Jakub Dawidek __LINE__, sc->sc_rootmount); 21854ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 21864ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 21872d1661a5SPawel Jakub Dawidek } 21882d1661a5SPawel Jakub Dawidek return; 21892d1661a5SPawel Jakub Dawidek } 21902d1661a5SPawel Jakub Dawidek 21912d1661a5SPawel Jakub Dawidek /* 2192a245a548SPawel Jakub Dawidek * Find the biggest genid. 2193a245a548SPawel Jakub Dawidek */ 2194a245a548SPawel Jakub Dawidek genid = 0; 2195a245a548SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 2196a245a548SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 2197a245a548SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 2198a245a548SPawel Jakub Dawidek continue; 2199a245a548SPawel Jakub Dawidek if (disk->d_genid > genid) 2200a245a548SPawel Jakub Dawidek genid = disk->d_genid; 2201a245a548SPawel Jakub Dawidek } 2202a245a548SPawel Jakub Dawidek sc->sc_genid = genid; 2203a245a548SPawel Jakub Dawidek /* 2204a245a548SPawel Jakub Dawidek * Remove all disks without the biggest genid. 2205a245a548SPawel Jakub Dawidek */ 2206a245a548SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 2207a245a548SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 2208a245a548SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 2209a245a548SPawel Jakub Dawidek continue; 2210a245a548SPawel Jakub Dawidek if (disk->d_genid < genid) { 2211a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, 2212a245a548SPawel Jakub Dawidek "Component %s (device %s) broken, skipping.", 2213a245a548SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 2214a245a548SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 2215a245a548SPawel Jakub Dawidek } 2216a245a548SPawel Jakub Dawidek } 2217a245a548SPawel Jakub Dawidek 2218a245a548SPawel Jakub Dawidek /* 22192d1661a5SPawel Jakub Dawidek * There must be at least 'sc->sc_ndisks - 1' components 22202d1661a5SPawel Jakub Dawidek * with the same syncid and without SYNCHRONIZING flag. 22212d1661a5SPawel Jakub Dawidek */ 22222d1661a5SPawel Jakub Dawidek 22232d1661a5SPawel Jakub Dawidek /* 22242d1661a5SPawel Jakub Dawidek * Find the biggest syncid, number of valid components and 22252d1661a5SPawel Jakub Dawidek * number of dirty components. 22262d1661a5SPawel Jakub Dawidek */ 22272d1661a5SPawel Jakub Dawidek ndirty = ndisks = syncid = 0; 22282d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 22292d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 22302d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 22312d1661a5SPawel Jakub Dawidek continue; 22322d1661a5SPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) != 0) 22332d1661a5SPawel Jakub Dawidek ndirty++; 22342d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_syncid > syncid) { 22352d1661a5SPawel Jakub Dawidek syncid = disk->d_sync.ds_syncid; 22362d1661a5SPawel Jakub Dawidek ndisks = 0; 22372d1661a5SPawel Jakub Dawidek } else if (disk->d_sync.ds_syncid < syncid) { 22382d1661a5SPawel Jakub Dawidek continue; 22392d1661a5SPawel Jakub Dawidek } 22402d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 22412d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING) != 0) { 22422d1661a5SPawel Jakub Dawidek continue; 22432d1661a5SPawel Jakub Dawidek } 22442d1661a5SPawel Jakub Dawidek ndisks++; 22452d1661a5SPawel Jakub Dawidek } 22462d1661a5SPawel Jakub Dawidek /* 22472d1661a5SPawel Jakub Dawidek * Do we have enough valid components? 22482d1661a5SPawel Jakub Dawidek */ 22492d1661a5SPawel Jakub Dawidek if (ndisks + 1 < sc->sc_ndisks) { 22502d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 22512d1661a5SPawel Jakub Dawidek "Device %s is broken, too few valid components.", 22522d1661a5SPawel Jakub Dawidek sc->sc_name); 22532d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 22542d1661a5SPawel Jakub Dawidek return; 22552d1661a5SPawel Jakub Dawidek } 22562d1661a5SPawel Jakub Dawidek /* 22572d1661a5SPawel Jakub Dawidek * If there is one DIRTY component and all disks are present, 22582d1661a5SPawel Jakub Dawidek * mark it for synchronization. If there is more than one DIRTY 22592d1661a5SPawel Jakub Dawidek * component, mark parity component for synchronization. 22602d1661a5SPawel Jakub Dawidek */ 22612d1661a5SPawel Jakub Dawidek if (ndisks == sc->sc_ndisks && ndirty == 1) { 22622d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 22632d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 22642d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 22652d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_DIRTY) == 0) { 22662d1661a5SPawel Jakub Dawidek continue; 22672d1661a5SPawel Jakub Dawidek } 22682d1661a5SPawel Jakub Dawidek disk->d_flags |= 22692d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING; 22702d1661a5SPawel Jakub Dawidek } 22712d1661a5SPawel Jakub Dawidek } else if (ndisks == sc->sc_ndisks && ndirty > 1) { 22722d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 22732d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_SYNCHRONIZING; 22742d1661a5SPawel Jakub Dawidek } 22752d1661a5SPawel Jakub Dawidek 22762d1661a5SPawel Jakub Dawidek sc->sc_syncid = syncid; 22772d1661a5SPawel Jakub Dawidek if (force) { 22782d1661a5SPawel Jakub Dawidek /* Remember to bump syncid on first write. */ 2279ea973705SPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_SYNCID; 22802d1661a5SPawel Jakub Dawidek } 22812d1661a5SPawel Jakub Dawidek if (ndisks == sc->sc_ndisks) 22822d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_COMPLETE; 22832d1661a5SPawel Jakub Dawidek else /* if (ndisks == sc->sc_ndisks - 1) */ 22842d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_DEGRADED; 22852d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s state changed from %s to %s.", 22862d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 22872d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 22882d1661a5SPawel Jakub Dawidek sc->sc_state = state; 22892d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 22902d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 22912d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 22922d1661a5SPawel Jakub Dawidek continue; 22932d1661a5SPawel Jakub Dawidek state = g_raid3_determine_state(disk); 22942d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, state, G_RAID3_EVENT_DONTWAIT); 2295a245a548SPawel Jakub Dawidek if (state == G_RAID3_DISK_STATE_STALE) 2296ea973705SPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_SYNCID; 22972d1661a5SPawel Jakub Dawidek } 22982d1661a5SPawel Jakub Dawidek break; 22992d1661a5SPawel Jakub Dawidek } 23002d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_DEGRADED: 23012d1661a5SPawel Jakub Dawidek /* 2302ea973705SPawel Jakub Dawidek * Genid need to be bumped immediately, so do it here. 23032d1661a5SPawel Jakub Dawidek */ 2304ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_GENID) != 0) { 2305a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_GENID; 2306a245a548SPawel Jakub Dawidek g_raid3_bump_genid(sc); 2307a245a548SPawel Jakub Dawidek } 2308a245a548SPawel Jakub Dawidek 23092d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NEW) > 0) 23102d1661a5SPawel Jakub Dawidek return; 23112d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 23122d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1) { 23132d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) 23142d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(sc); 23152d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 23162d1661a5SPawel Jakub Dawidek return; 23172d1661a5SPawel Jakub Dawidek } 23182d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) == 23192d1661a5SPawel Jakub Dawidek sc->sc_ndisks) { 23202d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_COMPLETE; 23212d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23222d1661a5SPawel Jakub Dawidek "Device %s state changed from %s to %s.", 23232d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 23242d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 23252d1661a5SPawel Jakub Dawidek sc->sc_state = state; 23262d1661a5SPawel Jakub Dawidek } 23272d1661a5SPawel Jakub Dawidek if (sc->sc_provider == NULL) 23282d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(sc); 23294ed854e8SPawel Jakub Dawidek if (sc->sc_rootmount != NULL) { 23304ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", __LINE__, 23314ed854e8SPawel Jakub Dawidek sc->sc_rootmount); 23324ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 23334ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 23344ed854e8SPawel Jakub Dawidek } 23352d1661a5SPawel Jakub Dawidek break; 23362d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_COMPLETE: 23372d1661a5SPawel Jakub Dawidek /* 2338ea973705SPawel Jakub Dawidek * Genid need to be bumped immediately, so do it here. 23392d1661a5SPawel Jakub Dawidek */ 2340ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_GENID) != 0) { 2341a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_GENID; 2342a245a548SPawel Jakub Dawidek g_raid3_bump_genid(sc); 2343a245a548SPawel Jakub Dawidek } 2344a245a548SPawel Jakub Dawidek 23452d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NEW) > 0) 23462d1661a5SPawel Jakub Dawidek return; 23472d1661a5SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) >= 23482d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1, 23492d1661a5SPawel Jakub Dawidek ("Too few ACTIVE components in COMPLETE state (device %s).", 23502d1661a5SPawel Jakub Dawidek sc->sc_name)); 23512d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) == 23522d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1) { 23532d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_DEGRADED; 23542d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 23552d1661a5SPawel Jakub Dawidek "Device %s state changed from %s to %s.", 23562d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 23572d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 23582d1661a5SPawel Jakub Dawidek sc->sc_state = state; 23592d1661a5SPawel Jakub Dawidek } 23602d1661a5SPawel Jakub Dawidek if (sc->sc_provider == NULL) 23612d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(sc); 23624ed854e8SPawel Jakub Dawidek if (sc->sc_rootmount != NULL) { 23634ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", __LINE__, 23644ed854e8SPawel Jakub Dawidek sc->sc_rootmount); 23654ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 23664ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 23674ed854e8SPawel Jakub Dawidek } 23682d1661a5SPawel Jakub Dawidek break; 23692d1661a5SPawel Jakub Dawidek default: 23702d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Wrong device state (%s, %s).", sc->sc_name, 23712d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state))); 23722d1661a5SPawel Jakub Dawidek break; 23732d1661a5SPawel Jakub Dawidek } 23742d1661a5SPawel Jakub Dawidek } 23752d1661a5SPawel Jakub Dawidek 23762d1661a5SPawel Jakub Dawidek /* 23772d1661a5SPawel Jakub Dawidek * Update disk state and device state if needed. 23782d1661a5SPawel Jakub Dawidek */ 23792d1661a5SPawel Jakub Dawidek #define DISK_STATE_CHANGED() G_RAID3_DEBUG(1, \ 23802d1661a5SPawel Jakub Dawidek "Disk %s state changed from %s to %s (device %s).", \ 23812d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), \ 23822d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state), \ 23832d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(state), sc->sc_name) 23842d1661a5SPawel Jakub Dawidek static int 2385d97d5ee9SPawel Jakub Dawidek g_raid3_update_disk(struct g_raid3_disk *disk, u_int state) 23862d1661a5SPawel Jakub Dawidek { 23872d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 23882d1661a5SPawel Jakub Dawidek 23892d1661a5SPawel Jakub Dawidek g_topology_assert(); 23902d1661a5SPawel Jakub Dawidek 23912d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 23922d1661a5SPawel Jakub Dawidek again: 23932d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "Changing disk %s state from %s to %s.", 23942d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), g_raid3_disk_state2str(disk->d_state), 23952d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(state)); 23962d1661a5SPawel Jakub Dawidek switch (state) { 23972d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 23982d1661a5SPawel Jakub Dawidek /* 23992d1661a5SPawel Jakub Dawidek * Possible scenarios: 24002d1661a5SPawel Jakub Dawidek * 1. New disk arrive. 24012d1661a5SPawel Jakub Dawidek */ 24022d1661a5SPawel Jakub Dawidek /* Previous state should be NONE. */ 24032d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NONE, 24042d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 24052d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24062d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 24072d1661a5SPawel Jakub Dawidek 24082d1661a5SPawel Jakub Dawidek disk->d_state = state; 24092d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s detected.", 24102d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 24112d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_STARTING) 24122d1661a5SPawel Jakub Dawidek break; 24132d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 24142d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 24152d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 24162d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 24172d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 24182d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24192d1661a5SPawel Jakub Dawidek state = g_raid3_determine_state(disk); 24202d1661a5SPawel Jakub Dawidek if (state != G_RAID3_DISK_STATE_NONE) 24212d1661a5SPawel Jakub Dawidek goto again; 24222d1661a5SPawel Jakub Dawidek break; 24232d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 24242d1661a5SPawel Jakub Dawidek /* 24252d1661a5SPawel Jakub Dawidek * Possible scenarios: 24262d1661a5SPawel Jakub Dawidek * 1. New disk does not need synchronization. 24272d1661a5SPawel Jakub Dawidek * 2. Synchronization process finished successfully. 24282d1661a5SPawel Jakub Dawidek */ 24292d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 24302d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 24312d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 24322d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 24332d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 24342d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24352d1661a5SPawel Jakub Dawidek /* Previous state should be NEW or SYNCHRONIZING. */ 24362d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW || 24372d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 24382d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 24392d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24402d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 24412d1661a5SPawel Jakub Dawidek 2442bf31327cSPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 24432d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_SYNCHRONIZING; 24442d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 24452d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 0); 24462d1661a5SPawel Jakub Dawidek } 24472d1661a5SPawel Jakub Dawidek disk->d_state = state; 24482d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = 0; 24492d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = 0; 24500962f942SPawel Jakub Dawidek g_raid3_update_idle(sc, disk); 2451bf31327cSPawel Jakub Dawidek g_raid3_update_metadata(disk); 24522d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s activated.", 24532d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 24542d1661a5SPawel Jakub Dawidek break; 24552d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 24562d1661a5SPawel Jakub Dawidek /* 24572d1661a5SPawel Jakub Dawidek * Possible scenarios: 24582d1661a5SPawel Jakub Dawidek * 1. Stale disk was connected. 24592d1661a5SPawel Jakub Dawidek */ 24602d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 24612d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 24622d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 24632d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24642d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 24652d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 24662d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 24672d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 24682d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 24692d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24702d1661a5SPawel Jakub Dawidek /* 24712d1661a5SPawel Jakub Dawidek * STALE state is only possible if device is marked 24722d1661a5SPawel Jakub Dawidek * NOAUTOSYNC. 24732d1661a5SPawel Jakub Dawidek */ 24742d1661a5SPawel Jakub Dawidek KASSERT((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0, 24752d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 24762d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 24772d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 24782d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24792d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 24802d1661a5SPawel Jakub Dawidek 24812d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 24822d1661a5SPawel Jakub Dawidek disk->d_state = state; 24832d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 24842d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s is stale.", 24852d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 24862d1661a5SPawel Jakub Dawidek break; 24872d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 24882d1661a5SPawel Jakub Dawidek /* 24892d1661a5SPawel Jakub Dawidek * Possible scenarios: 24902d1661a5SPawel Jakub Dawidek * 1. Disk which needs synchronization was connected. 24912d1661a5SPawel Jakub Dawidek */ 24922d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 24932d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 24942d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 24952d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 24962d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 24972d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 24982d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 24992d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 25002d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 25012d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 25022d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 25032d1661a5SPawel Jakub Dawidek 25042d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NEW) 25052d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 25062d1661a5SPawel Jakub Dawidek disk->d_state = state; 25072d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) { 25082d1661a5SPawel Jakub Dawidek g_raid3_sync_start(sc); 25092d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 25102d1661a5SPawel Jakub Dawidek } 25112d1661a5SPawel Jakub Dawidek break; 25122d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_DISCONNECTED: 25132d1661a5SPawel Jakub Dawidek /* 25142d1661a5SPawel Jakub Dawidek * Possible scenarios: 25152d1661a5SPawel Jakub Dawidek * 1. Device wasn't running yet, but disk disappear. 25162d1661a5SPawel Jakub Dawidek * 2. Disk was active and disapppear. 25172d1661a5SPawel Jakub Dawidek * 3. Disk disappear during synchronization process. 25182d1661a5SPawel Jakub Dawidek */ 25192d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 25202d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 25212d1661a5SPawel Jakub Dawidek /* 25222d1661a5SPawel Jakub Dawidek * Previous state should be ACTIVE, STALE or 25232d1661a5SPawel Jakub Dawidek * SYNCHRONIZING. 25242d1661a5SPawel Jakub Dawidek */ 25252d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 25262d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_STALE || 25272d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 25282d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", 25292d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 25302d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 25312d1661a5SPawel Jakub Dawidek } else if (sc->sc_state == G_RAID3_DEVICE_STATE_STARTING) { 25322d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 25332d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 25342d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", 25352d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 25362d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 25372d1661a5SPawel Jakub Dawidek /* 25382d1661a5SPawel Jakub Dawidek * Reset bumping syncid if disk disappeared in STARTING 25392d1661a5SPawel Jakub Dawidek * state. 25402d1661a5SPawel Jakub Dawidek */ 2541ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_SYNCID) != 0) 2542a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_SYNCID; 25432d1661a5SPawel Jakub Dawidek #ifdef INVARIANTS 25442d1661a5SPawel Jakub Dawidek } else { 25452d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Wrong device state (%s, %s, %s, %s).", 25462d1661a5SPawel Jakub Dawidek sc->sc_name, 25472d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 25482d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 25492d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 25502d1661a5SPawel Jakub Dawidek #endif 25512d1661a5SPawel Jakub Dawidek } 25522d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 25532d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s disconnected.", 25542d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 25552d1661a5SPawel Jakub Dawidek 25562d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 25572d1661a5SPawel Jakub Dawidek break; 25582d1661a5SPawel Jakub Dawidek default: 25592d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Unknown state (%u).", state)); 25602d1661a5SPawel Jakub Dawidek break; 25612d1661a5SPawel Jakub Dawidek } 25622d1661a5SPawel Jakub Dawidek return (0); 25632d1661a5SPawel Jakub Dawidek } 25642d1661a5SPawel Jakub Dawidek #undef DISK_STATE_CHANGED 25652d1661a5SPawel Jakub Dawidek 2566ea973705SPawel Jakub Dawidek int 25672d1661a5SPawel Jakub Dawidek g_raid3_read_metadata(struct g_consumer *cp, struct g_raid3_metadata *md) 25682d1661a5SPawel Jakub Dawidek { 25692d1661a5SPawel Jakub Dawidek struct g_provider *pp; 25702d1661a5SPawel Jakub Dawidek u_char *buf; 25712d1661a5SPawel Jakub Dawidek int error; 25722d1661a5SPawel Jakub Dawidek 25732d1661a5SPawel Jakub Dawidek g_topology_assert(); 25742d1661a5SPawel Jakub Dawidek 25752d1661a5SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 25762d1661a5SPawel Jakub Dawidek if (error != 0) 25772d1661a5SPawel Jakub Dawidek return (error); 25782d1661a5SPawel Jakub Dawidek pp = cp->provider; 25792d1661a5SPawel Jakub Dawidek g_topology_unlock(); 25802d1661a5SPawel Jakub Dawidek /* Metadata are stored on last sector. */ 25812d1661a5SPawel Jakub Dawidek buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 25822d1661a5SPawel Jakub Dawidek &error); 25832d1661a5SPawel Jakub Dawidek g_topology_lock(); 25842d1661a5SPawel Jakub Dawidek g_access(cp, -1, 0, 0); 25858a4a44b5SMaxim Sobolev if (buf == NULL) { 2586a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Cannot read metadata from %s (error=%d).", 2587a245a548SPawel Jakub Dawidek cp->provider->name, error); 25882d1661a5SPawel Jakub Dawidek return (error); 25892d1661a5SPawel Jakub Dawidek } 25902d1661a5SPawel Jakub Dawidek 25912d1661a5SPawel Jakub Dawidek /* Decode metadata. */ 25922d1661a5SPawel Jakub Dawidek error = raid3_metadata_decode(buf, md); 25932d1661a5SPawel Jakub Dawidek g_free(buf); 25942d1661a5SPawel Jakub Dawidek if (strcmp(md->md_magic, G_RAID3_MAGIC) != 0) 25952d1661a5SPawel Jakub Dawidek return (EINVAL); 2596a245a548SPawel Jakub Dawidek if (md->md_version > G_RAID3_VERSION) { 2597a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, 2598a245a548SPawel Jakub Dawidek "Kernel module is too old to handle metadata from %s.", 2599a245a548SPawel Jakub Dawidek cp->provider->name); 2600a245a548SPawel Jakub Dawidek return (EINVAL); 2601a245a548SPawel Jakub Dawidek } 26022d1661a5SPawel Jakub Dawidek if (error != 0) { 26032d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "MD5 metadata hash mismatch for provider %s.", 26042d1661a5SPawel Jakub Dawidek cp->provider->name); 26052d1661a5SPawel Jakub Dawidek return (error); 26062d1661a5SPawel Jakub Dawidek } 26072d1661a5SPawel Jakub Dawidek 26082d1661a5SPawel Jakub Dawidek return (0); 26092d1661a5SPawel Jakub Dawidek } 26102d1661a5SPawel Jakub Dawidek 26112d1661a5SPawel Jakub Dawidek static int 26122d1661a5SPawel Jakub Dawidek g_raid3_check_metadata(struct g_raid3_softc *sc, struct g_provider *pp, 26132d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md) 26142d1661a5SPawel Jakub Dawidek { 26152d1661a5SPawel Jakub Dawidek 26162d1661a5SPawel Jakub Dawidek if (md->md_no >= sc->sc_ndisks) { 26172d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Invalid disk %s number (no=%u), skipping.", 26182d1661a5SPawel Jakub Dawidek pp->name, md->md_no); 26192d1661a5SPawel Jakub Dawidek return (EINVAL); 26202d1661a5SPawel Jakub Dawidek } 26212d1661a5SPawel Jakub Dawidek if (sc->sc_disks[md->md_no].d_state != G_RAID3_DISK_STATE_NODISK) { 26222d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (no=%u) already exists, skipping.", 26232d1661a5SPawel Jakub Dawidek pp->name, md->md_no); 26242d1661a5SPawel Jakub Dawidek return (EEXIST); 26252d1661a5SPawel Jakub Dawidek } 26262d1661a5SPawel Jakub Dawidek if (md->md_all != sc->sc_ndisks) { 26272d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26282d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 26292d1661a5SPawel Jakub Dawidek "md_all", pp->name, sc->sc_name); 26302d1661a5SPawel Jakub Dawidek return (EINVAL); 26312d1661a5SPawel Jakub Dawidek } 26322d1661a5SPawel Jakub Dawidek if (md->md_mediasize != sc->sc_mediasize) { 26332d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26342d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 26352d1661a5SPawel Jakub Dawidek "md_mediasize", pp->name, sc->sc_name); 26362d1661a5SPawel Jakub Dawidek return (EINVAL); 26372d1661a5SPawel Jakub Dawidek } 26382d1661a5SPawel Jakub Dawidek if ((md->md_mediasize % (sc->sc_ndisks - 1)) != 0) { 26392d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26402d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 26412d1661a5SPawel Jakub Dawidek "md_mediasize", pp->name, sc->sc_name); 26422d1661a5SPawel Jakub Dawidek return (EINVAL); 26432d1661a5SPawel Jakub Dawidek } 26442d1661a5SPawel Jakub Dawidek if ((sc->sc_mediasize / (sc->sc_ndisks - 1)) > pp->mediasize) { 26452d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26462d1661a5SPawel Jakub Dawidek "Invalid size of disk %s (device %s), skipping.", pp->name, 26472d1661a5SPawel Jakub Dawidek sc->sc_name); 26482d1661a5SPawel Jakub Dawidek return (EINVAL); 26492d1661a5SPawel Jakub Dawidek } 26502d1661a5SPawel Jakub Dawidek if ((md->md_sectorsize / pp->sectorsize) < sc->sc_ndisks - 1) { 26512d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26522d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 26532d1661a5SPawel Jakub Dawidek "md_sectorsize", pp->name, sc->sc_name); 26542d1661a5SPawel Jakub Dawidek return (EINVAL); 26552d1661a5SPawel Jakub Dawidek } 26562d1661a5SPawel Jakub Dawidek if (md->md_sectorsize != sc->sc_sectorsize) { 26572d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26582d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 26592d1661a5SPawel Jakub Dawidek "md_sectorsize", pp->name, sc->sc_name); 26602d1661a5SPawel Jakub Dawidek return (EINVAL); 26612d1661a5SPawel Jakub Dawidek } 26622d1661a5SPawel Jakub Dawidek if ((sc->sc_sectorsize % pp->sectorsize) != 0) { 26632d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26642d1661a5SPawel Jakub Dawidek "Invalid sector size of disk %s (device %s), skipping.", 26652d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 26662d1661a5SPawel Jakub Dawidek return (EINVAL); 26672d1661a5SPawel Jakub Dawidek } 26682d1661a5SPawel Jakub Dawidek if ((md->md_mflags & ~G_RAID3_DEVICE_FLAG_MASK) != 0) { 26692d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26702d1661a5SPawel Jakub Dawidek "Invalid device flags on disk %s (device %s), skipping.", 26712d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 26722d1661a5SPawel Jakub Dawidek return (EINVAL); 26732d1661a5SPawel Jakub Dawidek } 2674dba915cfSPawel Jakub Dawidek if ((md->md_mflags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 2675dba915cfSPawel Jakub Dawidek (md->md_mflags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 2676dba915cfSPawel Jakub Dawidek /* 2677dba915cfSPawel Jakub Dawidek * VERIFY and ROUND-ROBIN options are mutally exclusive. 2678dba915cfSPawel Jakub Dawidek */ 2679dba915cfSPawel Jakub Dawidek G_RAID3_DEBUG(1, "Both VERIFY and ROUND-ROBIN flags exist on " 2680dba915cfSPawel Jakub Dawidek "disk %s (device %s), skipping.", pp->name, sc->sc_name); 2681dba915cfSPawel Jakub Dawidek return (EINVAL); 2682dba915cfSPawel Jakub Dawidek } 26832d1661a5SPawel Jakub Dawidek if ((md->md_dflags & ~G_RAID3_DISK_FLAG_MASK) != 0) { 26842d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 26852d1661a5SPawel Jakub Dawidek "Invalid disk flags on disk %s (device %s), skipping.", 26862d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 26872d1661a5SPawel Jakub Dawidek return (EINVAL); 26882d1661a5SPawel Jakub Dawidek } 26892d1661a5SPawel Jakub Dawidek return (0); 26902d1661a5SPawel Jakub Dawidek } 26912d1661a5SPawel Jakub Dawidek 2692ea973705SPawel Jakub Dawidek int 26932d1661a5SPawel Jakub Dawidek g_raid3_add_disk(struct g_raid3_softc *sc, struct g_provider *pp, 26942d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md) 26952d1661a5SPawel Jakub Dawidek { 26962d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 26972d1661a5SPawel Jakub Dawidek int error; 26982d1661a5SPawel Jakub Dawidek 26992d1661a5SPawel Jakub Dawidek g_topology_assert(); 27002d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Adding disk %s.", pp->name); 27012d1661a5SPawel Jakub Dawidek 27022d1661a5SPawel Jakub Dawidek error = g_raid3_check_metadata(sc, pp, md); 27032d1661a5SPawel Jakub Dawidek if (error != 0) 27042d1661a5SPawel Jakub Dawidek return (error); 2705a245a548SPawel Jakub Dawidek if (sc->sc_state != G_RAID3_DEVICE_STATE_STARTING && 2706a245a548SPawel Jakub Dawidek md->md_genid < sc->sc_genid) { 2707a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Component %s (device %s) broken, skipping.", 2708a245a548SPawel Jakub Dawidek pp->name, sc->sc_name); 2709a245a548SPawel Jakub Dawidek return (EINVAL); 2710a245a548SPawel Jakub Dawidek } 27112d1661a5SPawel Jakub Dawidek disk = g_raid3_init_disk(sc, pp, md, &error); 27122d1661a5SPawel Jakub Dawidek if (disk == NULL) 27132d1661a5SPawel Jakub Dawidek return (error); 27142d1661a5SPawel Jakub Dawidek error = g_raid3_event_send(disk, G_RAID3_DISK_STATE_NEW, 27152d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_WAIT); 2716a245a548SPawel Jakub Dawidek if (error != 0) 27172d1661a5SPawel Jakub Dawidek return (error); 2718a245a548SPawel Jakub Dawidek if (md->md_version < G_RAID3_VERSION) { 2719a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Upgrading metadata on %s (v%d->v%d).", 2720a245a548SPawel Jakub Dawidek pp->name, md->md_version, G_RAID3_VERSION); 2721a245a548SPawel Jakub Dawidek g_raid3_update_metadata(disk); 2722a245a548SPawel Jakub Dawidek } 2723a245a548SPawel Jakub Dawidek return (0); 27242d1661a5SPawel Jakub Dawidek } 27252d1661a5SPawel Jakub Dawidek 27262d1661a5SPawel Jakub Dawidek static int 27272d1661a5SPawel Jakub Dawidek g_raid3_access(struct g_provider *pp, int acr, int acw, int ace) 27282d1661a5SPawel Jakub Dawidek { 27292d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2730d97d5ee9SPawel Jakub Dawidek int dcr, dcw, dce; 27312d1661a5SPawel Jakub Dawidek 27322d1661a5SPawel Jakub Dawidek g_topology_assert(); 27332d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access request for %s: r%dw%de%d.", pp->name, acr, 27342d1661a5SPawel Jakub Dawidek acw, ace); 27352d1661a5SPawel Jakub Dawidek 27362d1661a5SPawel Jakub Dawidek dcr = pp->acr + acr; 27372d1661a5SPawel Jakub Dawidek dcw = pp->acw + acw; 27382d1661a5SPawel Jakub Dawidek dce = pp->ace + ace; 27392d1661a5SPawel Jakub Dawidek 27402d1661a5SPawel Jakub Dawidek sc = pp->geom->softc; 27412d1661a5SPawel Jakub Dawidek if (sc == NULL || 2742463674f7SPawel Jakub Dawidek g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks - 1 || 2743463674f7SPawel Jakub Dawidek (sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 27442d1661a5SPawel Jakub Dawidek if (acr <= 0 && acw <= 0 && ace <= 0) 27452d1661a5SPawel Jakub Dawidek return (0); 27462d1661a5SPawel Jakub Dawidek else 27472d1661a5SPawel Jakub Dawidek return (ENXIO); 27482d1661a5SPawel Jakub Dawidek } 27490962f942SPawel Jakub Dawidek if (dcw == 0 && !sc->sc_idle) 27500962f942SPawel Jakub Dawidek g_raid3_idle(sc, 1); 2751d97d5ee9SPawel Jakub Dawidek return (0); 27522d1661a5SPawel Jakub Dawidek } 27532d1661a5SPawel Jakub Dawidek 27542d1661a5SPawel Jakub Dawidek static struct g_geom * 27552d1661a5SPawel Jakub Dawidek g_raid3_create(struct g_class *mp, const struct g_raid3_metadata *md) 27562d1661a5SPawel Jakub Dawidek { 27572d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 27582d1661a5SPawel Jakub Dawidek struct g_geom *gp; 27592d1661a5SPawel Jakub Dawidek int error, timeout; 27602d1661a5SPawel Jakub Dawidek u_int n; 27612d1661a5SPawel Jakub Dawidek 27622d1661a5SPawel Jakub Dawidek g_topology_assert(); 27632d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Creating device %s (id=%u).", md->md_name, md->md_id); 27642d1661a5SPawel Jakub Dawidek 27652d1661a5SPawel Jakub Dawidek /* One disk is minimum. */ 27662d1661a5SPawel Jakub Dawidek if (md->md_all < 1) 27672d1661a5SPawel Jakub Dawidek return (NULL); 27682d1661a5SPawel Jakub Dawidek /* 27692d1661a5SPawel Jakub Dawidek * Action geom. 27702d1661a5SPawel Jakub Dawidek */ 27712d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "%s", md->md_name); 27722d1661a5SPawel Jakub Dawidek sc = malloc(sizeof(*sc), M_RAID3, M_WAITOK | M_ZERO); 27732d1661a5SPawel Jakub Dawidek sc->sc_disks = malloc(sizeof(struct g_raid3_disk) * md->md_all, M_RAID3, 27742d1661a5SPawel Jakub Dawidek M_WAITOK | M_ZERO); 27752d1661a5SPawel Jakub Dawidek gp->start = g_raid3_start; 27762d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_orphan; 27772d1661a5SPawel Jakub Dawidek gp->access = g_raid3_access; 27782d1661a5SPawel Jakub Dawidek gp->dumpconf = g_raid3_dumpconf; 27792d1661a5SPawel Jakub Dawidek 27802d1661a5SPawel Jakub Dawidek sc->sc_id = md->md_id; 27812d1661a5SPawel Jakub Dawidek sc->sc_mediasize = md->md_mediasize; 27822d1661a5SPawel Jakub Dawidek sc->sc_sectorsize = md->md_sectorsize; 27832d1661a5SPawel Jakub Dawidek sc->sc_ndisks = md->md_all; 2784f5a2f7feSPawel Jakub Dawidek sc->sc_round_robin = 0; 27852d1661a5SPawel Jakub Dawidek sc->sc_flags = md->md_mflags; 2786a245a548SPawel Jakub Dawidek sc->sc_bump_id = 0; 27870962f942SPawel Jakub Dawidek sc->sc_idle = 1; 278801f1f41cSPawel Jakub Dawidek sc->sc_last_write = time_uptime; 27890962f942SPawel Jakub Dawidek sc->sc_writes = 0; 2790afd05d74SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 2791afd05d74SPawel Jakub Dawidek sc->sc_disks[n].d_softc = sc; 2792afd05d74SPawel Jakub Dawidek sc->sc_disks[n].d_no = n; 27932d1661a5SPawel Jakub Dawidek sc->sc_disks[n].d_state = G_RAID3_DISK_STATE_NODISK; 2794afd05d74SPawel Jakub Dawidek } 27952d1661a5SPawel Jakub Dawidek bioq_init(&sc->sc_queue); 27962d1661a5SPawel Jakub Dawidek mtx_init(&sc->sc_queue_mtx, "graid3:queue", NULL, MTX_DEF); 27972d1661a5SPawel Jakub Dawidek TAILQ_INIT(&sc->sc_events); 27982d1661a5SPawel Jakub Dawidek mtx_init(&sc->sc_events_mtx, "graid3:events", NULL, MTX_DEF); 27992d1661a5SPawel Jakub Dawidek callout_init(&sc->sc_callout, CALLOUT_MPSAFE); 28002d1661a5SPawel Jakub Dawidek sc->sc_state = G_RAID3_DEVICE_STATE_STARTING; 28012d1661a5SPawel Jakub Dawidek gp->softc = sc; 28022d1661a5SPawel Jakub Dawidek sc->sc_geom = gp; 28032d1661a5SPawel Jakub Dawidek sc->sc_provider = NULL; 28042d1661a5SPawel Jakub Dawidek /* 28052d1661a5SPawel Jakub Dawidek * Synchronization geom. 28062d1661a5SPawel Jakub Dawidek */ 28072d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "%s.sync", md->md_name); 28082d1661a5SPawel Jakub Dawidek gp->softc = sc; 28092d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_orphan; 28102d1661a5SPawel Jakub Dawidek sc->sc_sync.ds_geom = gp; 28112d1661a5SPawel Jakub Dawidek sc->sc_zone_64k = uma_zcreate("gr3:64k", 65536, NULL, NULL, NULL, NULL, 28122d1661a5SPawel Jakub Dawidek UMA_ALIGN_PTR, 0); 28132d1661a5SPawel Jakub Dawidek uma_zone_set_max(sc->sc_zone_64k, g_raid3_n64k); 28142d1661a5SPawel Jakub Dawidek sc->sc_zone_16k = uma_zcreate("gr3:16k", 16384, NULL, NULL, NULL, NULL, 28152d1661a5SPawel Jakub Dawidek UMA_ALIGN_PTR, 0); 281687e9d284SPawel Jakub Dawidek uma_zone_set_max(sc->sc_zone_16k, g_raid3_n16k); 28172d1661a5SPawel Jakub Dawidek sc->sc_zone_4k = uma_zcreate("gr3:4k", 4096, NULL, NULL, NULL, NULL, 28182d1661a5SPawel Jakub Dawidek UMA_ALIGN_PTR, 0); 28192d1661a5SPawel Jakub Dawidek uma_zone_set_max(sc->sc_zone_4k, g_raid3_n4k); 28202d1661a5SPawel Jakub Dawidek error = kthread_create(g_raid3_worker, sc, &sc->sc_worker, 0, 0, 28212d1661a5SPawel Jakub Dawidek "g_raid3 %s", md->md_name); 28222d1661a5SPawel Jakub Dawidek if (error != 0) { 28232d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Cannot create kernel thread for %s.", 28242d1661a5SPawel Jakub Dawidek sc->sc_name); 28252d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_64k); 28262d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_16k); 28272d1661a5SPawel Jakub Dawidek uma_zdestroy(sc->sc_zone_4k); 28282d1661a5SPawel Jakub Dawidek g_destroy_geom(sc->sc_sync.ds_geom); 28292d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_events_mtx); 28302d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 28312d1661a5SPawel Jakub Dawidek g_destroy_geom(sc->sc_geom); 28322d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 28332d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 28342d1661a5SPawel Jakub Dawidek return (NULL); 28352d1661a5SPawel Jakub Dawidek } 28362d1661a5SPawel Jakub Dawidek 28372d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id); 28382d1661a5SPawel Jakub Dawidek 28394ed854e8SPawel Jakub Dawidek sc->sc_rootmount = root_mount_hold("GRAID3"); 28404ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_hold %p", sc->sc_rootmount); 28414ed854e8SPawel Jakub Dawidek 28422d1661a5SPawel Jakub Dawidek /* 28432d1661a5SPawel Jakub Dawidek * Run timeout. 28442d1661a5SPawel Jakub Dawidek */ 28452d1661a5SPawel Jakub Dawidek timeout = atomic_load_acq_int(&g_raid3_timeout); 28462d1661a5SPawel Jakub Dawidek callout_reset(&sc->sc_callout, timeout * hz, g_raid3_go, sc); 28472d1661a5SPawel Jakub Dawidek return (sc->sc_geom); 28482d1661a5SPawel Jakub Dawidek } 28492d1661a5SPawel Jakub Dawidek 28502d1661a5SPawel Jakub Dawidek int 28512d1661a5SPawel Jakub Dawidek g_raid3_destroy(struct g_raid3_softc *sc, boolean_t force) 28522d1661a5SPawel Jakub Dawidek { 28532d1661a5SPawel Jakub Dawidek struct g_provider *pp; 28542d1661a5SPawel Jakub Dawidek 28552d1661a5SPawel Jakub Dawidek g_topology_assert(); 28562d1661a5SPawel Jakub Dawidek 28572d1661a5SPawel Jakub Dawidek if (sc == NULL) 28582d1661a5SPawel Jakub Dawidek return (ENXIO); 28592d1661a5SPawel Jakub Dawidek pp = sc->sc_provider; 28602d1661a5SPawel Jakub Dawidek if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 28612d1661a5SPawel Jakub Dawidek if (force) { 28624485f000SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s is still open, so it " 28632d1661a5SPawel Jakub Dawidek "can't be definitely removed.", pp->name); 28642d1661a5SPawel Jakub Dawidek } else { 28652d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28662d1661a5SPawel Jakub Dawidek "Device %s is still open (r%dw%de%d).", pp->name, 28672d1661a5SPawel Jakub Dawidek pp->acr, pp->acw, pp->ace); 28682d1661a5SPawel Jakub Dawidek return (EBUSY); 28692d1661a5SPawel Jakub Dawidek } 28702d1661a5SPawel Jakub Dawidek } 28712d1661a5SPawel Jakub Dawidek 28722d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 28732d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_WAIT; 28742d1661a5SPawel Jakub Dawidek g_topology_unlock(); 28752d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 28762d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 28772d1661a5SPawel Jakub Dawidek wakeup(sc); 28782d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 28792d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 28802d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, &sc->sc_worker); 28812d1661a5SPawel Jakub Dawidek while (sc->sc_worker != NULL) 28822d1661a5SPawel Jakub Dawidek tsleep(&sc->sc_worker, PRIBIO, "r3:destroy", hz / 5); 28832d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Woken up %p.", __func__, &sc->sc_worker); 28842d1661a5SPawel Jakub Dawidek g_topology_lock(); 28852d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(sc); 28862d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 28872d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 28882d1661a5SPawel Jakub Dawidek return (0); 28892d1661a5SPawel Jakub Dawidek } 28902d1661a5SPawel Jakub Dawidek 28912d1661a5SPawel Jakub Dawidek static void 28922d1661a5SPawel Jakub Dawidek g_raid3_taste_orphan(struct g_consumer *cp) 28932d1661a5SPawel Jakub Dawidek { 28942d1661a5SPawel Jakub Dawidek 28952d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("%s called while tasting %s.", __func__, 28962d1661a5SPawel Jakub Dawidek cp->provider->name)); 28972d1661a5SPawel Jakub Dawidek } 28982d1661a5SPawel Jakub Dawidek 28992d1661a5SPawel Jakub Dawidek static struct g_geom * 29002d1661a5SPawel Jakub Dawidek g_raid3_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 29012d1661a5SPawel Jakub Dawidek { 29022d1661a5SPawel Jakub Dawidek struct g_raid3_metadata md; 29032d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 29042d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 29052d1661a5SPawel Jakub Dawidek struct g_geom *gp; 29062d1661a5SPawel Jakub Dawidek int error; 29072d1661a5SPawel Jakub Dawidek 29082d1661a5SPawel Jakub Dawidek g_topology_assert(); 29092d1661a5SPawel Jakub Dawidek g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 29102d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Tasting %s.", pp->name); 29112d1661a5SPawel Jakub Dawidek 29122d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "raid3:taste"); 29132d1661a5SPawel Jakub Dawidek /* This orphan function should be never called. */ 29142d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_taste_orphan; 29152d1661a5SPawel Jakub Dawidek cp = g_new_consumer(gp); 29162d1661a5SPawel Jakub Dawidek g_attach(cp, pp); 29172d1661a5SPawel Jakub Dawidek error = g_raid3_read_metadata(cp, &md); 29182d1661a5SPawel Jakub Dawidek g_detach(cp); 29192d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 29202d1661a5SPawel Jakub Dawidek g_destroy_geom(gp); 29212d1661a5SPawel Jakub Dawidek if (error != 0) 29222d1661a5SPawel Jakub Dawidek return (NULL); 29232d1661a5SPawel Jakub Dawidek gp = NULL; 29242d1661a5SPawel Jakub Dawidek 29252d1661a5SPawel Jakub Dawidek if (md.md_provider[0] != '\0' && strcmp(md.md_provider, pp->name) != 0) 29262d1661a5SPawel Jakub Dawidek return (NULL); 2927e6890985SPawel Jakub Dawidek if (md.md_provsize != 0 && md.md_provsize != pp->mediasize) 2928e6890985SPawel Jakub Dawidek return (NULL); 29292d1661a5SPawel Jakub Dawidek if (g_raid3_debug >= 2) 29302d1661a5SPawel Jakub Dawidek raid3_metadata_dump(&md); 29312d1661a5SPawel Jakub Dawidek 29322d1661a5SPawel Jakub Dawidek /* 29332d1661a5SPawel Jakub Dawidek * Let's check if device already exists. 29342d1661a5SPawel Jakub Dawidek */ 293545d5e85aSPawel Jakub Dawidek sc = NULL; 29362d1661a5SPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 29372d1661a5SPawel Jakub Dawidek sc = gp->softc; 29382d1661a5SPawel Jakub Dawidek if (sc == NULL) 29392d1661a5SPawel Jakub Dawidek continue; 29402d1661a5SPawel Jakub Dawidek if (sc->sc_sync.ds_geom == gp) 29412d1661a5SPawel Jakub Dawidek continue; 29422d1661a5SPawel Jakub Dawidek if (strcmp(md.md_name, sc->sc_name) != 0) 29432d1661a5SPawel Jakub Dawidek continue; 29442d1661a5SPawel Jakub Dawidek if (md.md_id != sc->sc_id) { 29452d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s already configured.", 29462d1661a5SPawel Jakub Dawidek sc->sc_name); 29472d1661a5SPawel Jakub Dawidek return (NULL); 29482d1661a5SPawel Jakub Dawidek } 29492d1661a5SPawel Jakub Dawidek break; 29502d1661a5SPawel Jakub Dawidek } 29512d1661a5SPawel Jakub Dawidek if (gp == NULL) { 29522d1661a5SPawel Jakub Dawidek gp = g_raid3_create(mp, &md); 29532d1661a5SPawel Jakub Dawidek if (gp == NULL) { 29542d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot create device %s.", 29552d1661a5SPawel Jakub Dawidek md.md_name); 29562d1661a5SPawel Jakub Dawidek return (NULL); 29572d1661a5SPawel Jakub Dawidek } 29582d1661a5SPawel Jakub Dawidek sc = gp->softc; 29592d1661a5SPawel Jakub Dawidek } 29602d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 29612d1661a5SPawel Jakub Dawidek error = g_raid3_add_disk(sc, pp, &md); 29622d1661a5SPawel Jakub Dawidek if (error != 0) { 29632d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot add disk %s to %s (error=%d).", 29642d1661a5SPawel Jakub Dawidek pp->name, gp->name, error); 29652d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NODISK) == 29662d1661a5SPawel Jakub Dawidek sc->sc_ndisks) { 29672d1661a5SPawel Jakub Dawidek g_raid3_destroy(sc, 1); 29682d1661a5SPawel Jakub Dawidek } 29692d1661a5SPawel Jakub Dawidek return (NULL); 29702d1661a5SPawel Jakub Dawidek } 29712d1661a5SPawel Jakub Dawidek return (gp); 29722d1661a5SPawel Jakub Dawidek } 29732d1661a5SPawel Jakub Dawidek 29742d1661a5SPawel Jakub Dawidek static int 29752d1661a5SPawel Jakub Dawidek g_raid3_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused, 29762d1661a5SPawel Jakub Dawidek struct g_geom *gp) 29772d1661a5SPawel Jakub Dawidek { 29782d1661a5SPawel Jakub Dawidek 29792d1661a5SPawel Jakub Dawidek return (g_raid3_destroy(gp->softc, 0)); 29802d1661a5SPawel Jakub Dawidek } 29812d1661a5SPawel Jakub Dawidek 29822d1661a5SPawel Jakub Dawidek static void 29832d1661a5SPawel Jakub Dawidek g_raid3_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 29842d1661a5SPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 29852d1661a5SPawel Jakub Dawidek { 29862d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 29872d1661a5SPawel Jakub Dawidek 29882d1661a5SPawel Jakub Dawidek g_topology_assert(); 29892d1661a5SPawel Jakub Dawidek 29902d1661a5SPawel Jakub Dawidek sc = gp->softc; 29912d1661a5SPawel Jakub Dawidek if (sc == NULL) 29922d1661a5SPawel Jakub Dawidek return; 29932d1661a5SPawel Jakub Dawidek /* Skip synchronization geom. */ 29942d1661a5SPawel Jakub Dawidek if (gp == sc->sc_sync.ds_geom) 29952d1661a5SPawel Jakub Dawidek return; 29962d1661a5SPawel Jakub Dawidek if (pp != NULL) { 29972d1661a5SPawel Jakub Dawidek /* Nothing here. */ 29982d1661a5SPawel Jakub Dawidek } else if (cp != NULL) { 29992d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 30002d1661a5SPawel Jakub Dawidek 30012d1661a5SPawel Jakub Dawidek disk = cp->private; 30022d1661a5SPawel Jakub Dawidek if (disk == NULL) 30032d1661a5SPawel Jakub Dawidek return; 30042d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Type>", indent); 30052d1661a5SPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) 30062d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "PARITY"); 30072d1661a5SPawel Jakub Dawidek else 30082d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "DATA"); 30092d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Type>\n"); 30102d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Number>%u</Number>\n", indent, 30112d1661a5SPawel Jakub Dawidek (u_int)disk->d_no); 30122d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 30132d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Synchronized>", indent); 30142d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_offset_done == 0) 30152d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "0%%"); 30162d1661a5SPawel Jakub Dawidek else { 30172d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%u%%", 30182d1661a5SPawel Jakub Dawidek (u_int)((disk->d_sync.ds_offset_done * 100) / 3019c0d68b6eSPawel Jakub Dawidek (sc->sc_mediasize / (sc->sc_ndisks - 1)))); 30202d1661a5SPawel Jakub Dawidek } 30212d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Synchronized>\n"); 30222d1661a5SPawel Jakub Dawidek } 30232d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, 30242d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid); 3025a245a548SPawel Jakub Dawidek sbuf_printf(sb, "%s<GenID>%u</GenID>\n", indent, disk->d_genid); 30262d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Flags>", indent); 30272d1661a5SPawel Jakub Dawidek if (disk->d_flags == 0) 30282d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "NONE"); 30292d1661a5SPawel Jakub Dawidek else { 30302d1661a5SPawel Jakub Dawidek int first = 1; 30312d1661a5SPawel Jakub Dawidek 30322d1661a5SPawel Jakub Dawidek #define ADD_FLAG(flag, name) do { \ 30332d1661a5SPawel Jakub Dawidek if ((disk->d_flags & (flag)) != 0) { \ 30342d1661a5SPawel Jakub Dawidek if (!first) \ 30352d1661a5SPawel Jakub Dawidek sbuf_printf(sb, ", "); \ 30362d1661a5SPawel Jakub Dawidek else \ 30372d1661a5SPawel Jakub Dawidek first = 0; \ 30382d1661a5SPawel Jakub Dawidek sbuf_printf(sb, name); \ 30392d1661a5SPawel Jakub Dawidek } \ 30402d1661a5SPawel Jakub Dawidek } while (0) 30412d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_DIRTY, "DIRTY"); 30422d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_HARDCODED, "HARDCODED"); 30432d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_SYNCHRONIZING, 30442d1661a5SPawel Jakub Dawidek "SYNCHRONIZING"); 30452d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_FORCE_SYNC, "FORCE_SYNC"); 30463aae74ecSPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_BROKEN, "BROKEN"); 30472d1661a5SPawel Jakub Dawidek #undef ADD_FLAG 30482d1661a5SPawel Jakub Dawidek } 30492d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Flags>\n"); 30502d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<State>%s</State>\n", indent, 30512d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state)); 30522d1661a5SPawel Jakub Dawidek } else { 30532d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id); 30542d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, sc->sc_syncid); 3055a245a548SPawel Jakub Dawidek sbuf_printf(sb, "%s<GenID>%u</GenID>\n", indent, sc->sc_genid); 30562d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Flags>", indent); 30572d1661a5SPawel Jakub Dawidek if (sc->sc_flags == 0) 30582d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "NONE"); 30592d1661a5SPawel Jakub Dawidek else { 30602d1661a5SPawel Jakub Dawidek int first = 1; 30612d1661a5SPawel Jakub Dawidek 30622d1661a5SPawel Jakub Dawidek #define ADD_FLAG(flag, name) do { \ 30632d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & (flag)) != 0) { \ 30642d1661a5SPawel Jakub Dawidek if (!first) \ 30652d1661a5SPawel Jakub Dawidek sbuf_printf(sb, ", "); \ 30662d1661a5SPawel Jakub Dawidek else \ 30672d1661a5SPawel Jakub Dawidek first = 0; \ 30682d1661a5SPawel Jakub Dawidek sbuf_printf(sb, name); \ 30692d1661a5SPawel Jakub Dawidek } \ 30702d1661a5SPawel Jakub Dawidek } while (0) 30712d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DEVICE_FLAG_NOAUTOSYNC, "NOAUTOSYNC"); 3072f5a2f7feSPawel Jakub Dawidek ADD_FLAG(G_RAID3_DEVICE_FLAG_ROUND_ROBIN, 3073f5a2f7feSPawel Jakub Dawidek "ROUND-ROBIN"); 3074dba915cfSPawel Jakub Dawidek ADD_FLAG(G_RAID3_DEVICE_FLAG_VERIFY, "VERIFY"); 30752d1661a5SPawel Jakub Dawidek #undef ADD_FLAG 30762d1661a5SPawel Jakub Dawidek } 30772d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Flags>\n"); 30782d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Components>%u</Components>\n", indent, 30792d1661a5SPawel Jakub Dawidek sc->sc_ndisks); 308028b31df7SPawel Jakub Dawidek sbuf_printf(sb, "%s<State>%s</State>\n", indent, 308128b31df7SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state)); 30822d1661a5SPawel Jakub Dawidek } 30832d1661a5SPawel Jakub Dawidek } 30842d1661a5SPawel Jakub Dawidek 30859da3072cSPawel Jakub Dawidek static void 30869da3072cSPawel Jakub Dawidek g_raid3_shutdown(void *arg, int howto) 30879da3072cSPawel Jakub Dawidek { 30889da3072cSPawel Jakub Dawidek struct g_class *mp; 30899da3072cSPawel Jakub Dawidek struct g_geom *gp, *gp2; 30909da3072cSPawel Jakub Dawidek 30919da3072cSPawel Jakub Dawidek mp = arg; 3092fdc3c6ceSPawel Jakub Dawidek DROP_GIANT(); 30939da3072cSPawel Jakub Dawidek g_topology_lock(); 30949da3072cSPawel Jakub Dawidek LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 30959da3072cSPawel Jakub Dawidek if (gp->softc == NULL) 30969da3072cSPawel Jakub Dawidek continue; 30979da3072cSPawel Jakub Dawidek g_raid3_destroy(gp->softc, 1); 30989da3072cSPawel Jakub Dawidek } 30999da3072cSPawel Jakub Dawidek g_topology_unlock(); 3100fdc3c6ceSPawel Jakub Dawidek PICKUP_GIANT(); 31019da3072cSPawel Jakub Dawidek #if 0 31029da3072cSPawel Jakub Dawidek tsleep(&gp, PRIBIO, "r3:shutdown", hz * 20); 31039da3072cSPawel Jakub Dawidek #endif 31049da3072cSPawel Jakub Dawidek } 31059da3072cSPawel Jakub Dawidek 31069da3072cSPawel Jakub Dawidek static void 31079da3072cSPawel Jakub Dawidek g_raid3_init(struct g_class *mp) 31089da3072cSPawel Jakub Dawidek { 31099da3072cSPawel Jakub Dawidek 31109da3072cSPawel Jakub Dawidek g_raid3_ehtag = EVENTHANDLER_REGISTER(shutdown_post_sync, 31119da3072cSPawel Jakub Dawidek g_raid3_shutdown, mp, SHUTDOWN_PRI_FIRST); 31129da3072cSPawel Jakub Dawidek if (g_raid3_ehtag == NULL) 31139da3072cSPawel Jakub Dawidek G_RAID3_DEBUG(0, "Warning! Cannot register shutdown event."); 31149da3072cSPawel Jakub Dawidek } 31159da3072cSPawel Jakub Dawidek 31169da3072cSPawel Jakub Dawidek static void 31179da3072cSPawel Jakub Dawidek g_raid3_fini(struct g_class *mp) 31189da3072cSPawel Jakub Dawidek { 31199da3072cSPawel Jakub Dawidek 31209da3072cSPawel Jakub Dawidek if (g_raid3_ehtag == NULL) 31219da3072cSPawel Jakub Dawidek return; 31229da3072cSPawel Jakub Dawidek EVENTHANDLER_DEREGISTER(shutdown_post_sync, g_raid3_ehtag); 31239da3072cSPawel Jakub Dawidek } 31249da3072cSPawel Jakub Dawidek 31252d1661a5SPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_raid3_class, g_raid3); 3126