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

📄 rrc_raid5.c

📁 create raid tool at linux
💻 C
字号:
/* RAID5 driver for reconfiguration */#include "raidreconf.h"#include "rrc_common.h"/* private contextual data for this driver */typedef struct {	int		algorithm;		/* which parity computation */	int		raid_disks;		/* # disks in RAID	    */	int		data_disks;		/* # data disks in RAID     */	int		chunk_size;		/* bytes/chunk		    */	rrc_disk_t	*disks;			/* disk info array	    */	int		*disk_id_idx;		/* direct lookup of disk_id */	unsigned long	tot_chunks;		/* chunks in this RAID	    */	unsigned long	cur_block;		/* current block	    */	unsigned long	tot_blocks;		/* blocks to copy	    */	unsigned long	blocks_per_chunk;	/* should always be 1	    */	unsigned long	*disk_total_blocks;	/* # blocks for each disk   */} raid5_driver_private_t;/* function prototypes */static void *emalloc (int size);static unsigned long raid5_compute_sector (unsigned long, unsigned int *,     unsigned int *, raid5_driver_private_t *);static unsigned long compute_blocknr (raid5_driver_private_t *, int,     unsigned long);/* initialize this driver */static const char *raid5_initialize (void *context, md_cfg_entry_t *cfg, rrc_disk_t *cfgdisks,    unsigned long *blocks){	int d;	unsigned long max_disk_id = 0;	raid5_driver_private_t *ctx = (raid5_driver_private_t *) context;	if (cfg->array.param.level != 5)		return ("Wrong level for RAID-5 Driver");	if (cfg->array.param.nr_disks < 3)		return "Too few disks for RAID5";	ctx->raid_disks = cfg->array.param.nr_disks;	ctx->data_disks = ctx->raid_disks-1;	ctx->chunk_size = cfg->array.param.chunk_size;	ctx->algorithm = cfg->array.param.layout;	ctx->cur_block = 0;	ctx->disks = cfgdisks;	/* sum the total blocks in the array */	ctx->tot_chunks = 0;	for (d = 0; d < ctx->raid_disks; ++d)		ctx->tot_chunks += ctx->disks[d].chunks;	/* RAID5 uses one disk's worth of data for parity, so subtract it */	ctx->tot_chunks -= ctx->disks[0].chunks;	/* set up the disk_id -> disks[] mapping */	for (d = 0; d < ctx->raid_disks; ++d)		if (ctx->disks[d].disk_id > max_disk_id)			max_disk_id = ctx->disks[d].disk_id;	if (max_disk_id > 0) {		ctx->disk_id_idx = emalloc (sizeof (int) * (max_disk_id + 1));		for (d = 0; d < ctx->raid_disks; ++d)			ctx->disk_id_idx[ctx->disks[d].disk_id] = d;	}		ctx->blocks_per_chunk = (cfg->array.param.chunk_size / MD_BLK_SIZ) / 	    reconf_block_size;		*blocks = ctx->blocks_per_chunk * ctx->tot_chunks;	/* we only want to actually copy the MIN blocks of the arrays */	if (source_blocks && sink_blocks)		ctx->tot_blocks = MIN (source_blocks, sink_blocks);	else		ctx->tot_blocks = *blocks;	ctx->disk_total_blocks = emalloc (sizeof (unsigned long) * 	    ctx->raid_disks);	for (d = 0; d < ctx->raid_disks; ++d)		ctx->disk_total_blocks[d] = 		    cfgdisks[d].chunks * (ctx->chunk_size / MD_BLK_SIZ) / 		    reconf_block_size;	return NULL;}/* fill the wish_list with wishes for blocks we wish to write */static driver_status_traid5_request_blocks (void *context){	raid5_driver_private_t *ctx = (raid5_driver_private_t *) context;	while (ctx->cur_block < ctx->tot_blocks) {		if (!can_wish_again ())			return LDR_INCOMPLETE;		insert_wish (ctx->cur_block);		++ctx->cur_block;	}	return LDR_DONE;}/* update the super-block, tell the kernel about any new disks, and** start the array*/static const char *raid5_update_super (void *context){	unsigned long d;	int mdfile;	int rc;	mdu_param_t mdpar;	printf ("Updating superblocks...\n");	if (analyze_sb (&ver, mkraid, new_md_cfg, 1, 0, 1)) {		fprintf (stderr, "Error analyzing superblock.\n");		return "RAID-5 Superblock analysis error";	}	/* Tell the kernel about this */	mdfile = open (new_md_cfg->md_name, O_RDONLY);	if (mdfile < 0) {		static char grump[1024];		snprintf (grump, sizeof (grump), "can't open %s (%s).", 		    new_md_cfg->md_name, strerror (errno));		fprintf (stderr, "%s\n", grump);		return (grump);	}	/* turn off the clean state bit, 	** so the parity blocks will be recalculated	** "Unclean!  Unclean!"	*/	new_md_cfg->array.param.state &= ~(1 << MD_SB_CLEAN);	rc = ioctl (mdfile, SET_ARRAY_INFO, 	    (unsigned long) &new_md_cfg->array.param);	if (rc) {		fprintf (stderr, "Failed setting array info for device %s\n", 		    new_md_cfg->md_name);		return "RAID-5 Superblock info error";	}		printf ("Array is updated with kernel.\n");	for (d = 0; d != new_md_cfg->array.param.nr_disks; d++) {		rc = ioctl (mdfile, ADD_NEW_DISK,		    (unsigned long) (new_md_cfg->array.disks + d));		if (rc) {			static char grump[1024];			snprintf (grump, sizeof (grump), 			    "Failed adding disk %lu to array.", d);			fprintf (stderr, "%s\n", grump);			return (grump);		}	}	close (mdfile);	printf ("Disks re-inserted in array... "	    "Hold on while starting the array...\n");	mdfile = open (new_md_cfg->md_name, O_RDWR);	if (mdfile < 0) {		static char grump[1024];		snprintf (grump, sizeof (grump), "can't open %s (%s).", 		    new_md_cfg->md_name, strerror (errno));		fprintf (stderr, "%s\n", grump);		return (grump);	}	/* Now run the array ! */	memset (&mdpar, 0, sizeof (mdpar));	mdpar.personality = RAID5;	mdpar.chunk_size = new_md_cfg->array.param.chunk_size;	rc = ioctl (mdfile, RUN_ARRAY, (unsigned long) &mdpar);	close (mdfile);	if (rc) {		switch (errno) {		case EBUSY:			printf ("Array %s is already running\n", 			    new_md_cfg->md_name);			break;		default:			perror(new_md_cfg->md_name);		}		return "RAID-5 Superblock update error";	}	return 0;}/* the following func is lifted (and edited) from the kernel sources *//* * Input: a 'big' sector number, * Output: index of the data and parity disk, and the sector # in them. */static unsigned longraid5_compute_sector (unsigned long r_sector,     unsigned int *dd_idx,    unsigned int *pd_idx,     raid5_driver_private_t *ctx){	unsigned long stripe;	unsigned long chunk_number;	unsigned int chunk_offset;# ifdef TESTING# define PU(V)	printf ("%s = %lu ", #V, V)# else# define PU(V)# endif /* TESTING */	/* First compute the information on this sector */	/*	 * Compute the chunk number and the sector offset inside the chunk	 */	chunk_number = r_sector / ctx->blocks_per_chunk;	chunk_offset = r_sector % ctx->blocks_per_chunk;	PU (r_sector);	PU (chunk_number);	PU (chunk_offset);	/*	 * Compute the stripe number	 */	stripe = chunk_number / ctx->data_disks;	PU (stripe);	/*	 * Compute the data disk and parity disk indexes inside the stripe	 */	*dd_idx = chunk_number % ctx->data_disks;	/*	 * Select the parity disk based on the user selected algorithm.	 *//***********************************************************	if (ctx->level == 4)		*pd_idx = ctx->data_disks;	else ***********************************************************/	switch (ctx->algorithm) {	case RAID5_ALGORITHM_LEFT_ASYMMETRIC:		*pd_idx = ctx->data_disks - stripe % ctx->raid_disks;		if (*dd_idx >= *pd_idx)			(*dd_idx)++;		break;	case RAID5_ALGORITHM_RIGHT_ASYMMETRIC:		*pd_idx = stripe % ctx->raid_disks;		if (*dd_idx >= *pd_idx)			(*dd_idx)++;		break;	case RAID5_ALGORITHM_LEFT_SYMMETRIC:		*pd_idx = ctx->data_disks - stripe % ctx->raid_disks;		*dd_idx = (*pd_idx + 1 + *dd_idx) % ctx->raid_disks;		break;	case RAID5_ALGORITHM_RIGHT_SYMMETRIC:		*pd_idx = stripe % ctx->raid_disks;		*dd_idx = (*pd_idx + 1 + *dd_idx) % ctx->raid_disks;		break;	default:		fprintf (stderr, "raid5: unsupported algorithm %d\n", 		    ctx->algorithm);	}	PU (*dd_idx);	PU (*pd_idx);	/*	 * Finally, compute the new sector number	 */# ifdef TESTING	printf ("old sector # = %lu, new sector # = %lu\n", r_sector,	    stripe * blocks_per_chunk + chunk_offset);# endif	return stripe * ctx->blocks_per_chunk + chunk_offset;}static const char *raid5_map_global_to_local (void *context, unsigned long gblock, int *diskid,    unsigned long *lblock){	raid5_driver_private_t *ctx = (raid5_driver_private_t *) context;	int disk_idx, parity_id;# define ROUTINE	"raid5_map_global_to_local"	*lblock = raid5_compute_sector (gblock, &disk_idx, &parity_id, ctx);	if (*lblock >= ctx->disk_total_blocks[disk_idx]) {		fprintf (stderr, 		    "\n%s: disk %d block out of range: %lu (%lu) gblock = %lu\n",		    ROUTINE, disk_idx, *lblock, 		    ctx->disk_total_blocks[disk_idx], gblock);		abort ();	}	*diskid = ctx->disks[disk_idx].disk_id;	return (NULL);# undef ROUTINE}/* the following func is lifted from the kernel sources also */static unsigned longcompute_blocknr (raid5_driver_private_t *ctx, int i, unsigned long dblock){	int raid_disks = ctx->raid_disks, data_disks = raid_disks - 1;	unsigned long new_sector = dblock;	unsigned long stripe = new_sector / ctx->blocks_per_chunk;	int chunk_offset = new_sector % ctx->blocks_per_chunk;	int chunk_number, pd_idx;	unsigned long r_sector, blocknr;	/* compute the parity disk index "pd_idx" */	pd_idx = stripe % raid_disks;	if (ctx->algorithm == RAID5_ALGORITHM_LEFT_ASYMMETRIC ||	    ctx->algorithm == RAID5_ALGORITHM_LEFT_SYMMETRIC)		pd_idx = data_disks - pd_idx;	if (pd_idx == i)	/* parity block, flag it */		return (ULONG_MAX);	/* adjust the data disk index "i" */	switch (ctx->algorithm) {	case RAID5_ALGORITHM_LEFT_ASYMMETRIC:	case RAID5_ALGORITHM_RIGHT_ASYMMETRIC:		if (i > pd_idx)			i--;		break;	case RAID5_ALGORITHM_LEFT_SYMMETRIC:	case RAID5_ALGORITHM_RIGHT_SYMMETRIC:		if (i < pd_idx)			i += raid_disks;		i -= (pd_idx + 1);		break;	default:		fprintf (stderr, "raid5: unsupported algorithm %d\n", 		    ctx->algorithm);	}	/* calculate the new sector & block number */	chunk_number = stripe * data_disks + i;	r_sector = chunk_number * ctx->blocks_per_chunk + chunk_offset;	blocknr = r_sector;	return blocknr;}/* return the global block number from a sink disk id and disk-block */static unsigned longraid5_map_local_to_global (void *context, int disk_idx, unsigned long dblock){	raid5_driver_private_t *ctx = (raid5_driver_private_t *) context;	int disk_id = ctx->disks[ctx->disk_id_idx[disk_idx]].disk_id;	return compute_blocknr (ctx, disk_id, dblock);}/* for each block above gblock, mark as free */static voidraid5_free_blocks_above_gblock (void *context, unsigned long gblock){	raid5_driver_private_t *ctx = (raid5_driver_private_t *) context;	unsigned long block, dblock;	unsigned long tot_blocks = ctx->tot_chunks * ctx->blocks_per_chunk;	for (block = gblock; block < tot_blocks; ++block) {		int diskid;		raid5_map_global_to_local (ctx, block, &diskid, &dblock);		unchecked_mark_disk_block_free (diskid, dblock);	}}static voidraid5_unfree_all_blocks (void *context){	raid5_driver_private_t *ctx = (raid5_driver_private_t *) context;	int disk;	for (disk = 0; disk < ctx->raid_disks; ++disk) {		unsigned long block;		for (block = 0; block < ctx->disk_total_blocks[disk]; ++block)			mark_disk_block_unfree (ctx->disks[disk].disk_id, 			    block);	}}level_driver_t *new_raid5_driver (void){	level_driver_t *drv = malloc (sizeof (level_driver_t));	raid5_driver_private_t *ctx = malloc (sizeof (raid5_driver_private_t));	if (!drv || !ctx)		return (0);		drv->initialize = raid5_initialize;	drv->request_blocks = raid5_request_blocks;	drv->update_super = raid5_update_super;	drv->map_global_to_local = raid5_map_global_to_local;	drv->map_local_to_global = raid5_map_local_to_global;	drv->free_blocks_above_gblock = raid5_free_blocks_above_gblock;	drv->unfree_all_blocks = raid5_unfree_all_blocks;	drv->priv = ctx;	ctx->algorithm = -1;	ctx->raid_disks = 0;	ctx->data_disks = 0;	ctx->chunk_size = 0;	ctx->disks = NULL;	ctx->tot_chunks = 0;	ctx->blocks_per_chunk = 0;	ctx->disk_total_blocks = NULL;	return drv;}/* die on error from malloc */static void *emalloc (int size){	void *ret;	ret = malloc ((size_t) size);	if (ret == NULL) {		fprintf (stderr, "Out of memory: abort ()\n");		abort ();	}	return (ret);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -