📄 rrc_common.c
字号:
/* * Common interface for the level drivers * * (C) 2000 by Jakob Oestergaard * * This source is covered by the GNU GPL, the same as all Linux kernel * sources. */#include "rrc_common.h"#include "raidreconf.h"typedef struct wishlist_diskid_t { int source_disk_id; wish_t *wish_list; struct wishlist_diskid_t *next;} wishlist_diskid_t;typedef struct giftlist_diskid_t { int sink_disk_id; fulfilled_t *gift_list; struct giftlist_diskid_t *next;} giftlist_diskid_t;unsigned max_wishes = 0;unsigned long reconf_block_size = 0;wishlist_diskid_t *wish_lists = 0;giftlist_diskid_t *gift_lists = 0;static unsigned wish_list_length = 0;static unsigned gift_list_length = 0;static unsigned long nr_wishes_hooked = 0;static unsigned long nr_gifts_hooked = 0;static unsigned long nr_max_wishes_hooked = 0;static unsigned long nr_max_gifts_hooked = 0;/* Stuff for OOM handling... */static int is_out_of_memory = 0;#define MALLOC_TRY_SIZE (sizeof(wish_t) + sizeof(fulfilled_t) + reconf_block_size)/* Free block management */char **source_disk_free_map = 0;unsigned long *source_disk_free_size = 0;unsigned long *nr_free_disk_blocks = 0;/* Some disk management as well */int nr_unique_disks = 0;rrc_disk_t **global_disk_rrc = 0;/* Stats */static unsigned long free_friends_depth = 0;#define GOOD_READ_LENGTH 128const char *initialize_unique_disks (void){ int dsk; global_disk_rrc = (rrc_disk_t **) malloc (sizeof (rrc_disk_t *) * (old_md_cfg->array.param.nr_disks + new_md_cfg->array.param.nr_disks)); if (!global_disk_rrc) return "Out of memory allocating global disk rrc array"; for (dsk = 0; dsk != old_md_cfg->array.param.nr_disks; dsk++) { int rdsk; for (rdsk = nr_unique_disks; rdsk; rdsk--) if (global_disk_rrc[rdsk - 1]->disk_id == old_rrc_cfg[dsk].disk_id) break; if (!rdsk) global_disk_rrc[nr_unique_disks++] = old_rrc_cfg + dsk; } for (dsk = 0; dsk != new_md_cfg->array.param.nr_disks; dsk++) { int rdsk; for (rdsk = nr_unique_disks; rdsk; rdsk--) if (global_disk_rrc[rdsk - 1]->disk_id == new_rrc_cfg[dsk].disk_id) break; if (!rdsk) global_disk_rrc[nr_unique_disks++] = new_rrc_cfg + dsk; } fprintf (stderr, "%i unique disks detected.\n", nr_unique_disks); return 0;}voidprint_common_stats (void){ fprintf (stderr, "Maximum friend-freeing depth: %9lu\n", free_friends_depth); fprintf (stderr, "Total wishes hooked: %9lu\n", nr_wishes_hooked); fprintf (stderr, "Maximum wishes hooked: %9lu\n", nr_max_wishes_hooked); fprintf (stderr, "Total gifts hooked: %9lu\n", nr_gifts_hooked); fprintf (stderr, "Maximum gifts hooked: %9lu\n", nr_max_gifts_hooked);}/* Utility routines for wish_list and gift_list handling */wish_t *wish_list_source_diskid (int diskid){ wishlist_diskid_t *wlb; for (wlb = wish_lists; wlb; wlb = wlb->next) if (wlb->source_disk_id == diskid) break; if (!wlb) return 0; return wlb->wish_list;}fulfilled_t *gift_list_sink_diskid (int diskid){ giftlist_diskid_t *flb; for (flb = gift_lists; flb; flb = flb->next) if (flb->sink_disk_id == diskid) break; if (!flb) return 0; return flb->gift_list;}voidhook_wish (wish_t * wish){ wishlist_diskid_t *wlb; for (wlb = wish_lists; wlb; wlb = wlb->next) if (wlb->source_disk_id == wish->source_disk_id) break; if (!wlb) { wishlist_diskid_t *nwl = (wishlist_diskid_t *) malloc (sizeof (wishlist_diskid_t)); if (!nwl) { /* XXX: Implement a safe_malloc() wish emergency pre-allocated pool */ fprintf (stderr, "Out of memory where we must not fail. Hope you didn't need those data anyway...\n"); abort (); } /* hook wish */ wish->next = 0; nwl->wish_list = wish; wish_list_length++; /* hook wish list */ nwl->source_disk_id = wish->source_disk_id; nwl->next = wish_lists; wish_lists = nwl; /* Account */ nr_wishes_hooked++; if (wish_list_length > nr_max_wishes_hooked) nr_max_wishes_hooked = wish_list_length; return; } /* just hook wish */ wish->next = wlb->wish_list; wlb->wish_list = wish; wish_list_length++; /* account */ nr_wishes_hooked++; if (wish_list_length > nr_max_wishes_hooked) nr_max_wishes_hooked = wish_list_length;}voidunhook_wish (wish_t * wish){ wishlist_diskid_t *wlb; wish_t *pwish; for (wlb = wish_lists; wlb; wlb = wlb->next) if (wlb->source_disk_id == wish->source_disk_id) break; if (!wlb) { fprintf (stderr, "\nunhook_wish() was asked to unhook a wish for a disk with no wishs. Continuing anyway.\n"); return; } if (wish == wlb->wish_list) { assert (wish_list_length); /* Unhook first wish */ wlb->wish_list = wish->next; free (wish); wish_list_length--; return; } /* Find wish and unhook it */ for (pwish = wlb->wish_list; pwish; pwish = pwish->next) if (pwish->next == wish) break; if (!pwish) { fprintf (stderr, "\nunhook_wish() was asked to unhook a non-existant wish. Continuing anyway.\n"); return; } assert (wish_list_length); pwish->next = wish->next; free (wish); wish_list_length--;}voidhook_gift (fulfilled_t * gift){ giftlist_diskid_t *flb; for (flb = gift_lists; flb; flb = flb->next) if (flb->sink_disk_id == gift->sink_disk_id) break; if (!flb) { giftlist_diskid_t *ngl = (giftlist_diskid_t *) malloc (sizeof (giftlist_diskid_t)); if (!ngl) { fprintf (stderr, "\nOut of memory when hooking gift. Will jump into ocean.\n"); abort (); } /* hook gift into new disk giftlist */ ngl->gift_list = gift; gift->next = 0; gift_list_length++; /* hook disk gift list */ ngl->sink_disk_id = gift->sink_disk_id; ngl->next = gift_lists; gift_lists = ngl; /* Account */ nr_gifts_hooked++; if (gift_list_length > nr_max_gifts_hooked) nr_max_gifts_hooked = gift_list_length; return; } /* just hook gift */ gift->next = flb->gift_list; flb->gift_list = gift; gift_list_length++; /* Account */ nr_gifts_hooked++; if (gift_list_length > nr_max_gifts_hooked) nr_max_gifts_hooked = gift_list_length;}voidunhook_gift (fulfilled_t * gift){ giftlist_diskid_t *flb; fulfilled_t *pgift; for (flb = gift_lists; flb; flb = flb->next) if (flb->sink_disk_id == gift->sink_disk_id) break; if (!flb) { fprintf (stderr, "\nunhook_gift() was asked to unhook a gift for a disk with no gifts. Continuing anyway.\n"); return; } if (gift == flb->gift_list) { assert (gift_list_length); /* Unhook first gift */ flb->gift_list = gift->next; free (gift->data); free (gift); gift_list_length--; return; } /* Find gift and unhook it */ for (pgift = flb->gift_list; pgift; pgift = pgift->next) if (pgift->next == gift) break; if (!pgift) { fprintf (stderr, "\nunhook_gift() was asked to unhook a non-existant gift. Continuing anyway.\n"); return; } assert (gift_list_length); pgift->next = gift->next; free (gift->data); free (gift); gift_list_length--;}const char *setup_free_blocks (unsigned ndisks, rrc_disk_t * diskcfg){ int d; source_disk_free_map = (char **) malloc (sizeof (char *) * ndisks); if (!source_disk_free_map) return "Cannot allocate free disk map"; source_disk_free_size = (unsigned long *) malloc (sizeof (unsigned long) * ndisks); if (!source_disk_free_size) return "Cannot allocate free disk map size array"; nr_free_disk_blocks = (unsigned long *) malloc (sizeof (unsigned long) * ndisks); if (!nr_free_disk_blocks) return "Cannot allocate per-disk free block accounting array"; for (d = 0; d != ndisks; d++) { /* allocate one bit for each block */ source_disk_free_size[d] = (diskcfg[d].reconf_blocks + 7) / 8; source_disk_free_map[d] = (char *) malloc (source_disk_free_size[d]); if (!source_disk_free_map[d]) return "Cannot allocate free disk map for specific disk"; /* Initially, no blocks are free */ memset (source_disk_free_map[d], 0, source_disk_free_size[d]); /* Update per-disk stuff */ nr_free_disk_blocks[d] = 0; } fprintf (stderr, "Allocated free block map for %i disks\n", ndisks); return 0;}/* The good stuff */intcan_wish_again (void){ if (is_out_of_memory) return 0; return wish_list_length < max_wishes;}intis_gblock_in_source (unsigned long gblock){ return gblock < source_blocks;}voidinsert_wish (unsigned long gblock){ const char *ret; wish_t *nwish; int source_disk_id, sink_disk_id; unsigned long source_disk_block, sink_disk_block; int free_on_source; /* * If block is free already, there's no need to free it. But we * must check that it's free on both the source and the sink */ ret = source_driver->map_global_to_local (source_driver->priv, gblock, &source_disk_id, &source_disk_block); if (ret) { fprintf (stderr, "\nSource driver returned error: \"%s\". Will dump core.\n", ret); abort (); } free_on_source = is_disk_block_free (source_disk_id, source_disk_block); ret = sink_driver->map_global_to_local (sink_driver->priv, gblock, &sink_disk_id, &sink_disk_block); if (ret) { fprintf (stderr, "\nSink driver returned error: \"%s\". Will dump core.\n", ret); abort (); } if (free_on_source && is_disk_block_free (sink_disk_id, sink_disk_block)) {/* fprintf(stderr, "Block %lu is free already\n", gblock); */ return; } /* Insert wish */ nwish = (wish_t *) malloc (sizeof (wish_t)); if (!nwish) { fprintf (stderr, "\nOut of memory when inserting wish. Hoping to live thru it...\n"); is_out_of_memory = 1; return; } /* If this block is not free on the sink disk, insert it in the wish_list ** as well. */ nwish->sink_disk_id = sink_disk_id; nwish->sink_rblock = sink_disk_block; /* We also wish for blocks that aren't in the source... */ if (is_gblock_in_source (gblock)) { /* Have the source driver map the global block to source-disk,block addressing */ nwish->source_disk_id = source_disk_id; nwish->source_rblock = source_disk_block; } else { /* Blocks outside of the source are treated specially. We pretend that their source and * sink disks and disk blocks are identical */ nwish->source_disk_id = nwish->sink_disk_id; nwish->source_rblock = nwish->sink_rblock; } /* * This may be a request to free a block from the source disks, where the * corrosponding location on the sink disks is not yet free. * The common reader will detect this case and bring two gifts from only * one wish. So, worst case, we will end up with twice as many gifts * as we had wishes. */#if 0 fprintf (stderr, "Hooking wish: src disk %i blk %4lu -> sink disk %i blk %4lu\n", nwish->source_disk_id, nwish->source_rblock, nwish->sink_disk_id, nwish->sink_rblock);#endif hook_wish (nwish);}unsigned longnr_free_blocks (void){ unsigned long ret = 0; int d; for (d = 0; d != old_md_cfg->array.param.nr_disks; d++) { ret += nr_free_disk_blocks[d];/* fprintf(stderr, "\nFree blocks in disk %i = %lu\n", d, nr_free_disk_blocks[d]); */ } return ret;}intis_diskid_in_source (int diskid){ int d; for (d = 0; d != old_md_cfg->array.param.nr_disks; d++) if (old_rrc_cfg[d].disk_id == diskid) return 1; return 0;}intis_disk_block_free (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 is free per definition */ return 1; } /* fast check first */ if (!nr_free_disk_blocks[disk]) return 0; if (block >= old_rrc_cfg[disk].reconf_blocks) { /* Block is out of scope on disk. This must be an error as we cannot resize devices */ fprintf (stderr, "\nBlock %lu is out of scope in is_disk_block_free request on diskid %i\n", block, diskid); /* added 9-Jan-2001 DSC */ return 0; } /* Then look in map */ blk = block / 8; ofs = block % 8; if (blk >= source_disk_free_size[disk]) { fprintf (stderr, "\nA driver inquired about a free block out of range. Let's see what will happen.\n"); return 0; } return !!(source_disk_free_map[disk][blk] & (1 << ofs));}static voidcommon_mark_disk_block_free (int diskid, unsigned long block, int check){ int disk; unsigned long blk, ofs;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -