📄 vinumconfig.c
字号:
/* * To do: * * Don't store drive configuration on the config DB: read each drive's header * to decide where it is. * * Accept any old crap in the config_<foo> functions, and complain when * we try to bring it up. * * When trying to bring volumes up, check that the complete address range * is covered. *//*- * 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: vinumconfig.c,v 1.8.2.4 1999/05/05 05:16:20 grog Exp $ */#define STATIC static#define REALLYKERNEL#include "opt_vinum.h"#include <dev/vinum/vinumhdr.h>#include <dev/vinum/request.h>#define MAXTOKEN 64 /* maximum number of tokens in a line *//* * We can afford the luxury of global variables here, * since start_config ensures that these functions * are single-threaded. *//* These are indices in vinum_conf of the last-mentioned of each kind of object */static int current_drive = -1; /* note the last drive we mention, for * some defaults */static int current_plex = -1; /* and the same for the last plex */static int current_volume = -1; /* and the last volme */static struct _ioctl_reply *ioctl_reply; /* struct to return via ioctl *//* These values are used by most of these routines, so set them as globals */static char *token[MAXTOKEN]; /* pointers to individual tokens */static int tokens; /* number of tokens */#define TOCONS 0x01#define TOTTY 0x02#define TOLOG 0x04struct putchar_arg { int flags; struct tty *tty;};#define MSG_MAX 1024 /* maximum length of a formatted message *//* * Format an error message and return to the user in the reply. * CARE: This routine is designed to be called only from the * configuration routines, so it assumes it's the owner of * the configuration lock, and unlocks it on exit */void throw_rude_remark(int error, char *msg,...){ int retval; va_list ap; char *text; static int finishing; /* don't recurse */ int was_finishing; va_start(ap, msg); if ((ioctl_reply != NULL) /* we're called from the user */ &&(!(vinum_conf.flags & VF_READING_CONFIG))) { /* and not reading from disk: return msg */ /* * We can't just format to ioctl_reply, since it * may contain our input parameters */ text = Malloc(MSG_MAX); if (text == NULL) { log(LOG_ERR, "vinum: can't allocate error message buffer\n"); printf("vinum: "); vprintf(msg, ap); /* print to the console */ printf("\n"); } else { retval = kvprintf(msg, NULL, (void *) text, 10, ap); text[retval] = '\0'; /* delimit */ strcpy(ioctl_reply->msg, text); ioctl_reply->error = error; /* first byte is the error number */ Free(text); } } else { printf("vinum: "); vprintf(msg, ap); /* print to the console */ printf("\n"); } va_end(ap); if (vinum_conf.flags & VF_READING_CONFIG) { /* go through to the bitter end, */ if ((vinum_conf.flags & VF_READING_CONFIG) /* we're reading from disk, */ &&((daemon_options & daemon_noupdate) == 0)) { log(LOG_NOTICE, "Disabling configuration updates\n"); daemon_options |= daemon_noupdate; } return; } /* * We have a problem here: we want to unlock the * configuration, which implies tidying up, but * if we find an error while tidying up, we could * recurse for ever. Use this kludge to only try * once */ was_finishing = finishing; finishing = 1; finish_config(was_finishing); /* unlock anything we may be holding */ finishing = was_finishing; longjmp(command_fail, error);}/* Function declarations */int atoi(char *); /* no atoi in the kernel *//* Minimal version of atoi */int atoi(char *s){ /* no atoi in the kernel */ int r = 0; int sign = 1; while (((*s >= '0') && (*s <= '9')) || (*s == '-')) { if (*s == '-') sign = -sign; else r = r * 10 + (*s - '0'); } return r;}/* * Check a volume to see if the plex is already assigned to it. * Return index in volume->plex, or -1 if not assigned */int my_plex(int volno, int plexno){ int i; struct volume *vol; vol = &VOL[volno]; /* point to volno */ for (i = 0; i < vol->plexes; i++) if (vol->plex[i] == plexno) return i; return -1; /* not found */}/* * Check a plex to see if the subdisk is already assigned to it. * Return index in plex->sd, or -1 if not assigned */int my_sd(int plexno, int sdno){ int i; struct plex *plex; plex = &PLEX[plexno]; for (i = 0; i < plex->subdisks; i++) if (plex->sdnos[i] == sdno) return i; return -1; /* not found */}/* * Check that this operation is being done from the config * saved on disk. * longjmp out if not. op is the name of the operation. */void checkdiskconfig(char *op){ if ((vinum_conf.flags & VF_READING_CONFIG) == 0) throw_rude_remark(EPERM, "Can't perform '%s' from config file", op);}/* Add plex to the volume if possible */int give_plex_to_volume(int volno, int plexno){ struct volume *vol; /* * It's not an error for the plex to already * belong to the volume, but we need to check a * number of things to make sure it's done right. * Some day. */ if (my_plex(volno, plexno) >= 0) return plexno; /* that's it */ vol = &VOL[volno]; /* point to volume */ if (vol->plexes == MAXPLEX) /* all plexes allocated */ throw_rude_remark(ENOSPC, "Too many plexes for volume %s", vol->name); else if ((vol->plexes > 0) /* we have other plexes */ &&((vol->flags & VF_CONFIG_SETUPSTATE) == 0)) /* and we're not setting up state */ invalidate_subdisks(&PLEX[plexno], sd_stale); /* make the subdisks invalid */ vol->plex[vol->plexes] = plexno; /* this one */ vol->plexes++; /* add another plex */ PLEX[plexno].volno = volno; /* note the number of our volume */ return vol->plexes - 1; /* and return its index */}/* * Add subdisk to a plex if possible */int give_sd_to_plex(int plexno, int sdno){ int i; struct plex *plex; struct sd *sd; /* * It's not an error for the sd to already * belong to the plex, but we need to check a * number of things to make sure it's done right. * Some day. */ i = my_sd(plexno, sdno); if (i >= 0) /* does it already belong to us? */ return i; /* that's it */ plex = &PLEX[plexno]; /* point to the plex */ sd = &SD[sdno]; /* and the subdisk */ /* Do we have an offset? Otherwise put it after the last one */ if (sd->plexoffset < 0) { /* no offset specified */ if (plex->subdisks > 0) { struct sd *lastsd = &SD[plex->sdnos[plex->subdisks - 1]]; /* last subdisk */ if (plex->organization == plex_concat) /* concat, */ sd->plexoffset = lastsd->sectors + lastsd->plexoffset; /* starts here */ else /* striped or RAID-5, */ sd->plexoffset = plex->stripesize * plex->subdisks; /* starts here */ } else /* first subdisk */ sd->plexoffset = 0; /* start at the beginning */ } if (plex->subdisks == MAXSD) /* we already have our maximum */ throw_rude_remark(ENOSPC, /* crap out */ "Can't add %s to %s: plex full", sd->name, plex->name); plex->subdisks++; /* another entry */ if (plex->subdisks >= plex->subdisks_allocated) /* need more space */ EXPAND(plex->sdnos, int, plex->subdisks_allocated, INITIAL_SUBDISKS_IN_PLEX); /* Adjust size of plex and volume. */ if (plex->organization == plex_raid5) plex->length = (plex->subdisks - 1) * sd->sectors; /* size is one disk short */ else plex->length += sd->sectors; /* plex gets this much bigger */ if (plex->volno >= 0) /* we have a volume */ VOL[plex->volno].size = max(VOL[plex->volno].size, plex->length); /* adjust its size */ /* * We need to check that the subdisks don't overlap, * but we can't do that until a point where we *must* * know the size of all the subdisks. That's not * here. But we need to sort them by offset */ for (i = 0; i < plex->subdisks - 1; i++) { if (sd->plexoffset < SD[plex->sdnos[i]].plexoffset) { /* it fits before this one */ /* First move any remaining subdisks by one */ int j; for (j = plex->subdisks - 1; j > i; j--) /* move up one at a time */ plex->sdnos[j] = plex->sdnos[j - 1]; plex->sdnos[i] = sdno; sd->plexsdno = i; /* note where we are in the subdisk */ return i; } } /* * The plex doesn't have any subdisk with a larger * offset. Insert it */ plex->sdnos[i] = sdno; sd->plexsdno = i; /* note where we are in the subdisk */ return i;}/* * Add a subdisk to drive if possible. The pointer to the drive * must already be stored in the sd structure, but the drive * doesn't know about the subdisk yet. */static void give_sd_to_drive(int sdno){ struct sd *sd; /* pointer to subdisk */ struct drive *drive; /* and drive */ int fe; /* index in free list */ int sfe; /* and index of subdisk when assigning max */ sd = &SD[sdno]; /* point to sd */ drive = &DRIVE[sd->driveno]; /* and drive */ if (drive->state != drive_up) { update_sd_state(sdno); /* that crashes the subdisk */ return; } if ((drive->sectors_available == 0) /* no space left */ ||(sd->sectors > drive->sectors_available)) { /* or too big, */ sd->driveoffset = -1; /* don't be confusing */ sd->state = sd_down; /* make it down */ throw_rude_remark(ENOSPC, "No space for %s on %s", sd->name, drive->label.name); return; /* in case we come back here */ } drive->subdisks_used++; /* one more subdisk */ if (sd->sectors == 0) { /* take the largest chunk */ sfe = 0; /* to keep the compiler happy */ for (fe = 0; fe < drive->freelist_entries; fe++) { if (drive->freelist[fe].sectors >= sd->sectors) { /* more space here */ sd->sectors = drive->freelist[fe].sectors; /* take it */ sd->driveoffset = drive->freelist[fe].offset; sfe = fe; /* and note the index for later */ } } if (sd->sectors == 0) /* no luck, */ throw_rude_remark(ENOSPC, /* give up */ "No space for %s on %s", sd->name, drive->label.name); if (sfe < (drive->freelist_entries - 1)) /* not the last one, */ bcopy(&drive->freelist[sfe + 1], &drive->freelist[sfe], (drive->freelist_entries - sfe) * sizeof(struct drive_freelist)); drive->freelist_entries--; /* one less entry */ drive->sectors_available -= sd->sectors; /* and note how much less space we have */ } else if (sd->driveoffset < 0) { /* no offset specified, find one */ for (fe = 0; fe < drive->freelist_entries; fe++) { if (drive->freelist[fe].sectors >= sd->sectors) { /* it'll fit here */ sd->driveoffset = drive->freelist[fe].offset; if (sd->sectors == drive->freelist[fe].sectors) { /* used up the entire entry */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -