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 + -
显示快捷键?