geom_vinum_state.c revision 190507
1234353Sdim/*- 2198090Srdivacky * Copyright (c) 2004, 2007 Lukas Ertl 3198090Srdivacky * All rights reserved. 4198090Srdivacky * 5198090Srdivacky * Redistribution and use in source and binary forms, with or without 6198090Srdivacky * modification, are permitted provided that the following conditions 7198090Srdivacky * are met: 8198090Srdivacky * 1. Redistributions of source code must retain the above copyright 9198090Srdivacky * notice, this list of conditions and the following disclaimer. 10198090Srdivacky * 2. Redistributions in binary form must reproduce the above copyright 11198090Srdivacky * notice, this list of conditions and the following disclaimer in the 12198090Srdivacky * documentation and/or other materials provided with the distribution. 13198090Srdivacky * 14198090Srdivacky * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15198090Srdivacky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16234353Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17199481Srdivacky * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18218893Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19198090Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20226633Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22198090Srdivacky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23199481Srdivacky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24198090Srdivacky * SUCH DAMAGE. 25198090Srdivacky */ 26198090Srdivacky 27198090Srdivacky#include <sys/cdefs.h> 28208599Srdivacky__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_state.c 190507 2009-03-28 17:20:08Z lulf $"); 29226633Sdim 30249423Sdim#include <sys/libkern.h> 31249423Sdim#include <sys/malloc.h> 32249423Sdim 33198090Srdivacky#include <geom/geom.h> 34224145Sdim#include <geom/vinum/geom_vinum_var.h> 35198090Srdivacky#include <geom/vinum/geom_vinum.h> 36198892Srdivacky#include <geom/vinum/geom_vinum_share.h> 37198090Srdivacky 38224145Sdimvoid 39224145Sdimgv_setstate(struct g_geom *gp, struct gctl_req *req) 40224145Sdim{ 41224145Sdim struct gv_softc *sc; 42198090Srdivacky struct gv_sd *s; 43198090Srdivacky struct gv_drive *d; 44198090Srdivacky struct gv_volume *v; 45198090Srdivacky struct gv_plex *p; 46198090Srdivacky char *obj, *state; 47198090Srdivacky int f, *flags, type; 48226633Sdim 49234353Sdim f = 0; 50226633Sdim obj = gctl_get_param(req, "object", NULL); 51226633Sdim if (obj == NULL) { 52243830Sdim gctl_error(req, "no object given"); 53243830Sdim return; 54243830Sdim } 55243830Sdim 56243830Sdim state = gctl_get_param(req, "state", NULL); 57218893Sdim if (state == NULL) { 58218893Sdim gctl_error(req, "no state given"); 59239462Sdim return; 60239462Sdim } 61239462Sdim 62218893Sdim flags = gctl_get_paraml(req, "flags", sizeof(*flags)); 63218893Sdim if (flags == NULL) { 64218893Sdim gctl_error(req, "no flags given"); 65218893Sdim return; 66218893Sdim } 67218893Sdim 68218893Sdim if (*flags & GV_FLAG_F) 69218893Sdim f = GV_SETSTATE_FORCE; 70218893Sdim 71218893Sdim sc = gp->softc; 72218893Sdim type = gv_object_type(sc, obj); 73218893Sdim switch (type) { 74218893Sdim case GV_TYPE_VOL: 75218893Sdim if (gv_volstatei(state) < 0) { 76218893Sdim gctl_error(req, "invalid volume state '%s'", state); 77218893Sdim break; 78218893Sdim } 79218893Sdim v = gv_find_vol(sc, obj); 80218893Sdim gv_post_event(sc, GV_EVENT_SET_VOL_STATE, v, NULL, 81218893Sdim gv_volstatei(state), f); 82218893Sdim break; 83218893Sdim 84218893Sdim case GV_TYPE_PLEX: 85218893Sdim if (gv_plexstatei(state) < 0) { 86218893Sdim gctl_error(req, "invalid plex state '%s'", state); 87218893Sdim break; 88218893Sdim } 89198892Srdivacky p = gv_find_plex(sc, obj); 90224145Sdim gv_post_event(sc, GV_EVENT_SET_PLEX_STATE, p, NULL, 91198892Srdivacky gv_plexstatei(state), f); 92218893Sdim break; 93218893Sdim 94218893Sdim case GV_TYPE_SD: 95218893Sdim if (gv_sdstatei(state) < 0) { 96218893Sdim gctl_error(req, "invalid subdisk state '%s'", state); 97218893Sdim break; 98198090Srdivacky } 99198090Srdivacky s = gv_find_sd(sc, obj); 100218893Sdim gv_post_event(sc, GV_EVENT_SET_SD_STATE, s, NULL, 101218893Sdim gv_sdstatei(state), f); 102218893Sdim break; 103218893Sdim 104218893Sdim case GV_TYPE_DRIVE: 105218893Sdim if (gv_drivestatei(state) < 0) { 106218893Sdim gctl_error(req, "invalid drive state '%s'", state); 107218893Sdim break; 108218893Sdim } 109249423Sdim d = gv_find_drive(sc, obj); 110218893Sdim gv_post_event(sc, GV_EVENT_SET_DRIVE_STATE, d, NULL, 111218893Sdim gv_drivestatei(state), f); 112218893Sdim break; 113218893Sdim 114218893Sdim default: 115218893Sdim gctl_error(req, "unknown object '%s'", obj); 116218893Sdim break; 117218893Sdim } 118249423Sdim} 119218893Sdim 120218893Sdim/* Update drive state; return 0 if the state changes, otherwise error. */ 121198090Srdivackyint 122198090Srdivackygv_set_drive_state(struct gv_drive *d, int newstate, int flags) 123198090Srdivacky{ 124198090Srdivacky struct gv_sd *s; 125198090Srdivacky int oldstate; 126198090Srdivacky 127198090Srdivacky KASSERT(d != NULL, ("gv_set_drive_state: NULL d")); 128198090Srdivacky 129198090Srdivacky oldstate = d->state; 130198090Srdivacky 131198090Srdivacky if (newstate == oldstate) 132210299Sed return (0); 133198090Srdivacky 134198090Srdivacky /* We allow to take down an open drive only with force. */ 135198090Srdivacky if ((newstate == GV_DRIVE_DOWN) && gv_consumer_is_open(d->consumer) && 136198090Srdivacky (!(flags & GV_SETSTATE_FORCE))) 137198090Srdivacky return (GV_ERR_ISBUSY); 138198090Srdivacky 139198090Srdivacky d->state = newstate; 140198090Srdivacky 141198090Srdivacky if (d->state != oldstate) { 142198090Srdivacky LIST_FOREACH(s, &d->subdisks, from_drive) 143198090Srdivacky gv_update_sd_state(s); 144198090Srdivacky } 145198090Srdivacky 146198090Srdivacky /* Save the config back to disk. */ 147198090Srdivacky if (flags & GV_SETSTATE_CONFIG) 148198090Srdivacky gv_save_config(d->vinumconf); 149198090Srdivacky 150198090Srdivacky return (0); 151198090Srdivacky} 152224145Sdim 153224145Sdimint 154234353Sdimgv_set_sd_state(struct gv_sd *s, int newstate, int flags) 155198090Srdivacky{ 156198090Srdivacky struct gv_drive *d; 157198090Srdivacky struct gv_plex *p; 158198090Srdivacky int oldstate, status; 159198090Srdivacky 160198090Srdivacky KASSERT(s != NULL, ("gv_set_sd_state: NULL s")); 161198090Srdivacky 162198090Srdivacky oldstate = s->state; 163198090Srdivacky 164234353Sdim /* We are optimistic and assume it will work. */ 165198090Srdivacky status = 0; 166198090Srdivacky 167198090Srdivacky if (newstate == oldstate) 168198090Srdivacky return (0); 169198090Srdivacky 170198090Srdivacky switch (newstate) { 171198090Srdivacky case GV_SD_DOWN: 172198090Srdivacky /* 173198090Srdivacky * If we're attached to a plex, we won't go down without use of 174198090Srdivacky * force. 175198090Srdivacky */ 176198090Srdivacky if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE)) 177198090Srdivacky return (GV_ERR_ISATTACHED); 178198090Srdivacky break; 179198090Srdivacky 180198090Srdivacky case GV_SD_REVIVING: 181226633Sdim case GV_SD_INITIALIZING: 182198090Srdivacky /* 183198090Srdivacky * Only do this if we're forced, since it usually is done 184198090Srdivacky * internally, and then we do use the force flag. 185198090Srdivacky */ 186198090Srdivacky if (!flags & GV_SETSTATE_FORCE) 187198090Srdivacky return (GV_ERR_SETSTATE); 188198090Srdivacky break; 189198090Srdivacky 190198090Srdivacky case GV_SD_UP: 191198090Srdivacky /* We can't bring the subdisk up if our drive is dead. */ 192198090Srdivacky d = s->drive_sc; 193198090Srdivacky if ((d == NULL) || (d->state != GV_DRIVE_UP)) 194198090Srdivacky return (GV_ERR_SETSTATE); 195198090Srdivacky 196198090Srdivacky /* Check from where we want to be brought up. */ 197198090Srdivacky switch (s->state) { 198198090Srdivacky case GV_SD_REVIVING: 199198090Srdivacky case GV_SD_INITIALIZING: 200198090Srdivacky /* 201198090Srdivacky * The subdisk was initializing. We allow it to be 202198090Srdivacky * brought up. 203198090Srdivacky */ 204198090Srdivacky break; 205198090Srdivacky 206198090Srdivacky case GV_SD_DOWN: 207198090Srdivacky /* 208198090Srdivacky * The subdisk is currently down. We allow it to be 209198090Srdivacky * brought up if it is not attached to a plex. 210198090Srdivacky */ 211198090Srdivacky p = s->plex_sc; 212198090Srdivacky if (p == NULL) 213198090Srdivacky break; 214218893Sdim 215198090Srdivacky /* 216198090Srdivacky * If this subdisk is attached to a plex, we allow it 217198090Srdivacky * to be brought up if the plex if it's not a RAID5 218198090Srdivacky * plex, otherwise it's made 'stale'. 219198090Srdivacky */ 220198090Srdivacky 221198090Srdivacky if (p->org != GV_PLEX_RAID5) 222198090Srdivacky break; 223198090Srdivacky else if (s->flags & GV_SD_CANGOUP) { 224198090Srdivacky s->flags &= ~GV_SD_CANGOUP; 225218893Sdim break; 226198090Srdivacky } else if (flags & GV_SETSTATE_FORCE) 227198090Srdivacky break; 228198090Srdivacky else 229198090Srdivacky s->state = GV_SD_STALE; 230198090Srdivacky 231198090Srdivacky status = GV_ERR_SETSTATE; 232198090Srdivacky break; 233198090Srdivacky 234198090Srdivacky case GV_SD_STALE: 235198090Srdivacky /* 236198090Srdivacky * A stale subdisk can be brought up only if it's part 237198090Srdivacky * of a concat or striped plex that's the only one in a 238198090Srdivacky * volume, or if the subdisk isn't attached to a plex. 239198090Srdivacky * Otherwise it needs to be revived or initialized 240218893Sdim * first. 241198090Srdivacky */ 242198090Srdivacky p = s->plex_sc; 243198090Srdivacky if (p == NULL || flags & GV_SETSTATE_FORCE) 244198090Srdivacky break; 245198090Srdivacky 246198090Srdivacky if ((p->org != GV_PLEX_RAID5 && 247198090Srdivacky p->vol_sc->plexcount == 1) || 248198090Srdivacky (p->flags & GV_PLEX_SYNCING && 249198090Srdivacky p->synced > 0 && 250198090Srdivacky p->org == GV_PLEX_RAID5)) 251198090Srdivacky break; 252198090Srdivacky else 253198090Srdivacky return (GV_ERR_SETSTATE); 254198090Srdivacky 255198090Srdivacky default: 256198090Srdivacky return (GV_ERR_INVSTATE); 257198090Srdivacky } 258198090Srdivacky break; 259198090Srdivacky 260198090Srdivacky /* Other state transitions are only possible with force. */ 261198090Srdivacky default: 262198090Srdivacky if (!(flags & GV_SETSTATE_FORCE)) 263198090Srdivacky return (GV_ERR_SETSTATE); 264198090Srdivacky } 265198090Srdivacky 266198090Srdivacky /* We can change the state and do it. */ 267198090Srdivacky if (status == 0) 268198090Srdivacky s->state = newstate; 269198090Srdivacky 270198090Srdivacky /* Update our plex, if we're attached to one. */ 271198090Srdivacky if (s->plex_sc != NULL) 272198090Srdivacky gv_update_plex_state(s->plex_sc); 273198090Srdivacky 274198090Srdivacky /* Save the config back to disk. */ 275198090Srdivacky if (flags & GV_SETSTATE_CONFIG) 276198090Srdivacky gv_save_config(s->vinumconf); 277198090Srdivacky 278206083Srdivacky return (status); 279198090Srdivacky} 280206083Srdivacky 281206083Srdivackyint 282206083Srdivackygv_set_plex_state(struct gv_plex *p, int newstate, int flags) 283206083Srdivacky{ 284206083Srdivacky struct gv_volume *v; 285206083Srdivacky int oldstate, plexdown; 286198090Srdivacky 287198090Srdivacky KASSERT(p != NULL, ("gv_set_plex_state: NULL p")); 288198090Srdivacky 289251662Sdim oldstate = p->state; 290198090Srdivacky v = p->vol_sc; 291251662Sdim plexdown = 0; 292251662Sdim 293251662Sdim if (newstate == oldstate) 294251662Sdim return (0); 295251662Sdim 296251662Sdim switch (newstate) { 297251662Sdim case GV_PLEX_UP: 298251662Sdim /* Let update_plex handle if the plex can come up */ 299198090Srdivacky gv_update_plex_state(p); 300198090Srdivacky if (p->state != GV_PLEX_UP && !(flags & GV_SETSTATE_FORCE)) 301198090Srdivacky return (GV_ERR_SETSTATE); 302198090Srdivacky p->state = newstate; 303198090Srdivacky break; 304198090Srdivacky case GV_PLEX_DOWN: 305198090Srdivacky /* 306198090Srdivacky * Set state to GV_PLEX_DOWN only if no-one is using the plex, 307198090Srdivacky * or if the state is forced. 308198090Srdivacky */ 309198090Srdivacky if (v != NULL) { 310198090Srdivacky /* If the only one up, force is needed. */ 311198090Srdivacky plexdown = gv_plexdown(v); 312198090Srdivacky if ((v->plexcount == 1 || 313198090Srdivacky (v->plexcount - plexdown == 1)) && 314198090Srdivacky ((flags & GV_SETSTATE_FORCE) == 0)) 315198090Srdivacky return (GV_ERR_SETSTATE); 316198090Srdivacky } 317218893Sdim p->state = newstate; 318198090Srdivacky break; 319218893Sdim case GV_PLEX_DEGRADED: 320218893Sdim /* Only used internally, so we have to be forced. */ 321218893Sdim if (flags & GV_SETSTATE_FORCE) 322218893Sdim p->state = newstate; 323218893Sdim break; 324218893Sdim } 325218893Sdim 326218893Sdim /* Update our volume if we have one. */ 327218893Sdim if (v != NULL) 328218893Sdim gv_update_vol_state(v); 329218893Sdim 330218893Sdim /* Save config. */ 331218893Sdim if (flags & GV_SETSTATE_CONFIG) 332218893Sdim gv_save_config(p->vinumconf); 333218893Sdim return (0); 334218893Sdim} 335218893Sdim 336218893Sdimint 337198090Srdivackygv_set_vol_state(struct gv_volume *v, int newstate, int flags) 338198090Srdivacky{ 339198090Srdivacky int oldstate; 340198090Srdivacky 341198090Srdivacky KASSERT(v != NULL, ("gv_set_vol_state: NULL v")); 342198090Srdivacky 343198090Srdivacky oldstate = v->state; 344198090Srdivacky 345198090Srdivacky if (newstate == oldstate) 346198090Srdivacky return (0); 347198090Srdivacky 348198090Srdivacky switch (newstate) { 349198090Srdivacky case GV_VOL_UP: 350198090Srdivacky /* Let update handle if the volume can come up. */ 351198090Srdivacky gv_update_vol_state(v); 352198090Srdivacky if (v->state != GV_VOL_UP && !(flags & GV_SETSTATE_FORCE)) 353198090Srdivacky return (GV_ERR_SETSTATE); 354198090Srdivacky v->state = newstate; 355198090Srdivacky break; 356198090Srdivacky case GV_VOL_DOWN: 357198090Srdivacky /* 358198090Srdivacky * Set state to GV_VOL_DOWN only if no-one is using the volume, 359198090Srdivacky * or if the state should be forced. 360198090Srdivacky */ 361198090Srdivacky if (!gv_provider_is_open(v->provider) && 362198090Srdivacky !(flags & GV_SETSTATE_FORCE)) 363198892Srdivacky return (GV_ERR_ISBUSY); 364198892Srdivacky v->state = newstate; 365198090Srdivacky break; 366198090Srdivacky } 367198090Srdivacky /* Save config */ 368198090Srdivacky if (flags & GV_SETSTATE_CONFIG) 369198090Srdivacky gv_save_config(v->vinumconf); 370198090Srdivacky return (0); 371198090Srdivacky} 372198090Srdivacky 373198090Srdivacky/* Update the state of a subdisk based on its environment. */ 374198090Srdivackyvoid 375198090Srdivackygv_update_sd_state(struct gv_sd *s) 376198090Srdivacky{ 377198090Srdivacky struct gv_drive *d; 378198090Srdivacky int oldstate; 379198090Srdivacky 380198090Srdivacky KASSERT(s != NULL, ("gv_update_sd_state: NULL s")); 381206083Srdivacky d = s->drive_sc; 382206083Srdivacky KASSERT(d != NULL, ("gv_update_sd_state: NULL d")); 383206083Srdivacky 384206083Srdivacky oldstate = s->state; 385206083Srdivacky 386198090Srdivacky /* If our drive isn't up we cannot be up either. */ 387198090Srdivacky if (d->state != GV_DRIVE_UP) { 388198090Srdivacky s->state = GV_SD_DOWN; 389198090Srdivacky /* If this subdisk was just created, we assume it is good.*/ 390198090Srdivacky } else if (s->flags & GV_SD_NEWBORN) { 391198090Srdivacky s->state = GV_SD_UP; 392198090Srdivacky s->flags &= ~GV_SD_NEWBORN; 393198090Srdivacky } else if (s->state != GV_SD_UP) { 394198090Srdivacky if (s->flags & GV_SD_CANGOUP) { 395198090Srdivacky s->state = GV_SD_UP; 396198090Srdivacky s->flags &= ~GV_SD_CANGOUP; 397198090Srdivacky } else 398198090Srdivacky s->state = GV_SD_STALE; 399198090Srdivacky } else 400198090Srdivacky s->state = GV_SD_UP; 401198090Srdivacky 402198090Srdivacky if (s->state != oldstate) 403198090Srdivacky G_VINUM_DEBUG(1, "subdisk %s state change: %s -> %s", s->name, 404198090Srdivacky gv_sdstate(oldstate), gv_sdstate(s->state)); 405198090Srdivacky 406198090Srdivacky /* Update the plex, if we have one. */ 407198090Srdivacky if (s->plex_sc != NULL) 408210299Sed gv_update_plex_state(s->plex_sc); 409210299Sed} 410198090Srdivacky 411198090Srdivacky/* Update the state of a plex based on its environment. */ 412198090Srdivackyvoid 413198090Srdivackygv_update_plex_state(struct gv_plex *p) 414198090Srdivacky{ 415226633Sdim struct gv_sd *s; 416198090Srdivacky int sdstates; 417198090Srdivacky int oldstate; 418198090Srdivacky 419198090Srdivacky KASSERT(p != NULL, ("gv_update_plex_state: NULL p")); 420198090Srdivacky 421198090Srdivacky oldstate = p->state; 422198090Srdivacky 423226633Sdim /* First, check the state of our subdisks. */ 424226633Sdim sdstates = gv_sdstatemap(p); 425226633Sdim 426226633Sdim /* If all subdisks are up, our plex can be up, too. */ 427226633Sdim if (sdstates == GV_SD_UPSTATE) 428226633Sdim p->state = GV_PLEX_UP; 429210299Sed 430198090Srdivacky /* One or more of our subdisks are down. */ 431198090Srdivacky else if (sdstates & GV_SD_DOWNSTATE) { 432198090Srdivacky /* A RAID5 plex can handle one dead subdisk. */ 433198090Srdivacky if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1)) 434198090Srdivacky p->state = GV_PLEX_DEGRADED; 435210299Sed else 436198090Srdivacky p->state = GV_PLEX_DOWN; 437226633Sdim 438226633Sdim /* Some of our subdisks are initializing. */ 439226633Sdim } else if (sdstates & GV_SD_INITSTATE) { 440226633Sdim 441198090Srdivacky if (p->flags & GV_PLEX_SYNCING || 442198090Srdivacky p->flags & GV_PLEX_REBUILDING) 443198090Srdivacky p->state = GV_PLEX_DEGRADED; 444198090Srdivacky else 445198090Srdivacky p->state = GV_PLEX_DOWN; 446198090Srdivacky } else 447198090Srdivacky p->state = GV_PLEX_DOWN; 448198090Srdivacky 449198090Srdivacky if (p->state == GV_PLEX_UP) { 450198090Srdivacky LIST_FOREACH(s, &p->subdisks, in_plex) { 451234353Sdim if (s->flags & GV_SD_GROW) { 452234353Sdim p->state = GV_PLEX_GROWABLE; 453234353Sdim break; 454234353Sdim } 455234353Sdim } 456234353Sdim } 457234353Sdim 458234353Sdim if (p->state != oldstate) 459234353Sdim G_VINUM_DEBUG(1, "plex %s state change: %s -> %s", p->name, 460234353Sdim gv_plexstate(oldstate), gv_plexstate(p->state)); 461234353Sdim 462234353Sdim /* Update our volume, if we have one. */ 463234353Sdim if (p->vol_sc != NULL) 464234353Sdim gv_update_vol_state(p->vol_sc); 465234353Sdim} 466234353Sdim 467198090Srdivacky/* Update the volume state based on its plexes. */ 468198090Srdivackyvoid 469198090Srdivackygv_update_vol_state(struct gv_volume *v) 470198090Srdivacky{ 471198090Srdivacky struct gv_plex *p; 472198090Srdivacky 473249423Sdim KASSERT(v != NULL, ("gv_update_vol_state: NULL v")); 474249423Sdim 475249423Sdim /* The volume can't be up without plexes. */ 476198090Srdivacky if (v->plexcount == 0) { 477198090Srdivacky v->state = GV_VOL_DOWN; 478198090Srdivacky return; 479198090Srdivacky } 480198090Srdivacky 481198090Srdivacky LIST_FOREACH(p, &v->plexes, in_volume) { 482198090Srdivacky /* One of our plexes is accessible, and so are we. */ 483198090Srdivacky if (p->state > GV_PLEX_DEGRADED) { 484198090Srdivacky v->state = GV_VOL_UP; 485198090Srdivacky return; 486198090Srdivacky 487198090Srdivacky /* We can handle a RAID5 plex with one dead subdisk as well. */ 488198090Srdivacky } else if ((p->org == GV_PLEX_RAID5) && 489198090Srdivacky (p->state == GV_PLEX_DEGRADED)) { 490198090Srdivacky v->state = GV_VOL_UP; 491198090Srdivacky return; 492198090Srdivacky } 493198090Srdivacky } 494198090Srdivacky 495198090Srdivacky /* Not one of our plexes is up, so we can't be either. */ 496198090Srdivacky v->state = GV_VOL_DOWN; 497198090Srdivacky} 498198090Srdivacky 499198090Srdivacky/* Return a state map for the subdisks of a plex. */ 500198090Srdivackyint 501198090Srdivackygv_sdstatemap(struct gv_plex *p) 502198090Srdivacky{ 503198090Srdivacky struct gv_sd *s; 504198090Srdivacky int statemap; 505198090Srdivacky 506198090Srdivacky KASSERT(p != NULL, ("gv_sdstatemap: NULL p")); 507198090Srdivacky 508198090Srdivacky statemap = 0; 509198090Srdivacky p->sddown = 0; /* No subdisks down yet. */ 510198090Srdivacky 511198090Srdivacky LIST_FOREACH(s, &p->subdisks, in_plex) { 512198090Srdivacky switch (s->state) { 513198090Srdivacky case GV_SD_DOWN: 514198090Srdivacky case GV_SD_STALE: 515198090Srdivacky statemap |= GV_SD_DOWNSTATE; 516198090Srdivacky p->sddown++; /* Another unusable subdisk. */ 517198090Srdivacky break; 518198090Srdivacky 519198090Srdivacky case GV_SD_UP: 520198090Srdivacky statemap |= GV_SD_UPSTATE; 521234353Sdim break; 522234353Sdim 523198090Srdivacky case GV_SD_INITIALIZING: 524198090Srdivacky statemap |= GV_SD_INITSTATE; 525198090Srdivacky break; 526198090Srdivacky 527198090Srdivacky case GV_SD_REVIVING: 528198090Srdivacky statemap |= GV_SD_INITSTATE; 529198090Srdivacky p->sddown++; /* XXX: Another unusable subdisk? */ 530198090Srdivacky break; 531199989Srdivacky } 532199989Srdivacky } 533199989Srdivacky return (statemap); 534199989Srdivacky} 535234353Sdim