📄 reconfiguration.c
字号:
/* * The main reconfiguration routine. * * (C) 2000 by Jakob Oestergaard * * This source is covered by the GNU GPL, the same as all Linux kernel * sources. * */#include "raidreconf.h"#include "rrc_common.h"#include <stdio.h>mdu_version_t ver;int test = 0;int algorithm_check = 0;#ifndef MAX#define MAX(a,b) ((a)>(b)?(a):(b))#endif#ifndef MIN#define MIN(a,b) ((a)<(b)?(a):(b))#endif#define MAX_RECONF_BLKS_PER_CHUNK 10#define MIN_MEM_KB (1024*10)#define MAX_MEM_KB (1024*1024*2)#define MAX_WISHES 10000level_driver_t *source_driver;level_driver_t *sink_driver;md_cfg_entry_t *old_md_cfg;md_cfg_entry_t *new_md_cfg;rrc_disk_t *old_rrc_cfg;rrc_disk_t *new_rrc_cfg;unsigned long source_blocks = 0, sink_blocks = 0;/* Find gcd(a,b) using Euclid's Algorithm */static unsignedeuclid (unsigned a, unsigned b){ unsigned small = MIN (a, b); unsigned large = MAX (a, b); while (small != large) { unsigned nnew = large - small; small = MIN (small, nnew); large = MAX (small, nnew); } return small;}/* Find out how many of the black ones is in the system */static const char *getphysmem (unsigned *mkb){ FILE *mf = fopen ("/proc/meminfo", "r"); if (!mf) return "Couldn't open /proc/meminfo for reading!"; assert (mkb); while (!feof (mf)) { char lbuf[1024]; int rc; if (!fgets (lbuf, 1024, mf)) { fclose (mf); return "Cannot read from /proc/meminfo"; } if (!strncmp (lbuf, "MemTotal:", 9)) { rc = sscanf (lbuf, "MemTotal:\t %u", mkb); fclose (mf); if (rc != 1) return "Parse error reading memory from /proc/meminfo"; return 0; } } fclose (mf); return "Couldn't parse /proc/meminfo!";}/* Allocate the source_disk free map */static const char *alloc_source_disk_map (void){ unsigned int sd; assert (reconf_block_size); source_disk_free_map = (char **) malloc (sizeof (char *) * old_md_cfg->array.param.nr_disks); if (!source_disk_free_map) return "Cannot allocate source_disk_free_map"; for (sd = 0; sd != old_md_cfg->array.param.nr_disks; sd++) { /* initialize .reconf_blocks in rrc structure */ old_rrc_cfg[sd].reconf_blocks = old_rrc_cfg[sd].blocks;#if 0 old_rrc_cfg[sd].reconf_blocks = old_rrc_cfg[sd].chunks * (old_md_cfg->array.param.chunk_size / MD_BLK_SIZ) / reconf_block_size;#endif /* We wish to allocate one bit for each reconf. block */ source_disk_free_map[sd] = (char *) malloc ((old_rrc_cfg[sd].reconf_blocks + 7) / 8); if (!source_disk_free_map[sd]) return "Cannot allocate disk free map for one disk"; /* Initialize */ memset (source_disk_free_map[sd], 0, (old_rrc_cfg[sd].reconf_blocks + 7) / 8); } /* Initialize the sink disk .reconf_blocks as well */ for (sd = 0; sd != new_md_cfg->array.param.nr_disks; sd++) { new_rrc_cfg[sd].reconf_blocks = new_rrc_cfg[sd].blocks;#if 0 new_rrc_cfg[sd].reconf_blocks = new_rrc_cfg[sd].chunks * (new_md_cfg->array.param.chunk_size / MD_BLK_SIZ) / reconf_block_size;#endif } return 0;}/* The main thing */const char *run_reconfiguration (void){ const char *ret; unsigned physmem; int source_complete = 0; time_t last_p = 0; char msgbuf[2048]; assert (source_driver); assert (sink_driver); assert (old_md_cfg); assert (new_md_cfg); assert (old_rrc_cfg); assert (new_rrc_cfg); /* Find block size */ reconf_block_size = euclid (old_md_cfg->array.param.chunk_size / MD_BLK_SIZ, new_md_cfg->array.param.chunk_size / MD_BLK_SIZ); if (!reconf_block_size || (old_md_cfg->array.param.chunk_size / MD_BLK_SIZ / reconf_block_size > MAX_RECONF_BLKS_PER_CHUNK) || (new_md_cfg->array.param.chunk_size / MD_BLK_SIZ / reconf_block_size > MAX_RECONF_BLKS_PER_CHUNK)) { fprintf (stderr, "Old array chunk size is %u KB, new array chunk size is %u KB, gcd is %lu KB, this is not good.\n", old_md_cfg->array.param.chunk_size / MD_BLK_SIZ, new_md_cfg->array.param.chunk_size / MD_BLK_SIZ, reconf_block_size); return "Wild array configuration or internal error."; } fprintf (stderr, "Using %lu Kbyte blocks to move from %i Kbyte chunks to %i Kbyte chunks.\n", reconf_block_size, old_md_cfg->array.param.chunk_size / MD_BLK_SIZ, new_md_cfg->array.param.chunk_size / MD_BLK_SIZ); /* Allocate source disk map and initialize sink disks .reconf_blocks as well */ if ((ret = alloc_source_disk_map ())) return ret; /* Dimension wish list according to phys. memory in the system */ if ((ret = getphysmem (&physmem))) return ret; if (physmem < MIN_MEM_KB || physmem > MAX_MEM_KB) return "Physical memory in system seems unreasonable."; fprintf (stderr, "Detected %u KB of physical memory in system\n", physmem); /* Let's be just slightly nice to the system, it should have it's hands full soon anyway */ max_wishes = physmem / 3 / (reconf_block_size + sizeof (wish_t) + sizeof (fulfilled_t)); /* We limit the maximum number of wishes, because we have some inefficient searches going on in the request merging code... */ if (max_wishes > MAX_WISHES) max_wishes = MAX_WISHES; fprintf (stderr, "A maximum of %u outstanding requests is allowed\n", max_wishes); /* Initialize drivers */ /* set up source first, so that sink driver can have it's # of blocks */ if ( (ret = source_driver->initialize (source_driver->priv, old_md_cfg, old_rrc_cfg, &source_blocks))) return ret; if ((ret = sink_driver->initialize (sink_driver->priv, new_md_cfg, new_rrc_cfg, &sink_blocks))) return ret; if (source_blocks > sink_blocks) { sprintf (msgbuf, "I will SHRINK your old device %s of %lu blocks\n" "to a new device %s of %lu blocks\n" "using a block-size of %lu KB", old_md_cfg->md_name, source_blocks, new_md_cfg->md_name, sink_blocks, reconf_block_size); } else if (source_blocks < sink_blocks) { sprintf (msgbuf, "I will grow your old device %s of %lu blocks\n" "to a new device %s of %lu blocks\n" "using a block-size of %lu KB", old_md_cfg->md_name, source_blocks, new_md_cfg->md_name, sink_blocks, reconf_block_size); } else { sprintf (msgbuf, "I will convert your old device %s of %lu blocks\n" "to a new device %s of same size\n" "using a block-size of %lu KB", old_md_cfg->md_name, source_blocks, new_md_cfg->md_name, reconf_block_size); } confirm (msgbuf); fprintf (stderr, "Converting %lu block device to %lu block device\n", source_blocks, sink_blocks); if ( (ret = setup_free_blocks (old_md_cfg->array.param.nr_disks, old_rrc_cfg))) return ret; if ((ret = initialize_unique_disks ())) return ret; /* * First we mark all blocks the sink won't need as free in the source */ source_driver->free_blocks_above_gblock (source_driver->priv, sink_blocks); /* * Then we unfree all blocks in the sink, to make sure they are actually * requested by the sink requester */ sink_driver->unfree_all_blocks (sink_driver->priv); /* Now start the show ! */ while (!source_complete) { driver_status_t drc; time_t now = time (0); if (now - last_p) { last_p = now; /* progress is the number of free blocks / the number of blocks in the source */ hash_progress (nr_free_blocks (), source_blocks); } drc = sink_driver->request_blocks (sink_driver->priv); if (drc == LDR_FAILED) return "Source driver failed while reading blocks!"; else if (drc == LDR_DONE) source_complete = 1; fulfill_wishes (!source_complete); if ((ret = generic_write_blocks (1))) { fprintf (stderr, "Generic writer returned failure.\n"); return ret; } } assert (!nr_wishes_left ()); /* * Now we mark all blocks the sink won't need as free in the source, * this is needed for the following consistency check to succeed */ source_driver->free_blocks_above_gblock (source_driver->priv, sink_blocks);#if 0 if (nr_free_blocks () != source_blocks) { fprintf (stderr, "\nA mismatch between the number of freed blocks (%lu) and the number of source \n" "blocks (%lu) was detected. Printing debug info...\n", nr_free_blocks (), source_blocks); debug_print_nonfree_blocks (); return "Internal error"; }#endif hash_progress (nr_free_blocks (), source_blocks); fprintf (stderr, "\nSource drained, flushing sink.\n"); generic_write_blocks (0); assert (!nr_gifts_left ()); if (!test) { fprintf (stderr, "Reconfiguration succeeded, will update superblocks...\n"); if ((ret = sink_driver->update_super (new_md_cfg))) return ret; } else { fprintf (stderr, "Because of --test switch we will not update the superblocks\n"); } print_common_stats (); fprintf (stderr, "Congratulations, your array has been reconfigured,\n" "and no errors seem to have occured.\n"); return 0;}voidconfirm (const char *s){ char buf[10]; printf ("---------------------------------------------------\n" "%s\nIs this what you want? (yes/no): ", s); fflush (stdout); if (test) { printf (" (assuming yes, because of --test switch)\n"); } else { fscanf (stdin, "%4s", buf); if (strcmp (buf, "yes")) { exit (1); } }}voidhash_progress (unsigned long now, unsigned long total){#define PBLEN 44 char buf[PBLEN + 1]; unsigned long li; unsigned long i; static int lstate = 0; char lead[] = { '/', '-', '\\', '|' }; if (now > total) now = total; i = li = now * PBLEN / total; lstate++; lstate &= 3; memset (buf, ' ', PBLEN); buf[PBLEN] = 0; while (i) buf[--i] = '#'; printf ("\rWorking (%c) [%08lu/%08lu] [%s] ", lead[lstate], now, total, buf); fflush (stdout);#undef PBLEN}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -