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

📄 rrc_common.c

📁 create raid tool at linux
💻 C
📖 第 1 页 / 共 2 页
字号:
	for (disk = 0; disk != old_md_cfg->array.param.nr_disks; disk++)		if (old_rrc_cfg[disk].disk_id == diskid)			break;	if (disk == old_md_cfg->array.param.nr_disks) {		/* disk is not in source, so block is free per definition */		fprintf (stderr, "\ndisk_id %i not in source\n", diskid);		return;	}	if (block >= old_rrc_cfg[disk].reconf_blocks) {		/* Block must be free, since it's definitely not in the source disk scope. */		/* But this must also be an error, as we cannot resize a single device */		fprintf (stderr,			 "\nblock %lu is out of range on diskid %i\n",			 block, diskid);		return;	}	/* Then look in map */	blk = block / 8;	ofs = block % 8;	if (blk >= source_disk_free_size[disk]) {		/* blocks out of range are also free */		fprintf (stderr,			 "\nblock %lu out of range for free map on diskid %i\n",			 block, diskid);		abort ();	}	if (!(source_disk_free_map[disk][blk] & (1 << ofs))) {		source_disk_free_map[disk][blk] |= (1 << ofs);		nr_free_disk_blocks[disk]++;		if (nr_free_disk_blocks[disk] >		    old_rrc_cfg[disk].reconf_blocks) {			abort ();		}		if (nr_free_blocks () > source_blocks) {			abort ();		}	}	else if (check) {		fprintf (stderr,			 "\nDouble free of block %lu on diskid %i\n",			 block, disk);	}}voidmark_disk_block_free (int diskid, unsigned long block){	common_mark_disk_block_free (diskid, block, 1);}voidunchecked_mark_disk_block_free (int diskid, unsigned long block){	common_mark_disk_block_free (diskid, block, 0);}voidmark_disk_block_unfree (int diskid, unsigned long block){	int disk;	unsigned long blk, ofs;	for (disk = 0; disk != old_md_cfg->array.param.nr_disks; disk++)		if (old_rrc_cfg[disk].disk_id == diskid)			break;	if (disk == old_md_cfg->array.param.nr_disks) {		/* disk is not in source, so block cannot be unfreed		 * This is an acceptable error, (in order to keep the unfree_all_blocks() routines simple		 */		return;	}	if (block >= old_rrc_cfg[disk].reconf_blocks) {		fprintf (stderr,			 "\nblock %lu is out of range on diskid %i and cannot be unfreed \n",			 block, diskid);		abort ();	}	/* Then look in map */	blk = block / 8;	ofs = block % 8;	if (blk >= source_disk_free_size[disk]) {		/* blocks out of range are also free */		fprintf (stderr,			 "\nblock %lu out of range for free map on diskid %i\n",			 block, diskid);		abort ();	}	if (source_disk_free_map[disk][blk] & (1 << ofs)) {		assert (nr_free_disk_blocks[disk]);		source_disk_free_map[disk][blk] =		    source_disk_free_map[disk][blk] & ~(1 << ofs);		nr_free_disk_blocks[disk]--;	}	else {		/* We don't care about unfreeing unfree blocks */	}}voiddebug_print_nonfree_blocks (void){	int disk;	for (disk = 0; disk != old_md_cfg->array.param.nr_disks; disk++) {		unsigned long blk;		fprintf (stderr, "\nUnfree blocks on disk %i\n", disk);		for (blk = 0; blk != old_rrc_cfg[disk].reconf_blocks;		     blk++) {			if (!is_disk_block_free			    (old_rrc_cfg[disk].disk_id,			     blk)) fprintf (stderr, "%lu ", blk);		}	}}voiddebug_print_wish_list (void){	wishlist_diskid_t *wll = wish_lists;	while (wll) {		wish_t *wl;		fprintf (stderr, "Wish list for source disk id %i:\n",			 wll->source_disk_id);		for (wl = wll->wish_list; wl; wl = wl->next)			fprintf (stderr,				 "  source disk id %i block %lu , sink disk id %i block %lu\n",				 wl->source_disk_id, wl->source_rblock,				 wl->sink_disk_id, wl->sink_rblock);		wll = wll->next;	}}const char *generic_write_blocks (int partial){	/*	 * Find nice long consecutive sequences for each disk...	 *	 * To-do: Optimization: Start with disks that didn't have read requests,	 * or had read requests near the write-point. Only if we have to, we	 * should use the disks we're also reading from.	 */	int dsk;	const char *ret = 0;	/* Traverse sink disks */	for (dsk = 0; dsk != new_md_cfg->array.param.nr_disks; dsk++) {		fulfilled_t *gift =		    gift_list_sink_diskid (new_rrc_cfg[dsk].disk_id);		if (!gift)			continue;		/* Now write gifts to disks, sorted */		while (gift) {			fulfilled_t *cgift, *best_gift = gift;			unsigned long long lrc;			for (cgift = gift; cgift; cgift = cgift->next)				if (cgift->sink_rblock <				    best_gift->sink_rblock) best_gift =					    cgift;			/* Seek and write */			lrc = raidseek (new_rrc_cfg[dsk].fd,					best_gift->sink_rblock *					reconf_block_size);			if (lrc == -1) {				fprintf (stderr,					 "\nWriter seek error on disk %i block %lu\n",					 dsk,					 best_gift->sink_rblock *					 reconf_block_size);				abort ();			}			if (!algorithm_check) {				int rc =				    write (new_rrc_cfg[dsk].fd,					   best_gift->data,					   reconf_block_size * 1024);				if (rc == -1) {					fprintf (stderr,						 "\nWrite error on disk %i\n",						 dsk);					ret =					    "Writer failed to flush data to disk - bad blocks on disk ?";				}			}			/* Unhook the gift */			unhook_gift (best_gift);			/* Update gift pointer, as we may just have unhooked the head */			gift =			    gift_list_sink_diskid (new_rrc_cfg[dsk].						   disk_id);		}		/* Yes, we could sync() here, but it's better to schedule write to as many drives		 * as possible before doing so 		 */	}	/* sync() disks for two reasons:	 * It's nice to know that the data reached the platter.  However	 * this isn't much good usually, since if the reconfiguration fails	 * the layout is hosed anyway.	 * If we will be reading from the same disks, it's important for us	 * to know that the write has completed, if we will be doing more	 * sophisticated requesting in the future 	 */	for (dsk = 0; dsk != new_md_cfg->array.param.nr_disks; dsk++)		fsync (new_rrc_cfg[dsk].fd);	return ret;}intmust_fulfill_more (int partial){	/* We tell the source driver whether we require that it	 * fulfills more wishes.	 * It will only ask us this if there are no good sequences	 * left, so we should only tell it "yes" if we really need	 * those extra gifts	 */	if (!wish_list_length)		return 0;	if (!partial)		return !!nr_wishes_left ();	/* We consider the number of wishes, the number of max. wishes	 * and the number of gifts.	 * if the (wishes fulfilled)/(wishes left) fraction is too small, we tell the	 * driver to keep working.	 *	 * This stuff can be tuned...  We could also take into account the current	 * free_friends_depth, as that is the number of _extra_ un-wished-for	 * gifts that ``sometimes'' occur when fulfilling one single wish.	 */	return (gift_list_length * 10 / wish_list_length) < 7;}unsignednr_wishes_left (void){	return wish_list_length;}unsignednr_gifts_left (void){	return gift_list_length;}/* * This routine should be generalized to simply fulfill wishes on all disk id's * in a reasonably sequential manner.  This will save us from re-implementing * the read_blocks routine for each raid level, as these routines are actually * identical anyways... */voidfulfill_wishes (int partial){	/*	 * Read requests from the wish_list, fulfill wishes until	 * either:	 * A)  There are no more wishes	 * B)  There aren't any good wishes left and we've fulfilled enough	 *	 * This routine has O(np^2) behaviour for p total wishes in n sequences - which is bad.	 * Improvements:	 *     sort wishes at wish-time	 */	while (nr_wishes_left ()) {		wish_t *wp;		unsigned long length, best_length = 0;		int disk, best_disk = -1;		unsigned long begin, best_begin = 0;		unsigned long end, best_end = 0;		int progress;		/*		 * Look for a good fat contigous read 		 */		for (disk = 0; disk != nr_unique_disks; disk++) {			unsigned long low_block = 0;			int diskid = global_disk_rrc[disk]->disk_id;			end = 0;			begin = global_disk_rrc[disk]->reconf_blocks;			/* Find request with lowest block >= low_block */			for (wp = wish_list_source_diskid (diskid); wp;			     wp = wp->next) {				assert (wp->source_disk_id == diskid);				if (wp->source_rblock >= low_block				    && wp->source_rblock < begin)					begin = wp->source_rblock;			}			/* If there's no wishes for blocks on this disk, keep moving */			if (begin == global_disk_rrc[disk]->reconf_blocks)				continue;			length = 1;			end = begin + 1;			/* Now look for requests that follow begin. */			progress = 1;			while (progress) {				progress = 0;				for (wp = wish_list_source_diskid (diskid);				     wp; wp = wp->next) {					assert (wp->source_disk_id ==						diskid);					if (wp->source_rblock == end) {						end++;						length++;						progress = 1;					}				}			}			/* Is this one better ? */			if (length > best_length) {				best_length = length;				best_disk = disk;				best_begin = begin;				best_end = end;			}		}		/* So we have a best request - maybe */		if (best_length > GOOD_READ_LENGTH		    || (must_fulfill_more (partial) && best_length > 0)) {			fulfill_wish (global_disk_rrc[best_disk]->disk_id,				      best_begin, best_end);		}		else if (must_fulfill_more (partial)) {			/* there was no best request */			fprintf (stderr,				 "\nNo best request in reader... best is %lu [%lu-%lu]. This is an internal error"				 " - I will dump core..\n", best_length,				 best_begin, best_end);			fprintf (stderr, "%u wishes left\n",				 nr_wishes_left ());			fprintf (stderr, "%lu free blocks\n",				 nr_free_blocks ());			debug_print_wish_list ();			abort ();		}		else {			/* We don't want to read anymore, and we don't have to */			assert (partial);/*        fprintf(stderr, "\nReader skipping early, wishes are crappy.\n"); */			return;		}	}	/* Good, we're done. */}static voidfree_block_and_friends (int diskid, unsigned long block){	unsigned long cdepth = 0;	while (!is_disk_block_free (diskid, block)) {		unsigned long source_block;		int dsk;		fulfilled_t *gift;		unsigned long gblock;		const char *ret;		cdepth++;		/* Calculate block and disk numbers */		source_block = block * reconf_block_size;		for (dsk = 0; dsk != old_md_cfg->array.param.nr_disks;		     dsk++)			if (old_rrc_cfg[dsk].disk_id == diskid)				break;		if (dsk == old_md_cfg->array.param.nr_disks) {			fprintf (stderr,				 "Diskid %i is not in source, when freeing blocks and their friends...\n",				 diskid);			abort ();		}		/* Seek to and read the block */		if (raidseek (old_rrc_cfg[dsk].fd, source_block) == -1) {			fprintf (stderr,				 "\nSeek error in fulfill_wish() (secondary) for disk %i block %lu. Will dump core.\n",				 dsk, source_block);			abort ();		}		gift = (fulfilled_t *) malloc (sizeof (fulfilled_t));		if (!gift) {			fprintf (stderr,				 "\nOh cr*p, we failed malloc() when setting up secondary gift. Dump core for now.\n");			abort ();		}		/* Calculate sink disk for block we're reading */		gblock =		    source_driver->map_local_to_global (source_driver->							priv, diskid,							block);		/* We must catch the case where we're shrinking, and the global block 		   ** does exist in the sink, but not in the source, and for RAID[45], we		   ** should ignore parity blocks (flagged by gblock being ULONG_MAX)		 */		if (gblock >= sink_blocks) {			free (gift);			return;		}		/* Now map to sink diskid and block */		if (		    (ret =		     sink_driver->map_global_to_local (sink_driver->priv,						       gblock,						       &gift->sink_disk_id,						       &gift->						       sink_rblock))) {			fprintf (stderr,				 "Sink driver returned fatal error: \"%s\"\n",				 ret);			abort ();		}		/* Allocate data area and fill it */		if (!		    (gift->data =		     (char *) malloc (reconf_block_size * 1024))) {			fprintf (stderr,				 "\nWe couldn't allocate memory for the secondary gift buffer."				 " Dying horrible death for now.\n");			abort ();		}		if (!algorithm_check) {			int rc =			    read (old_rrc_cfg[dsk].fd, gift->data,				  reconf_block_size * 1024);			if (rc == -1) {				fprintf (stderr,					 "\nSecondary request: Read error on disk %i in souce (disk_id=%i)."					 " Bad blocks on disk ?.\n", dsk,					 diskid);				abort ();			}		}		else {			/* Make sure that we also actually commit any over-comitted pages */			memset (gift->data, 0, reconf_block_size * 1024);		}		/* Mark the block as free */		mark_disk_block_free (diskid, block);		/* Hook the un-wished-for gift as well */		hook_gift (gift);		/* Repeat procedure -  the sink disk and block is our new prospect... */		diskid = gift->sink_disk_id;		block = gift->sink_rblock;	}	if (cdepth > free_friends_depth)		free_friends_depth = cdepth;}voidfulfill_wish (int source_diskid, unsigned long begin, unsigned long end){	/*	 * This routine will read a sequence of blocks as requested	 */	unsigned long curr_block = begin;	while (curr_block != end) {		wish_t *wishbase = wish_list_source_diskid (source_diskid);		if (!wishbase) {			fprintf (stderr,				 "\nNo wishes on disk_id %i given to fulfill_wish() routine!\n",				 source_diskid);			return;		}		/* Now find the wish for the current block */		for (; wishbase; wishbase = wishbase->next)			if (wishbase->source_rblock == curr_block)				break;		if (!wishbase) {			fprintf (stderr,				 "\nFound hole in the claimed contiguous wish sequence... Will dump core.\n");			abort ();		}		free_block_and_friends (wishbase->source_disk_id,					wishbase->source_rblock);		/* Unhook the wish */		unhook_wish (wishbase);		/* Next block */		curr_block++;	}}

⌨️ 快捷键说明

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