⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reconfiguration.c

📁 create raid tool at linux
💻 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 + -