12d1661a5SPawel Jakub Dawidek /*- 2e6757059SPawel Jakub Dawidek * Copyright (c) 2004-2006 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"); 653aae74ecSPawel Jakub Dawidek static u_int g_raid3_disconnect_on_failure = 1; 6667cae8aaSPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.disconnect_on_failure", 6767cae8aaSPawel Jakub Dawidek &g_raid3_disconnect_on_failure); 683aae74ecSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, disconnect_on_failure, CTLFLAG_RW, 693aae74ecSPawel Jakub Dawidek &g_raid3_disconnect_on_failure, 0, "Disconnect component on I/O failure."); 70e6757059SPawel Jakub Dawidek static u_int g_raid3_syncreqs = 2; 713650be51SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.sync_requests", &g_raid3_syncreqs); 723650be51SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, sync_requests, CTLFLAG_RDTUN, 733650be51SPawel Jakub Dawidek &g_raid3_syncreqs, 0, "Parallel synchronization I/O requests."); 742d1661a5SPawel Jakub Dawidek 752d1661a5SPawel Jakub Dawidek static u_int g_raid3_n64k = 50; 762d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n64k", &g_raid3_n64k); 772d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n64k, CTLFLAG_RD, &g_raid3_n64k, 0, 782d1661a5SPawel Jakub Dawidek "Maximum number of 64kB allocations"); 792d1661a5SPawel Jakub Dawidek static u_int g_raid3_n16k = 200; 802d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n16k", &g_raid3_n16k); 812d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n16k, CTLFLAG_RD, &g_raid3_n16k, 0, 822d1661a5SPawel Jakub Dawidek "Maximum number of 16kB allocations"); 832d1661a5SPawel Jakub Dawidek static u_int g_raid3_n4k = 1200; 842d1661a5SPawel Jakub Dawidek TUNABLE_INT("kern.geom.raid3.n4k", &g_raid3_n4k); 852d1661a5SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, n4k, CTLFLAG_RD, &g_raid3_n4k, 0, 862d1661a5SPawel Jakub Dawidek "Maximum number of 4kB allocations"); 872d1661a5SPawel Jakub Dawidek 882d1661a5SPawel Jakub Dawidek SYSCTL_NODE(_kern_geom_raid3, OID_AUTO, stat, CTLFLAG_RW, 0, 892d1661a5SPawel Jakub Dawidek "GEOM_RAID3 statistics"); 90dba915cfSPawel Jakub Dawidek static u_int g_raid3_parity_mismatch = 0; 91dba915cfSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, parity_mismatch, CTLFLAG_RD, 92dba915cfSPawel Jakub Dawidek &g_raid3_parity_mismatch, 0, "Number of failures in VERIFY mode"); 932d1661a5SPawel Jakub Dawidek 942d1661a5SPawel Jakub Dawidek #define MSLEEP(ident, mtx, priority, wmesg, timeout) do { \ 952d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, (ident)); \ 962d1661a5SPawel Jakub Dawidek msleep((ident), (mtx), (priority), (wmesg), (timeout)); \ 972d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Woken up %p.", __func__, (ident)); \ 982d1661a5SPawel Jakub Dawidek } while (0) 992d1661a5SPawel Jakub Dawidek 100712fe9bdSPawel Jakub Dawidek static eventhandler_tag g_raid3_pre_sync = NULL; 1012d1661a5SPawel Jakub Dawidek 1022d1661a5SPawel Jakub Dawidek static int g_raid3_destroy_geom(struct gctl_req *req, struct g_class *mp, 1032d1661a5SPawel Jakub Dawidek struct g_geom *gp); 1042d1661a5SPawel Jakub Dawidek static g_taste_t g_raid3_taste; 1059da3072cSPawel Jakub Dawidek static void g_raid3_init(struct g_class *mp); 1069da3072cSPawel Jakub Dawidek static void g_raid3_fini(struct g_class *mp); 1072d1661a5SPawel Jakub Dawidek 1082d1661a5SPawel Jakub Dawidek struct g_class g_raid3_class = { 1092d1661a5SPawel Jakub Dawidek .name = G_RAID3_CLASS_NAME, 1102d1661a5SPawel Jakub Dawidek .version = G_VERSION, 1112d1661a5SPawel Jakub Dawidek .ctlreq = g_raid3_config, 1122d1661a5SPawel Jakub Dawidek .taste = g_raid3_taste, 1139da3072cSPawel Jakub Dawidek .destroy_geom = g_raid3_destroy_geom, 1149da3072cSPawel Jakub Dawidek .init = g_raid3_init, 1159da3072cSPawel Jakub Dawidek .fini = g_raid3_fini 1162d1661a5SPawel Jakub Dawidek }; 1172d1661a5SPawel Jakub Dawidek 1182d1661a5SPawel Jakub Dawidek 1192d1661a5SPawel Jakub Dawidek static void g_raid3_destroy_provider(struct g_raid3_softc *sc); 120d97d5ee9SPawel Jakub Dawidek static int g_raid3_update_disk(struct g_raid3_disk *disk, u_int state); 121d97d5ee9SPawel Jakub Dawidek static void g_raid3_update_device(struct g_raid3_softc *sc, boolean_t force); 1222d1661a5SPawel Jakub Dawidek static void g_raid3_dumpconf(struct sbuf *sb, const char *indent, 1232d1661a5SPawel Jakub Dawidek struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp); 1242d1661a5SPawel Jakub Dawidek static void g_raid3_sync_stop(struct g_raid3_softc *sc, int type); 1253650be51SPawel Jakub Dawidek static int g_raid3_register_request(struct bio *pbp); 1263650be51SPawel Jakub Dawidek static void g_raid3_sync_release(struct g_raid3_softc *sc); 1272d1661a5SPawel Jakub Dawidek 1282d1661a5SPawel Jakub Dawidek 1292d1661a5SPawel Jakub Dawidek static const char * 1302d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(int state) 1312d1661a5SPawel Jakub Dawidek { 1322d1661a5SPawel Jakub Dawidek 1332d1661a5SPawel Jakub Dawidek switch (state) { 1342d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NODISK: 1352d1661a5SPawel Jakub Dawidek return ("NODISK"); 1362d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NONE: 1372d1661a5SPawel Jakub Dawidek return ("NONE"); 1382d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 1392d1661a5SPawel Jakub Dawidek return ("NEW"); 1402d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 1412d1661a5SPawel Jakub Dawidek return ("ACTIVE"); 1422d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 1432d1661a5SPawel Jakub Dawidek return ("STALE"); 1442d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 1452d1661a5SPawel Jakub Dawidek return ("SYNCHRONIZING"); 1462d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_DISCONNECTED: 1472d1661a5SPawel Jakub Dawidek return ("DISCONNECTED"); 1482d1661a5SPawel Jakub Dawidek default: 1492d1661a5SPawel Jakub Dawidek return ("INVALID"); 1502d1661a5SPawel Jakub Dawidek } 1512d1661a5SPawel Jakub Dawidek } 1522d1661a5SPawel Jakub Dawidek 1532d1661a5SPawel Jakub Dawidek static const char * 1542d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(int state) 1552d1661a5SPawel Jakub Dawidek { 1562d1661a5SPawel Jakub Dawidek 1572d1661a5SPawel Jakub Dawidek switch (state) { 1582d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_STARTING: 1592d1661a5SPawel Jakub Dawidek return ("STARTING"); 1602d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_DEGRADED: 1612d1661a5SPawel Jakub Dawidek return ("DEGRADED"); 1622d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_COMPLETE: 1632d1661a5SPawel Jakub Dawidek return ("COMPLETE"); 1642d1661a5SPawel Jakub Dawidek default: 1652d1661a5SPawel Jakub Dawidek return ("INVALID"); 1662d1661a5SPawel Jakub Dawidek } 1672d1661a5SPawel Jakub Dawidek } 1682d1661a5SPawel Jakub Dawidek 1692d1661a5SPawel Jakub Dawidek const char * 1702d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(struct g_raid3_disk *disk) 1712d1661a5SPawel Jakub Dawidek { 1722d1661a5SPawel Jakub Dawidek 1732d1661a5SPawel Jakub Dawidek if (disk->d_consumer == NULL || disk->d_consumer->provider == NULL) 1742d1661a5SPawel Jakub Dawidek return ("[unknown]"); 1752d1661a5SPawel Jakub Dawidek return (disk->d_name); 1762d1661a5SPawel Jakub Dawidek } 1772d1661a5SPawel Jakub Dawidek 1783650be51SPawel Jakub Dawidek static int 1793650be51SPawel Jakub Dawidek g_raid3_uma_ctor(void *mem, int size, void *arg, int flags) 1803650be51SPawel Jakub Dawidek { 1813650be51SPawel Jakub Dawidek struct g_raid3_zone *sz = arg; 1823650be51SPawel Jakub Dawidek 1830d14fae5SPawel Jakub Dawidek if (sz->sz_max > 0 && sz->sz_inuse == sz->sz_max) 1843650be51SPawel Jakub Dawidek return (ENOMEM); 1853650be51SPawel Jakub Dawidek sz->sz_inuse++; 1863650be51SPawel Jakub Dawidek return (0); 1873650be51SPawel Jakub Dawidek } 1883650be51SPawel Jakub Dawidek 1893650be51SPawel Jakub Dawidek static void 1903650be51SPawel Jakub Dawidek g_raid3_uma_dtor(void *mem, int size, void *arg) 1913650be51SPawel Jakub Dawidek { 1923650be51SPawel Jakub Dawidek struct g_raid3_zone *sz = arg; 1933650be51SPawel Jakub Dawidek 1943650be51SPawel Jakub Dawidek sz->sz_inuse--; 1953650be51SPawel Jakub Dawidek } 1963650be51SPawel Jakub Dawidek 1972d1661a5SPawel Jakub Dawidek #define g_raid3_xor(src1, src2, dst, size) \ 1982d1661a5SPawel Jakub Dawidek _g_raid3_xor((uint64_t *)(src1), (uint64_t *)(src2), \ 1992d1661a5SPawel Jakub Dawidek (uint64_t *)(dst), (size_t)size) 2002d1661a5SPawel Jakub Dawidek static void 2012d1661a5SPawel Jakub Dawidek _g_raid3_xor(uint64_t *src1, uint64_t *src2, uint64_t *dst, size_t size) 2022d1661a5SPawel Jakub Dawidek { 2032d1661a5SPawel Jakub Dawidek 2042d1661a5SPawel Jakub Dawidek KASSERT((size % 128) == 0, ("Invalid size: %zu.", size)); 2052d1661a5SPawel Jakub Dawidek for (; size > 0; size -= 128) { 2062d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2072d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2082d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2092d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2102d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2112d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2122d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2132d1661a5SPawel Jakub Dawidek *dst++ = (*src1++) ^ (*src2++); 2142d1661a5SPawel Jakub Dawidek *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 } 2232d1661a5SPawel Jakub Dawidek } 2242d1661a5SPawel Jakub Dawidek 225dba915cfSPawel Jakub Dawidek static int 226dba915cfSPawel Jakub Dawidek g_raid3_is_zero(struct bio *bp) 227dba915cfSPawel Jakub Dawidek { 228dba915cfSPawel Jakub Dawidek static const uint64_t zeros[] = { 229dba915cfSPawel Jakub Dawidek 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 230dba915cfSPawel Jakub Dawidek }; 231dba915cfSPawel Jakub Dawidek u_char *addr; 232dba915cfSPawel Jakub Dawidek ssize_t size; 233dba915cfSPawel Jakub Dawidek 234dba915cfSPawel Jakub Dawidek size = bp->bio_length; 235dba915cfSPawel Jakub Dawidek addr = (u_char *)bp->bio_data; 236dba915cfSPawel Jakub Dawidek for (; size > 0; size -= sizeof(zeros), addr += sizeof(zeros)) { 237dba915cfSPawel Jakub Dawidek if (bcmp(addr, zeros, sizeof(zeros)) != 0) 238dba915cfSPawel Jakub Dawidek return (0); 239dba915cfSPawel Jakub Dawidek } 240dba915cfSPawel Jakub Dawidek return (1); 241dba915cfSPawel Jakub Dawidek } 242dba915cfSPawel Jakub Dawidek 2432d1661a5SPawel Jakub Dawidek /* 2442d1661a5SPawel Jakub Dawidek * --- Events handling functions --- 2452d1661a5SPawel Jakub Dawidek * Events in geom_raid3 are used to maintain disks and device status 2462d1661a5SPawel Jakub Dawidek * from one thread to simplify locking. 2472d1661a5SPawel Jakub Dawidek */ 2482d1661a5SPawel Jakub Dawidek static void 2492d1661a5SPawel Jakub Dawidek g_raid3_event_free(struct g_raid3_event *ep) 2502d1661a5SPawel Jakub Dawidek { 2512d1661a5SPawel Jakub Dawidek 2522d1661a5SPawel Jakub Dawidek free(ep, M_RAID3); 2532d1661a5SPawel Jakub Dawidek } 2542d1661a5SPawel Jakub Dawidek 2552d1661a5SPawel Jakub Dawidek int 2562d1661a5SPawel Jakub Dawidek g_raid3_event_send(void *arg, int state, int flags) 2572d1661a5SPawel Jakub Dawidek { 2582d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2592d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 2602d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 2612d1661a5SPawel Jakub Dawidek int error; 2622d1661a5SPawel Jakub Dawidek 2632d1661a5SPawel Jakub Dawidek ep = malloc(sizeof(*ep), M_RAID3, M_WAITOK); 2642d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sending event %p.", __func__, ep); 2652d1661a5SPawel Jakub Dawidek if ((flags & G_RAID3_EVENT_DEVICE) != 0) { 2662d1661a5SPawel Jakub Dawidek disk = NULL; 2672d1661a5SPawel Jakub Dawidek sc = arg; 2682d1661a5SPawel Jakub Dawidek } else { 2692d1661a5SPawel Jakub Dawidek disk = arg; 2702d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 2712d1661a5SPawel Jakub Dawidek } 2722d1661a5SPawel Jakub Dawidek ep->e_disk = disk; 2732d1661a5SPawel Jakub Dawidek ep->e_state = state; 2742d1661a5SPawel Jakub Dawidek ep->e_flags = flags; 2752d1661a5SPawel Jakub Dawidek ep->e_error = 0; 2762d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2772d1661a5SPawel Jakub Dawidek TAILQ_INSERT_TAIL(&sc->sc_events, ep, e_next); 2782d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 2792d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 2802d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 2812d1661a5SPawel Jakub Dawidek wakeup(sc); 2822d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 2832d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 2842d1661a5SPawel Jakub Dawidek if ((flags & G_RAID3_EVENT_DONTWAIT) != 0) 2852d1661a5SPawel Jakub Dawidek return (0); 2863650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 2872d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, ep); 2883650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 2892d1661a5SPawel Jakub Dawidek while ((ep->e_flags & G_RAID3_EVENT_DONE) == 0) { 2902d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 2912d1661a5SPawel Jakub Dawidek MSLEEP(ep, &sc->sc_events_mtx, PRIBIO | PDROP, "r3:event", 2922d1661a5SPawel Jakub Dawidek hz * 5); 2932d1661a5SPawel Jakub Dawidek } 2942d1661a5SPawel Jakub Dawidek error = ep->e_error; 2952d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 2963650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 2972d1661a5SPawel Jakub Dawidek return (error); 2982d1661a5SPawel Jakub Dawidek } 2992d1661a5SPawel Jakub Dawidek 3002d1661a5SPawel Jakub Dawidek static struct g_raid3_event * 3012d1661a5SPawel Jakub Dawidek g_raid3_event_get(struct g_raid3_softc *sc) 3022d1661a5SPawel Jakub Dawidek { 3032d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 3042d1661a5SPawel Jakub Dawidek 3052d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 3062d1661a5SPawel Jakub Dawidek ep = TAILQ_FIRST(&sc->sc_events); 3072d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 3082d1661a5SPawel Jakub Dawidek return (ep); 3092d1661a5SPawel Jakub Dawidek } 3102d1661a5SPawel Jakub Dawidek 3112d1661a5SPawel Jakub Dawidek static void 312d97d5ee9SPawel Jakub Dawidek g_raid3_event_remove(struct g_raid3_softc *sc, struct g_raid3_event *ep) 313d97d5ee9SPawel Jakub Dawidek { 314d97d5ee9SPawel Jakub Dawidek 315d97d5ee9SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 316d97d5ee9SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_events, ep, e_next); 317d97d5ee9SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 318d97d5ee9SPawel Jakub Dawidek } 319d97d5ee9SPawel Jakub Dawidek 320d97d5ee9SPawel Jakub Dawidek static void 3212d1661a5SPawel Jakub Dawidek g_raid3_event_cancel(struct g_raid3_disk *disk) 3222d1661a5SPawel Jakub Dawidek { 3232d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 3242d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep, *tmpep; 3252d1661a5SPawel Jakub Dawidek 3262d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 3273650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 3283650be51SPawel Jakub Dawidek 3292d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 3302d1661a5SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(ep, &sc->sc_events, e_next, tmpep) { 3312d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DEVICE) != 0) 3322d1661a5SPawel Jakub Dawidek continue; 3332d1661a5SPawel Jakub Dawidek if (ep->e_disk != disk) 3342d1661a5SPawel Jakub Dawidek continue; 3352d1661a5SPawel Jakub Dawidek TAILQ_REMOVE(&sc->sc_events, ep, e_next); 3362d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) 3372d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 3382d1661a5SPawel Jakub Dawidek else { 3392d1661a5SPawel Jakub Dawidek ep->e_error = ECANCELED; 3402d1661a5SPawel Jakub Dawidek wakeup(ep); 3412d1661a5SPawel Jakub Dawidek } 3422d1661a5SPawel Jakub Dawidek } 3432d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 3442d1661a5SPawel Jakub Dawidek } 3452d1661a5SPawel Jakub Dawidek 3462d1661a5SPawel Jakub Dawidek /* 3472d1661a5SPawel Jakub Dawidek * Return the number of disks in the given state. 3482d1661a5SPawel Jakub Dawidek * If state is equal to -1, count all connected disks. 3492d1661a5SPawel Jakub Dawidek */ 3502d1661a5SPawel Jakub Dawidek u_int 3512d1661a5SPawel Jakub Dawidek g_raid3_ndisks(struct g_raid3_softc *sc, int state) 3522d1661a5SPawel Jakub Dawidek { 3532d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 354fa6a7837SDavid E. O'Brien u_int n, ndisks; 3552d1661a5SPawel Jakub Dawidek 3563650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_LOCKED); 3573650be51SPawel 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 4073650be51SPawel Jakub Dawidek g_topology_assert(); 4083650be51SPawel Jakub Dawidek 409d97d5ee9SPawel Jakub Dawidek cp = arg; 410d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Consumer %s destroyed.", cp->provider->name); 411d97d5ee9SPawel Jakub Dawidek g_detach(cp); 412d97d5ee9SPawel Jakub Dawidek g_destroy_consumer(cp); 413d97d5ee9SPawel Jakub Dawidek } 414d97d5ee9SPawel Jakub Dawidek 415d97d5ee9SPawel Jakub Dawidek static void 4162d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(struct g_raid3_softc *sc, struct g_consumer *cp) 4172d1661a5SPawel Jakub Dawidek { 418d97d5ee9SPawel Jakub Dawidek struct g_provider *pp; 419d97d5ee9SPawel Jakub Dawidek int retaste_wait; 4202d1661a5SPawel Jakub Dawidek 4212d1661a5SPawel Jakub Dawidek g_topology_assert(); 4222d1661a5SPawel Jakub Dawidek 4232d1661a5SPawel Jakub Dawidek cp->private = NULL; 4242d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 4252d1661a5SPawel Jakub Dawidek return; 4262d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Consumer %s destroyed.", cp->provider->name); 427d97d5ee9SPawel Jakub Dawidek pp = cp->provider; 428d97d5ee9SPawel Jakub Dawidek retaste_wait = 0; 429d97d5ee9SPawel Jakub Dawidek if (cp->acw == 1) { 430d97d5ee9SPawel Jakub Dawidek if ((pp->geom->flags & G_GEOM_WITHER) == 0) 431d97d5ee9SPawel Jakub Dawidek retaste_wait = 1; 432d97d5ee9SPawel Jakub Dawidek } 433d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access %s r%dw%de%d = %d", pp->name, -cp->acr, 434d97d5ee9SPawel Jakub Dawidek -cp->acw, -cp->ace, 0); 435d97d5ee9SPawel Jakub Dawidek if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 436d97d5ee9SPawel Jakub Dawidek g_access(cp, -cp->acr, -cp->acw, -cp->ace); 437d97d5ee9SPawel Jakub Dawidek if (retaste_wait) { 438d97d5ee9SPawel Jakub Dawidek /* 439d97d5ee9SPawel Jakub Dawidek * After retaste event was send (inside g_access()), we can send 440d97d5ee9SPawel Jakub Dawidek * event to detach and destroy consumer. 441d97d5ee9SPawel Jakub Dawidek * A class, which has consumer to the given provider connected 442d97d5ee9SPawel Jakub Dawidek * will not receive retaste event for the provider. 443d97d5ee9SPawel Jakub Dawidek * This is the way how I ignore retaste events when I close 444d97d5ee9SPawel Jakub Dawidek * consumers opened for write: I detach and destroy consumer 445d97d5ee9SPawel Jakub Dawidek * after retaste event is sent. 446d97d5ee9SPawel Jakub Dawidek */ 447d97d5ee9SPawel Jakub Dawidek g_post_event(g_raid3_destroy_consumer, cp, M_WAITOK, NULL); 448d97d5ee9SPawel Jakub Dawidek return; 449d97d5ee9SPawel Jakub Dawidek } 450d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Consumer %s destroyed.", pp->name); 4512d1661a5SPawel Jakub Dawidek g_detach(cp); 4522d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 4532d1661a5SPawel Jakub Dawidek } 4542d1661a5SPawel Jakub Dawidek 4552d1661a5SPawel Jakub Dawidek static int 4562d1661a5SPawel Jakub Dawidek g_raid3_connect_disk(struct g_raid3_disk *disk, struct g_provider *pp) 4572d1661a5SPawel Jakub Dawidek { 45834cb1517SPawel Jakub Dawidek struct g_consumer *cp; 4592d1661a5SPawel Jakub Dawidek int error; 4602d1661a5SPawel Jakub Dawidek 4613650be51SPawel Jakub Dawidek g_topology_assert_not(); 4622d1661a5SPawel Jakub Dawidek KASSERT(disk->d_consumer == NULL, 4632d1661a5SPawel Jakub Dawidek ("Disk already connected (device %s).", disk->d_softc->sc_name)); 4642d1661a5SPawel Jakub Dawidek 4653650be51SPawel Jakub Dawidek g_topology_lock(); 46634cb1517SPawel Jakub Dawidek cp = g_new_consumer(disk->d_softc->sc_geom); 46734cb1517SPawel Jakub Dawidek error = g_attach(cp, pp); 468d97d5ee9SPawel Jakub Dawidek if (error != 0) { 46934cb1517SPawel Jakub Dawidek g_destroy_consumer(cp); 4703650be51SPawel Jakub Dawidek g_topology_unlock(); 47134cb1517SPawel Jakub Dawidek return (error); 47234cb1517SPawel Jakub Dawidek } 47334cb1517SPawel Jakub Dawidek error = g_access(cp, 1, 1, 1); 4743650be51SPawel Jakub Dawidek g_topology_unlock(); 47534cb1517SPawel Jakub Dawidek if (error != 0) { 47634cb1517SPawel Jakub Dawidek g_detach(cp); 47734cb1517SPawel Jakub Dawidek g_destroy_consumer(cp); 478d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot open consumer %s (error=%d).", 479d97d5ee9SPawel Jakub Dawidek pp->name, error); 480d97d5ee9SPawel Jakub Dawidek return (error); 481d97d5ee9SPawel Jakub Dawidek } 48234cb1517SPawel Jakub Dawidek disk->d_consumer = cp; 48334cb1517SPawel Jakub Dawidek disk->d_consumer->private = disk; 48434cb1517SPawel Jakub Dawidek disk->d_consumer->index = 0; 4852d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Disk %s connected.", g_raid3_get_diskname(disk)); 4862d1661a5SPawel Jakub Dawidek return (0); 4872d1661a5SPawel Jakub Dawidek } 4882d1661a5SPawel Jakub Dawidek 4892d1661a5SPawel Jakub Dawidek static void 4902d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(struct g_raid3_softc *sc, struct g_consumer *cp) 4912d1661a5SPawel Jakub Dawidek { 4922d1661a5SPawel Jakub Dawidek 4932d1661a5SPawel Jakub Dawidek g_topology_assert(); 4942d1661a5SPawel Jakub Dawidek 4952d1661a5SPawel Jakub Dawidek if (cp == NULL) 4962d1661a5SPawel Jakub Dawidek return; 497d97d5ee9SPawel Jakub Dawidek if (cp->provider != NULL) 4982d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, cp); 499d97d5ee9SPawel Jakub Dawidek else 5002d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 5012d1661a5SPawel Jakub Dawidek } 5022d1661a5SPawel Jakub Dawidek 5032d1661a5SPawel Jakub Dawidek /* 5042d1661a5SPawel Jakub Dawidek * Initialize disk. This means allocate memory, create consumer, attach it 5052d1661a5SPawel Jakub Dawidek * to the provider and open access (r1w1e1) to it. 5062d1661a5SPawel Jakub Dawidek */ 5072d1661a5SPawel Jakub Dawidek static struct g_raid3_disk * 5082d1661a5SPawel Jakub Dawidek g_raid3_init_disk(struct g_raid3_softc *sc, struct g_provider *pp, 5092d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md, int *errorp) 5102d1661a5SPawel Jakub Dawidek { 5112d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 5122d1661a5SPawel Jakub Dawidek int error; 5132d1661a5SPawel Jakub Dawidek 5142d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[md->md_no]; 5152d1661a5SPawel Jakub Dawidek error = g_raid3_connect_disk(disk, pp); 51634cb1517SPawel Jakub Dawidek if (error != 0) { 51734cb1517SPawel Jakub Dawidek if (errorp != NULL) 51834cb1517SPawel Jakub Dawidek *errorp = error; 51934cb1517SPawel Jakub Dawidek return (NULL); 52034cb1517SPawel Jakub Dawidek } 5212d1661a5SPawel Jakub Dawidek disk->d_state = G_RAID3_DISK_STATE_NONE; 5222d1661a5SPawel Jakub Dawidek disk->d_flags = md->md_dflags; 5232d1661a5SPawel Jakub Dawidek if (md->md_provider[0] != '\0') 5242d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_HARDCODED; 5252d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = NULL; 5262d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = md->md_sync_offset; 5272d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = md->md_sync_offset; 528a245a548SPawel Jakub Dawidek disk->d_genid = md->md_genid; 5292d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = md->md_syncid; 5302d1661a5SPawel Jakub Dawidek if (errorp != NULL) 5312d1661a5SPawel Jakub Dawidek *errorp = 0; 5322d1661a5SPawel Jakub Dawidek return (disk); 5332d1661a5SPawel Jakub Dawidek } 5342d1661a5SPawel Jakub Dawidek 5352d1661a5SPawel Jakub Dawidek static void 5362d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(struct g_raid3_disk *disk) 5372d1661a5SPawel Jakub Dawidek { 5382d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 5392d1661a5SPawel Jakub Dawidek 5403650be51SPawel Jakub Dawidek g_topology_assert_not(); 5413650be51SPawel Jakub Dawidek sc = disk->d_softc; 5423650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 5432d1661a5SPawel Jakub Dawidek 5442d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 5452d1661a5SPawel Jakub Dawidek return; 5462d1661a5SPawel Jakub Dawidek g_raid3_event_cancel(disk); 5472d1661a5SPawel Jakub Dawidek switch (disk->d_state) { 5482d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 5492d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL) 5502d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 1); 5512d1661a5SPawel Jakub Dawidek /* FALLTHROUGH */ 5522d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 5532d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 5542d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 5553650be51SPawel Jakub Dawidek g_topology_lock(); 5562d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(sc, disk->d_consumer); 5573650be51SPawel Jakub Dawidek g_topology_unlock(); 5582d1661a5SPawel Jakub Dawidek disk->d_consumer = NULL; 5592d1661a5SPawel Jakub Dawidek break; 5602d1661a5SPawel Jakub Dawidek default: 5612d1661a5SPawel Jakub Dawidek KASSERT(0 == 1, ("Wrong disk state (%s, %s).", 5622d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 5632d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 5642d1661a5SPawel Jakub Dawidek } 5652d1661a5SPawel Jakub Dawidek disk->d_state = G_RAID3_DISK_STATE_NODISK; 5662d1661a5SPawel Jakub Dawidek } 5672d1661a5SPawel Jakub Dawidek 5682d1661a5SPawel Jakub Dawidek static void 5692d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(struct g_raid3_softc *sc) 5702d1661a5SPawel Jakub Dawidek { 5712d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 5729da3072cSPawel Jakub Dawidek struct g_raid3_disk *disk; 5732d1661a5SPawel Jakub Dawidek struct g_geom *gp; 5742d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 5752d1661a5SPawel Jakub Dawidek u_int n; 5762d1661a5SPawel Jakub Dawidek 5773650be51SPawel Jakub Dawidek g_topology_assert_not(); 5783650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 5792d1661a5SPawel Jakub Dawidek 5802d1661a5SPawel Jakub Dawidek gp = sc->sc_geom; 5812d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) 5822d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(sc); 5839da3072cSPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 5849da3072cSPawel Jakub Dawidek disk = &sc->sc_disks[n]; 585d97d5ee9SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 5869da3072cSPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 5879da3072cSPawel Jakub Dawidek g_raid3_update_metadata(disk); 5889da3072cSPawel Jakub Dawidek g_raid3_destroy_disk(disk); 5899da3072cSPawel Jakub Dawidek } 590d97d5ee9SPawel Jakub Dawidek } 5912d1661a5SPawel Jakub Dawidek while ((ep = g_raid3_event_get(sc)) != NULL) { 592d97d5ee9SPawel Jakub Dawidek g_raid3_event_remove(sc, ep); 5932d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) 5942d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 5952d1661a5SPawel Jakub Dawidek else { 5962d1661a5SPawel Jakub Dawidek ep->e_error = ECANCELED; 5972d1661a5SPawel Jakub Dawidek ep->e_flags |= G_RAID3_EVENT_DONE; 5982d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, ep); 5992d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 6002d1661a5SPawel Jakub Dawidek wakeup(ep); 6012d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 6022d1661a5SPawel Jakub Dawidek } 6032d1661a5SPawel Jakub Dawidek } 6042d1661a5SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 6052d1661a5SPawel Jakub Dawidek cp = LIST_FIRST(&sc->sc_sync.ds_geom->consumer); 6063650be51SPawel Jakub Dawidek g_topology_lock(); 6072d1661a5SPawel Jakub Dawidek if (cp != NULL) 6082d1661a5SPawel Jakub Dawidek g_raid3_disconnect_consumer(sc, cp); 6092d1661a5SPawel Jakub Dawidek g_wither_geom(sc->sc_sync.ds_geom, ENXIO); 6102d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s destroyed.", gp->name); 6112d1661a5SPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 6123650be51SPawel Jakub Dawidek g_topology_unlock(); 6133650be51SPawel Jakub Dawidek uma_zdestroy(sc->sc_zones[G_RAID3_ZONE_64K].sz_zone); 6143650be51SPawel Jakub Dawidek uma_zdestroy(sc->sc_zones[G_RAID3_ZONE_16K].sz_zone); 6153650be51SPawel Jakub Dawidek uma_zdestroy(sc->sc_zones[G_RAID3_ZONE_4K].sz_zone); 6163650be51SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 6173650be51SPawel Jakub Dawidek mtx_destroy(&sc->sc_events_mtx); 6183650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 6193650be51SPawel Jakub Dawidek sx_destroy(&sc->sc_lock); 6202d1661a5SPawel Jakub Dawidek } 6212d1661a5SPawel Jakub Dawidek 6222d1661a5SPawel Jakub Dawidek static void 6232d1661a5SPawel Jakub Dawidek g_raid3_orphan(struct g_consumer *cp) 6242d1661a5SPawel Jakub Dawidek { 6252d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 6262d1661a5SPawel Jakub Dawidek 6272d1661a5SPawel Jakub Dawidek g_topology_assert(); 6282d1661a5SPawel Jakub Dawidek 6292d1661a5SPawel Jakub Dawidek disk = cp->private; 6302d1661a5SPawel Jakub Dawidek if (disk == NULL) 6312d1661a5SPawel Jakub Dawidek return; 632ea973705SPawel Jakub Dawidek disk->d_softc->sc_bump_id = G_RAID3_BUMP_SYNCID; 6332d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 6342d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 6352d1661a5SPawel Jakub Dawidek } 6362d1661a5SPawel Jakub Dawidek 6372d1661a5SPawel Jakub Dawidek static int 6382d1661a5SPawel Jakub Dawidek g_raid3_write_metadata(struct g_raid3_disk *disk, struct g_raid3_metadata *md) 6392d1661a5SPawel Jakub Dawidek { 6402d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 6412d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 6422d1661a5SPawel Jakub Dawidek off_t offset, length; 6432d1661a5SPawel Jakub Dawidek u_char *sector; 644d97d5ee9SPawel Jakub Dawidek int error = 0; 6452d1661a5SPawel Jakub Dawidek 6463650be51SPawel Jakub Dawidek g_topology_assert_not(); 6472d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 6483650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_LOCKED); 6493650be51SPawel Jakub Dawidek 6502d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 6512d1661a5SPawel Jakub Dawidek KASSERT(cp != NULL, ("NULL consumer (%s).", sc->sc_name)); 6522d1661a5SPawel Jakub Dawidek KASSERT(cp->provider != NULL, ("NULL provider (%s).", sc->sc_name)); 6533650be51SPawel Jakub Dawidek KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1, 654d97d5ee9SPawel Jakub Dawidek ("Consumer %s closed? (r%dw%de%d).", cp->provider->name, cp->acr, 655d97d5ee9SPawel Jakub Dawidek cp->acw, cp->ace)); 6562d1661a5SPawel Jakub Dawidek length = cp->provider->sectorsize; 6572d1661a5SPawel Jakub Dawidek offset = cp->provider->mediasize - length; 6582d1661a5SPawel Jakub Dawidek sector = malloc((size_t)length, M_RAID3, M_WAITOK | M_ZERO); 6592d1661a5SPawel Jakub Dawidek if (md != NULL) 6602d1661a5SPawel Jakub Dawidek raid3_metadata_encode(md, sector); 6612d1661a5SPawel Jakub Dawidek error = g_write_data(cp, offset, sector, length); 6622d1661a5SPawel Jakub Dawidek free(sector, M_RAID3); 6632d1661a5SPawel Jakub Dawidek if (error != 0) { 6643aae74ecSPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_BROKEN) == 0) { 6653aae74ecSPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot write metadata on %s " 6663aae74ecSPawel Jakub Dawidek "(device=%s, error=%d).", 6673aae74ecSPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name, error); 6683aae74ecSPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_BROKEN; 6693aae74ecSPawel Jakub Dawidek } else { 6703aae74ecSPawel Jakub Dawidek G_RAID3_DEBUG(1, "Cannot write metadata on %s " 6713aae74ecSPawel Jakub Dawidek "(device=%s, error=%d).", 6723aae74ecSPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name, error); 6733aae74ecSPawel Jakub Dawidek } 6743aae74ecSPawel Jakub Dawidek if (g_raid3_disconnect_on_failure && 6753aae74ecSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 6763aae74ecSPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 6773aae74ecSPawel Jakub Dawidek g_raid3_event_send(disk, 6783aae74ecSPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 6792d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 6802d1661a5SPawel Jakub Dawidek } 6813aae74ecSPawel Jakub Dawidek } 6822d1661a5SPawel Jakub Dawidek return (error); 6832d1661a5SPawel Jakub Dawidek } 6842d1661a5SPawel Jakub Dawidek 6852d1661a5SPawel Jakub Dawidek int 6862d1661a5SPawel Jakub Dawidek g_raid3_clear_metadata(struct g_raid3_disk *disk) 6872d1661a5SPawel Jakub Dawidek { 6882d1661a5SPawel Jakub Dawidek int error; 6892d1661a5SPawel Jakub Dawidek 6903650be51SPawel Jakub Dawidek g_topology_assert_not(); 6913650be51SPawel Jakub Dawidek sx_assert(&disk->d_softc->sc_lock, SX_LOCKED); 6923650be51SPawel Jakub Dawidek 6932d1661a5SPawel Jakub Dawidek error = g_raid3_write_metadata(disk, NULL); 6942d1661a5SPawel Jakub Dawidek if (error == 0) { 6952d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Metadata on %s cleared.", 6962d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 6972d1661a5SPawel Jakub Dawidek } else { 6982d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 6992d1661a5SPawel Jakub Dawidek "Cannot clear metadata on disk %s (error=%d).", 7002d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), error); 7012d1661a5SPawel Jakub Dawidek } 7022d1661a5SPawel Jakub Dawidek return (error); 7032d1661a5SPawel Jakub Dawidek } 7042d1661a5SPawel Jakub Dawidek 7052d1661a5SPawel Jakub Dawidek void 7062d1661a5SPawel Jakub Dawidek g_raid3_fill_metadata(struct g_raid3_disk *disk, struct g_raid3_metadata *md) 7072d1661a5SPawel Jakub Dawidek { 7082d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 709e6890985SPawel Jakub Dawidek struct g_provider *pp; 7102d1661a5SPawel Jakub Dawidek 7112d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 7122d1661a5SPawel Jakub Dawidek strlcpy(md->md_magic, G_RAID3_MAGIC, sizeof(md->md_magic)); 7132d1661a5SPawel Jakub Dawidek md->md_version = G_RAID3_VERSION; 7142d1661a5SPawel Jakub Dawidek strlcpy(md->md_name, sc->sc_name, sizeof(md->md_name)); 7152d1661a5SPawel Jakub Dawidek md->md_id = sc->sc_id; 7162d1661a5SPawel Jakub Dawidek md->md_all = sc->sc_ndisks; 717a245a548SPawel Jakub Dawidek md->md_genid = sc->sc_genid; 7182d1661a5SPawel Jakub Dawidek md->md_mediasize = sc->sc_mediasize; 7192d1661a5SPawel Jakub Dawidek md->md_sectorsize = sc->sc_sectorsize; 7202d1661a5SPawel Jakub Dawidek md->md_mflags = (sc->sc_flags & G_RAID3_DEVICE_FLAG_MASK); 7212d1661a5SPawel Jakub Dawidek md->md_no = disk->d_no; 7222d1661a5SPawel Jakub Dawidek md->md_syncid = disk->d_sync.ds_syncid; 7232d1661a5SPawel Jakub Dawidek md->md_dflags = (disk->d_flags & G_RAID3_DISK_FLAG_MASK); 724c082905bSPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_SYNCHRONIZING) 7252d1661a5SPawel Jakub Dawidek md->md_sync_offset = 0; 726c082905bSPawel Jakub Dawidek else { 727c082905bSPawel Jakub Dawidek md->md_sync_offset = 728c082905bSPawel Jakub Dawidek disk->d_sync.ds_offset_done / (sc->sc_ndisks - 1); 729c082905bSPawel Jakub Dawidek } 730e6890985SPawel Jakub Dawidek if (disk->d_consumer != NULL && disk->d_consumer->provider != NULL) 731e6890985SPawel Jakub Dawidek pp = disk->d_consumer->provider; 732e6890985SPawel Jakub Dawidek else 733e6890985SPawel Jakub Dawidek pp = NULL; 734e6890985SPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_HARDCODED) != 0 && pp != NULL) 735e6890985SPawel Jakub Dawidek strlcpy(md->md_provider, pp->name, sizeof(md->md_provider)); 736e6890985SPawel Jakub Dawidek else 7372d1661a5SPawel Jakub Dawidek bzero(md->md_provider, sizeof(md->md_provider)); 738e6890985SPawel Jakub Dawidek if (pp != NULL) 739e6890985SPawel Jakub Dawidek md->md_provsize = pp->mediasize; 740e6890985SPawel Jakub Dawidek else 741e6890985SPawel Jakub Dawidek md->md_provsize = 0; 7422d1661a5SPawel Jakub Dawidek } 7432d1661a5SPawel Jakub Dawidek 7442d1661a5SPawel Jakub Dawidek void 7452d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(struct g_raid3_disk *disk) 7462d1661a5SPawel Jakub Dawidek { 7473650be51SPawel Jakub Dawidek struct g_raid3_softc *sc; 7482d1661a5SPawel Jakub Dawidek struct g_raid3_metadata md; 7492d1661a5SPawel Jakub Dawidek int error; 7502d1661a5SPawel Jakub Dawidek 7513650be51SPawel Jakub Dawidek g_topology_assert_not(); 7523650be51SPawel Jakub Dawidek sc = disk->d_softc; 7533650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_LOCKED); 7543650be51SPawel Jakub Dawidek 7552d1661a5SPawel Jakub Dawidek g_raid3_fill_metadata(disk, &md); 7562d1661a5SPawel Jakub Dawidek error = g_raid3_write_metadata(disk, &md); 7572d1661a5SPawel Jakub Dawidek if (error == 0) { 7582d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Metadata on %s updated.", 7592d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 7602d1661a5SPawel Jakub Dawidek } else { 7612d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 7622d1661a5SPawel Jakub Dawidek "Cannot update metadata on disk %s (error=%d).", 7632d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), error); 7642d1661a5SPawel Jakub Dawidek } 7652d1661a5SPawel Jakub Dawidek } 7662d1661a5SPawel Jakub Dawidek 7672d1661a5SPawel Jakub Dawidek static void 768d97d5ee9SPawel Jakub Dawidek g_raid3_bump_syncid(struct g_raid3_softc *sc) 7692d1661a5SPawel Jakub Dawidek { 7702d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 7712d1661a5SPawel Jakub Dawidek u_int n; 7722d1661a5SPawel Jakub Dawidek 7733650be51SPawel Jakub Dawidek g_topology_assert_not(); 7743650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 7752d1661a5SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) > 0, 7762d1661a5SPawel Jakub Dawidek ("%s called with no active disks (device=%s).", __func__, 7772d1661a5SPawel Jakub Dawidek sc->sc_name)); 7782d1661a5SPawel Jakub Dawidek 7792d1661a5SPawel Jakub Dawidek sc->sc_syncid++; 780a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s: syncid bumped to %u.", sc->sc_name, 781a245a548SPawel Jakub Dawidek sc->sc_syncid); 7822d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 7832d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 7842d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 7852d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 7862d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = sc->sc_syncid; 7872d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 7882d1661a5SPawel Jakub Dawidek } 7892d1661a5SPawel Jakub Dawidek } 7902d1661a5SPawel Jakub Dawidek } 7912d1661a5SPawel Jakub Dawidek 7924d006a98SPawel Jakub Dawidek static void 793a245a548SPawel Jakub Dawidek g_raid3_bump_genid(struct g_raid3_softc *sc) 794a245a548SPawel Jakub Dawidek { 795a245a548SPawel Jakub Dawidek struct g_raid3_disk *disk; 796a245a548SPawel Jakub Dawidek u_int n; 797a245a548SPawel Jakub Dawidek 7983650be51SPawel Jakub Dawidek g_topology_assert_not(); 7993650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 800a245a548SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) > 0, 801a245a548SPawel Jakub Dawidek ("%s called with no active disks (device=%s).", __func__, 802a245a548SPawel Jakub Dawidek sc->sc_name)); 803a245a548SPawel Jakub Dawidek 804a245a548SPawel Jakub Dawidek sc->sc_genid++; 805a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s: genid bumped to %u.", sc->sc_name, 806a245a548SPawel Jakub Dawidek sc->sc_genid); 807a245a548SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 808a245a548SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 809a245a548SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 810a245a548SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 811a245a548SPawel Jakub Dawidek disk->d_genid = sc->sc_genid; 812a245a548SPawel Jakub Dawidek g_raid3_update_metadata(disk); 813a245a548SPawel Jakub Dawidek } 814a245a548SPawel Jakub Dawidek } 815a245a548SPawel Jakub Dawidek } 816a245a548SPawel Jakub Dawidek 8170962f942SPawel Jakub Dawidek static int 8183650be51SPawel Jakub Dawidek g_raid3_idle(struct g_raid3_softc *sc, int acw) 8194d006a98SPawel Jakub Dawidek { 8204d006a98SPawel Jakub Dawidek struct g_raid3_disk *disk; 8214d006a98SPawel Jakub Dawidek u_int i; 8220962f942SPawel Jakub Dawidek int timeout; 8234d006a98SPawel Jakub Dawidek 8243650be51SPawel Jakub Dawidek g_topology_assert_not(); 8253650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 8263650be51SPawel Jakub Dawidek 8270962f942SPawel Jakub Dawidek if (sc->sc_provider == NULL) 8280962f942SPawel Jakub Dawidek return (0); 8290962f942SPawel Jakub Dawidek if (sc->sc_idle) 8300962f942SPawel Jakub Dawidek return (0); 8310962f942SPawel Jakub Dawidek if (sc->sc_writes > 0) 8320962f942SPawel Jakub Dawidek return (0); 8333650be51SPawel Jakub Dawidek if (acw > 0 || (acw == -1 && sc->sc_provider->acw > 0)) { 83401f1f41cSPawel Jakub Dawidek timeout = g_raid3_idletime - (time_uptime - sc->sc_last_write); 8350962f942SPawel Jakub Dawidek if (timeout > 0) 8360962f942SPawel Jakub Dawidek return (timeout); 8370962f942SPawel Jakub Dawidek } 8384d006a98SPawel Jakub Dawidek sc->sc_idle = 1; 8394d006a98SPawel Jakub Dawidek for (i = 0; i < sc->sc_ndisks; i++) { 8404d006a98SPawel Jakub Dawidek disk = &sc->sc_disks[i]; 8414d006a98SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) 8424d006a98SPawel Jakub Dawidek continue; 8434d006a98SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as clean.", 8444d006a98SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 8454d006a98SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 8464d006a98SPawel Jakub Dawidek g_raid3_update_metadata(disk); 8474d006a98SPawel Jakub Dawidek } 8480962f942SPawel Jakub Dawidek return (0); 8494d006a98SPawel Jakub Dawidek } 8504d006a98SPawel Jakub Dawidek 8514d006a98SPawel Jakub Dawidek static void 8524d006a98SPawel Jakub Dawidek g_raid3_unidle(struct g_raid3_softc *sc) 8534d006a98SPawel Jakub Dawidek { 8544d006a98SPawel Jakub Dawidek struct g_raid3_disk *disk; 8554d006a98SPawel Jakub Dawidek u_int i; 8564d006a98SPawel Jakub Dawidek 8573650be51SPawel Jakub Dawidek g_topology_assert_not(); 8583650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 8593650be51SPawel Jakub Dawidek 8604d006a98SPawel Jakub Dawidek sc->sc_idle = 0; 86101f1f41cSPawel Jakub Dawidek sc->sc_last_write = time_uptime; 8624d006a98SPawel Jakub Dawidek for (i = 0; i < sc->sc_ndisks; i++) { 8634d006a98SPawel Jakub Dawidek disk = &sc->sc_disks[i]; 8644d006a98SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) 8654d006a98SPawel Jakub Dawidek continue; 8664d006a98SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as dirty.", 8674d006a98SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 8684d006a98SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 8694d006a98SPawel Jakub Dawidek g_raid3_update_metadata(disk); 8704d006a98SPawel Jakub Dawidek } 8714d006a98SPawel Jakub Dawidek } 8724d006a98SPawel Jakub Dawidek 8732d1661a5SPawel Jakub Dawidek /* 8742d1661a5SPawel Jakub Dawidek * Treat bio_driver1 field in parent bio as list head and field bio_caller1 8752d1661a5SPawel Jakub Dawidek * in child bio as pointer to the next element on the list. 8762d1661a5SPawel Jakub Dawidek */ 8772d1661a5SPawel Jakub Dawidek #define G_RAID3_HEAD_BIO(pbp) (pbp)->bio_driver1 8782d1661a5SPawel Jakub Dawidek 8792d1661a5SPawel Jakub Dawidek #define G_RAID3_NEXT_BIO(cbp) (cbp)->bio_caller1 8802d1661a5SPawel Jakub Dawidek 8812d1661a5SPawel Jakub Dawidek #define G_RAID3_FOREACH_BIO(pbp, bp) \ 8822d1661a5SPawel Jakub Dawidek for ((bp) = G_RAID3_HEAD_BIO(pbp); (bp) != NULL; \ 8832d1661a5SPawel Jakub Dawidek (bp) = G_RAID3_NEXT_BIO(bp)) 8842d1661a5SPawel Jakub Dawidek 8852d1661a5SPawel Jakub Dawidek #define G_RAID3_FOREACH_SAFE_BIO(pbp, bp, tmpbp) \ 8862d1661a5SPawel Jakub Dawidek for ((bp) = G_RAID3_HEAD_BIO(pbp); \ 8872d1661a5SPawel Jakub Dawidek (bp) != NULL && ((tmpbp) = G_RAID3_NEXT_BIO(bp), 1); \ 8882d1661a5SPawel Jakub Dawidek (bp) = (tmpbp)) 8892d1661a5SPawel Jakub Dawidek 8902d1661a5SPawel Jakub Dawidek static void 8912d1661a5SPawel Jakub Dawidek g_raid3_init_bio(struct bio *pbp) 8922d1661a5SPawel Jakub Dawidek { 8932d1661a5SPawel Jakub Dawidek 8942d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = NULL; 8952d1661a5SPawel Jakub Dawidek } 8962d1661a5SPawel Jakub Dawidek 8972d1661a5SPawel Jakub Dawidek static void 898dba915cfSPawel Jakub Dawidek g_raid3_remove_bio(struct bio *cbp) 899dba915cfSPawel Jakub Dawidek { 900dba915cfSPawel Jakub Dawidek struct bio *pbp, *bp; 901dba915cfSPawel Jakub Dawidek 902dba915cfSPawel Jakub Dawidek pbp = cbp->bio_parent; 903dba915cfSPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == cbp) 904dba915cfSPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = G_RAID3_NEXT_BIO(cbp); 905dba915cfSPawel Jakub Dawidek else { 906dba915cfSPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 907dba915cfSPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == cbp) { 908dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); 909dba915cfSPawel Jakub Dawidek break; 910dba915cfSPawel Jakub Dawidek } 911dba915cfSPawel Jakub Dawidek } 912dba915cfSPawel Jakub Dawidek } 913dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 914dba915cfSPawel Jakub Dawidek } 915dba915cfSPawel Jakub Dawidek 916dba915cfSPawel Jakub Dawidek static void 917dba915cfSPawel Jakub Dawidek g_raid3_replace_bio(struct bio *sbp, struct bio *dbp) 918dba915cfSPawel Jakub Dawidek { 919dba915cfSPawel Jakub Dawidek struct bio *pbp, *bp; 920dba915cfSPawel Jakub Dawidek 921dba915cfSPawel Jakub Dawidek g_raid3_remove_bio(sbp); 922dba915cfSPawel Jakub Dawidek pbp = dbp->bio_parent; 923dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(sbp) = G_RAID3_NEXT_BIO(dbp); 924dba915cfSPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == dbp) 925dba915cfSPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = sbp; 926dba915cfSPawel Jakub Dawidek else { 927dba915cfSPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 928dba915cfSPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == dbp) { 929dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = sbp; 930dba915cfSPawel Jakub Dawidek break; 931dba915cfSPawel Jakub Dawidek } 932dba915cfSPawel Jakub Dawidek } 933dba915cfSPawel Jakub Dawidek } 934dba915cfSPawel Jakub Dawidek G_RAID3_NEXT_BIO(dbp) = NULL; 935dba915cfSPawel Jakub Dawidek } 936dba915cfSPawel Jakub Dawidek 937dba915cfSPawel Jakub Dawidek static void 9382d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(struct g_raid3_softc *sc, struct bio *cbp) 9392d1661a5SPawel Jakub Dawidek { 9402d1661a5SPawel Jakub Dawidek struct bio *bp, *pbp; 9412d1661a5SPawel Jakub Dawidek size_t size; 9422d1661a5SPawel Jakub Dawidek 9432d1661a5SPawel Jakub Dawidek pbp = cbp->bio_parent; 9442d1661a5SPawel Jakub Dawidek pbp->bio_children--; 9452d1661a5SPawel Jakub Dawidek KASSERT(cbp->bio_data != NULL, ("NULL bio_data")); 9462d1661a5SPawel Jakub Dawidek size = pbp->bio_length / (sc->sc_ndisks - 1); 9473650be51SPawel Jakub Dawidek uma_zfree_arg(sc->sc_zones[g_raid3_zone(size)].sz_zone, 9483650be51SPawel Jakub Dawidek cbp->bio_data, 9493650be51SPawel Jakub Dawidek &sc->sc_zones[g_raid3_zone(size)]); 9502d1661a5SPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == cbp) { 9512d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = G_RAID3_NEXT_BIO(cbp); 9522d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 9532d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 9542d1661a5SPawel Jakub Dawidek } else { 9552d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 9562d1661a5SPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == cbp) 9572d1661a5SPawel Jakub Dawidek break; 9582d1661a5SPawel Jakub Dawidek } 959dba915cfSPawel Jakub Dawidek if (bp != NULL) { 960dba915cfSPawel Jakub Dawidek KASSERT(G_RAID3_NEXT_BIO(bp) != NULL, 961dba915cfSPawel Jakub Dawidek ("NULL bp->bio_driver1")); 9622d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); 9632d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 964dba915cfSPawel Jakub Dawidek } 9652d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 9662d1661a5SPawel Jakub Dawidek } 9672d1661a5SPawel Jakub Dawidek } 9682d1661a5SPawel Jakub Dawidek 9692d1661a5SPawel Jakub Dawidek static struct bio * 9702d1661a5SPawel Jakub Dawidek g_raid3_clone_bio(struct g_raid3_softc *sc, struct bio *pbp) 9712d1661a5SPawel Jakub Dawidek { 9722d1661a5SPawel Jakub Dawidek struct bio *bp, *cbp; 9732d1661a5SPawel Jakub Dawidek size_t size; 9743650be51SPawel Jakub Dawidek int memflag; 9752d1661a5SPawel Jakub Dawidek 9762d1661a5SPawel Jakub Dawidek cbp = g_clone_bio(pbp); 9772d1661a5SPawel Jakub Dawidek if (cbp == NULL) 9782d1661a5SPawel Jakub Dawidek return (NULL); 9792d1661a5SPawel Jakub Dawidek size = pbp->bio_length / (sc->sc_ndisks - 1); 9803650be51SPawel Jakub Dawidek if ((pbp->bio_cflags & G_RAID3_BIO_CFLAG_REGULAR) != 0) 9813650be51SPawel Jakub Dawidek memflag = M_WAITOK; 9822d1661a5SPawel Jakub Dawidek else 9833650be51SPawel Jakub Dawidek memflag = M_NOWAIT; 9843650be51SPawel Jakub Dawidek cbp->bio_data = uma_zalloc_arg(sc->sc_zones[g_raid3_zone(size)].sz_zone, 9853650be51SPawel Jakub Dawidek &sc->sc_zones[g_raid3_zone(size)], memflag); 9863650be51SPawel Jakub Dawidek sc->sc_zones[g_raid3_zone(size)].sz_requested++; 9873650be51SPawel Jakub Dawidek if (cbp->bio_data == NULL) { 9883650be51SPawel Jakub Dawidek sc->sc_zones[g_raid3_zone(size)].sz_failed++; 9892d1661a5SPawel Jakub Dawidek pbp->bio_children--; 9902d1661a5SPawel Jakub Dawidek g_destroy_bio(cbp); 9912d1661a5SPawel Jakub Dawidek return (NULL); 9922d1661a5SPawel Jakub Dawidek } 9932d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(cbp) = NULL; 9942d1661a5SPawel Jakub Dawidek if (G_RAID3_HEAD_BIO(pbp) == NULL) 9952d1661a5SPawel Jakub Dawidek G_RAID3_HEAD_BIO(pbp) = cbp; 9962d1661a5SPawel Jakub Dawidek else { 9972d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, bp) { 9982d1661a5SPawel Jakub Dawidek if (G_RAID3_NEXT_BIO(bp) == NULL) { 9992d1661a5SPawel Jakub Dawidek G_RAID3_NEXT_BIO(bp) = cbp; 10002d1661a5SPawel Jakub Dawidek break; 10012d1661a5SPawel Jakub Dawidek } 10022d1661a5SPawel Jakub Dawidek } 10032d1661a5SPawel Jakub Dawidek } 10042d1661a5SPawel Jakub Dawidek return (cbp); 10052d1661a5SPawel Jakub Dawidek } 10062d1661a5SPawel Jakub Dawidek 10072d1661a5SPawel Jakub Dawidek static void 10082d1661a5SPawel Jakub Dawidek g_raid3_scatter(struct bio *pbp) 10092d1661a5SPawel Jakub Dawidek { 10102d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 10112d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 1012ee40c7aaSPawel Jakub Dawidek struct bio *bp, *cbp, *tmpbp; 10132d1661a5SPawel Jakub Dawidek off_t atom, cadd, padd, left; 10142d1661a5SPawel Jakub Dawidek 10152d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 10162d1661a5SPawel Jakub Dawidek bp = NULL; 10172d1661a5SPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_NOPARITY) == 0) { 10182d1661a5SPawel Jakub Dawidek /* 10192d1661a5SPawel Jakub Dawidek * Find bio for which we should calculate data. 10202d1661a5SPawel Jakub Dawidek */ 10212d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 10222d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { 10232d1661a5SPawel Jakub Dawidek bp = cbp; 10242d1661a5SPawel Jakub Dawidek break; 10252d1661a5SPawel Jakub Dawidek } 10262d1661a5SPawel Jakub Dawidek } 10272d1661a5SPawel Jakub Dawidek KASSERT(bp != NULL, ("NULL parity bio.")); 10282d1661a5SPawel Jakub Dawidek } 10292d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 10302d1661a5SPawel Jakub Dawidek cadd = padd = 0; 10312d1661a5SPawel Jakub Dawidek for (left = pbp->bio_length; left > 0; left -= sc->sc_sectorsize) { 10322d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 10332d1661a5SPawel Jakub Dawidek if (cbp == bp) 10342d1661a5SPawel Jakub Dawidek continue; 10352d1661a5SPawel Jakub Dawidek bcopy(pbp->bio_data + padd, cbp->bio_data + cadd, atom); 10362d1661a5SPawel Jakub Dawidek padd += atom; 10372d1661a5SPawel Jakub Dawidek } 10382d1661a5SPawel Jakub Dawidek cadd += atom; 10392d1661a5SPawel Jakub Dawidek } 10402d1661a5SPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_NOPARITY) == 0) { 10412d1661a5SPawel Jakub Dawidek /* 10422d1661a5SPawel Jakub Dawidek * Calculate parity. 10432d1661a5SPawel Jakub Dawidek */ 10442d1661a5SPawel Jakub Dawidek bzero(bp->bio_data, bp->bio_length); 10452d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_SAFE_BIO(pbp, cbp, tmpbp) { 10462d1661a5SPawel Jakub Dawidek if (cbp == bp) 10472d1661a5SPawel Jakub Dawidek continue; 10482d1661a5SPawel Jakub Dawidek g_raid3_xor(cbp->bio_data, bp->bio_data, bp->bio_data, 10492d1661a5SPawel Jakub Dawidek bp->bio_length); 10502d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_NODISK) != 0) 10512d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 10522d1661a5SPawel Jakub Dawidek } 10532d1661a5SPawel Jakub Dawidek } 1054ee40c7aaSPawel Jakub Dawidek G_RAID3_FOREACH_SAFE_BIO(pbp, cbp, tmpbp) { 10552d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 10562d1661a5SPawel Jakub Dawidek 10572d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 10582d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 10592d1661a5SPawel Jakub Dawidek cbp->bio_to = cp->provider; 10602d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Sending request."); 10613650be51SPawel Jakub Dawidek KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1, 1062d97d5ee9SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 1063d97d5ee9SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 106479e61493SPawel Jakub Dawidek cp->index++; 10650962f942SPawel Jakub Dawidek sc->sc_writes++; 10662d1661a5SPawel Jakub Dawidek g_io_request(cbp, cp); 10672d1661a5SPawel Jakub Dawidek } 10682d1661a5SPawel Jakub Dawidek } 10692d1661a5SPawel Jakub Dawidek 10702d1661a5SPawel Jakub Dawidek static void 10712d1661a5SPawel Jakub Dawidek g_raid3_gather(struct bio *pbp) 10722d1661a5SPawel Jakub Dawidek { 10732d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 10742d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 1075f5a2f7feSPawel Jakub Dawidek struct bio *xbp, *fbp, *cbp; 10762d1661a5SPawel Jakub Dawidek off_t atom, cadd, padd, left; 10772d1661a5SPawel Jakub Dawidek 10782d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 10792d1661a5SPawel Jakub Dawidek /* 1080f5a2f7feSPawel Jakub Dawidek * Find bio for which we have to calculate data. 10812d1661a5SPawel Jakub Dawidek * While going through this path, check if all requests 10822d1661a5SPawel Jakub Dawidek * succeeded, if not, deny whole request. 1083f5a2f7feSPawel Jakub Dawidek * If we're in COMPLETE mode, we allow one request to fail, 1084f5a2f7feSPawel Jakub Dawidek * so if we find one, we're sending it to the parity consumer. 1085f5a2f7feSPawel Jakub Dawidek * If there are more failed requests, we deny whole request. 10862d1661a5SPawel Jakub Dawidek */ 1087f5a2f7feSPawel Jakub Dawidek xbp = fbp = NULL; 10882d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 10892d1661a5SPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { 1090f5a2f7feSPawel Jakub Dawidek KASSERT(xbp == NULL, ("More than one parity bio.")); 1091f5a2f7feSPawel Jakub Dawidek xbp = cbp; 10922d1661a5SPawel Jakub Dawidek } 10932d1661a5SPawel Jakub Dawidek if (cbp->bio_error == 0) 10942d1661a5SPawel Jakub Dawidek continue; 10952d1661a5SPawel Jakub Dawidek /* 10962d1661a5SPawel Jakub Dawidek * Found failed request. 10972d1661a5SPawel Jakub Dawidek */ 1098f5a2f7feSPawel Jakub Dawidek if (fbp == NULL) { 1099f5a2f7feSPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_DEGRADED) != 0) { 11002d1661a5SPawel Jakub Dawidek /* 1101f5a2f7feSPawel Jakub Dawidek * We are already in degraded mode, so we can't 1102f5a2f7feSPawel Jakub Dawidek * accept any failures. 11032d1661a5SPawel Jakub Dawidek */ 1104f5a2f7feSPawel Jakub Dawidek if (pbp->bio_error == 0) 110517fec17eSPawel Jakub Dawidek pbp->bio_error = cbp->bio_error; 11062d1661a5SPawel Jakub Dawidek } else { 1107f5a2f7feSPawel Jakub Dawidek fbp = cbp; 11082d1661a5SPawel Jakub Dawidek } 1109f5a2f7feSPawel Jakub Dawidek } else { 11102d1661a5SPawel Jakub Dawidek /* 11112d1661a5SPawel Jakub Dawidek * Next failed request, that's too many. 11122d1661a5SPawel Jakub Dawidek */ 11132d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 1114f5a2f7feSPawel Jakub Dawidek pbp->bio_error = fbp->bio_error; 11152d1661a5SPawel Jakub Dawidek } 11163aae74ecSPawel Jakub Dawidek disk = cbp->bio_caller2; 11173aae74ecSPawel Jakub Dawidek if (disk == NULL) 11183aae74ecSPawel Jakub Dawidek continue; 11193aae74ecSPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_BROKEN) == 0) { 11203aae74ecSPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_BROKEN; 11213aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(0, cbp, "Request failed (error=%d).", 11223aae74ecSPawel Jakub Dawidek cbp->bio_error); 11233aae74ecSPawel Jakub Dawidek } else { 11243aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(1, cbp, "Request failed (error=%d).", 11253aae74ecSPawel Jakub Dawidek cbp->bio_error); 11263aae74ecSPawel Jakub Dawidek } 11273aae74ecSPawel Jakub Dawidek if (g_raid3_disconnect_on_failure && 11283aae74ecSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 11293aae74ecSPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 11303aae74ecSPawel Jakub Dawidek g_raid3_event_send(disk, 11313aae74ecSPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 11323aae74ecSPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 11333aae74ecSPawel Jakub Dawidek } 11342d1661a5SPawel Jakub Dawidek } 11352d1661a5SPawel Jakub Dawidek if (pbp->bio_error != 0) 11362d1661a5SPawel Jakub Dawidek goto finish; 1137dba915cfSPawel Jakub Dawidek if (fbp != NULL && (pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) { 1138dba915cfSPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_VERIFY; 1139dba915cfSPawel Jakub Dawidek if (xbp != fbp) 1140dba915cfSPawel Jakub Dawidek g_raid3_replace_bio(xbp, fbp); 1141dba915cfSPawel Jakub Dawidek g_raid3_destroy_bio(sc, fbp); 1142dba915cfSPawel Jakub Dawidek } else if (fbp != NULL) { 11432d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 11442d1661a5SPawel Jakub Dawidek 11452d1661a5SPawel Jakub Dawidek /* 11462d1661a5SPawel Jakub Dawidek * One request failed, so send the same request to 11472d1661a5SPawel Jakub Dawidek * the parity consumer. 11482d1661a5SPawel Jakub Dawidek */ 1149f5a2f7feSPawel Jakub Dawidek disk = pbp->bio_driver2; 11502d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { 1151f5a2f7feSPawel Jakub Dawidek pbp->bio_error = fbp->bio_error; 11522d1661a5SPawel Jakub Dawidek goto finish; 11532d1661a5SPawel Jakub Dawidek } 11542d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 11552d1661a5SPawel Jakub Dawidek pbp->bio_inbed--; 1156f5a2f7feSPawel Jakub Dawidek fbp->bio_flags &= ~(BIO_DONE | BIO_ERROR); 1157f5a2f7feSPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) 1158f5a2f7feSPawel Jakub Dawidek fbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 1159f5a2f7feSPawel Jakub Dawidek fbp->bio_error = 0; 1160f5a2f7feSPawel Jakub Dawidek fbp->bio_completed = 0; 1161f5a2f7feSPawel Jakub Dawidek fbp->bio_children = 0; 1162f5a2f7feSPawel Jakub Dawidek fbp->bio_inbed = 0; 11632d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 1164f5a2f7feSPawel Jakub Dawidek fbp->bio_caller2 = disk; 1165f5a2f7feSPawel Jakub Dawidek fbp->bio_to = cp->provider; 1166f5a2f7feSPawel Jakub Dawidek G_RAID3_LOGREQ(3, fbp, "Sending request (recover)."); 11673650be51SPawel Jakub Dawidek KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1, 11682d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 11692d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 117079e61493SPawel Jakub Dawidek cp->index++; 1171f5a2f7feSPawel Jakub Dawidek g_io_request(fbp, cp); 11722d1661a5SPawel Jakub Dawidek return; 11732d1661a5SPawel Jakub Dawidek } 1174f5a2f7feSPawel Jakub Dawidek if (xbp != NULL) { 1175f5a2f7feSPawel Jakub Dawidek /* 1176f5a2f7feSPawel Jakub Dawidek * Calculate parity. 1177f5a2f7feSPawel Jakub Dawidek */ 1178f5a2f7feSPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 1179f5a2f7feSPawel Jakub Dawidek if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) 1180f5a2f7feSPawel Jakub Dawidek continue; 1181f5a2f7feSPawel Jakub Dawidek g_raid3_xor(cbp->bio_data, xbp->bio_data, xbp->bio_data, 1182f5a2f7feSPawel Jakub Dawidek xbp->bio_length); 1183f5a2f7feSPawel Jakub Dawidek } 1184f5a2f7feSPawel Jakub Dawidek xbp->bio_cflags &= ~G_RAID3_BIO_CFLAG_PARITY; 1185dba915cfSPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) { 1186dba915cfSPawel Jakub Dawidek if (!g_raid3_is_zero(xbp)) { 1187dba915cfSPawel Jakub Dawidek g_raid3_parity_mismatch++; 1188dba915cfSPawel Jakub Dawidek pbp->bio_error = EIO; 1189dba915cfSPawel Jakub Dawidek goto finish; 1190dba915cfSPawel Jakub Dawidek } 1191dba915cfSPawel Jakub Dawidek g_raid3_destroy_bio(sc, xbp); 1192dba915cfSPawel Jakub Dawidek } 11932d1661a5SPawel Jakub Dawidek } 11942d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 11952d1661a5SPawel Jakub Dawidek cadd = padd = 0; 11962d1661a5SPawel Jakub Dawidek for (left = pbp->bio_length; left > 0; left -= sc->sc_sectorsize) { 11972d1661a5SPawel Jakub Dawidek G_RAID3_FOREACH_BIO(pbp, cbp) { 11982d1661a5SPawel Jakub Dawidek bcopy(cbp->bio_data + cadd, pbp->bio_data + padd, atom); 11992d1661a5SPawel Jakub Dawidek pbp->bio_completed += atom; 12002d1661a5SPawel Jakub Dawidek padd += atom; 12012d1661a5SPawel Jakub Dawidek } 12022d1661a5SPawel Jakub Dawidek cadd += atom; 12032d1661a5SPawel Jakub Dawidek } 12042d1661a5SPawel Jakub Dawidek finish: 12052d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 12062d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, pbp, "Request finished."); 12074cf67afeSPawel Jakub Dawidek else { 12084cf67afeSPawel Jakub Dawidek if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) 12094cf67afeSPawel Jakub Dawidek G_RAID3_LOGREQ(1, pbp, "Verification error."); 12102d1661a5SPawel Jakub Dawidek else 12112d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, pbp, "Request failed."); 12124cf67afeSPawel Jakub Dawidek } 1213dba915cfSPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_MASK; 12142d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) 12152d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 1216290c6161SPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 12172d1661a5SPawel Jakub Dawidek } 12182d1661a5SPawel Jakub Dawidek 12192d1661a5SPawel Jakub Dawidek static void 12202d1661a5SPawel Jakub Dawidek g_raid3_done(struct bio *bp) 12212d1661a5SPawel Jakub Dawidek { 12222d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 12232d1661a5SPawel Jakub Dawidek 12242d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 12252d1661a5SPawel Jakub Dawidek bp->bio_cflags |= G_RAID3_BIO_CFLAG_REGULAR; 12262d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Regular request done (error=%d).", bp->bio_error); 12272d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 12282d1661a5SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 12292d1661a5SPawel Jakub Dawidek wakeup(sc); 12302d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 12312d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 12322d1661a5SPawel Jakub Dawidek } 12332d1661a5SPawel Jakub Dawidek 12342d1661a5SPawel Jakub Dawidek static void 12352d1661a5SPawel Jakub Dawidek g_raid3_regular_request(struct bio *cbp) 12362d1661a5SPawel Jakub Dawidek { 12372d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 12382d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 12392d1661a5SPawel Jakub Dawidek struct bio *pbp; 12402d1661a5SPawel Jakub Dawidek 12412d1661a5SPawel Jakub Dawidek g_topology_assert_not(); 12422d1661a5SPawel Jakub Dawidek 12432d1661a5SPawel Jakub Dawidek pbp = cbp->bio_parent; 12442d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 12450962f942SPawel Jakub Dawidek cbp->bio_from->index--; 12460962f942SPawel Jakub Dawidek if (cbp->bio_cmd == BIO_WRITE) 12470962f942SPawel Jakub Dawidek sc->sc_writes--; 12482d1661a5SPawel Jakub Dawidek disk = cbp->bio_from->private; 12492d1661a5SPawel Jakub Dawidek if (disk == NULL) { 12502d1661a5SPawel Jakub Dawidek g_topology_lock(); 12512d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, cbp->bio_from); 12522d1661a5SPawel Jakub Dawidek g_topology_unlock(); 12532d1661a5SPawel Jakub Dawidek } 12542d1661a5SPawel Jakub Dawidek 12552d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Request finished."); 12562d1661a5SPawel Jakub Dawidek pbp->bio_inbed++; 12572d1661a5SPawel Jakub Dawidek KASSERT(pbp->bio_inbed <= pbp->bio_children, 12582d1661a5SPawel Jakub Dawidek ("bio_inbed (%u) is bigger than bio_children (%u).", pbp->bio_inbed, 12592d1661a5SPawel Jakub Dawidek pbp->bio_children)); 12602d1661a5SPawel Jakub Dawidek if (pbp->bio_inbed != pbp->bio_children) 12612d1661a5SPawel Jakub Dawidek return; 12622d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 12632d1661a5SPawel Jakub Dawidek case BIO_READ: 12642d1661a5SPawel Jakub Dawidek g_raid3_gather(pbp); 12652d1661a5SPawel Jakub Dawidek break; 12662d1661a5SPawel Jakub Dawidek case BIO_WRITE: 12672d1661a5SPawel Jakub Dawidek case BIO_DELETE: 12682d1661a5SPawel Jakub Dawidek { 12692d1661a5SPawel Jakub Dawidek int error = 0; 12702d1661a5SPawel Jakub Dawidek 12712d1661a5SPawel Jakub Dawidek pbp->bio_completed = pbp->bio_length; 12722d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) { 12733aae74ecSPawel Jakub Dawidek if (cbp->bio_error == 0) { 12743aae74ecSPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 12753aae74ecSPawel Jakub Dawidek continue; 12762d1661a5SPawel Jakub Dawidek } 12773aae74ecSPawel Jakub Dawidek 12782d1661a5SPawel Jakub Dawidek if (error == 0) 12792d1661a5SPawel Jakub Dawidek error = cbp->bio_error; 12802d1661a5SPawel Jakub Dawidek else if (pbp->bio_error == 0) { 12812d1661a5SPawel Jakub Dawidek /* 12822d1661a5SPawel Jakub Dawidek * Next failed request, that's too many. 12832d1661a5SPawel Jakub Dawidek */ 12842d1661a5SPawel Jakub Dawidek pbp->bio_error = error; 12852d1661a5SPawel Jakub Dawidek } 12863aae74ecSPawel Jakub Dawidek 12873aae74ecSPawel Jakub Dawidek disk = cbp->bio_caller2; 12883aae74ecSPawel Jakub Dawidek if (disk == NULL) { 12893aae74ecSPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 12903aae74ecSPawel Jakub Dawidek continue; 12913aae74ecSPawel Jakub Dawidek } 12923aae74ecSPawel Jakub Dawidek 12933aae74ecSPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_BROKEN) == 0) { 12943aae74ecSPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_BROKEN; 12953aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(0, cbp, 12963aae74ecSPawel Jakub Dawidek "Request failed (error=%d).", 12973aae74ecSPawel Jakub Dawidek cbp->bio_error); 12983aae74ecSPawel Jakub Dawidek } else { 12993aae74ecSPawel Jakub Dawidek G_RAID3_LOGREQ(1, cbp, 13003aae74ecSPawel Jakub Dawidek "Request failed (error=%d).", 13013aae74ecSPawel Jakub Dawidek cbp->bio_error); 13023aae74ecSPawel Jakub Dawidek } 13033aae74ecSPawel Jakub Dawidek if (g_raid3_disconnect_on_failure && 13043aae74ecSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 13053aae74ecSPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 13063aae74ecSPawel Jakub Dawidek g_raid3_event_send(disk, 13073aae74ecSPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 13083aae74ecSPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 13092d1661a5SPawel Jakub Dawidek } 13102d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 13112d1661a5SPawel Jakub Dawidek } 13122d1661a5SPawel Jakub Dawidek if (pbp->bio_error == 0) 13132d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, pbp, "Request finished."); 13142d1661a5SPawel Jakub Dawidek else 13152d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, pbp, "Request failed."); 13162d1661a5SPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_DEGRADED; 13172d1661a5SPawel Jakub Dawidek pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_NOPARITY; 13183650be51SPawel Jakub Dawidek bioq_remove(&sc->sc_inflight, pbp); 13193650be51SPawel Jakub Dawidek /* Release delayed sync requests if possible. */ 13203650be51SPawel Jakub Dawidek g_raid3_sync_release(sc); 13212d1661a5SPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 13222d1661a5SPawel Jakub Dawidek break; 13232d1661a5SPawel Jakub Dawidek } 13242d1661a5SPawel Jakub Dawidek } 13252d1661a5SPawel Jakub Dawidek } 13262d1661a5SPawel Jakub Dawidek 13272d1661a5SPawel Jakub Dawidek static void 13282d1661a5SPawel Jakub Dawidek g_raid3_sync_done(struct bio *bp) 13292d1661a5SPawel Jakub Dawidek { 13302d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 13312d1661a5SPawel Jakub Dawidek 13322d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request delivered."); 13332d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 13342d1661a5SPawel Jakub Dawidek bp->bio_cflags |= G_RAID3_BIO_CFLAG_SYNC; 13352d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 13362d1661a5SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 13372d1661a5SPawel Jakub Dawidek wakeup(sc); 13382d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 13392d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 13402d1661a5SPawel Jakub Dawidek } 13412d1661a5SPawel Jakub Dawidek 13422d1661a5SPawel Jakub Dawidek static void 13432d1661a5SPawel Jakub Dawidek g_raid3_start(struct bio *bp) 13442d1661a5SPawel Jakub Dawidek { 13452d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 13462d1661a5SPawel Jakub Dawidek 13472d1661a5SPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 13482d1661a5SPawel Jakub Dawidek /* 13492d1661a5SPawel Jakub Dawidek * If sc == NULL or there are no valid disks, provider's error 13502d1661a5SPawel Jakub Dawidek * should be set and g_raid3_start() should not be called at all. 13512d1661a5SPawel Jakub Dawidek */ 13522d1661a5SPawel Jakub Dawidek KASSERT(sc != NULL && (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 13532d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE), 13542d1661a5SPawel Jakub Dawidek ("Provider's error should be set (error=%d)(device=%s).", 13552d1661a5SPawel Jakub Dawidek bp->bio_to->error, bp->bio_to->name)); 13562d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Request received."); 13572d1661a5SPawel Jakub Dawidek 13582d1661a5SPawel Jakub Dawidek switch (bp->bio_cmd) { 13592d1661a5SPawel Jakub Dawidek case BIO_READ: 13602d1661a5SPawel Jakub Dawidek case BIO_WRITE: 13612d1661a5SPawel Jakub Dawidek case BIO_DELETE: 13622d1661a5SPawel Jakub Dawidek break; 13632d1661a5SPawel Jakub Dawidek case BIO_GETATTR: 13642d1661a5SPawel Jakub Dawidek default: 13652d1661a5SPawel Jakub Dawidek g_io_deliver(bp, EOPNOTSUPP); 13662d1661a5SPawel Jakub Dawidek return; 13672d1661a5SPawel Jakub Dawidek } 13682d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 13692d1661a5SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_queue, bp); 13702d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 13712d1661a5SPawel Jakub Dawidek wakeup(sc); 13722d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 13732d1661a5SPawel Jakub Dawidek } 13742d1661a5SPawel Jakub Dawidek 13752d1661a5SPawel Jakub Dawidek /* 13763650be51SPawel Jakub Dawidek * Return TRUE if the given request is colliding with a in-progress 13773650be51SPawel Jakub Dawidek * synchronization request. 13782d1661a5SPawel Jakub Dawidek */ 13793650be51SPawel Jakub Dawidek static int 13803650be51SPawel Jakub Dawidek g_raid3_sync_collision(struct g_raid3_softc *sc, struct bio *bp) 13812d1661a5SPawel Jakub Dawidek { 13822d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 13833650be51SPawel Jakub Dawidek struct bio *sbp; 13843650be51SPawel Jakub Dawidek off_t rstart, rend, sstart, send; 13853650be51SPawel Jakub Dawidek int i; 13863650be51SPawel Jakub Dawidek 13873650be51SPawel Jakub Dawidek disk = sc->sc_syncdisk; 13883650be51SPawel Jakub Dawidek if (disk == NULL) 13893650be51SPawel Jakub Dawidek return (0); 13903650be51SPawel Jakub Dawidek rstart = bp->bio_offset; 13913650be51SPawel Jakub Dawidek rend = bp->bio_offset + bp->bio_length; 13923650be51SPawel Jakub Dawidek for (i = 0; i < g_raid3_syncreqs; i++) { 13933650be51SPawel Jakub Dawidek sbp = disk->d_sync.ds_bios[i]; 13943650be51SPawel Jakub Dawidek if (sbp == NULL) 13953650be51SPawel Jakub Dawidek continue; 13963650be51SPawel Jakub Dawidek sstart = sbp->bio_offset; 13973650be51SPawel Jakub Dawidek send = sbp->bio_length; 13983650be51SPawel Jakub Dawidek if (sbp->bio_cmd == BIO_WRITE) { 13993650be51SPawel Jakub Dawidek sstart *= sc->sc_ndisks - 1; 14003650be51SPawel Jakub Dawidek send *= sc->sc_ndisks - 1; 14013650be51SPawel Jakub Dawidek } 14023650be51SPawel Jakub Dawidek send += sstart; 14033650be51SPawel Jakub Dawidek if (rend > sstart && rstart < send) 14043650be51SPawel Jakub Dawidek return (1); 14053650be51SPawel Jakub Dawidek } 14063650be51SPawel Jakub Dawidek return (0); 14073650be51SPawel Jakub Dawidek } 14083650be51SPawel Jakub Dawidek 14093650be51SPawel Jakub Dawidek /* 14103650be51SPawel Jakub Dawidek * Return TRUE if the given sync request is colliding with a in-progress regular 14113650be51SPawel Jakub Dawidek * request. 14123650be51SPawel Jakub Dawidek */ 14133650be51SPawel Jakub Dawidek static int 14143650be51SPawel Jakub Dawidek g_raid3_regular_collision(struct g_raid3_softc *sc, struct bio *sbp) 14153650be51SPawel Jakub Dawidek { 14163650be51SPawel Jakub Dawidek off_t rstart, rend, sstart, send; 14172d1661a5SPawel Jakub Dawidek struct bio *bp; 14182d1661a5SPawel Jakub Dawidek 14193650be51SPawel Jakub Dawidek if (sc->sc_syncdisk == NULL) 14203650be51SPawel Jakub Dawidek return (0); 14213650be51SPawel Jakub Dawidek sstart = sbp->bio_offset; 14223650be51SPawel Jakub Dawidek send = sstart + sbp->bio_length; 14233650be51SPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_inflight.queue, bio_queue) { 14243650be51SPawel Jakub Dawidek rstart = bp->bio_offset; 14253650be51SPawel Jakub Dawidek rend = bp->bio_offset + bp->bio_length; 14263650be51SPawel Jakub Dawidek if (rend > sstart && rstart < send) 14273650be51SPawel Jakub Dawidek return (1); 14282d1661a5SPawel Jakub Dawidek } 14293650be51SPawel Jakub Dawidek return (0); 14302d1661a5SPawel Jakub Dawidek } 14312d1661a5SPawel Jakub Dawidek 14323650be51SPawel Jakub Dawidek /* 14333650be51SPawel Jakub Dawidek * Puts request onto delayed queue. 14343650be51SPawel Jakub Dawidek */ 14353650be51SPawel Jakub Dawidek static void 14363650be51SPawel Jakub Dawidek g_raid3_regular_delay(struct g_raid3_softc *sc, struct bio *bp) 14373650be51SPawel Jakub Dawidek { 14383650be51SPawel Jakub Dawidek 14393650be51SPawel Jakub Dawidek G_RAID3_LOGREQ(2, bp, "Delaying request."); 14403650be51SPawel Jakub Dawidek bioq_insert_head(&sc->sc_regular_delayed, bp); 14413650be51SPawel Jakub Dawidek } 14423650be51SPawel Jakub Dawidek 14433650be51SPawel Jakub Dawidek /* 14443650be51SPawel Jakub Dawidek * Puts synchronization request onto delayed queue. 14453650be51SPawel Jakub Dawidek */ 14463650be51SPawel Jakub Dawidek static void 14473650be51SPawel Jakub Dawidek g_raid3_sync_delay(struct g_raid3_softc *sc, struct bio *bp) 14483650be51SPawel Jakub Dawidek { 14493650be51SPawel Jakub Dawidek 14503650be51SPawel Jakub Dawidek G_RAID3_LOGREQ(2, bp, "Delaying synchronization request."); 14513650be51SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_sync_delayed, bp); 14523650be51SPawel Jakub Dawidek } 14533650be51SPawel Jakub Dawidek 14543650be51SPawel Jakub Dawidek /* 14553650be51SPawel Jakub Dawidek * Releases delayed regular requests which don't collide anymore with sync 14563650be51SPawel Jakub Dawidek * requests. 14573650be51SPawel Jakub Dawidek */ 14583650be51SPawel Jakub Dawidek static void 14593650be51SPawel Jakub Dawidek g_raid3_regular_release(struct g_raid3_softc *sc) 14603650be51SPawel Jakub Dawidek { 14613650be51SPawel Jakub Dawidek struct bio *bp, *bp2; 14623650be51SPawel Jakub Dawidek 14633650be51SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_regular_delayed.queue, bio_queue, bp2) { 14643650be51SPawel Jakub Dawidek if (g_raid3_sync_collision(sc, bp)) 14653650be51SPawel Jakub Dawidek continue; 14663650be51SPawel Jakub Dawidek bioq_remove(&sc->sc_regular_delayed, bp); 14673650be51SPawel Jakub Dawidek G_RAID3_LOGREQ(2, bp, "Releasing delayed request (%p).", bp); 14683650be51SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 14693650be51SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 14703650be51SPawel Jakub Dawidek #if 0 14713650be51SPawel Jakub Dawidek /* 14723650be51SPawel Jakub Dawidek * wakeup() is not needed, because this function is called from 14733650be51SPawel Jakub Dawidek * the worker thread. 14743650be51SPawel Jakub Dawidek */ 14753650be51SPawel Jakub Dawidek wakeup(&sc->sc_queue); 14763650be51SPawel Jakub Dawidek #endif 14773650be51SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 14783650be51SPawel Jakub Dawidek } 14793650be51SPawel Jakub Dawidek } 14803650be51SPawel Jakub Dawidek 14813650be51SPawel Jakub Dawidek /* 14823650be51SPawel Jakub Dawidek * Releases delayed sync requests which don't collide anymore with regular 14833650be51SPawel Jakub Dawidek * requests. 14843650be51SPawel Jakub Dawidek */ 14853650be51SPawel Jakub Dawidek static void 14863650be51SPawel Jakub Dawidek g_raid3_sync_release(struct g_raid3_softc *sc) 14873650be51SPawel Jakub Dawidek { 14883650be51SPawel Jakub Dawidek struct bio *bp, *bp2; 14893650be51SPawel Jakub Dawidek 14903650be51SPawel Jakub Dawidek TAILQ_FOREACH_SAFE(bp, &sc->sc_sync_delayed.queue, bio_queue, bp2) { 14913650be51SPawel Jakub Dawidek if (g_raid3_regular_collision(sc, bp)) 14923650be51SPawel Jakub Dawidek continue; 14933650be51SPawel Jakub Dawidek bioq_remove(&sc->sc_sync_delayed, bp); 14943650be51SPawel Jakub Dawidek G_RAID3_LOGREQ(2, bp, 14953650be51SPawel Jakub Dawidek "Releasing delayed synchronization request."); 14963650be51SPawel Jakub Dawidek g_io_request(bp, bp->bio_from); 14973650be51SPawel Jakub Dawidek } 14983650be51SPawel Jakub Dawidek } 14993650be51SPawel Jakub Dawidek 15003650be51SPawel Jakub Dawidek /* 15013650be51SPawel Jakub Dawidek * Handle synchronization requests. 15023650be51SPawel Jakub Dawidek * Every synchronization request is two-steps process: first, READ request is 15033650be51SPawel Jakub Dawidek * send to active provider and then WRITE request (with read data) to the provider 15043650be51SPawel Jakub Dawidek * beeing synchronized. When WRITE is finished, new synchronization request is 15053650be51SPawel Jakub Dawidek * send. 15063650be51SPawel Jakub Dawidek */ 15072d1661a5SPawel Jakub Dawidek static void 15082d1661a5SPawel Jakub Dawidek g_raid3_sync_request(struct bio *bp) 15092d1661a5SPawel Jakub Dawidek { 15102d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 15112d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 15122d1661a5SPawel Jakub Dawidek 151379e61493SPawel Jakub Dawidek bp->bio_from->index--; 15142d1661a5SPawel Jakub Dawidek sc = bp->bio_from->geom->softc; 15152d1661a5SPawel Jakub Dawidek disk = bp->bio_from->private; 15162d1661a5SPawel Jakub Dawidek if (disk == NULL) { 15173650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); /* Avoid recursion on sc_lock. */ 15182d1661a5SPawel Jakub Dawidek g_topology_lock(); 15192d1661a5SPawel Jakub Dawidek g_raid3_kill_consumer(sc, bp->bio_from); 15202d1661a5SPawel Jakub Dawidek g_topology_unlock(); 15213650be51SPawel Jakub Dawidek free(bp->bio_data, M_RAID3); 15222d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 15233650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 15242d1661a5SPawel Jakub Dawidek return; 15252d1661a5SPawel Jakub Dawidek } 15262d1661a5SPawel Jakub Dawidek 15272d1661a5SPawel Jakub Dawidek /* 15282d1661a5SPawel Jakub Dawidek * Synchronization request. 15292d1661a5SPawel Jakub Dawidek */ 15302d1661a5SPawel Jakub Dawidek switch (bp->bio_cmd) { 15312d1661a5SPawel Jakub Dawidek case BIO_READ: 15322d1661a5SPawel Jakub Dawidek { 15332d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 15342d1661a5SPawel Jakub Dawidek u_char *dst, *src; 15352d1661a5SPawel Jakub Dawidek off_t left; 15362d1661a5SPawel Jakub Dawidek u_int atom; 15372d1661a5SPawel Jakub Dawidek 15382d1661a5SPawel Jakub Dawidek if (bp->bio_error != 0) { 15392d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, bp, 15402d1661a5SPawel Jakub Dawidek "Synchronization request failed (error=%d).", 15412d1661a5SPawel Jakub Dawidek bp->bio_error); 15422d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 15432d1661a5SPawel Jakub Dawidek return; 15442d1661a5SPawel Jakub Dawidek } 15452d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request finished."); 15462d1661a5SPawel Jakub Dawidek atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); 15472d1661a5SPawel Jakub Dawidek dst = src = bp->bio_data; 15482d1661a5SPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) { 15492d1661a5SPawel Jakub Dawidek u_int n; 15502d1661a5SPawel Jakub Dawidek 15512d1661a5SPawel Jakub Dawidek /* Parity component. */ 15522d1661a5SPawel Jakub Dawidek for (left = bp->bio_length; left > 0; 15532d1661a5SPawel Jakub Dawidek left -= sc->sc_sectorsize) { 15542d1661a5SPawel Jakub Dawidek bcopy(src, dst, atom); 15552d1661a5SPawel Jakub Dawidek src += atom; 15562d1661a5SPawel Jakub Dawidek for (n = 1; n < sc->sc_ndisks - 1; n++) { 15572d1661a5SPawel Jakub Dawidek g_raid3_xor(src, dst, dst, atom); 15582d1661a5SPawel Jakub Dawidek src += atom; 15592d1661a5SPawel Jakub Dawidek } 15602d1661a5SPawel Jakub Dawidek dst += atom; 15612d1661a5SPawel Jakub Dawidek } 15622d1661a5SPawel Jakub Dawidek } else { 15632d1661a5SPawel Jakub Dawidek /* Regular component. */ 15642d1661a5SPawel Jakub Dawidek src += atom * disk->d_no; 15652d1661a5SPawel Jakub Dawidek for (left = bp->bio_length; left > 0; 15662d1661a5SPawel Jakub Dawidek left -= sc->sc_sectorsize) { 15672d1661a5SPawel Jakub Dawidek bcopy(src, dst, atom); 15682d1661a5SPawel Jakub Dawidek src += sc->sc_sectorsize; 15692d1661a5SPawel Jakub Dawidek dst += atom; 15702d1661a5SPawel Jakub Dawidek } 15712d1661a5SPawel Jakub Dawidek } 15723650be51SPawel Jakub Dawidek bp->bio_driver1 = bp->bio_driver2 = NULL; 15733650be51SPawel Jakub Dawidek bp->bio_pflags = 0; 15742d1661a5SPawel Jakub Dawidek bp->bio_offset /= sc->sc_ndisks - 1; 15752d1661a5SPawel Jakub Dawidek bp->bio_length /= sc->sc_ndisks - 1; 15762d1661a5SPawel Jakub Dawidek bp->bio_cmd = BIO_WRITE; 15772d1661a5SPawel Jakub Dawidek bp->bio_cflags = 0; 15782d1661a5SPawel Jakub Dawidek bp->bio_children = bp->bio_inbed = 0; 15792d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 15803650be51SPawel Jakub Dawidek KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1, 15812d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, 15822d1661a5SPawel Jakub Dawidek cp->acr, cp->acw, cp->ace)); 158379e61493SPawel Jakub Dawidek cp->index++; 15842d1661a5SPawel Jakub Dawidek g_io_request(bp, cp); 15852d1661a5SPawel Jakub Dawidek return; 15862d1661a5SPawel Jakub Dawidek } 15872d1661a5SPawel Jakub Dawidek case BIO_WRITE: 1588d2fb9c62SPawel Jakub Dawidek { 1589d2fb9c62SPawel Jakub Dawidek struct g_raid3_disk_sync *sync; 15903650be51SPawel Jakub Dawidek off_t boffset, moffset; 15913650be51SPawel Jakub Dawidek void *data; 15923650be51SPawel Jakub Dawidek int i; 1593d2fb9c62SPawel Jakub Dawidek 15942d1661a5SPawel Jakub Dawidek if (bp->bio_error != 0) { 15952d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(0, bp, 15962d1661a5SPawel Jakub Dawidek "Synchronization request failed (error=%d).", 15972d1661a5SPawel Jakub Dawidek bp->bio_error); 15982d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 1599ea973705SPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_GENID; 16002d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 16012d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 16022d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 16032d1661a5SPawel Jakub Dawidek return; 16042d1661a5SPawel Jakub Dawidek } 16052d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Synchronization request finished."); 1606d2fb9c62SPawel Jakub Dawidek sync = &disk->d_sync; 16073650be51SPawel Jakub Dawidek if (sync->ds_offset == sc->sc_mediasize / (sc->sc_ndisks - 1) || 16083650be51SPawel Jakub Dawidek sync->ds_consumer == NULL || 16093650be51SPawel Jakub Dawidek (sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 16103650be51SPawel Jakub Dawidek /* Don't send more synchronization requests. */ 16113650be51SPawel Jakub Dawidek sync->ds_inflight--; 16123650be51SPawel Jakub Dawidek if (sync->ds_bios != NULL) { 1613ef25813dSRuslan Ermilov i = (int)(uintptr_t)bp->bio_caller1; 16143650be51SPawel Jakub Dawidek sync->ds_bios[i] = NULL; 16153650be51SPawel Jakub Dawidek } 16163650be51SPawel Jakub Dawidek free(bp->bio_data, M_RAID3); 16172d1661a5SPawel Jakub Dawidek g_destroy_bio(bp); 16183650be51SPawel Jakub Dawidek if (sync->ds_inflight > 0) 1619d2fb9c62SPawel Jakub Dawidek return; 16203650be51SPawel Jakub Dawidek if (sync->ds_consumer == NULL || 16213650be51SPawel Jakub Dawidek (sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 16223650be51SPawel Jakub Dawidek return; 16233650be51SPawel Jakub Dawidek } 16242d1661a5SPawel Jakub Dawidek /* 16252d1661a5SPawel Jakub Dawidek * Disk up-to-date, activate it. 16262d1661a5SPawel Jakub Dawidek */ 16272d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_ACTIVE, 16282d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 16292d1661a5SPawel Jakub Dawidek return; 16303650be51SPawel Jakub Dawidek } 16313650be51SPawel Jakub Dawidek 16323650be51SPawel Jakub Dawidek /* Send next synchronization request. */ 16333650be51SPawel Jakub Dawidek data = bp->bio_data; 16343650be51SPawel Jakub Dawidek bzero(bp, sizeof(*bp)); 16353650be51SPawel Jakub Dawidek bp->bio_cmd = BIO_READ; 16363650be51SPawel Jakub Dawidek bp->bio_offset = sync->ds_offset * (sc->sc_ndisks - 1); 16373650be51SPawel Jakub Dawidek bp->bio_length = MIN(MAXPHYS, sc->sc_mediasize - bp->bio_offset); 16383650be51SPawel Jakub Dawidek sync->ds_offset += bp->bio_length / (sc->sc_ndisks - 1); 16393650be51SPawel Jakub Dawidek bp->bio_done = g_raid3_sync_done; 16403650be51SPawel Jakub Dawidek bp->bio_data = data; 16413650be51SPawel Jakub Dawidek bp->bio_from = sync->ds_consumer; 16423650be51SPawel Jakub Dawidek bp->bio_to = sc->sc_provider; 16433650be51SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Sending synchronization request."); 16443650be51SPawel Jakub Dawidek sync->ds_consumer->index++; 16452d1661a5SPawel Jakub Dawidek /* 16463650be51SPawel Jakub Dawidek * Delay the request if it is colliding with a regular request. 16472d1661a5SPawel Jakub Dawidek */ 16483650be51SPawel Jakub Dawidek if (g_raid3_regular_collision(sc, bp)) 16493650be51SPawel Jakub Dawidek g_raid3_sync_delay(sc, bp); 16503650be51SPawel Jakub Dawidek else 16513650be51SPawel Jakub Dawidek g_io_request(bp, sync->ds_consumer); 16523650be51SPawel Jakub Dawidek 16533650be51SPawel Jakub Dawidek /* Release delayed requests if possible. */ 16543650be51SPawel Jakub Dawidek g_raid3_regular_release(sc); 16553650be51SPawel Jakub Dawidek 16563650be51SPawel Jakub Dawidek /* Find the smallest offset. */ 16573650be51SPawel Jakub Dawidek moffset = sc->sc_mediasize; 16583650be51SPawel Jakub Dawidek for (i = 0; i < g_raid3_syncreqs; i++) { 16593650be51SPawel Jakub Dawidek bp = sync->ds_bios[i]; 16603650be51SPawel Jakub Dawidek boffset = bp->bio_offset; 16613650be51SPawel Jakub Dawidek if (bp->bio_cmd == BIO_WRITE) 16623650be51SPawel Jakub Dawidek boffset *= sc->sc_ndisks - 1; 16633650be51SPawel Jakub Dawidek if (boffset < moffset) 16643650be51SPawel Jakub Dawidek moffset = boffset; 16653650be51SPawel Jakub Dawidek } 16663650be51SPawel Jakub Dawidek if (sync->ds_offset_done + (MAXPHYS * 100) < moffset) { 16673650be51SPawel Jakub Dawidek /* Update offset_done on every 100 blocks. */ 16683650be51SPawel Jakub Dawidek sync->ds_offset_done = moffset; 16692d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 16702d1661a5SPawel Jakub Dawidek } 16712d1661a5SPawel Jakub Dawidek return; 1672d2fb9c62SPawel Jakub Dawidek } 16732d1661a5SPawel Jakub Dawidek default: 16742d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Invalid command here: %u (device=%s)", 16752d1661a5SPawel Jakub Dawidek bp->bio_cmd, sc->sc_name)); 16762d1661a5SPawel Jakub Dawidek break; 16772d1661a5SPawel Jakub Dawidek } 16782d1661a5SPawel Jakub Dawidek } 16792d1661a5SPawel Jakub Dawidek 16802d1661a5SPawel Jakub Dawidek static int 16812d1661a5SPawel Jakub Dawidek g_raid3_register_request(struct bio *pbp) 16822d1661a5SPawel Jakub Dawidek { 16832d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 16842d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 16852d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 1686ee40c7aaSPawel Jakub Dawidek struct bio *cbp, *tmpbp; 16872d1661a5SPawel Jakub Dawidek off_t offset, length; 1688fa6a7837SDavid E. O'Brien u_int n, ndisks; 1689dba915cfSPawel Jakub Dawidek int round_robin, verify; 16902d1661a5SPawel Jakub Dawidek 1691fa6a7837SDavid E. O'Brien ndisks = 0; 16922d1661a5SPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 16932d1661a5SPawel Jakub Dawidek if ((pbp->bio_cflags & G_RAID3_BIO_CFLAG_REGSYNC) != 0 && 16942d1661a5SPawel Jakub Dawidek sc->sc_syncdisk == NULL) { 16952d1661a5SPawel Jakub Dawidek g_io_deliver(pbp, EIO); 16962d1661a5SPawel Jakub Dawidek return (0); 16972d1661a5SPawel Jakub Dawidek } 16982d1661a5SPawel Jakub Dawidek g_raid3_init_bio(pbp); 16992d1661a5SPawel Jakub Dawidek length = pbp->bio_length / (sc->sc_ndisks - 1); 17002d1661a5SPawel Jakub Dawidek offset = pbp->bio_offset / (sc->sc_ndisks - 1); 1701dba915cfSPawel Jakub Dawidek round_robin = verify = 0; 17022d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 17032d1661a5SPawel Jakub Dawidek case BIO_READ: 1704dba915cfSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 1705dba915cfSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 1706dba915cfSPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_VERIFY; 1707dba915cfSPawel Jakub Dawidek verify = 1; 1708dba915cfSPawel Jakub Dawidek ndisks = sc->sc_ndisks; 1709dba915cfSPawel Jakub Dawidek } else { 1710dba915cfSPawel Jakub Dawidek verify = 0; 17112d1661a5SPawel Jakub Dawidek ndisks = sc->sc_ndisks - 1; 1712dba915cfSPawel Jakub Dawidek } 1713dba915cfSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0 && 1714dba915cfSPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 1715dba915cfSPawel Jakub Dawidek round_robin = 1; 1716dba915cfSPawel Jakub Dawidek } else { 1717dba915cfSPawel Jakub Dawidek round_robin = 0; 1718dba915cfSPawel Jakub Dawidek } 1719dba915cfSPawel Jakub Dawidek KASSERT(!round_robin || !verify, 1720dba915cfSPawel Jakub Dawidek ("ROUND-ROBIN and VERIFY are mutually exclusive.")); 1721f5a2f7feSPawel Jakub Dawidek pbp->bio_driver2 = &sc->sc_disks[sc->sc_ndisks - 1]; 17222d1661a5SPawel Jakub Dawidek break; 17232d1661a5SPawel Jakub Dawidek case BIO_WRITE: 17242d1661a5SPawel Jakub Dawidek case BIO_DELETE: 17253650be51SPawel Jakub Dawidek /* 17263650be51SPawel Jakub Dawidek * Delay the request if it is colliding with a synchronization 17273650be51SPawel Jakub Dawidek * request. 17283650be51SPawel Jakub Dawidek */ 17293650be51SPawel Jakub Dawidek if (g_raid3_sync_collision(sc, pbp)) { 17303650be51SPawel Jakub Dawidek g_raid3_regular_delay(sc, pbp); 17313650be51SPawel Jakub Dawidek return (0); 17323650be51SPawel Jakub Dawidek } 1733d2fb9c62SPawel Jakub Dawidek 17344d006a98SPawel Jakub Dawidek if (sc->sc_idle) 17354d006a98SPawel Jakub Dawidek g_raid3_unidle(sc); 17360962f942SPawel Jakub Dawidek else 173701f1f41cSPawel Jakub Dawidek sc->sc_last_write = time_uptime; 17384d006a98SPawel Jakub Dawidek 17392d1661a5SPawel Jakub Dawidek ndisks = sc->sc_ndisks; 17402d1661a5SPawel Jakub Dawidek break; 17412d1661a5SPawel Jakub Dawidek } 17422d1661a5SPawel Jakub Dawidek for (n = 0; n < ndisks; n++) { 17432d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 17442d1661a5SPawel Jakub Dawidek cbp = g_raid3_clone_bio(sc, pbp); 17452d1661a5SPawel Jakub Dawidek if (cbp == NULL) { 17462d1661a5SPawel Jakub Dawidek while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) 17472d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 1748a65a0da2SPawel Jakub Dawidek /* 1749a65a0da2SPawel Jakub Dawidek * To prevent deadlock, we must run back up 1750a65a0da2SPawel Jakub Dawidek * with the ENOMEM for failed requests of any 1751a65a0da2SPawel Jakub Dawidek * of our consumers. Our own sync requests 1752a65a0da2SPawel Jakub Dawidek * can stick around, as they are finite. 1753a65a0da2SPawel Jakub Dawidek */ 1754a65a0da2SPawel Jakub Dawidek if ((pbp->bio_cflags & 1755a65a0da2SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_REGULAR) != 0) { 1756a65a0da2SPawel Jakub Dawidek g_io_deliver(pbp, ENOMEM); 1757a65a0da2SPawel Jakub Dawidek return (0); 1758a65a0da2SPawel Jakub Dawidek } 17592d1661a5SPawel Jakub Dawidek return (ENOMEM); 17602d1661a5SPawel Jakub Dawidek } 17612d1661a5SPawel Jakub Dawidek cbp->bio_offset = offset; 17622d1661a5SPawel Jakub Dawidek cbp->bio_length = length; 17632d1661a5SPawel Jakub Dawidek cbp->bio_done = g_raid3_done; 17642d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 17652d1661a5SPawel Jakub Dawidek case BIO_READ: 17662d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { 17672d1661a5SPawel Jakub Dawidek /* 17682d1661a5SPawel Jakub Dawidek * Replace invalid component with the parity 17692d1661a5SPawel Jakub Dawidek * component. 17702d1661a5SPawel Jakub Dawidek */ 17712d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 17722d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 17732d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 1774f5a2f7feSPawel Jakub Dawidek } else if (round_robin && 1775f5a2f7feSPawel Jakub Dawidek disk->d_no == sc->sc_round_robin) { 1776f5a2f7feSPawel Jakub Dawidek /* 1777f5a2f7feSPawel Jakub Dawidek * In round-robin mode skip one data component 1778f5a2f7feSPawel Jakub Dawidek * and use parity component when reading. 1779f5a2f7feSPawel Jakub Dawidek */ 1780f5a2f7feSPawel Jakub Dawidek pbp->bio_driver2 = disk; 1781f5a2f7feSPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 1782f5a2f7feSPawel Jakub Dawidek cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 1783f5a2f7feSPawel Jakub Dawidek sc->sc_round_robin++; 1784f5a2f7feSPawel Jakub Dawidek round_robin = 0; 1785dba915cfSPawel Jakub Dawidek } else if (verify && disk->d_no == sc->sc_ndisks - 1) { 1786dba915cfSPawel Jakub Dawidek cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; 17872d1661a5SPawel Jakub Dawidek } 17882d1661a5SPawel Jakub Dawidek break; 17892d1661a5SPawel Jakub Dawidek case BIO_WRITE: 17902d1661a5SPawel Jakub Dawidek case BIO_DELETE: 17912d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 17922d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 17932d1661a5SPawel Jakub Dawidek if (n == ndisks - 1) { 17942d1661a5SPawel Jakub Dawidek /* 17952d1661a5SPawel Jakub Dawidek * Active parity component, mark it as such. 17962d1661a5SPawel Jakub Dawidek */ 17972d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= 17982d1661a5SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_PARITY; 17992d1661a5SPawel Jakub Dawidek } 18002d1661a5SPawel Jakub Dawidek } else { 18012d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; 18022d1661a5SPawel Jakub Dawidek if (n == ndisks - 1) { 18032d1661a5SPawel Jakub Dawidek /* 18042d1661a5SPawel Jakub Dawidek * Parity component is not connected, 18052d1661a5SPawel Jakub Dawidek * so destroy its request. 18062d1661a5SPawel Jakub Dawidek */ 18072d1661a5SPawel Jakub Dawidek pbp->bio_pflags |= 18082d1661a5SPawel Jakub Dawidek G_RAID3_BIO_PFLAG_NOPARITY; 18092d1661a5SPawel Jakub Dawidek g_raid3_destroy_bio(sc, cbp); 18102d1661a5SPawel Jakub Dawidek cbp = NULL; 18112d1661a5SPawel Jakub Dawidek } else { 18122d1661a5SPawel Jakub Dawidek cbp->bio_cflags |= 18132d1661a5SPawel Jakub Dawidek G_RAID3_BIO_CFLAG_NODISK; 18142d1661a5SPawel Jakub Dawidek disk = NULL; 18152d1661a5SPawel Jakub Dawidek } 18162d1661a5SPawel Jakub Dawidek } 18172d1661a5SPawel Jakub Dawidek break; 18182d1661a5SPawel Jakub Dawidek } 18192d1661a5SPawel Jakub Dawidek if (cbp != NULL) 18202d1661a5SPawel Jakub Dawidek cbp->bio_caller2 = disk; 18212d1661a5SPawel Jakub Dawidek } 18222d1661a5SPawel Jakub Dawidek switch (pbp->bio_cmd) { 18232d1661a5SPawel Jakub Dawidek case BIO_READ: 1824f5a2f7feSPawel Jakub Dawidek if (round_robin) { 1825f5a2f7feSPawel Jakub Dawidek /* 1826f5a2f7feSPawel Jakub Dawidek * If we are in round-robin mode and 'round_robin' is 1827f5a2f7feSPawel Jakub Dawidek * still 1, it means, that we skipped parity component 1828f5a2f7feSPawel Jakub Dawidek * for this read and must reset sc_round_robin field. 1829f5a2f7feSPawel Jakub Dawidek */ 1830f5a2f7feSPawel Jakub Dawidek sc->sc_round_robin = 0; 1831f5a2f7feSPawel Jakub Dawidek } 1832ee40c7aaSPawel Jakub Dawidek G_RAID3_FOREACH_SAFE_BIO(pbp, cbp, tmpbp) { 18332d1661a5SPawel Jakub Dawidek disk = cbp->bio_caller2; 18342d1661a5SPawel Jakub Dawidek cp = disk->d_consumer; 18352d1661a5SPawel Jakub Dawidek cbp->bio_to = cp->provider; 18362d1661a5SPawel Jakub Dawidek G_RAID3_LOGREQ(3, cbp, "Sending request."); 18373650be51SPawel Jakub Dawidek KASSERT(cp->acr >= 1 && cp->acw >= 1 && cp->ace >= 1, 18382d1661a5SPawel Jakub Dawidek ("Consumer %s not opened (r%dw%de%d).", 18392d1661a5SPawel Jakub Dawidek cp->provider->name, cp->acr, cp->acw, cp->ace)); 184079e61493SPawel Jakub Dawidek cp->index++; 18412d1661a5SPawel Jakub Dawidek g_io_request(cbp, cp); 18422d1661a5SPawel Jakub Dawidek } 18432d1661a5SPawel Jakub Dawidek break; 18442d1661a5SPawel Jakub Dawidek case BIO_WRITE: 18452d1661a5SPawel Jakub Dawidek case BIO_DELETE: 18462d1661a5SPawel Jakub Dawidek /* 18473650be51SPawel Jakub Dawidek * Put request onto inflight queue, so we can check if new 18483650be51SPawel Jakub Dawidek * synchronization requests don't collide with it. 18493650be51SPawel Jakub Dawidek */ 18503650be51SPawel Jakub Dawidek bioq_insert_tail(&sc->sc_inflight, pbp); 18513650be51SPawel Jakub Dawidek 18523650be51SPawel Jakub Dawidek /* 18532d1661a5SPawel Jakub Dawidek * Bump syncid on first write. 18542d1661a5SPawel Jakub Dawidek */ 1855ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_SYNCID) != 0) { 1856a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_SYNCID; 1857d97d5ee9SPawel Jakub Dawidek g_raid3_bump_syncid(sc); 18582d1661a5SPawel Jakub Dawidek } 18592d1661a5SPawel Jakub Dawidek g_raid3_scatter(pbp); 18602d1661a5SPawel Jakub Dawidek break; 18612d1661a5SPawel Jakub Dawidek } 18622d1661a5SPawel Jakub Dawidek return (0); 18632d1661a5SPawel Jakub Dawidek } 18642d1661a5SPawel Jakub Dawidek 18652d1661a5SPawel Jakub Dawidek static int 18662d1661a5SPawel Jakub Dawidek g_raid3_can_destroy(struct g_raid3_softc *sc) 18672d1661a5SPawel Jakub Dawidek { 18682d1661a5SPawel Jakub Dawidek struct g_geom *gp; 18692d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 18702d1661a5SPawel Jakub Dawidek 18712d1661a5SPawel Jakub Dawidek g_topology_assert(); 18722d1661a5SPawel Jakub Dawidek gp = sc->sc_geom; 187318486a5eSPawel Jakub Dawidek if (gp->softc == NULL) 187418486a5eSPawel Jakub Dawidek return (1); 18752d1661a5SPawel Jakub Dawidek LIST_FOREACH(cp, &gp->consumer, consumer) { 18762d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 18772d1661a5SPawel Jakub Dawidek return (0); 18782d1661a5SPawel Jakub Dawidek } 18792d1661a5SPawel Jakub Dawidek gp = sc->sc_sync.ds_geom; 18802d1661a5SPawel Jakub Dawidek LIST_FOREACH(cp, &gp->consumer, consumer) { 18812d1661a5SPawel Jakub Dawidek if (g_raid3_is_busy(sc, cp)) 18822d1661a5SPawel Jakub Dawidek return (0); 18832d1661a5SPawel Jakub Dawidek } 18842d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "No I/O requests for %s, it can be destroyed.", 18852d1661a5SPawel Jakub Dawidek sc->sc_name); 18862d1661a5SPawel Jakub Dawidek return (1); 18872d1661a5SPawel Jakub Dawidek } 18882d1661a5SPawel Jakub Dawidek 18892d1661a5SPawel Jakub Dawidek static int 18902d1661a5SPawel Jakub Dawidek g_raid3_try_destroy(struct g_raid3_softc *sc) 18912d1661a5SPawel Jakub Dawidek { 18922d1661a5SPawel Jakub Dawidek 18933650be51SPawel Jakub Dawidek g_topology_assert_not(); 18943650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 18953650be51SPawel Jakub Dawidek 18964ed854e8SPawel Jakub Dawidek if (sc->sc_rootmount != NULL) { 18974ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", __LINE__, 18984ed854e8SPawel Jakub Dawidek sc->sc_rootmount); 18994ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 19004ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 19014ed854e8SPawel Jakub Dawidek } 19024ed854e8SPawel Jakub Dawidek 19032d1661a5SPawel Jakub Dawidek g_topology_lock(); 19042d1661a5SPawel Jakub Dawidek if (!g_raid3_can_destroy(sc)) { 19052d1661a5SPawel Jakub Dawidek g_topology_unlock(); 19062d1661a5SPawel Jakub Dawidek return (0); 19072d1661a5SPawel Jakub Dawidek } 190818486a5eSPawel Jakub Dawidek sc->sc_geom->softc = NULL; 190918486a5eSPawel Jakub Dawidek sc->sc_sync.ds_geom->softc = NULL; 1910a245a548SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_WAIT) != 0) { 19112d1661a5SPawel Jakub Dawidek g_topology_unlock(); 19122d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, 19132d1661a5SPawel Jakub Dawidek &sc->sc_worker); 19143650be51SPawel Jakub Dawidek /* Unlock sc_lock here, as it can be destroyed after wakeup. */ 19153650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 19162d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_worker); 19172d1661a5SPawel Jakub Dawidek sc->sc_worker = NULL; 19182d1661a5SPawel Jakub Dawidek } else { 19192d1661a5SPawel Jakub Dawidek g_topology_unlock(); 19203650be51SPawel Jakub Dawidek g_raid3_destroy_device(sc); 19212d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 19222d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 19232d1661a5SPawel Jakub Dawidek } 19242d1661a5SPawel Jakub Dawidek return (1); 19252d1661a5SPawel Jakub Dawidek } 19262d1661a5SPawel Jakub Dawidek 19272d1661a5SPawel Jakub Dawidek /* 19282d1661a5SPawel Jakub Dawidek * Worker thread. 19292d1661a5SPawel Jakub Dawidek */ 19302d1661a5SPawel Jakub Dawidek static void 19312d1661a5SPawel Jakub Dawidek g_raid3_worker(void *arg) 19322d1661a5SPawel Jakub Dawidek { 19332d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 19342d1661a5SPawel Jakub Dawidek struct g_raid3_event *ep; 19352d1661a5SPawel Jakub Dawidek struct bio *bp; 19360962f942SPawel Jakub Dawidek int timeout; 19372d1661a5SPawel Jakub Dawidek 19382d1661a5SPawel Jakub Dawidek sc = arg; 193963710c4dSJohn Baldwin mtx_lock_spin(&sched_lock); 194063710c4dSJohn Baldwin sched_prio(curthread, PRIBIO); 194163710c4dSJohn Baldwin mtx_unlock_spin(&sched_lock); 19422d1661a5SPawel Jakub Dawidek 19433650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 19442d1661a5SPawel Jakub Dawidek for (;;) { 19452d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: Let's see...", __func__); 19462d1661a5SPawel Jakub Dawidek /* 19472d1661a5SPawel Jakub Dawidek * First take a look at events. 19482d1661a5SPawel Jakub Dawidek * This is important to handle events before any I/O requests. 19492d1661a5SPawel Jakub Dawidek */ 19502d1661a5SPawel Jakub Dawidek ep = g_raid3_event_get(sc); 19513650be51SPawel Jakub Dawidek if (ep != NULL) { 1952d97d5ee9SPawel Jakub Dawidek g_raid3_event_remove(sc, ep); 19532d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DEVICE) != 0) { 19542d1661a5SPawel Jakub Dawidek /* Update only device status. */ 19552d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, 19562d1661a5SPawel Jakub Dawidek "Running event for device %s.", 19572d1661a5SPawel Jakub Dawidek sc->sc_name); 19582d1661a5SPawel Jakub Dawidek ep->e_error = 0; 1959d97d5ee9SPawel Jakub Dawidek g_raid3_update_device(sc, 1); 19602d1661a5SPawel Jakub Dawidek } else { 19612d1661a5SPawel Jakub Dawidek /* Update disk status. */ 19622d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "Running event for disk %s.", 19632d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(ep->e_disk)); 19642d1661a5SPawel Jakub Dawidek ep->e_error = g_raid3_update_disk(ep->e_disk, 1965d97d5ee9SPawel Jakub Dawidek ep->e_state); 19662d1661a5SPawel Jakub Dawidek if (ep->e_error == 0) 1967d97d5ee9SPawel Jakub Dawidek g_raid3_update_device(sc, 0); 19682d1661a5SPawel Jakub Dawidek } 19692d1661a5SPawel Jakub Dawidek if ((ep->e_flags & G_RAID3_EVENT_DONTWAIT) != 0) { 19702d1661a5SPawel Jakub Dawidek KASSERT(ep->e_error == 0, 19712d1661a5SPawel Jakub Dawidek ("Error cannot be handled.")); 19722d1661a5SPawel Jakub Dawidek g_raid3_event_free(ep); 19732d1661a5SPawel Jakub Dawidek } else { 19742d1661a5SPawel Jakub Dawidek ep->e_flags |= G_RAID3_EVENT_DONE; 19752d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, 19762d1661a5SPawel Jakub Dawidek ep); 19772d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_events_mtx); 19782d1661a5SPawel Jakub Dawidek wakeup(ep); 19792d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_events_mtx); 19802d1661a5SPawel Jakub Dawidek } 19812d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 19822d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 19833650be51SPawel Jakub Dawidek if (g_raid3_try_destroy(sc)) { 19843650be51SPawel Jakub Dawidek curthread->td_pflags &= ~TDP_GEOM; 19853650be51SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Thread exiting."); 19862d1661a5SPawel Jakub Dawidek kthread_exit(0); 19872d1661a5SPawel Jakub Dawidek } 19883650be51SPawel Jakub Dawidek } 19892d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 1.", __func__); 19902d1661a5SPawel Jakub Dawidek continue; 19912d1661a5SPawel Jakub Dawidek } 19922d1661a5SPawel Jakub Dawidek /* 19930962f942SPawel Jakub Dawidek * Check if we can mark array as CLEAN and if we can't take 19940962f942SPawel Jakub Dawidek * how much seconds should we wait. 19950962f942SPawel Jakub Dawidek */ 19963650be51SPawel Jakub Dawidek timeout = g_raid3_idle(sc, -1); 19970962f942SPawel Jakub Dawidek /* 19982d1661a5SPawel Jakub Dawidek * Now I/O requests. 19992d1661a5SPawel Jakub Dawidek */ 20002d1661a5SPawel Jakub Dawidek /* Get first request from the queue. */ 20012d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 20022d1661a5SPawel Jakub Dawidek bp = bioq_first(&sc->sc_queue); 20032d1661a5SPawel Jakub Dawidek if (bp == NULL) { 20042d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 20052d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_DESTROY) != 0) { 20062d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 20073650be51SPawel Jakub Dawidek if (g_raid3_try_destroy(sc)) { 20083650be51SPawel Jakub Dawidek curthread->td_pflags &= ~TDP_GEOM; 2009d7fad9f6SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Thread exiting."); 20102d1661a5SPawel Jakub Dawidek kthread_exit(0); 20113650be51SPawel Jakub Dawidek } 20122d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 20132d1661a5SPawel Jakub Dawidek } 20143650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 2015a2fe5c66SPawel Jakub Dawidek /* 2016a2fe5c66SPawel Jakub Dawidek * XXX: We can miss an event here, because an event 2017a2fe5c66SPawel Jakub Dawidek * can be added without sx-device-lock and without 2018a2fe5c66SPawel Jakub Dawidek * mtx-queue-lock. Maybe I should just stop using 2019a2fe5c66SPawel Jakub Dawidek * dedicated mutex for events synchronization and 2020a2fe5c66SPawel Jakub Dawidek * stick with the queue lock? 2021a2fe5c66SPawel Jakub Dawidek * The event will hang here until next I/O request 2022a2fe5c66SPawel Jakub Dawidek * or next event is received. 2023a2fe5c66SPawel Jakub Dawidek */ 20240962f942SPawel Jakub Dawidek MSLEEP(sc, &sc->sc_queue_mtx, PRIBIO | PDROP, "r3:w1", 20250962f942SPawel Jakub Dawidek timeout * hz); 20263650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 20279bb09163SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 4.", __func__); 20282d1661a5SPawel Jakub Dawidek continue; 20292d1661a5SPawel Jakub Dawidek } 203084edb86dSPawel Jakub Dawidek process: 20312d1661a5SPawel Jakub Dawidek bioq_remove(&sc->sc_queue, bp); 20322d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 20332d1661a5SPawel Jakub Dawidek 20343650be51SPawel Jakub Dawidek if ((bp->bio_cflags & G_RAID3_BIO_CFLAG_REGULAR) != 0) 20352d1661a5SPawel Jakub Dawidek g_raid3_regular_request(bp); 20363650be51SPawel Jakub Dawidek else if ((bp->bio_cflags & G_RAID3_BIO_CFLAG_SYNC) != 0) 20372d1661a5SPawel Jakub Dawidek g_raid3_sync_request(bp); 203884edb86dSPawel Jakub Dawidek else if (g_raid3_register_request(bp) != 0) { 20392d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 20403650be51SPawel Jakub Dawidek bioq_insert_head(&sc->sc_queue, bp); 204184edb86dSPawel Jakub Dawidek /* 204284edb86dSPawel Jakub Dawidek * We are short in memory, let see if there are finished 204384edb86dSPawel Jakub Dawidek * request we can free. 204484edb86dSPawel Jakub Dawidek */ 204584edb86dSPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_queue.queue, bio_queue) { 204684edb86dSPawel Jakub Dawidek if (bp->bio_cflags & G_RAID3_BIO_CFLAG_REGULAR) 204784edb86dSPawel Jakub Dawidek goto process; 20482d1661a5SPawel Jakub Dawidek } 204984edb86dSPawel Jakub Dawidek /* 205084edb86dSPawel Jakub Dawidek * No finished regular request, so at least keep 205184edb86dSPawel Jakub Dawidek * synchronization running. 205284edb86dSPawel Jakub Dawidek */ 205384edb86dSPawel Jakub Dawidek TAILQ_FOREACH(bp, &sc->sc_queue.queue, bio_queue) { 205484edb86dSPawel Jakub Dawidek if (bp->bio_cflags & G_RAID3_BIO_CFLAG_SYNC) 205584edb86dSPawel Jakub Dawidek goto process; 205684edb86dSPawel Jakub Dawidek } 205784edb86dSPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 205884edb86dSPawel Jakub Dawidek MSLEEP(&sc->sc_queue, &sc->sc_queue_mtx, PRIBIO | PDROP, 205984edb86dSPawel Jakub Dawidek "r3:lowmem", hz / 10); 206084edb86dSPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 20612d1661a5SPawel Jakub Dawidek } 2062d97d5ee9SPawel Jakub Dawidek G_RAID3_DEBUG(5, "%s: I'm here 9.", __func__); 20632d1661a5SPawel Jakub Dawidek } 20642d1661a5SPawel Jakub Dawidek } 20652d1661a5SPawel Jakub Dawidek 20662d1661a5SPawel Jakub Dawidek static void 20670962f942SPawel Jakub Dawidek g_raid3_update_idle(struct g_raid3_softc *sc, struct g_raid3_disk *disk) 20682d1661a5SPawel Jakub Dawidek { 20692d1661a5SPawel Jakub Dawidek 20703650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_LOCKED); 20710962f942SPawel Jakub Dawidek if (!sc->sc_idle && (disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) == 0) { 20722d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as dirty.", 20733650be51SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 20742d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 20750962f942SPawel Jakub Dawidek } else if (sc->sc_idle && 20760962f942SPawel Jakub Dawidek (disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) != 0) { 20772d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (device %s) marked as clean.", 20783650be51SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 20792d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 20802d1661a5SPawel Jakub Dawidek } 20812d1661a5SPawel Jakub Dawidek } 20822d1661a5SPawel Jakub Dawidek 20832d1661a5SPawel Jakub Dawidek static void 20842d1661a5SPawel Jakub Dawidek g_raid3_sync_start(struct g_raid3_softc *sc) 20852d1661a5SPawel Jakub Dawidek { 20862d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 20873650be51SPawel Jakub Dawidek struct g_consumer *cp; 20883650be51SPawel Jakub Dawidek struct bio *bp; 20892d1661a5SPawel Jakub Dawidek int error; 20902d1661a5SPawel Jakub Dawidek u_int n; 20912d1661a5SPawel Jakub Dawidek 20923650be51SPawel Jakub Dawidek g_topology_assert_not(); 20933650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 20942d1661a5SPawel Jakub Dawidek 20952d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 20962d1661a5SPawel Jakub Dawidek ("Device not in DEGRADED state (%s, %u).", sc->sc_name, 20972d1661a5SPawel Jakub Dawidek sc->sc_state)); 20982d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_syncdisk == NULL, ("Syncdisk is not NULL (%s, %u).", 20992d1661a5SPawel Jakub Dawidek sc->sc_name, sc->sc_state)); 21002d1661a5SPawel Jakub Dawidek disk = NULL; 21012d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 21022d1661a5SPawel Jakub Dawidek if (sc->sc_disks[n].d_state != G_RAID3_DISK_STATE_SYNCHRONIZING) 21032d1661a5SPawel Jakub Dawidek continue; 21042d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 21052d1661a5SPawel Jakub Dawidek break; 21062d1661a5SPawel Jakub Dawidek } 21072d1661a5SPawel Jakub Dawidek if (disk == NULL) 21082d1661a5SPawel Jakub Dawidek return; 21092d1661a5SPawel Jakub Dawidek 21103650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 21113650be51SPawel Jakub Dawidek g_topology_lock(); 21123650be51SPawel Jakub Dawidek cp = g_new_consumer(sc->sc_sync.ds_geom); 21133650be51SPawel Jakub Dawidek error = g_attach(cp, sc->sc_provider); 21143650be51SPawel Jakub Dawidek KASSERT(error == 0, 21153650be51SPawel Jakub Dawidek ("Cannot attach to %s (error=%d).", sc->sc_name, error)); 21163650be51SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 21173650be51SPawel Jakub Dawidek KASSERT(error == 0, ("Cannot open %s (error=%d).", sc->sc_name, error)); 21183650be51SPawel Jakub Dawidek g_topology_unlock(); 21193650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 21203650be51SPawel Jakub Dawidek 21212d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s.", sc->sc_name, 21222d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 21232d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_DIRTY; 21242d1661a5SPawel Jakub Dawidek KASSERT(disk->d_sync.ds_consumer == NULL, 21252d1661a5SPawel Jakub Dawidek ("Sync consumer already exists (device=%s, disk=%s).", 21262d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk))); 21273650be51SPawel Jakub Dawidek 21283650be51SPawel Jakub Dawidek disk->d_sync.ds_consumer = cp; 21292d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer->private = disk; 213079e61493SPawel Jakub Dawidek disk->d_sync.ds_consumer->index = 0; 21312d1661a5SPawel Jakub Dawidek sc->sc_syncdisk = disk; 21323650be51SPawel Jakub Dawidek 21333650be51SPawel Jakub Dawidek /* 21343650be51SPawel Jakub Dawidek * Allocate memory for synchronization bios and initialize them. 21353650be51SPawel Jakub Dawidek */ 21363650be51SPawel Jakub Dawidek disk->d_sync.ds_bios = malloc(sizeof(struct bio *) * g_raid3_syncreqs, 21373650be51SPawel Jakub Dawidek M_RAID3, M_WAITOK); 21383650be51SPawel Jakub Dawidek for (n = 0; n < g_raid3_syncreqs; n++) { 21393650be51SPawel Jakub Dawidek bp = g_alloc_bio(); 21403650be51SPawel Jakub Dawidek disk->d_sync.ds_bios[n] = bp; 21413650be51SPawel Jakub Dawidek bp->bio_parent = NULL; 21423650be51SPawel Jakub Dawidek bp->bio_cmd = BIO_READ; 21433650be51SPawel Jakub Dawidek bp->bio_data = malloc(MAXPHYS, M_RAID3, M_WAITOK); 21443650be51SPawel Jakub Dawidek bp->bio_cflags = 0; 21453650be51SPawel Jakub Dawidek bp->bio_offset = disk->d_sync.ds_offset * (sc->sc_ndisks - 1); 21463650be51SPawel Jakub Dawidek bp->bio_length = MIN(MAXPHYS, sc->sc_mediasize - bp->bio_offset); 21473650be51SPawel Jakub Dawidek disk->d_sync.ds_offset += bp->bio_length / (sc->sc_ndisks - 1); 21483650be51SPawel Jakub Dawidek bp->bio_done = g_raid3_sync_done; 21493650be51SPawel Jakub Dawidek bp->bio_from = disk->d_sync.ds_consumer; 21503650be51SPawel Jakub Dawidek bp->bio_to = sc->sc_provider; 2151ef25813dSRuslan Ermilov bp->bio_caller1 = (void *)(uintptr_t)n; 21523650be51SPawel Jakub Dawidek } 21533650be51SPawel Jakub Dawidek 21543650be51SPawel Jakub Dawidek /* Set the number of in-flight synchronization requests. */ 21553650be51SPawel Jakub Dawidek disk->d_sync.ds_inflight = g_raid3_syncreqs; 21563650be51SPawel Jakub Dawidek 21573650be51SPawel Jakub Dawidek /* 21583650be51SPawel Jakub Dawidek * Fire off first synchronization requests. 21593650be51SPawel Jakub Dawidek */ 21603650be51SPawel Jakub Dawidek for (n = 0; n < g_raid3_syncreqs; n++) { 21613650be51SPawel Jakub Dawidek bp = disk->d_sync.ds_bios[n]; 21623650be51SPawel Jakub Dawidek G_RAID3_LOGREQ(3, bp, "Sending synchronization request."); 21633650be51SPawel Jakub Dawidek disk->d_sync.ds_consumer->index++; 21643650be51SPawel Jakub Dawidek /* 21653650be51SPawel Jakub Dawidek * Delay the request if it is colliding with a regular request. 21663650be51SPawel Jakub Dawidek */ 21673650be51SPawel Jakub Dawidek if (g_raid3_regular_collision(sc, bp)) 21683650be51SPawel Jakub Dawidek g_raid3_sync_delay(sc, bp); 21693650be51SPawel Jakub Dawidek else 21703650be51SPawel Jakub Dawidek g_io_request(bp, disk->d_sync.ds_consumer); 21713650be51SPawel Jakub Dawidek } 21722d1661a5SPawel Jakub Dawidek } 21732d1661a5SPawel Jakub Dawidek 21742d1661a5SPawel Jakub Dawidek /* 21752d1661a5SPawel Jakub Dawidek * Stop synchronization process. 21762d1661a5SPawel Jakub Dawidek * type: 0 - synchronization finished 21772d1661a5SPawel Jakub Dawidek * 1 - synchronization stopped 21782d1661a5SPawel Jakub Dawidek */ 21792d1661a5SPawel Jakub Dawidek static void 21802d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(struct g_raid3_softc *sc, int type) 21812d1661a5SPawel Jakub Dawidek { 21822d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 21833650be51SPawel Jakub Dawidek struct g_consumer *cp; 21842d1661a5SPawel Jakub Dawidek 21853650be51SPawel Jakub Dawidek g_topology_assert_not(); 21863650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_LOCKED); 21873650be51SPawel Jakub Dawidek 21882d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED, 21892d1661a5SPawel Jakub Dawidek ("Device not in DEGRADED state (%s, %u).", sc->sc_name, 21902d1661a5SPawel Jakub Dawidek sc->sc_state)); 21912d1661a5SPawel Jakub Dawidek disk = sc->sc_syncdisk; 21922d1661a5SPawel Jakub Dawidek sc->sc_syncdisk = NULL; 21932d1661a5SPawel Jakub Dawidek KASSERT(disk != NULL, ("No disk was synchronized (%s).", sc->sc_name)); 21942d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 21952d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 21962d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 21972d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_consumer == NULL) 21982d1661a5SPawel Jakub Dawidek return; 21992d1661a5SPawel Jakub Dawidek 22002d1661a5SPawel Jakub Dawidek if (type == 0) { 22012d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s finished.", 22023650be51SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 22032d1661a5SPawel Jakub Dawidek } else /* if (type == 1) */ { 22042d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: rebuilding provider %s stopped.", 22053650be51SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 22062d1661a5SPawel Jakub Dawidek } 22073650be51SPawel Jakub Dawidek free(disk->d_sync.ds_bios, M_RAID3); 22083650be51SPawel Jakub Dawidek disk->d_sync.ds_bios = NULL; 22093650be51SPawel Jakub Dawidek cp = disk->d_sync.ds_consumer; 22102d1661a5SPawel Jakub Dawidek disk->d_sync.ds_consumer = NULL; 22112d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 22123650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); /* Avoid recursion on sc_lock. */ 22133650be51SPawel Jakub Dawidek g_topology_lock(); 22143650be51SPawel Jakub Dawidek g_raid3_kill_consumer(sc, cp); 22153650be51SPawel Jakub Dawidek g_topology_unlock(); 22163650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 22172d1661a5SPawel Jakub Dawidek } 22182d1661a5SPawel Jakub Dawidek 22192d1661a5SPawel Jakub Dawidek static void 22202d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(struct g_raid3_softc *sc) 22212d1661a5SPawel Jakub Dawidek { 22222d1661a5SPawel Jakub Dawidek struct g_provider *pp; 22232d1661a5SPawel Jakub Dawidek 22243650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_LOCKED); 22252d1661a5SPawel Jakub Dawidek 22263650be51SPawel Jakub Dawidek g_topology_lock(); 22272d1661a5SPawel Jakub Dawidek pp = g_new_providerf(sc->sc_geom, "raid3/%s", sc->sc_name); 22282d1661a5SPawel Jakub Dawidek pp->mediasize = sc->sc_mediasize; 22292d1661a5SPawel Jakub Dawidek pp->sectorsize = sc->sc_sectorsize; 22302d1661a5SPawel Jakub Dawidek sc->sc_provider = pp; 22312d1661a5SPawel Jakub Dawidek g_error_provider(pp, 0); 22323650be51SPawel Jakub Dawidek g_topology_unlock(); 22332d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s launched.", sc->sc_name, 22342d1661a5SPawel Jakub Dawidek pp->name); 22352d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED) 22362d1661a5SPawel Jakub Dawidek g_raid3_sync_start(sc); 22372d1661a5SPawel Jakub Dawidek } 22382d1661a5SPawel Jakub Dawidek 22392d1661a5SPawel Jakub Dawidek static void 22402d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(struct g_raid3_softc *sc) 22412d1661a5SPawel Jakub Dawidek { 22422d1661a5SPawel Jakub Dawidek struct bio *bp; 22432d1661a5SPawel Jakub Dawidek 22443650be51SPawel Jakub Dawidek g_topology_assert_not(); 22452d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_provider != NULL, ("NULL provider (device=%s).", 22462d1661a5SPawel Jakub Dawidek sc->sc_name)); 22472d1661a5SPawel Jakub Dawidek 22483650be51SPawel Jakub Dawidek g_topology_lock(); 22492d1661a5SPawel Jakub Dawidek g_error_provider(sc->sc_provider, ENXIO); 22502d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 22512d1661a5SPawel Jakub Dawidek while ((bp = bioq_first(&sc->sc_queue)) != NULL) { 22522d1661a5SPawel Jakub Dawidek bioq_remove(&sc->sc_queue, bp); 22532d1661a5SPawel Jakub Dawidek g_io_deliver(bp, ENXIO); 22542d1661a5SPawel Jakub Dawidek } 22552d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 22562d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s destroyed.", sc->sc_name, 22572d1661a5SPawel Jakub Dawidek sc->sc_provider->name); 22582d1661a5SPawel Jakub Dawidek sc->sc_provider->flags |= G_PF_WITHER; 22592d1661a5SPawel Jakub Dawidek g_orphan_provider(sc->sc_provider, ENXIO); 22603650be51SPawel Jakub Dawidek g_topology_unlock(); 22612d1661a5SPawel Jakub Dawidek sc->sc_provider = NULL; 22622d1661a5SPawel Jakub Dawidek if (sc->sc_syncdisk != NULL) 22632d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 1); 22642d1661a5SPawel Jakub Dawidek } 22652d1661a5SPawel Jakub Dawidek 22662d1661a5SPawel Jakub Dawidek static void 22672d1661a5SPawel Jakub Dawidek g_raid3_go(void *arg) 22682d1661a5SPawel Jakub Dawidek { 22692d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 22702d1661a5SPawel Jakub Dawidek 22712d1661a5SPawel Jakub Dawidek sc = arg; 22722d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Force device %s start due to timeout.", sc->sc_name); 22732d1661a5SPawel Jakub Dawidek g_raid3_event_send(sc, 0, 22742d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT | G_RAID3_EVENT_DEVICE); 22752d1661a5SPawel Jakub Dawidek } 22762d1661a5SPawel Jakub Dawidek 22772d1661a5SPawel Jakub Dawidek static u_int 22782d1661a5SPawel Jakub Dawidek g_raid3_determine_state(struct g_raid3_disk *disk) 22792d1661a5SPawel Jakub Dawidek { 22802d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 22812d1661a5SPawel Jakub Dawidek u_int state; 22822d1661a5SPawel Jakub Dawidek 22832d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 22842d1661a5SPawel Jakub Dawidek if (sc->sc_syncid == disk->d_sync.ds_syncid) { 22852d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 22862d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING) == 0) { 22872d1661a5SPawel Jakub Dawidek /* Disk does not need synchronization. */ 22882d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_ACTIVE; 22892d1661a5SPawel Jakub Dawidek } else { 22902d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & 22912d1661a5SPawel Jakub Dawidek G_RAID3_DEVICE_FLAG_NOAUTOSYNC) == 0 || 22922d1661a5SPawel Jakub Dawidek (disk->d_flags & 22932d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_FORCE_SYNC) != 0) { 22942d1661a5SPawel Jakub Dawidek /* 22952d1661a5SPawel Jakub Dawidek * We can start synchronization from 22962d1661a5SPawel Jakub Dawidek * the stored offset. 22972d1661a5SPawel Jakub Dawidek */ 22982d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_SYNCHRONIZING; 22992d1661a5SPawel Jakub Dawidek } else { 23002d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_STALE; 23012d1661a5SPawel Jakub Dawidek } 23022d1661a5SPawel Jakub Dawidek } 23032d1661a5SPawel Jakub Dawidek } else if (disk->d_sync.ds_syncid < sc->sc_syncid) { 23042d1661a5SPawel Jakub Dawidek /* 23052d1661a5SPawel Jakub Dawidek * Reset all synchronization data for this disk, 23062d1661a5SPawel Jakub Dawidek * because if it even was synchronized, it was 23072d1661a5SPawel Jakub Dawidek * synchronized to disks with different syncid. 23082d1661a5SPawel Jakub Dawidek */ 23092d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_SYNCHRONIZING; 23102d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = 0; 23112d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = 0; 23122d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = sc->sc_syncid; 23132d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) == 0 || 23142d1661a5SPawel Jakub Dawidek (disk->d_flags & G_RAID3_DISK_FLAG_FORCE_SYNC) != 0) { 23152d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_SYNCHRONIZING; 23162d1661a5SPawel Jakub Dawidek } else { 23172d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_STALE; 23182d1661a5SPawel Jakub Dawidek } 23192d1661a5SPawel Jakub Dawidek } else /* if (sc->sc_syncid < disk->d_sync.ds_syncid) */ { 23202d1661a5SPawel Jakub Dawidek /* 23212d1661a5SPawel Jakub Dawidek * Not good, NOT GOOD! 23222d1661a5SPawel Jakub Dawidek * It means that device was started on stale disks 23232d1661a5SPawel Jakub Dawidek * and more fresh disk just arrive. 23242d1661a5SPawel Jakub Dawidek * If there were writes, device is fucked up, sorry. 23252d1661a5SPawel Jakub Dawidek * I think the best choice here is don't touch 23262d1661a5SPawel Jakub Dawidek * this disk and inform the user laudly. 23272d1661a5SPawel Jakub Dawidek */ 23282d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s was started before the freshest " 23292d1661a5SPawel Jakub Dawidek "disk (%s) arrives!! It will not be connected to the " 23302d1661a5SPawel Jakub Dawidek "running device.", sc->sc_name, 23312d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 23322d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 23332d1661a5SPawel Jakub Dawidek state = G_RAID3_DISK_STATE_NONE; 23342d1661a5SPawel Jakub Dawidek /* Return immediately, because disk was destroyed. */ 23352d1661a5SPawel Jakub Dawidek return (state); 23362d1661a5SPawel Jakub Dawidek } 23372d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "State for %s disk: %s.", 23382d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), g_raid3_disk_state2str(state)); 23392d1661a5SPawel Jakub Dawidek return (state); 23402d1661a5SPawel Jakub Dawidek } 23412d1661a5SPawel Jakub Dawidek 23422d1661a5SPawel Jakub Dawidek /* 23432d1661a5SPawel Jakub Dawidek * Update device state. 23442d1661a5SPawel Jakub Dawidek */ 23452d1661a5SPawel Jakub Dawidek static void 2346d97d5ee9SPawel Jakub Dawidek g_raid3_update_device(struct g_raid3_softc *sc, boolean_t force) 23472d1661a5SPawel Jakub Dawidek { 23482d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 23492d1661a5SPawel Jakub Dawidek u_int state; 23502d1661a5SPawel Jakub Dawidek 23513650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 23522d1661a5SPawel Jakub Dawidek 23532d1661a5SPawel Jakub Dawidek switch (sc->sc_state) { 23542d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_STARTING: 23552d1661a5SPawel Jakub Dawidek { 2356a245a548SPawel Jakub Dawidek u_int n, ndirty, ndisks, genid, syncid; 23572d1661a5SPawel Jakub Dawidek 23582d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_provider == NULL, 23592d1661a5SPawel Jakub Dawidek ("Non-NULL provider in STARTING state (%s).", sc->sc_name)); 23602d1661a5SPawel Jakub Dawidek /* 23612d1661a5SPawel Jakub Dawidek * Are we ready? We are, if all disks are connected or 23622d1661a5SPawel Jakub Dawidek * one disk is missing and 'force' is true. 23632d1661a5SPawel Jakub Dawidek */ 23642d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, -1) + force == sc->sc_ndisks) { 23652d1661a5SPawel Jakub Dawidek if (!force) 23662d1661a5SPawel Jakub Dawidek callout_drain(&sc->sc_callout); 23672d1661a5SPawel Jakub Dawidek } else { 23682d1661a5SPawel Jakub Dawidek if (force) { 23692d1661a5SPawel Jakub Dawidek /* 23702d1661a5SPawel Jakub Dawidek * Timeout expired, so destroy device. 23712d1661a5SPawel Jakub Dawidek */ 23722d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 23734ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", 23744ed854e8SPawel Jakub Dawidek __LINE__, sc->sc_rootmount); 23754ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 23764ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 23772d1661a5SPawel Jakub Dawidek } 23782d1661a5SPawel Jakub Dawidek return; 23792d1661a5SPawel Jakub Dawidek } 23802d1661a5SPawel Jakub Dawidek 23812d1661a5SPawel Jakub Dawidek /* 2382a245a548SPawel Jakub Dawidek * Find the biggest genid. 2383a245a548SPawel Jakub Dawidek */ 2384a245a548SPawel Jakub Dawidek genid = 0; 2385a245a548SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 2386a245a548SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 2387a245a548SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 2388a245a548SPawel Jakub Dawidek continue; 2389a245a548SPawel Jakub Dawidek if (disk->d_genid > genid) 2390a245a548SPawel Jakub Dawidek genid = disk->d_genid; 2391a245a548SPawel Jakub Dawidek } 2392a245a548SPawel Jakub Dawidek sc->sc_genid = genid; 2393a245a548SPawel Jakub Dawidek /* 2394a245a548SPawel Jakub Dawidek * Remove all disks without the biggest genid. 2395a245a548SPawel Jakub Dawidek */ 2396a245a548SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 2397a245a548SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 2398a245a548SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 2399a245a548SPawel Jakub Dawidek continue; 2400a245a548SPawel Jakub Dawidek if (disk->d_genid < genid) { 2401a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, 2402a245a548SPawel Jakub Dawidek "Component %s (device %s) broken, skipping.", 2403a245a548SPawel Jakub Dawidek g_raid3_get_diskname(disk), sc->sc_name); 2404a245a548SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 2405a245a548SPawel Jakub Dawidek } 2406a245a548SPawel Jakub Dawidek } 2407a245a548SPawel Jakub Dawidek 2408a245a548SPawel Jakub Dawidek /* 24092d1661a5SPawel Jakub Dawidek * There must be at least 'sc->sc_ndisks - 1' components 24102d1661a5SPawel Jakub Dawidek * with the same syncid and without SYNCHRONIZING flag. 24112d1661a5SPawel Jakub Dawidek */ 24122d1661a5SPawel Jakub Dawidek 24132d1661a5SPawel Jakub Dawidek /* 24142d1661a5SPawel Jakub Dawidek * Find the biggest syncid, number of valid components and 24152d1661a5SPawel Jakub Dawidek * number of dirty components. 24162d1661a5SPawel Jakub Dawidek */ 24172d1661a5SPawel Jakub Dawidek ndirty = ndisks = syncid = 0; 24182d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 24192d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 24202d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 24212d1661a5SPawel Jakub Dawidek continue; 24222d1661a5SPawel Jakub Dawidek if ((disk->d_flags & G_RAID3_DISK_FLAG_DIRTY) != 0) 24232d1661a5SPawel Jakub Dawidek ndirty++; 24242d1661a5SPawel Jakub Dawidek if (disk->d_sync.ds_syncid > syncid) { 24252d1661a5SPawel Jakub Dawidek syncid = disk->d_sync.ds_syncid; 24262d1661a5SPawel Jakub Dawidek ndisks = 0; 24272d1661a5SPawel Jakub Dawidek } else if (disk->d_sync.ds_syncid < syncid) { 24282d1661a5SPawel Jakub Dawidek continue; 24292d1661a5SPawel Jakub Dawidek } 24302d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 24312d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING) != 0) { 24322d1661a5SPawel Jakub Dawidek continue; 24332d1661a5SPawel Jakub Dawidek } 24342d1661a5SPawel Jakub Dawidek ndisks++; 24352d1661a5SPawel Jakub Dawidek } 24362d1661a5SPawel Jakub Dawidek /* 24372d1661a5SPawel Jakub Dawidek * Do we have enough valid components? 24382d1661a5SPawel Jakub Dawidek */ 24392d1661a5SPawel Jakub Dawidek if (ndisks + 1 < sc->sc_ndisks) { 24402d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, 24412d1661a5SPawel Jakub Dawidek "Device %s is broken, too few valid components.", 24422d1661a5SPawel Jakub Dawidek sc->sc_name); 24432d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 24442d1661a5SPawel Jakub Dawidek return; 24452d1661a5SPawel Jakub Dawidek } 24462d1661a5SPawel Jakub Dawidek /* 24472d1661a5SPawel Jakub Dawidek * If there is one DIRTY component and all disks are present, 24482d1661a5SPawel Jakub Dawidek * mark it for synchronization. If there is more than one DIRTY 24492d1661a5SPawel Jakub Dawidek * component, mark parity component for synchronization. 24502d1661a5SPawel Jakub Dawidek */ 24512d1661a5SPawel Jakub Dawidek if (ndisks == sc->sc_ndisks && ndirty == 1) { 24522d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 24532d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 24542d1661a5SPawel Jakub Dawidek if ((disk->d_flags & 24552d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_DIRTY) == 0) { 24562d1661a5SPawel Jakub Dawidek continue; 24572d1661a5SPawel Jakub Dawidek } 24582d1661a5SPawel Jakub Dawidek disk->d_flags |= 24592d1661a5SPawel Jakub Dawidek G_RAID3_DISK_FLAG_SYNCHRONIZING; 24602d1661a5SPawel Jakub Dawidek } 24612d1661a5SPawel Jakub Dawidek } else if (ndisks == sc->sc_ndisks && ndirty > 1) { 24622d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[sc->sc_ndisks - 1]; 24632d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_SYNCHRONIZING; 24642d1661a5SPawel Jakub Dawidek } 24652d1661a5SPawel Jakub Dawidek 24662d1661a5SPawel Jakub Dawidek sc->sc_syncid = syncid; 24672d1661a5SPawel Jakub Dawidek if (force) { 24682d1661a5SPawel Jakub Dawidek /* Remember to bump syncid on first write. */ 2469ea973705SPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_SYNCID; 24702d1661a5SPawel Jakub Dawidek } 24712d1661a5SPawel Jakub Dawidek if (ndisks == sc->sc_ndisks) 24722d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_COMPLETE; 24732d1661a5SPawel Jakub Dawidek else /* if (ndisks == sc->sc_ndisks - 1) */ 24742d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_DEGRADED; 24752d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s state changed from %s to %s.", 24762d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 24772d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 24782d1661a5SPawel Jakub Dawidek sc->sc_state = state; 24792d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 24802d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 24812d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 24822d1661a5SPawel Jakub Dawidek continue; 24832d1661a5SPawel Jakub Dawidek state = g_raid3_determine_state(disk); 24842d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, state, G_RAID3_EVENT_DONTWAIT); 2485a245a548SPawel Jakub Dawidek if (state == G_RAID3_DISK_STATE_STALE) 2486ea973705SPawel Jakub Dawidek sc->sc_bump_id |= G_RAID3_BUMP_SYNCID; 24872d1661a5SPawel Jakub Dawidek } 24882d1661a5SPawel Jakub Dawidek break; 24892d1661a5SPawel Jakub Dawidek } 24902d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_DEGRADED: 24912d1661a5SPawel Jakub Dawidek /* 2492ea973705SPawel Jakub Dawidek * Genid need to be bumped immediately, so do it here. 24932d1661a5SPawel Jakub Dawidek */ 2494ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_GENID) != 0) { 2495a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_GENID; 2496a245a548SPawel Jakub Dawidek g_raid3_bump_genid(sc); 2497a245a548SPawel Jakub Dawidek } 2498a245a548SPawel Jakub Dawidek 24992d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NEW) > 0) 25002d1661a5SPawel Jakub Dawidek return; 25012d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 25022d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1) { 25032d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) 25042d1661a5SPawel Jakub Dawidek g_raid3_destroy_provider(sc); 25052d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 25062d1661a5SPawel Jakub Dawidek return; 25072d1661a5SPawel Jakub Dawidek } 25082d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) == 25092d1661a5SPawel Jakub Dawidek sc->sc_ndisks) { 25102d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_COMPLETE; 25112d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 25122d1661a5SPawel Jakub Dawidek "Device %s state changed from %s to %s.", 25132d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 25142d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 25152d1661a5SPawel Jakub Dawidek sc->sc_state = state; 25162d1661a5SPawel Jakub Dawidek } 25172d1661a5SPawel Jakub Dawidek if (sc->sc_provider == NULL) 25182d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(sc); 25194ed854e8SPawel Jakub Dawidek if (sc->sc_rootmount != NULL) { 25204ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", __LINE__, 25214ed854e8SPawel Jakub Dawidek sc->sc_rootmount); 25224ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 25234ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 25244ed854e8SPawel Jakub Dawidek } 25252d1661a5SPawel Jakub Dawidek break; 25262d1661a5SPawel Jakub Dawidek case G_RAID3_DEVICE_STATE_COMPLETE: 25272d1661a5SPawel Jakub Dawidek /* 2528ea973705SPawel Jakub Dawidek * Genid need to be bumped immediately, so do it here. 25292d1661a5SPawel Jakub Dawidek */ 2530ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_GENID) != 0) { 2531a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_GENID; 2532a245a548SPawel Jakub Dawidek g_raid3_bump_genid(sc); 2533a245a548SPawel Jakub Dawidek } 2534a245a548SPawel Jakub Dawidek 25352d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NEW) > 0) 25362d1661a5SPawel Jakub Dawidek return; 25372d1661a5SPawel Jakub Dawidek KASSERT(g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) >= 25382d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1, 25392d1661a5SPawel Jakub Dawidek ("Too few ACTIVE components in COMPLETE state (device %s).", 25402d1661a5SPawel Jakub Dawidek sc->sc_name)); 25412d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) == 25422d1661a5SPawel Jakub Dawidek sc->sc_ndisks - 1) { 25432d1661a5SPawel Jakub Dawidek state = G_RAID3_DEVICE_STATE_DEGRADED; 25442d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 25452d1661a5SPawel Jakub Dawidek "Device %s state changed from %s to %s.", 25462d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_device_state2str(sc->sc_state), 25472d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(state)); 25482d1661a5SPawel Jakub Dawidek sc->sc_state = state; 25492d1661a5SPawel Jakub Dawidek } 25502d1661a5SPawel Jakub Dawidek if (sc->sc_provider == NULL) 25512d1661a5SPawel Jakub Dawidek g_raid3_launch_provider(sc); 25524ed854e8SPawel Jakub Dawidek if (sc->sc_rootmount != NULL) { 25534ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_rel[%u] %p", __LINE__, 25544ed854e8SPawel Jakub Dawidek sc->sc_rootmount); 25554ed854e8SPawel Jakub Dawidek root_mount_rel(sc->sc_rootmount); 25564ed854e8SPawel Jakub Dawidek sc->sc_rootmount = NULL; 25574ed854e8SPawel Jakub Dawidek } 25582d1661a5SPawel Jakub Dawidek break; 25592d1661a5SPawel Jakub Dawidek default: 25602d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Wrong device state (%s, %s).", sc->sc_name, 25612d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state))); 25622d1661a5SPawel Jakub Dawidek break; 25632d1661a5SPawel Jakub Dawidek } 25642d1661a5SPawel Jakub Dawidek } 25652d1661a5SPawel Jakub Dawidek 25662d1661a5SPawel Jakub Dawidek /* 25672d1661a5SPawel Jakub Dawidek * Update disk state and device state if needed. 25682d1661a5SPawel Jakub Dawidek */ 25692d1661a5SPawel Jakub Dawidek #define DISK_STATE_CHANGED() G_RAID3_DEBUG(1, \ 25702d1661a5SPawel Jakub Dawidek "Disk %s state changed from %s to %s (device %s).", \ 25712d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), \ 25722d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state), \ 25732d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(state), sc->sc_name) 25742d1661a5SPawel Jakub Dawidek static int 2575d97d5ee9SPawel Jakub Dawidek g_raid3_update_disk(struct g_raid3_disk *disk, u_int state) 25762d1661a5SPawel Jakub Dawidek { 25772d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 25782d1661a5SPawel Jakub Dawidek 25792d1661a5SPawel Jakub Dawidek sc = disk->d_softc; 25803650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 25813650be51SPawel Jakub Dawidek 25822d1661a5SPawel Jakub Dawidek again: 25832d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(3, "Changing disk %s state from %s to %s.", 25842d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), g_raid3_disk_state2str(disk->d_state), 25852d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(state)); 25862d1661a5SPawel Jakub Dawidek switch (state) { 25872d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NEW: 25882d1661a5SPawel Jakub Dawidek /* 25892d1661a5SPawel Jakub Dawidek * Possible scenarios: 25902d1661a5SPawel Jakub Dawidek * 1. New disk arrive. 25912d1661a5SPawel Jakub Dawidek */ 25922d1661a5SPawel Jakub Dawidek /* Previous state should be NONE. */ 25932d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NONE, 25942d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 25952d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 25962d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 25972d1661a5SPawel Jakub Dawidek 25982d1661a5SPawel Jakub Dawidek disk->d_state = state; 25992d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s detected.", 26002d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 26012d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_STARTING) 26022d1661a5SPawel Jakub Dawidek break; 26032d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 26042d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 26052d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 26062d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 26072d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 26082d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26092d1661a5SPawel Jakub Dawidek state = g_raid3_determine_state(disk); 26102d1661a5SPawel Jakub Dawidek if (state != G_RAID3_DISK_STATE_NONE) 26112d1661a5SPawel Jakub Dawidek goto again; 26122d1661a5SPawel Jakub Dawidek break; 26132d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 26142d1661a5SPawel Jakub Dawidek /* 26152d1661a5SPawel Jakub Dawidek * Possible scenarios: 26162d1661a5SPawel Jakub Dawidek * 1. New disk does not need synchronization. 26172d1661a5SPawel Jakub Dawidek * 2. Synchronization process finished successfully. 26182d1661a5SPawel Jakub Dawidek */ 26192d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 26202d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 26212d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 26222d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 26232d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 26242d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26252d1661a5SPawel Jakub Dawidek /* Previous state should be NEW or SYNCHRONIZING. */ 26262d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW || 26272d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 26282d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 26292d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26302d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 26312d1661a5SPawel Jakub Dawidek 2632bf31327cSPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 26332d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_SYNCHRONIZING; 26342d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 26352d1661a5SPawel Jakub Dawidek g_raid3_sync_stop(sc, 0); 26362d1661a5SPawel Jakub Dawidek } 26372d1661a5SPawel Jakub Dawidek disk->d_state = state; 26382d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset = 0; 26392d1661a5SPawel Jakub Dawidek disk->d_sync.ds_offset_done = 0; 26400962f942SPawel Jakub Dawidek g_raid3_update_idle(sc, disk); 2641bf31327cSPawel Jakub Dawidek g_raid3_update_metadata(disk); 26422d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s activated.", 26432d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 26442d1661a5SPawel Jakub Dawidek break; 26452d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 26462d1661a5SPawel Jakub Dawidek /* 26472d1661a5SPawel Jakub Dawidek * Possible scenarios: 26482d1661a5SPawel Jakub Dawidek * 1. Stale disk was connected. 26492d1661a5SPawel Jakub Dawidek */ 26502d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 26512d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 26522d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 26532d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26542d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 26552d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 26562d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 26572d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 26582d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 26592d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26602d1661a5SPawel Jakub Dawidek /* 26612d1661a5SPawel Jakub Dawidek * STALE state is only possible if device is marked 26622d1661a5SPawel Jakub Dawidek * NOAUTOSYNC. 26632d1661a5SPawel Jakub Dawidek */ 26642d1661a5SPawel Jakub Dawidek KASSERT((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0, 26652d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 26662d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 26672d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 26682d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26692d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 26702d1661a5SPawel Jakub Dawidek 26712d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 26722d1661a5SPawel Jakub Dawidek disk->d_state = state; 26732d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 26742d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s is stale.", 26752d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 26762d1661a5SPawel Jakub Dawidek break; 26772d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 26782d1661a5SPawel Jakub Dawidek /* 26792d1661a5SPawel Jakub Dawidek * Possible scenarios: 26802d1661a5SPawel Jakub Dawidek * 1. Disk which needs synchronization was connected. 26812d1661a5SPawel Jakub Dawidek */ 26822d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 26832d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 26842d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", g_raid3_get_diskname(disk), 26852d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26862d1661a5SPawel Jakub Dawidek KASSERT(sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 26872d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE, 26882d1661a5SPawel Jakub Dawidek ("Wrong device state (%s, %s, %s, %s).", sc->sc_name, 26892d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 26902d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 26912d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 26922d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 26932d1661a5SPawel Jakub Dawidek 26942d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_NEW) 26952d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY; 26962d1661a5SPawel Jakub Dawidek disk->d_state = state; 26972d1661a5SPawel Jakub Dawidek if (sc->sc_provider != NULL) { 26982d1661a5SPawel Jakub Dawidek g_raid3_sync_start(sc); 26992d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 27002d1661a5SPawel Jakub Dawidek } 27012d1661a5SPawel Jakub Dawidek break; 27022d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_DISCONNECTED: 27032d1661a5SPawel Jakub Dawidek /* 27042d1661a5SPawel Jakub Dawidek * Possible scenarios: 27052d1661a5SPawel Jakub Dawidek * 1. Device wasn't running yet, but disk disappear. 27062d1661a5SPawel Jakub Dawidek * 2. Disk was active and disapppear. 27072d1661a5SPawel Jakub Dawidek * 3. Disk disappear during synchronization process. 27082d1661a5SPawel Jakub Dawidek */ 27092d1661a5SPawel Jakub Dawidek if (sc->sc_state == G_RAID3_DEVICE_STATE_DEGRADED || 27102d1661a5SPawel Jakub Dawidek sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { 27112d1661a5SPawel Jakub Dawidek /* 27122d1661a5SPawel Jakub Dawidek * Previous state should be ACTIVE, STALE or 27132d1661a5SPawel Jakub Dawidek * SYNCHRONIZING. 27142d1661a5SPawel Jakub Dawidek */ 27152d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_ACTIVE || 27162d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_STALE || 27172d1661a5SPawel Jakub Dawidek disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING, 27182d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", 27192d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 27202d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 27212d1661a5SPawel Jakub Dawidek } else if (sc->sc_state == G_RAID3_DEVICE_STATE_STARTING) { 27222d1661a5SPawel Jakub Dawidek /* Previous state should be NEW. */ 27232d1661a5SPawel Jakub Dawidek KASSERT(disk->d_state == G_RAID3_DISK_STATE_NEW, 27242d1661a5SPawel Jakub Dawidek ("Wrong disk state (%s, %s).", 27252d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 27262d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 27272d1661a5SPawel Jakub Dawidek /* 27282d1661a5SPawel Jakub Dawidek * Reset bumping syncid if disk disappeared in STARTING 27292d1661a5SPawel Jakub Dawidek * state. 27302d1661a5SPawel Jakub Dawidek */ 2731ea973705SPawel Jakub Dawidek if ((sc->sc_bump_id & G_RAID3_BUMP_SYNCID) != 0) 2732a245a548SPawel Jakub Dawidek sc->sc_bump_id &= ~G_RAID3_BUMP_SYNCID; 27332d1661a5SPawel Jakub Dawidek #ifdef INVARIANTS 27342d1661a5SPawel Jakub Dawidek } else { 27352d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Wrong device state (%s, %s, %s, %s).", 27362d1661a5SPawel Jakub Dawidek sc->sc_name, 27372d1661a5SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state), 27382d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk), 27392d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state))); 27402d1661a5SPawel Jakub Dawidek #endif 27412d1661a5SPawel Jakub Dawidek } 27422d1661a5SPawel Jakub Dawidek DISK_STATE_CHANGED(); 27432d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s: provider %s disconnected.", 27442d1661a5SPawel Jakub Dawidek sc->sc_name, g_raid3_get_diskname(disk)); 27452d1661a5SPawel Jakub Dawidek 27462d1661a5SPawel Jakub Dawidek g_raid3_destroy_disk(disk); 27472d1661a5SPawel Jakub Dawidek break; 27482d1661a5SPawel Jakub Dawidek default: 27492d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("Unknown state (%u).", state)); 27502d1661a5SPawel Jakub Dawidek break; 27512d1661a5SPawel Jakub Dawidek } 27522d1661a5SPawel Jakub Dawidek return (0); 27532d1661a5SPawel Jakub Dawidek } 27542d1661a5SPawel Jakub Dawidek #undef DISK_STATE_CHANGED 27552d1661a5SPawel Jakub Dawidek 2756ea973705SPawel Jakub Dawidek int 27572d1661a5SPawel Jakub Dawidek g_raid3_read_metadata(struct g_consumer *cp, struct g_raid3_metadata *md) 27582d1661a5SPawel Jakub Dawidek { 27592d1661a5SPawel Jakub Dawidek struct g_provider *pp; 27602d1661a5SPawel Jakub Dawidek u_char *buf; 27612d1661a5SPawel Jakub Dawidek int error; 27622d1661a5SPawel Jakub Dawidek 27632d1661a5SPawel Jakub Dawidek g_topology_assert(); 27642d1661a5SPawel Jakub Dawidek 27652d1661a5SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 27662d1661a5SPawel Jakub Dawidek if (error != 0) 27672d1661a5SPawel Jakub Dawidek return (error); 27682d1661a5SPawel Jakub Dawidek pp = cp->provider; 27692d1661a5SPawel Jakub Dawidek g_topology_unlock(); 27702d1661a5SPawel Jakub Dawidek /* Metadata are stored on last sector. */ 27712d1661a5SPawel Jakub Dawidek buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 27722d1661a5SPawel Jakub Dawidek &error); 27732d1661a5SPawel Jakub Dawidek g_topology_lock(); 27742d1661a5SPawel Jakub Dawidek g_access(cp, -1, 0, 0); 27758a4a44b5SMaxim Sobolev if (buf == NULL) { 2776a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Cannot read metadata from %s (error=%d).", 2777a245a548SPawel Jakub Dawidek cp->provider->name, error); 27782d1661a5SPawel Jakub Dawidek return (error); 27792d1661a5SPawel Jakub Dawidek } 27802d1661a5SPawel Jakub Dawidek 27812d1661a5SPawel Jakub Dawidek /* Decode metadata. */ 27822d1661a5SPawel Jakub Dawidek error = raid3_metadata_decode(buf, md); 27832d1661a5SPawel Jakub Dawidek g_free(buf); 27842d1661a5SPawel Jakub Dawidek if (strcmp(md->md_magic, G_RAID3_MAGIC) != 0) 27852d1661a5SPawel Jakub Dawidek return (EINVAL); 2786a245a548SPawel Jakub Dawidek if (md->md_version > G_RAID3_VERSION) { 2787a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, 2788a245a548SPawel Jakub Dawidek "Kernel module is too old to handle metadata from %s.", 2789a245a548SPawel Jakub Dawidek cp->provider->name); 2790a245a548SPawel Jakub Dawidek return (EINVAL); 2791a245a548SPawel Jakub Dawidek } 27922d1661a5SPawel Jakub Dawidek if (error != 0) { 27932d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "MD5 metadata hash mismatch for provider %s.", 27942d1661a5SPawel Jakub Dawidek cp->provider->name); 27952d1661a5SPawel Jakub Dawidek return (error); 27962d1661a5SPawel Jakub Dawidek } 27972d1661a5SPawel Jakub Dawidek 27982d1661a5SPawel Jakub Dawidek return (0); 27992d1661a5SPawel Jakub Dawidek } 28002d1661a5SPawel Jakub Dawidek 28012d1661a5SPawel Jakub Dawidek static int 28022d1661a5SPawel Jakub Dawidek g_raid3_check_metadata(struct g_raid3_softc *sc, struct g_provider *pp, 28032d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md) 28042d1661a5SPawel Jakub Dawidek { 28052d1661a5SPawel Jakub Dawidek 28062d1661a5SPawel Jakub Dawidek if (md->md_no >= sc->sc_ndisks) { 28072d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Invalid disk %s number (no=%u), skipping.", 28082d1661a5SPawel Jakub Dawidek pp->name, md->md_no); 28092d1661a5SPawel Jakub Dawidek return (EINVAL); 28102d1661a5SPawel Jakub Dawidek } 28112d1661a5SPawel Jakub Dawidek if (sc->sc_disks[md->md_no].d_state != G_RAID3_DISK_STATE_NODISK) { 28122d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Disk %s (no=%u) already exists, skipping.", 28132d1661a5SPawel Jakub Dawidek pp->name, md->md_no); 28142d1661a5SPawel Jakub Dawidek return (EEXIST); 28152d1661a5SPawel Jakub Dawidek } 28162d1661a5SPawel Jakub Dawidek if (md->md_all != sc->sc_ndisks) { 28172d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28182d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 28192d1661a5SPawel Jakub Dawidek "md_all", pp->name, sc->sc_name); 28202d1661a5SPawel Jakub Dawidek return (EINVAL); 28212d1661a5SPawel Jakub Dawidek } 28222d1661a5SPawel Jakub Dawidek if (md->md_mediasize != sc->sc_mediasize) { 28232d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28242d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 28252d1661a5SPawel Jakub Dawidek "md_mediasize", pp->name, sc->sc_name); 28262d1661a5SPawel Jakub Dawidek return (EINVAL); 28272d1661a5SPawel Jakub Dawidek } 28282d1661a5SPawel Jakub Dawidek if ((md->md_mediasize % (sc->sc_ndisks - 1)) != 0) { 28292d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28302d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 28312d1661a5SPawel Jakub Dawidek "md_mediasize", pp->name, sc->sc_name); 28322d1661a5SPawel Jakub Dawidek return (EINVAL); 28332d1661a5SPawel Jakub Dawidek } 28342d1661a5SPawel Jakub Dawidek if ((sc->sc_mediasize / (sc->sc_ndisks - 1)) > pp->mediasize) { 28352d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28362d1661a5SPawel Jakub Dawidek "Invalid size of disk %s (device %s), skipping.", pp->name, 28372d1661a5SPawel Jakub Dawidek sc->sc_name); 28382d1661a5SPawel Jakub Dawidek return (EINVAL); 28392d1661a5SPawel Jakub Dawidek } 28402d1661a5SPawel Jakub Dawidek if ((md->md_sectorsize / pp->sectorsize) < sc->sc_ndisks - 1) { 28412d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28422d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 28432d1661a5SPawel Jakub Dawidek "md_sectorsize", pp->name, sc->sc_name); 28442d1661a5SPawel Jakub Dawidek return (EINVAL); 28452d1661a5SPawel Jakub Dawidek } 28462d1661a5SPawel Jakub Dawidek if (md->md_sectorsize != sc->sc_sectorsize) { 28472d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28482d1661a5SPawel Jakub Dawidek "Invalid '%s' field on disk %s (device %s), skipping.", 28492d1661a5SPawel Jakub Dawidek "md_sectorsize", pp->name, sc->sc_name); 28502d1661a5SPawel Jakub Dawidek return (EINVAL); 28512d1661a5SPawel Jakub Dawidek } 28522d1661a5SPawel Jakub Dawidek if ((sc->sc_sectorsize % pp->sectorsize) != 0) { 28532d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28542d1661a5SPawel Jakub Dawidek "Invalid sector size of disk %s (device %s), skipping.", 28552d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 28562d1661a5SPawel Jakub Dawidek return (EINVAL); 28572d1661a5SPawel Jakub Dawidek } 28582d1661a5SPawel Jakub Dawidek if ((md->md_mflags & ~G_RAID3_DEVICE_FLAG_MASK) != 0) { 28592d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28602d1661a5SPawel Jakub Dawidek "Invalid device flags on disk %s (device %s), skipping.", 28612d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 28622d1661a5SPawel Jakub Dawidek return (EINVAL); 28632d1661a5SPawel Jakub Dawidek } 2864dba915cfSPawel Jakub Dawidek if ((md->md_mflags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 2865dba915cfSPawel Jakub Dawidek (md->md_mflags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 2866dba915cfSPawel Jakub Dawidek /* 2867dba915cfSPawel Jakub Dawidek * VERIFY and ROUND-ROBIN options are mutally exclusive. 2868dba915cfSPawel Jakub Dawidek */ 2869dba915cfSPawel Jakub Dawidek G_RAID3_DEBUG(1, "Both VERIFY and ROUND-ROBIN flags exist on " 2870dba915cfSPawel Jakub Dawidek "disk %s (device %s), skipping.", pp->name, sc->sc_name); 2871dba915cfSPawel Jakub Dawidek return (EINVAL); 2872dba915cfSPawel Jakub Dawidek } 28732d1661a5SPawel Jakub Dawidek if ((md->md_dflags & ~G_RAID3_DISK_FLAG_MASK) != 0) { 28742d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 28752d1661a5SPawel Jakub Dawidek "Invalid disk flags on disk %s (device %s), skipping.", 28762d1661a5SPawel Jakub Dawidek pp->name, sc->sc_name); 28772d1661a5SPawel Jakub Dawidek return (EINVAL); 28782d1661a5SPawel Jakub Dawidek } 28792d1661a5SPawel Jakub Dawidek return (0); 28802d1661a5SPawel Jakub Dawidek } 28812d1661a5SPawel Jakub Dawidek 2882ea973705SPawel Jakub Dawidek int 28832d1661a5SPawel Jakub Dawidek g_raid3_add_disk(struct g_raid3_softc *sc, struct g_provider *pp, 28842d1661a5SPawel Jakub Dawidek struct g_raid3_metadata *md) 28852d1661a5SPawel Jakub Dawidek { 28862d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 28872d1661a5SPawel Jakub Dawidek int error; 28882d1661a5SPawel Jakub Dawidek 28893650be51SPawel Jakub Dawidek g_topology_assert_not(); 28902d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Adding disk %s.", pp->name); 28912d1661a5SPawel Jakub Dawidek 28922d1661a5SPawel Jakub Dawidek error = g_raid3_check_metadata(sc, pp, md); 28932d1661a5SPawel Jakub Dawidek if (error != 0) 28942d1661a5SPawel Jakub Dawidek return (error); 2895a245a548SPawel Jakub Dawidek if (sc->sc_state != G_RAID3_DEVICE_STATE_STARTING && 2896a245a548SPawel Jakub Dawidek md->md_genid < sc->sc_genid) { 2897a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Component %s (device %s) broken, skipping.", 2898a245a548SPawel Jakub Dawidek pp->name, sc->sc_name); 2899a245a548SPawel Jakub Dawidek return (EINVAL); 2900a245a548SPawel Jakub Dawidek } 29012d1661a5SPawel Jakub Dawidek disk = g_raid3_init_disk(sc, pp, md, &error); 29022d1661a5SPawel Jakub Dawidek if (disk == NULL) 29032d1661a5SPawel Jakub Dawidek return (error); 29042d1661a5SPawel Jakub Dawidek error = g_raid3_event_send(disk, G_RAID3_DISK_STATE_NEW, 29052d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_WAIT); 2906a245a548SPawel Jakub Dawidek if (error != 0) 29072d1661a5SPawel Jakub Dawidek return (error); 2908a245a548SPawel Jakub Dawidek if (md->md_version < G_RAID3_VERSION) { 2909a245a548SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Upgrading metadata on %s (v%d->v%d).", 2910a245a548SPawel Jakub Dawidek pp->name, md->md_version, G_RAID3_VERSION); 2911a245a548SPawel Jakub Dawidek g_raid3_update_metadata(disk); 2912a245a548SPawel Jakub Dawidek } 2913a245a548SPawel Jakub Dawidek return (0); 29142d1661a5SPawel Jakub Dawidek } 29152d1661a5SPawel Jakub Dawidek 2916712fe9bdSPawel Jakub Dawidek static void 2917712fe9bdSPawel Jakub Dawidek g_raid3_destroy_delayed(void *arg, int flag) 2918712fe9bdSPawel Jakub Dawidek { 2919712fe9bdSPawel Jakub Dawidek struct g_raid3_softc *sc; 2920712fe9bdSPawel Jakub Dawidek int error; 2921712fe9bdSPawel Jakub Dawidek 2922712fe9bdSPawel Jakub Dawidek if (flag == EV_CANCEL) { 2923712fe9bdSPawel Jakub Dawidek G_RAID3_DEBUG(1, "Destroying canceled."); 2924712fe9bdSPawel Jakub Dawidek return; 2925712fe9bdSPawel Jakub Dawidek } 2926712fe9bdSPawel Jakub Dawidek sc = arg; 2927712fe9bdSPawel Jakub Dawidek g_topology_unlock(); 2928712fe9bdSPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 2929712fe9bdSPawel Jakub Dawidek KASSERT((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) == 0, 2930712fe9bdSPawel Jakub Dawidek ("DESTROY flag set on %s.", sc->sc_name)); 2931712fe9bdSPawel Jakub Dawidek KASSERT((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROYING) != 0, 2932712fe9bdSPawel Jakub Dawidek ("DESTROYING flag not set on %s.", sc->sc_name)); 2933712fe9bdSPawel Jakub Dawidek G_RAID3_DEBUG(0, "Destroying %s (delayed).", sc->sc_name); 2934712fe9bdSPawel Jakub Dawidek error = g_raid3_destroy(sc, G_RAID3_DESTROY_SOFT); 2935712fe9bdSPawel Jakub Dawidek if (error != 0) { 2936712fe9bdSPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot destroy %s.", sc->sc_name); 2937712fe9bdSPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 2938712fe9bdSPawel Jakub Dawidek } 2939712fe9bdSPawel Jakub Dawidek g_topology_lock(); 2940712fe9bdSPawel Jakub Dawidek } 2941712fe9bdSPawel Jakub Dawidek 29422d1661a5SPawel Jakub Dawidek static int 29432d1661a5SPawel Jakub Dawidek g_raid3_access(struct g_provider *pp, int acr, int acw, int ace) 29442d1661a5SPawel Jakub Dawidek { 29452d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2946712fe9bdSPawel Jakub Dawidek int dcr, dcw, dce, error = 0; 29472d1661a5SPawel Jakub Dawidek 29482d1661a5SPawel Jakub Dawidek g_topology_assert(); 29492d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Access request for %s: r%dw%de%d.", pp->name, acr, 29502d1661a5SPawel Jakub Dawidek acw, ace); 29512d1661a5SPawel Jakub Dawidek 29521f7fec3cSPawel Jakub Dawidek sc = pp->geom->softc; 29531f7fec3cSPawel Jakub Dawidek if (sc == NULL && acr <= 0 && acw <= 0 && ace <= 0) 29541f7fec3cSPawel Jakub Dawidek return (0); 29551f7fec3cSPawel Jakub Dawidek KASSERT(sc != NULL, ("NULL softc (provider=%s).", pp->name)); 29561f7fec3cSPawel Jakub Dawidek 29572d1661a5SPawel Jakub Dawidek dcr = pp->acr + acr; 29582d1661a5SPawel Jakub Dawidek dcw = pp->acw + acw; 29592d1661a5SPawel Jakub Dawidek dce = pp->ace + ace; 29602d1661a5SPawel Jakub Dawidek 29613650be51SPawel Jakub Dawidek g_topology_unlock(); 29623650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 2963712fe9bdSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0 || 29643650be51SPawel Jakub Dawidek g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks - 1) { 29653650be51SPawel Jakub Dawidek if (acr > 0 || acw > 0 || ace > 0) 29663650be51SPawel Jakub Dawidek error = ENXIO; 29673650be51SPawel Jakub Dawidek goto end; 29682d1661a5SPawel Jakub Dawidek } 29690962f942SPawel Jakub Dawidek if (dcw == 0 && !sc->sc_idle) 29703650be51SPawel Jakub Dawidek g_raid3_idle(sc, dcw); 2971712fe9bdSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROYING) != 0) { 2972712fe9bdSPawel Jakub Dawidek if (acr > 0 || acw > 0 || ace > 0) { 2973712fe9bdSPawel Jakub Dawidek error = ENXIO; 2974712fe9bdSPawel Jakub Dawidek goto end; 2975712fe9bdSPawel Jakub Dawidek } 2976712fe9bdSPawel Jakub Dawidek if (dcr == 0 && dcw == 0 && dce == 0) { 2977712fe9bdSPawel Jakub Dawidek g_post_event(g_raid3_destroy_delayed, sc, M_WAITOK, 2978712fe9bdSPawel Jakub Dawidek sc, NULL); 2979712fe9bdSPawel Jakub Dawidek } 2980712fe9bdSPawel Jakub Dawidek } 29813650be51SPawel Jakub Dawidek end: 29823650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 29833650be51SPawel Jakub Dawidek g_topology_lock(); 29843650be51SPawel Jakub Dawidek return (error); 29852d1661a5SPawel Jakub Dawidek } 29862d1661a5SPawel Jakub Dawidek 29872d1661a5SPawel Jakub Dawidek static struct g_geom * 29882d1661a5SPawel Jakub Dawidek g_raid3_create(struct g_class *mp, const struct g_raid3_metadata *md) 29892d1661a5SPawel Jakub Dawidek { 29902d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 29912d1661a5SPawel Jakub Dawidek struct g_geom *gp; 29922d1661a5SPawel Jakub Dawidek int error, timeout; 29932d1661a5SPawel Jakub Dawidek u_int n; 29942d1661a5SPawel Jakub Dawidek 29952d1661a5SPawel Jakub Dawidek g_topology_assert(); 29962d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Creating device %s (id=%u).", md->md_name, md->md_id); 29972d1661a5SPawel Jakub Dawidek 29982d1661a5SPawel Jakub Dawidek /* One disk is minimum. */ 29992d1661a5SPawel Jakub Dawidek if (md->md_all < 1) 30002d1661a5SPawel Jakub Dawidek return (NULL); 30012d1661a5SPawel Jakub Dawidek /* 30022d1661a5SPawel Jakub Dawidek * Action geom. 30032d1661a5SPawel Jakub Dawidek */ 30042d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "%s", md->md_name); 30052d1661a5SPawel Jakub Dawidek sc = malloc(sizeof(*sc), M_RAID3, M_WAITOK | M_ZERO); 30062d1661a5SPawel Jakub Dawidek sc->sc_disks = malloc(sizeof(struct g_raid3_disk) * md->md_all, M_RAID3, 30072d1661a5SPawel Jakub Dawidek M_WAITOK | M_ZERO); 30082d1661a5SPawel Jakub Dawidek gp->start = g_raid3_start; 30092d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_orphan; 30102d1661a5SPawel Jakub Dawidek gp->access = g_raid3_access; 30112d1661a5SPawel Jakub Dawidek gp->dumpconf = g_raid3_dumpconf; 30122d1661a5SPawel Jakub Dawidek 30132d1661a5SPawel Jakub Dawidek sc->sc_id = md->md_id; 30142d1661a5SPawel Jakub Dawidek sc->sc_mediasize = md->md_mediasize; 30152d1661a5SPawel Jakub Dawidek sc->sc_sectorsize = md->md_sectorsize; 30162d1661a5SPawel Jakub Dawidek sc->sc_ndisks = md->md_all; 3017f5a2f7feSPawel Jakub Dawidek sc->sc_round_robin = 0; 30182d1661a5SPawel Jakub Dawidek sc->sc_flags = md->md_mflags; 3019a245a548SPawel Jakub Dawidek sc->sc_bump_id = 0; 30200962f942SPawel Jakub Dawidek sc->sc_idle = 1; 302101f1f41cSPawel Jakub Dawidek sc->sc_last_write = time_uptime; 30220962f942SPawel Jakub Dawidek sc->sc_writes = 0; 3023afd05d74SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 3024afd05d74SPawel Jakub Dawidek sc->sc_disks[n].d_softc = sc; 3025afd05d74SPawel Jakub Dawidek sc->sc_disks[n].d_no = n; 30262d1661a5SPawel Jakub Dawidek sc->sc_disks[n].d_state = G_RAID3_DISK_STATE_NODISK; 3027afd05d74SPawel Jakub Dawidek } 30283650be51SPawel Jakub Dawidek sx_init(&sc->sc_lock, "graid3:lock"); 30292d1661a5SPawel Jakub Dawidek bioq_init(&sc->sc_queue); 30302d1661a5SPawel Jakub Dawidek mtx_init(&sc->sc_queue_mtx, "graid3:queue", NULL, MTX_DEF); 30313650be51SPawel Jakub Dawidek bioq_init(&sc->sc_regular_delayed); 30323650be51SPawel Jakub Dawidek bioq_init(&sc->sc_inflight); 30333650be51SPawel Jakub Dawidek bioq_init(&sc->sc_sync_delayed); 30342d1661a5SPawel Jakub Dawidek TAILQ_INIT(&sc->sc_events); 30352d1661a5SPawel Jakub Dawidek mtx_init(&sc->sc_events_mtx, "graid3:events", NULL, MTX_DEF); 30362d1661a5SPawel Jakub Dawidek callout_init(&sc->sc_callout, CALLOUT_MPSAFE); 30372d1661a5SPawel Jakub Dawidek sc->sc_state = G_RAID3_DEVICE_STATE_STARTING; 30382d1661a5SPawel Jakub Dawidek gp->softc = sc; 30392d1661a5SPawel Jakub Dawidek sc->sc_geom = gp; 30402d1661a5SPawel Jakub Dawidek sc->sc_provider = NULL; 30412d1661a5SPawel Jakub Dawidek /* 30422d1661a5SPawel Jakub Dawidek * Synchronization geom. 30432d1661a5SPawel Jakub Dawidek */ 30442d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "%s.sync", md->md_name); 30452d1661a5SPawel Jakub Dawidek gp->softc = sc; 30462d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_orphan; 30472d1661a5SPawel Jakub Dawidek sc->sc_sync.ds_geom = gp; 30483650be51SPawel Jakub Dawidek 30493650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_64K].sz_zone = uma_zcreate("gr3:64k", 65536, 30503650be51SPawel Jakub Dawidek g_raid3_uma_ctor, g_raid3_uma_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); 30513650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_64K].sz_inuse = 0; 30523650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_64K].sz_max = g_raid3_n64k; 30533650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_64K].sz_requested = 30543650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_64K].sz_failed = 0; 30553650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_16K].sz_zone = uma_zcreate("gr3:16k", 16384, 30563650be51SPawel Jakub Dawidek g_raid3_uma_ctor, g_raid3_uma_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); 30573650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_16K].sz_inuse = 0; 30583650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_16K].sz_max = g_raid3_n16k; 30593650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_16K].sz_requested = 30603650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_16K].sz_failed = 0; 30613650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_4K].sz_zone = uma_zcreate("gr3:4k", 4096, 30623650be51SPawel Jakub Dawidek g_raid3_uma_ctor, g_raid3_uma_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); 30633650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_4K].sz_inuse = 0; 30643650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_4K].sz_max = g_raid3_n4k; 30653650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_4K].sz_requested = 30663650be51SPawel Jakub Dawidek sc->sc_zones[G_RAID3_ZONE_4K].sz_failed = 0; 30673650be51SPawel Jakub Dawidek 30682d1661a5SPawel Jakub Dawidek error = kthread_create(g_raid3_worker, sc, &sc->sc_worker, 0, 0, 30692d1661a5SPawel Jakub Dawidek "g_raid3 %s", md->md_name); 30702d1661a5SPawel Jakub Dawidek if (error != 0) { 30712d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Cannot create kernel thread for %s.", 30722d1661a5SPawel Jakub Dawidek sc->sc_name); 30733650be51SPawel Jakub Dawidek uma_zdestroy(sc->sc_zones[G_RAID3_ZONE_64K].sz_zone); 30743650be51SPawel Jakub Dawidek uma_zdestroy(sc->sc_zones[G_RAID3_ZONE_16K].sz_zone); 30753650be51SPawel Jakub Dawidek uma_zdestroy(sc->sc_zones[G_RAID3_ZONE_4K].sz_zone); 30762d1661a5SPawel Jakub Dawidek g_destroy_geom(sc->sc_sync.ds_geom); 30772d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_events_mtx); 30782d1661a5SPawel Jakub Dawidek mtx_destroy(&sc->sc_queue_mtx); 30793650be51SPawel Jakub Dawidek sx_destroy(&sc->sc_lock); 30802d1661a5SPawel Jakub Dawidek g_destroy_geom(sc->sc_geom); 30812d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 30822d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 30832d1661a5SPawel Jakub Dawidek return (NULL); 30842d1661a5SPawel Jakub Dawidek } 30852d1661a5SPawel Jakub Dawidek 30862d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id); 30872d1661a5SPawel Jakub Dawidek 30884ed854e8SPawel Jakub Dawidek sc->sc_rootmount = root_mount_hold("GRAID3"); 30894ed854e8SPawel Jakub Dawidek G_RAID3_DEBUG(1, "root_mount_hold %p", sc->sc_rootmount); 30904ed854e8SPawel Jakub Dawidek 30912d1661a5SPawel Jakub Dawidek /* 30922d1661a5SPawel Jakub Dawidek * Run timeout. 30932d1661a5SPawel Jakub Dawidek */ 30942d1661a5SPawel Jakub Dawidek timeout = atomic_load_acq_int(&g_raid3_timeout); 30952d1661a5SPawel Jakub Dawidek callout_reset(&sc->sc_callout, timeout * hz, g_raid3_go, sc); 30962d1661a5SPawel Jakub Dawidek return (sc->sc_geom); 30972d1661a5SPawel Jakub Dawidek } 30982d1661a5SPawel Jakub Dawidek 30992d1661a5SPawel Jakub Dawidek int 3100712fe9bdSPawel Jakub Dawidek g_raid3_destroy(struct g_raid3_softc *sc, int how) 31012d1661a5SPawel Jakub Dawidek { 31022d1661a5SPawel Jakub Dawidek struct g_provider *pp; 31032d1661a5SPawel Jakub Dawidek 31043650be51SPawel Jakub Dawidek g_topology_assert_not(); 31052d1661a5SPawel Jakub Dawidek if (sc == NULL) 31062d1661a5SPawel Jakub Dawidek return (ENXIO); 31073650be51SPawel Jakub Dawidek sx_assert(&sc->sc_lock, SX_XLOCKED); 31083650be51SPawel Jakub Dawidek 31092d1661a5SPawel Jakub Dawidek pp = sc->sc_provider; 31102d1661a5SPawel Jakub Dawidek if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 3111712fe9bdSPawel Jakub Dawidek switch (how) { 3112712fe9bdSPawel Jakub Dawidek case G_RAID3_DESTROY_SOFT: 31132d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, 31142d1661a5SPawel Jakub Dawidek "Device %s is still open (r%dw%de%d).", pp->name, 31152d1661a5SPawel Jakub Dawidek pp->acr, pp->acw, pp->ace); 31162d1661a5SPawel Jakub Dawidek return (EBUSY); 3117712fe9bdSPawel Jakub Dawidek case G_RAID3_DESTROY_DELAYED: 3118712fe9bdSPawel Jakub Dawidek G_RAID3_DEBUG(1, 3119712fe9bdSPawel Jakub Dawidek "Device %s will be destroyed on last close.", 3120712fe9bdSPawel Jakub Dawidek pp->name); 3121712fe9bdSPawel Jakub Dawidek if (sc->sc_syncdisk != NULL) 3122712fe9bdSPawel Jakub Dawidek g_raid3_sync_stop(sc, 1); 3123712fe9bdSPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROYING; 3124712fe9bdSPawel Jakub Dawidek return (EBUSY); 3125712fe9bdSPawel Jakub Dawidek case G_RAID3_DESTROY_HARD: 3126712fe9bdSPawel Jakub Dawidek G_RAID3_DEBUG(1, "Device %s is still open, so it " 3127712fe9bdSPawel Jakub Dawidek "can't be definitely removed.", pp->name); 3128712fe9bdSPawel Jakub Dawidek break; 31292d1661a5SPawel Jakub Dawidek } 31302d1661a5SPawel Jakub Dawidek } 31312d1661a5SPawel Jakub Dawidek 313218486a5eSPawel Jakub Dawidek g_topology_lock(); 313318486a5eSPawel Jakub Dawidek if (sc->sc_geom->softc == NULL) { 313418486a5eSPawel Jakub Dawidek g_topology_unlock(); 313518486a5eSPawel Jakub Dawidek return (0); 313618486a5eSPawel Jakub Dawidek } 313718486a5eSPawel Jakub Dawidek sc->sc_geom->softc = NULL; 313818486a5eSPawel Jakub Dawidek sc->sc_sync.ds_geom->softc = NULL; 313918486a5eSPawel Jakub Dawidek g_topology_unlock(); 314018486a5eSPawel Jakub Dawidek 31412d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_DESTROY; 31422d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_WAIT; 31432d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Waking up %p.", __func__, sc); 31443650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 31452d1661a5SPawel Jakub Dawidek mtx_lock(&sc->sc_queue_mtx); 31462d1661a5SPawel Jakub Dawidek wakeup(sc); 31472d1661a5SPawel Jakub Dawidek wakeup(&sc->sc_queue); 31482d1661a5SPawel Jakub Dawidek mtx_unlock(&sc->sc_queue_mtx); 31492d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Sleeping %p.", __func__, &sc->sc_worker); 31502d1661a5SPawel Jakub Dawidek while (sc->sc_worker != NULL) 31512d1661a5SPawel Jakub Dawidek tsleep(&sc->sc_worker, PRIBIO, "r3:destroy", hz / 5); 31522d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(4, "%s: Woken up %p.", __func__, &sc->sc_worker); 31533650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 31542d1661a5SPawel Jakub Dawidek g_raid3_destroy_device(sc); 31552d1661a5SPawel Jakub Dawidek free(sc->sc_disks, M_RAID3); 31562d1661a5SPawel Jakub Dawidek free(sc, M_RAID3); 31572d1661a5SPawel Jakub Dawidek return (0); 31582d1661a5SPawel Jakub Dawidek } 31592d1661a5SPawel Jakub Dawidek 31602d1661a5SPawel Jakub Dawidek static void 31612d1661a5SPawel Jakub Dawidek g_raid3_taste_orphan(struct g_consumer *cp) 31622d1661a5SPawel Jakub Dawidek { 31632d1661a5SPawel Jakub Dawidek 31642d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("%s called while tasting %s.", __func__, 31652d1661a5SPawel Jakub Dawidek cp->provider->name)); 31662d1661a5SPawel Jakub Dawidek } 31672d1661a5SPawel Jakub Dawidek 31682d1661a5SPawel Jakub Dawidek static struct g_geom * 31692d1661a5SPawel Jakub Dawidek g_raid3_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 31702d1661a5SPawel Jakub Dawidek { 31712d1661a5SPawel Jakub Dawidek struct g_raid3_metadata md; 31722d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 31732d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 31742d1661a5SPawel Jakub Dawidek struct g_geom *gp; 31752d1661a5SPawel Jakub Dawidek int error; 31762d1661a5SPawel Jakub Dawidek 31772d1661a5SPawel Jakub Dawidek g_topology_assert(); 31782d1661a5SPawel Jakub Dawidek g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 31792d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(2, "Tasting %s.", pp->name); 31802d1661a5SPawel Jakub Dawidek 31812d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "raid3:taste"); 31822d1661a5SPawel Jakub Dawidek /* This orphan function should be never called. */ 31832d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_taste_orphan; 31842d1661a5SPawel Jakub Dawidek cp = g_new_consumer(gp); 31852d1661a5SPawel Jakub Dawidek g_attach(cp, pp); 31862d1661a5SPawel Jakub Dawidek error = g_raid3_read_metadata(cp, &md); 31872d1661a5SPawel Jakub Dawidek g_detach(cp); 31882d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 31892d1661a5SPawel Jakub Dawidek g_destroy_geom(gp); 31902d1661a5SPawel Jakub Dawidek if (error != 0) 31912d1661a5SPawel Jakub Dawidek return (NULL); 31922d1661a5SPawel Jakub Dawidek gp = NULL; 31932d1661a5SPawel Jakub Dawidek 31942d1661a5SPawel Jakub Dawidek if (md.md_provider[0] != '\0' && strcmp(md.md_provider, pp->name) != 0) 31952d1661a5SPawel Jakub Dawidek return (NULL); 3196e6890985SPawel Jakub Dawidek if (md.md_provsize != 0 && md.md_provsize != pp->mediasize) 3197e6890985SPawel Jakub Dawidek return (NULL); 31982d1661a5SPawel Jakub Dawidek if (g_raid3_debug >= 2) 31992d1661a5SPawel Jakub Dawidek raid3_metadata_dump(&md); 32002d1661a5SPawel Jakub Dawidek 32012d1661a5SPawel Jakub Dawidek /* 32022d1661a5SPawel Jakub Dawidek * Let's check if device already exists. 32032d1661a5SPawel Jakub Dawidek */ 320445d5e85aSPawel Jakub Dawidek sc = NULL; 32052d1661a5SPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 32062d1661a5SPawel Jakub Dawidek sc = gp->softc; 32072d1661a5SPawel Jakub Dawidek if (sc == NULL) 32082d1661a5SPawel Jakub Dawidek continue; 32092d1661a5SPawel Jakub Dawidek if (sc->sc_sync.ds_geom == gp) 32102d1661a5SPawel Jakub Dawidek continue; 32112d1661a5SPawel Jakub Dawidek if (strcmp(md.md_name, sc->sc_name) != 0) 32122d1661a5SPawel Jakub Dawidek continue; 32132d1661a5SPawel Jakub Dawidek if (md.md_id != sc->sc_id) { 32142d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Device %s already configured.", 32152d1661a5SPawel Jakub Dawidek sc->sc_name); 32162d1661a5SPawel Jakub Dawidek return (NULL); 32172d1661a5SPawel Jakub Dawidek } 32182d1661a5SPawel Jakub Dawidek break; 32192d1661a5SPawel Jakub Dawidek } 32202d1661a5SPawel Jakub Dawidek if (gp == NULL) { 32212d1661a5SPawel Jakub Dawidek gp = g_raid3_create(mp, &md); 32222d1661a5SPawel Jakub Dawidek if (gp == NULL) { 32232d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot create device %s.", 32242d1661a5SPawel Jakub Dawidek md.md_name); 32252d1661a5SPawel Jakub Dawidek return (NULL); 32262d1661a5SPawel Jakub Dawidek } 32272d1661a5SPawel Jakub Dawidek sc = gp->softc; 32282d1661a5SPawel Jakub Dawidek } 32292d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 32303650be51SPawel Jakub Dawidek g_topology_unlock(); 32313650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 32322d1661a5SPawel Jakub Dawidek error = g_raid3_add_disk(sc, pp, &md); 32332d1661a5SPawel Jakub Dawidek if (error != 0) { 32342d1661a5SPawel Jakub Dawidek G_RAID3_DEBUG(0, "Cannot add disk %s to %s (error=%d).", 32352d1661a5SPawel Jakub Dawidek pp->name, gp->name, error); 32362d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_NODISK) == 32372d1661a5SPawel Jakub Dawidek sc->sc_ndisks) { 3238712fe9bdSPawel Jakub Dawidek g_cancel_event(sc); 32392d1661a5SPawel Jakub Dawidek g_raid3_destroy(sc, 1); 32403650be51SPawel Jakub Dawidek g_topology_lock(); 32412d1661a5SPawel Jakub Dawidek return (NULL); 32422d1661a5SPawel Jakub Dawidek } 32433650be51SPawel Jakub Dawidek gp = NULL; 32443650be51SPawel Jakub Dawidek } 32453650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 32463650be51SPawel Jakub Dawidek g_topology_lock(); 32472d1661a5SPawel Jakub Dawidek return (gp); 32482d1661a5SPawel Jakub Dawidek } 32492d1661a5SPawel Jakub Dawidek 32502d1661a5SPawel Jakub Dawidek static int 32512d1661a5SPawel Jakub Dawidek g_raid3_destroy_geom(struct gctl_req *req __unused, struct g_class *mp __unused, 32522d1661a5SPawel Jakub Dawidek struct g_geom *gp) 32532d1661a5SPawel Jakub Dawidek { 32543650be51SPawel Jakub Dawidek struct g_raid3_softc *sc; 32553650be51SPawel Jakub Dawidek int error; 32562d1661a5SPawel Jakub Dawidek 32573650be51SPawel Jakub Dawidek g_topology_unlock(); 32583650be51SPawel Jakub Dawidek sc = gp->softc; 32593650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 3260712fe9bdSPawel Jakub Dawidek g_cancel_event(sc); 32613650be51SPawel Jakub Dawidek error = g_raid3_destroy(gp->softc, 0); 32623650be51SPawel Jakub Dawidek if (error != 0) 32633650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 32643650be51SPawel Jakub Dawidek g_topology_lock(); 32653650be51SPawel Jakub Dawidek return (error); 32662d1661a5SPawel Jakub Dawidek } 32672d1661a5SPawel Jakub Dawidek 32682d1661a5SPawel Jakub Dawidek static void 32692d1661a5SPawel Jakub Dawidek g_raid3_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 32702d1661a5SPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 32712d1661a5SPawel Jakub Dawidek { 32722d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 32732d1661a5SPawel Jakub Dawidek 32742d1661a5SPawel Jakub Dawidek g_topology_assert(); 32752d1661a5SPawel Jakub Dawidek 32762d1661a5SPawel Jakub Dawidek sc = gp->softc; 32772d1661a5SPawel Jakub Dawidek if (sc == NULL) 32782d1661a5SPawel Jakub Dawidek return; 32792d1661a5SPawel Jakub Dawidek /* Skip synchronization geom. */ 32802d1661a5SPawel Jakub Dawidek if (gp == sc->sc_sync.ds_geom) 32812d1661a5SPawel Jakub Dawidek return; 32822d1661a5SPawel Jakub Dawidek if (pp != NULL) { 32832d1661a5SPawel Jakub Dawidek /* Nothing here. */ 32842d1661a5SPawel Jakub Dawidek } else if (cp != NULL) { 32852d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 32862d1661a5SPawel Jakub Dawidek 32872d1661a5SPawel Jakub Dawidek disk = cp->private; 32882d1661a5SPawel Jakub Dawidek if (disk == NULL) 32892d1661a5SPawel Jakub Dawidek return; 32903650be51SPawel Jakub Dawidek g_topology_unlock(); 32913650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 32922d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Type>", indent); 32932d1661a5SPawel Jakub Dawidek if (disk->d_no == sc->sc_ndisks - 1) 32942d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "PARITY"); 32952d1661a5SPawel Jakub Dawidek else 32962d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "DATA"); 32972d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Type>\n"); 32982d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Number>%u</Number>\n", indent, 32992d1661a5SPawel Jakub Dawidek (u_int)disk->d_no); 33002d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) { 33012d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Synchronized>", indent); 33023650be51SPawel Jakub Dawidek if (disk->d_sync.ds_offset == 0) 33032d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "0%%"); 33042d1661a5SPawel Jakub Dawidek else { 33052d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%u%%", 33063650be51SPawel Jakub Dawidek (u_int)((disk->d_sync.ds_offset * 100) / 3307c0d68b6eSPawel Jakub Dawidek (sc->sc_mediasize / (sc->sc_ndisks - 1)))); 33082d1661a5SPawel Jakub Dawidek } 33092d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Synchronized>\n"); 33102d1661a5SPawel Jakub Dawidek } 33112d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, 33122d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid); 3313a245a548SPawel Jakub Dawidek sbuf_printf(sb, "%s<GenID>%u</GenID>\n", indent, disk->d_genid); 33142d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Flags>", indent); 33152d1661a5SPawel Jakub Dawidek if (disk->d_flags == 0) 33162d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "NONE"); 33172d1661a5SPawel Jakub Dawidek else { 33182d1661a5SPawel Jakub Dawidek int first = 1; 33192d1661a5SPawel Jakub Dawidek 33202d1661a5SPawel Jakub Dawidek #define ADD_FLAG(flag, name) do { \ 33212d1661a5SPawel Jakub Dawidek if ((disk->d_flags & (flag)) != 0) { \ 33222d1661a5SPawel Jakub Dawidek if (!first) \ 33232d1661a5SPawel Jakub Dawidek sbuf_printf(sb, ", "); \ 33242d1661a5SPawel Jakub Dawidek else \ 33252d1661a5SPawel Jakub Dawidek first = 0; \ 33262d1661a5SPawel Jakub Dawidek sbuf_printf(sb, name); \ 33272d1661a5SPawel Jakub Dawidek } \ 33282d1661a5SPawel Jakub Dawidek } while (0) 33292d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_DIRTY, "DIRTY"); 33302d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_HARDCODED, "HARDCODED"); 33312d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_SYNCHRONIZING, 33322d1661a5SPawel Jakub Dawidek "SYNCHRONIZING"); 33332d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_FORCE_SYNC, "FORCE_SYNC"); 33343aae74ecSPawel Jakub Dawidek ADD_FLAG(G_RAID3_DISK_FLAG_BROKEN, "BROKEN"); 33352d1661a5SPawel Jakub Dawidek #undef ADD_FLAG 33362d1661a5SPawel Jakub Dawidek } 33372d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Flags>\n"); 33382d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<State>%s</State>\n", indent, 33392d1661a5SPawel Jakub Dawidek g_raid3_disk_state2str(disk->d_state)); 33403650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 33413650be51SPawel Jakub Dawidek g_topology_lock(); 33422d1661a5SPawel Jakub Dawidek } else { 33433650be51SPawel Jakub Dawidek g_topology_unlock(); 33443650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 33453650be51SPawel Jakub Dawidek sbuf_printf(sb, "%s<Zone4kRequested>%u</Zone4kRequested>\n", 33463650be51SPawel Jakub Dawidek indent, sc->sc_zones[G_RAID3_ZONE_4K].sz_requested); 33473650be51SPawel Jakub Dawidek sbuf_printf(sb, "%s<Zone4kFailed>%u</Zone4kFailed>\n", 33483650be51SPawel Jakub Dawidek indent, sc->sc_zones[G_RAID3_ZONE_4K].sz_failed); 33493650be51SPawel Jakub Dawidek sbuf_printf(sb, "%s<Zone16kRequested>%u</Zone16kRequested>\n", 33503650be51SPawel Jakub Dawidek indent, sc->sc_zones[G_RAID3_ZONE_16K].sz_requested); 33513650be51SPawel Jakub Dawidek sbuf_printf(sb, "%s<Zone16kFailed>%u</Zone16kFailed>\n", 33523650be51SPawel Jakub Dawidek indent, sc->sc_zones[G_RAID3_ZONE_16K].sz_failed); 33533650be51SPawel Jakub Dawidek sbuf_printf(sb, "%s<Zone64kRequested>%u</Zone64kRequested>\n", 33543650be51SPawel Jakub Dawidek indent, sc->sc_zones[G_RAID3_ZONE_64K].sz_requested); 33553650be51SPawel Jakub Dawidek sbuf_printf(sb, "%s<Zone64kFailed>%u</Zone64kFailed>\n", 33563650be51SPawel Jakub Dawidek indent, sc->sc_zones[G_RAID3_ZONE_64K].sz_failed); 33572d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id); 33582d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, sc->sc_syncid); 3359a245a548SPawel Jakub Dawidek sbuf_printf(sb, "%s<GenID>%u</GenID>\n", indent, sc->sc_genid); 33602d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Flags>", indent); 33612d1661a5SPawel Jakub Dawidek if (sc->sc_flags == 0) 33622d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "NONE"); 33632d1661a5SPawel Jakub Dawidek else { 33642d1661a5SPawel Jakub Dawidek int first = 1; 33652d1661a5SPawel Jakub Dawidek 33662d1661a5SPawel Jakub Dawidek #define ADD_FLAG(flag, name) do { \ 33672d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & (flag)) != 0) { \ 33682d1661a5SPawel Jakub Dawidek if (!first) \ 33692d1661a5SPawel Jakub Dawidek sbuf_printf(sb, ", "); \ 33702d1661a5SPawel Jakub Dawidek else \ 33712d1661a5SPawel Jakub Dawidek first = 0; \ 33722d1661a5SPawel Jakub Dawidek sbuf_printf(sb, name); \ 33732d1661a5SPawel Jakub Dawidek } \ 33742d1661a5SPawel Jakub Dawidek } while (0) 33752d1661a5SPawel Jakub Dawidek ADD_FLAG(G_RAID3_DEVICE_FLAG_NOAUTOSYNC, "NOAUTOSYNC"); 3376f5a2f7feSPawel Jakub Dawidek ADD_FLAG(G_RAID3_DEVICE_FLAG_ROUND_ROBIN, 3377f5a2f7feSPawel Jakub Dawidek "ROUND-ROBIN"); 3378dba915cfSPawel Jakub Dawidek ADD_FLAG(G_RAID3_DEVICE_FLAG_VERIFY, "VERIFY"); 33792d1661a5SPawel Jakub Dawidek #undef ADD_FLAG 33802d1661a5SPawel Jakub Dawidek } 33812d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "</Flags>\n"); 33822d1661a5SPawel Jakub Dawidek sbuf_printf(sb, "%s<Components>%u</Components>\n", indent, 33832d1661a5SPawel Jakub Dawidek sc->sc_ndisks); 338428b31df7SPawel Jakub Dawidek sbuf_printf(sb, "%s<State>%s</State>\n", indent, 338528b31df7SPawel Jakub Dawidek g_raid3_device_state2str(sc->sc_state)); 33863650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 33873650be51SPawel Jakub Dawidek g_topology_lock(); 33882d1661a5SPawel Jakub Dawidek } 33892d1661a5SPawel Jakub Dawidek } 33902d1661a5SPawel Jakub Dawidek 33919da3072cSPawel Jakub Dawidek static void 33923650be51SPawel Jakub Dawidek g_raid3_shutdown_pre_sync(void *arg, int howto) 33939da3072cSPawel Jakub Dawidek { 33949da3072cSPawel Jakub Dawidek struct g_class *mp; 33959da3072cSPawel Jakub Dawidek struct g_geom *gp, *gp2; 33963650be51SPawel Jakub Dawidek struct g_raid3_softc *sc; 3397712fe9bdSPawel Jakub Dawidek int error; 33989da3072cSPawel Jakub Dawidek 33999da3072cSPawel Jakub Dawidek mp = arg; 3400fdc3c6ceSPawel Jakub Dawidek DROP_GIANT(); 34019da3072cSPawel Jakub Dawidek g_topology_lock(); 34029da3072cSPawel Jakub Dawidek LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { 34033650be51SPawel Jakub Dawidek if ((sc = gp->softc) == NULL) 34049da3072cSPawel Jakub Dawidek continue; 3405712fe9bdSPawel Jakub Dawidek /* Skip synchronization geom. */ 3406712fe9bdSPawel Jakub Dawidek if (gp == sc->sc_sync.ds_geom) 3407712fe9bdSPawel Jakub Dawidek continue; 34083650be51SPawel Jakub Dawidek g_topology_unlock(); 34093650be51SPawel Jakub Dawidek sx_xlock(&sc->sc_lock); 3410712fe9bdSPawel Jakub Dawidek g_cancel_event(sc); 3411712fe9bdSPawel Jakub Dawidek error = g_raid3_destroy(sc, G_RAID3_DESTROY_DELAYED); 3412712fe9bdSPawel Jakub Dawidek if (error != 0) 34133650be51SPawel Jakub Dawidek sx_xunlock(&sc->sc_lock); 34143650be51SPawel Jakub Dawidek g_topology_lock(); 34153650be51SPawel Jakub Dawidek } 34163650be51SPawel Jakub Dawidek g_topology_unlock(); 34173650be51SPawel Jakub Dawidek PICKUP_GIANT(); 34183650be51SPawel Jakub Dawidek } 34193650be51SPawel Jakub Dawidek 34203650be51SPawel Jakub Dawidek static void 34219da3072cSPawel Jakub Dawidek g_raid3_init(struct g_class *mp) 34229da3072cSPawel Jakub Dawidek { 34239da3072cSPawel Jakub Dawidek 34243650be51SPawel Jakub Dawidek g_raid3_pre_sync = EVENTHANDLER_REGISTER(shutdown_pre_sync, 34253650be51SPawel Jakub Dawidek g_raid3_shutdown_pre_sync, mp, SHUTDOWN_PRI_FIRST); 3426712fe9bdSPawel Jakub Dawidek if (g_raid3_pre_sync == NULL) 34279da3072cSPawel Jakub Dawidek G_RAID3_DEBUG(0, "Warning! Cannot register shutdown event."); 34289da3072cSPawel Jakub Dawidek } 34299da3072cSPawel Jakub Dawidek 34309da3072cSPawel Jakub Dawidek static void 34319da3072cSPawel Jakub Dawidek g_raid3_fini(struct g_class *mp) 34329da3072cSPawel Jakub Dawidek { 34339da3072cSPawel Jakub Dawidek 34343650be51SPawel Jakub Dawidek if (g_raid3_pre_sync != NULL) 34353650be51SPawel Jakub Dawidek EVENTHANDLER_DEREGISTER(shutdown_pre_sync, g_raid3_pre_sync); 34369da3072cSPawel Jakub Dawidek } 34379da3072cSPawel Jakub Dawidek 34382d1661a5SPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_raid3_class, g_raid3); 3439