vinumstate.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 949 行 · 第 1/2 页
C
949 行
/*- * Copyright (c) 1997, 1998 * Nan Yang Computer Services Limited. All rights reserved. * * This software is distributed under the so-called ``Berkeley * License'': * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Nan Yang Computer * Services Limited. * 4. Neither the name of the Company nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * This software is provided ``as is'', and any express or implied * warranties, including, but not limited to, the implied warranties of * merchantability and fitness for a particular purpose are disclaimed. * In no event shall the company or contributors be liable for any * direct, indirect, incidental, special, exemplary, or consequential * damages (including, but not limited to, procurement of substitute * goods or services; loss of use, data, or profits; or business * interruption) however caused and on any theory of liability, whether * in contract, strict liability, or tort (including negligence or * otherwise) arising in any way out of the use of this software, even if * advised of the possibility of such damage. * * $Id: vinumstate.c,v 1.7.2.5 1999/05/05 05:20:33 grog Exp $ */#define REALLYKERNEL#include "opt_vinum.h"#include <dev/vinum/vinumhdr.h>#include <dev/vinum/request.h>/* Update drive state *//* Return 1 if the state changes, otherwise 0 */int set_drive_state(int driveno, enum drivestate newstate, enum setstateflags flags){ struct drive *drive = &DRIVE[driveno]; int oldstate = drive->state; int sdno; if (drive->state == drive_unallocated) /* no drive to do anything with, */ return 0; if (newstate != oldstate) { /* don't change it if it's not different */ if ((newstate == drive_down) /* the drive's going down */ &&(!(flags & setstate_force)) && (drive->opencount != 0)) /* we can't do it */ return 0; /* don't do it */ drive->state = newstate; /* set the state */ if (drive->label.name[0] != '\0') /* we have a name, */ log(LOG_INFO, "vinum: drive %s is %s\n", drive->label.name, drive_state(drive->state)); if ((drive->state == drive_up) && (drive->vp == NULL)) /* should be open, but we're not */ init_drive(drive, 1); /* which changes the state again */ if (newstate != oldstate) { /* state has changed */ for (sdno = 0; sdno < vinum_conf.subdisks_allocated; sdno++) { /* find this drive's subdisks */ if ((SD[sdno].state >= sd_referenced) && (SD[sdno].driveno == driveno)) /* belongs to this drive */ update_sd_state(sdno); /* update the state */ } } if ((flags & setstate_configuring) == 0) /* configuring? */ save_config(); /* no: save the updated configuration now */ return 1; } return 0;}/* * Try to set the subdisk state. Return 1 if state changed to * what we wanted, -1 if it changed to something else, and 0 * if no change. * * This routine is called both from the user (up, down states * only) and internally. */int set_sd_state(int sdno, enum sdstate newstate, enum setstateflags flags){ struct sd *sd = &SD[sdno]; struct plex *plex; struct volume *vol; int oldstate = sd->state; int status = 1; /* status to return */ if ((newstate == oldstate) || (sd->state == sd_unallocated)) /* no subdisk to do anything with, */ return 0; if (sd->driveoffset < 0) { /* not allocated space */ sd->state = sd_down; if (newstate != sd_down) { if (sd->plexno >= 0) sdstatemap(&PLEX[sd->plexno]); /* count up subdisks */ return -1; } } else { /* space allocated */ switch (newstate) { case sd_down: /* take it down? */ /* * If we're attached to a plex, and we're * not reborn, we won't go down without * use of force. */ if ((!flags & setstate_force) && (sd->plexno >= 0) && (sd->state != sd_reborn)) return 0; /* don't do it */ break; case sd_up: if (DRIVE[sd->driveno].state != drive_up) /* can't bring the sd up if the drive isn't, */ return 0; /* not even by force */ switch (sd->state) { case sd_crashed: case sd_reborn: case sd_down: /* been down, no data lost */ /* * If we're associated with a plex, and * the plex isn't up, or we're the only * subdisk in the plex, we can do it */ if ((sd->plexno >= 0) && (((PLEX[sd->plexno].state < plex_firstup) || (PLEX[sd->plexno].subdisks > 1)))) break; /* do it */ /* * XXX Get this right: make sure that other plexes in * the volume cover this address space, otherwise * we make this one sd_up. * * Do we even want this any more? */ if (oldstate != sd_reborn) { sd->state = sd_reborn; /* here it is again */ log(LOG_INFO, "vinum: subdisk %s is %s, not %s\n", sd->name, sd_state(sd->state), sd_state(newstate)); } status = -1; break; case sd_init: /* brand new */ if (flags & setstate_configuring) /* we're doing this while configuring */ break; /* otherwise it's like being empty */ /* FALLTHROUGH */ case sd_empty: /* * If we're associated with a plex which * is down, or which is the only one in the * volume, and we're not a RAID-5 plex, we * can come up without being inconsistent. * Internally, we use the force flag to bring * up a RAID-5 plex after initialization. */ if ((sd->plexno >= 0) && ((PLEX[sd->plexno].organization != plex_raid5) || (flags & setstate_force)) && (((PLEX[sd->plexno].state < plex_firstup) || (PLEX[sd->plexno].subdisks > 1)))) break; /* Otherwise it's just out of date */ /* FALLTHROUGH */ case sd_stale: /* out of date info, need reviving */ case sd_obsolete: /* * 1. If the subdisk is not part of a plex, bring it up, don't revive. * * 2. If the subdisk is part of a one-plex volume or an unattached plex, * and it's not RAID-5, we *can't revive*. The subdisk doesn't * change its state. * * 3. If the subdisk is part of a one-plex volume or an unattached plex, * and it's RAID-5, but more than one subdisk is down, we *still * can't revive*. The subdisk doesn't change its state. * * 4. If the subdisk is part of a multi-plex volume, we'll change to * reviving and let the revive routines find out whether it will work * or not. If they don't, the revive stops with an error message, * but the state doesn't change (FWIW). */ if (sd->plexno < 0) /* no plex associated, */ break; /* bring it up */ plex = &PLEX[sd->plexno]; if (plex->volno >= 0) /* have a volume */ vol = &VOL[plex->volno]; else vol = NULL; /* * We can't do it if: * * 1: we don't have a volume * 2: we're the only plex in the volume * 3: we're a RAID-5 plex, and more than one subdisk is down. */ if (((vol == NULL) || (vol->plexes == 1)) && ((plex->organization != plex_raid5) || (plex->sddowncount > 1))) return 0; /* can't do it */ sd->state = sd_reviving; /* put in reviving state */ sd->revived = 0; /* nothing done yet */ status = EAGAIN; /* need to repeat */ break; /* * XXX This is silly. We need to be able to * bring the subdisk up when it's finished * initializing, but not from the user. We * use the same ioctl in each case, but Vinum(8) * doesn't supply the -f flag, so we use that * to decide whether to do it or not */ case sd_initializing: if (flags & setstate_force) break; /* do it if we have to */ return 0; /* no */ case sd_reviving: if (flags & setstate_force) /* insist, */ break; return EAGAIN; /* no, try again */ default: /* can't do it */ /* * There's no way to bring subdisks up directly from * other states. First they need to be initialized * or revived */ return 0; } break; default: /* other ones, only internal with force */ if ((flags & setstate_force) == 0) /* no force? What's this? */ return 0; /* don't do it */ } } if (status == 1) { /* we can do it, */ sd->state = newstate; log(LOG_INFO, "vinum: %s is %s\n", sd->name, sd_state(sd->state)); } else /* we don't get here with status 0 */ log(LOG_INFO, "vinum: %s is %s, not %s\n", sd->name, sd_state(sd->state), sd_state(newstate)); if (sd->plexno >= 0) /* we belong to a plex */ update_plex_state(sd->plexno); /* update plex state */ if ((flags & setstate_configuring) == 0) /* save config now */ save_config(); return status;}/* * Set the state of a plex dependent on its subdisks. * This time round, we'll let plex state just reflect * aggregate subdisk state, so this becomes an order of * magnitude less complicated. In particular, ignore * the requested state. */int set_plex_state(int plexno, enum plexstate state, enum setstateflags flags){ struct plex *plex; /* point to our plex */ enum plexstate oldstate; enum volplexstate vps; /* how do we compare with the other plexes? */ plex = &PLEX[plexno]; /* point to our plex */ oldstate = plex->state; /* * If the plex isn't allocated, * or it's already in the the state we want, * and it's not up, just return. If it's up, * we still need to do some housekeeping. */ if ((plex->state == plex_unallocated) || ((state == oldstate) && (state != plex_up))) return 0; vps = vpstate(plex); /* how do we compare with the other plexes? */ switch (state) { /* * We can't bring the plex up, even by force, * unless it's ready. update_plex_state * checks that */ case plex_up: /* bring the plex up */ update_plex_state(plex->plexno); /* it'll come up if it can */ break; case plex_down: /* want to take it down */ /* * If we're the only one, or the only one * which is up, we need force to do it. */ if (((vps == volplex_onlyus) || (vps == volplex_onlyusup)) && (!(flags & setstate_force))) return 0; /* can't do it */ plex->state = state; /* do it */ invalidate_subdisks(plex, sd_down); /* and down all up subdisks */ break; /* * This is only requested internally. * Trust ourselves */ case plex_faulty: plex->state = state; /* do it */ invalidate_subdisks(plex, sd_crashed); /* and crash all up subdisks */ break; case plex_initializing: /* XXX consider what safeguards we need here */ if ((flags & setstate_force) == 0) return 0; plex->state = state; /* do it */ break; /* What's this? */ default: return 0; } if (plex->state != oldstate) /* we've changed, */ log(LOG_INFO, /* tell them about it */ "vinum: %s is %s\n", plex->name, plex_state(plex->state)); /* * Now see what we have left, and whether * we're taking the volume down */ if (plex->volno >= 0) /* we have a volume */ update_volume_state(plex->volno); /* update its state */ if ((flags & setstate_configuring) == 0) /* save config now */ save_config(); /* yes: save the updated configuration */ return 1;}/* Update the state of a plex dependent on its plexes. */int set_volume_state(int volno, enum volumestate state, enum setstateflags flags){ struct volume *vol = &VOL[volno]; /* point to our volume */ if ((vol->state == state) /* we're there already */ ||(vol->state == volume_unallocated)) /* or no volume to do anything with, */ return 0; if (state == volume_up) /* want to come up */ update_volume_state(volno); else if (state == volume_down) { /* want to go down */ if (((vol->flags & VF_OPEN) == 0) /* not open */ ||((flags & setstate_force) != 0)) { /* or we're forcing */ vol->state = volume_down; log(LOG_INFO, "vinum: volume %s is %s\n", vol->name, volume_state(vol->state)); if ((flags & setstate_configuring) == 0) /* save config now */ save_config(); /* yes: save the updated configuration */ return 1; } } return 0; /* no change */}/* Set the state of a subdisk based on its environment */void update_sd_state(int sdno){ struct sd *sd; struct drive *drive; enum sdstate oldstate; sd = &SD[sdno]; oldstate = sd->state; drive = &DRIVE[sd->driveno]; if (drive->state == drive_up) { switch (sd->state) { case sd_down: case sd_crashed: sd->state = sd_reborn; /* back up again with no loss */ break; default: break; } } else { /* down or worse */ switch (sd->state) { case sd_up: case sd_reborn: case sd_reviving: case sd_empty: sd->state = sd_crashed; /* lost our drive */ break; default: break; } } if (sd->state != oldstate) /* state has changed, */ log(LOG_INFO, /* say so */ "vinum: %s is %s\n", sd->name, sd_state(sd->state)); if (sd->plexno >= 0) /* we're part of a plex, */ update_plex_state(sd->plexno); /* update its state */}/* * Force a plex and all its subdisks * into an 'up' state. This is a helper * for update_plex_state. */void forceup(int plexno){ struct plex *plex; int sdno; plex = &PLEX[plexno]; /* point to the plex */ plex->state = plex_up; /* and bring it up */ /* change the subdisks to up state */ for (sdno = 0; sdno < plex->subdisks; sdno++) { SD[plex->sdnos[sdno]].state = sd_up; log(LOG_INFO, /* tell them about it */ "vinum: %s is up\n", SD[plex->sdnos[sdno]].name); }}/* Set the state of a plex based on its environment */void update_plex_state(int plexno){ struct plex *plex; /* point to our plex */ enum plexstate oldstate; enum sdstates statemap; /* get a map of the subdisk states */ enum volplexstate vps; /* how do we compare with the other plexes? */ plex = &PLEX[plexno]; /* point to our plex */ oldstate = plex->state; statemap = sdstatemap(plex); /* get a map of the subdisk states */ vps = vpstate(plex); /* how do we compare with the other plexes? */ if ((statemap == sd_emptystate) /* all subdisks empty */&&((vps & volplex_otherup) == 0) /* and no other plex is up */ &&((plex->organization == plex_concat) /* and we're not RAID-5 */ ||(plex->organization == plex_striped))) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?