/* * makes sure that the number of free blocks is equal to the number * of free bits in the bitmap block. */ void ssd_assert_plane_freebits(int plane_num, int elem_num, ssd_element_metadata *metadata, ssd_t *s) { int f1; f1 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f1 == metadata->plane_meta[plane_num].free_blocks); }
/* * migrate data from a cold block to "to_blk" */ int ssd_migrate_cold_data(int to_blk, double *mcost, int plane_num, int elem_num, ssd_t *s) { int i; int from_blk = -1; double oldest_erase_time = simtime; double cost = 0; int bitpos; #if SSD_ASSERT_ALL int f1; int f2; #endif ssd_element_metadata *metadata = &(s->elements[elem_num].metadata); // first select the coldest of all blocks. // one way to select is to find the one that has the oldest // erasure time. if (plane_num == -1) { for (i = 0; i < s->params.blocks_per_element; i ++) { if (metadata->block_usage[i].num_valid > 0) { if (metadata->block_usage[i].time_of_last_erasure < oldest_erase_time) { oldest_erase_time = metadata->block_usage[i].time_of_last_erasure; from_blk = i; } } } } else { #if SSD_ASSERT_ALL f1 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f1 == metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks); #endif bitpos = plane_num * s->params.blocks_per_plane; for (i = bitpos; i < bitpos + (int)s->params.blocks_per_plane; i ++) { int block = ssd_bitpos_to_block(i, s); ASSERT(metadata->block_usage[block].plane_num == plane_num); if (metadata->block_usage[block].num_valid > 0) { if (metadata->block_usage[block].time_of_last_erasure < oldest_erase_time) { oldest_erase_time = metadata->block_usage[block].time_of_last_erasure; from_blk = block; } } } } ASSERT(from_blk != -1); if (plane_num != -1) { ASSERT(metadata->block_usage[from_blk].plane_num == metadata->block_usage[to_blk].plane_num); } // next, clean the block to which we'll transfer the // cold data cost += _ssd_clean_block_fully(to_blk, metadata->block_usage[to_blk].plane_num, elem_num, metadata, s); #if SSD_ASSERT_ALL if (plane_num != -1) { f2 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f2 == metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks); } #endif // then, migrate the cold data to the worn out block. // for which, we first read all the valid data cost += metadata->block_usage[from_blk].num_valid * s->params.page_read_latency; // include the write cost cost += metadata->block_usage[from_blk].num_valid * s->params.page_write_latency; // if the src and dest blocks are on different planes // include the transfer cost also cost += ssd_crossover_cost(s, metadata, from_blk, to_blk); // the cost of erasing the cold block (represented by from_blk) // will be added later ... // finally, update the metadata metadata->block_usage[to_blk].bsn = metadata->block_usage[from_blk].bsn; metadata->block_usage[to_blk].num_valid = metadata->block_usage[from_blk].num_valid; metadata->block_usage[from_blk].num_valid = 0; for (i = 0; i < s->params.pages_per_block; i ++) { int lpn = metadata->block_usage[from_blk].page[i]; if (lpn != -1) { ASSERT(metadata->lba_table[lpn] == (from_blk * s->params.pages_per_block + i)); metadata->lba_table[lpn] = to_blk * s->params.pages_per_block + i; } metadata->block_usage[to_blk].page[i] = metadata->block_usage[from_blk].page[i]; } metadata->block_usage[to_blk].state = metadata->block_usage[from_blk].state; bitpos = ssd_block_to_bitpos(s, to_blk); ssd_set_bit(metadata->free_blocks, bitpos); metadata->tot_free_blocks --; metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks --; #if SSD_ASSERT_ALL if (plane_num != -1) { f2 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f2 == metadata->plane_meta[metadata->block_usage[to_blk].plane_num].free_blocks); } #endif ssd_assert_free_blocks(s, metadata); ASSERT(metadata->block_usage[from_blk].num_valid == 0); #if ASSERT_FREEBITS if (plane_num != -1) { f2 = ssd_free_bits(plane_num, elem_num, metadata, s); ASSERT(f1 == f2); } #endif *mcost = cost; // stat metadata->tot_migrations ++; metadata->tot_pgs_migrated += metadata->block_usage[to_blk].num_valid; metadata->mig_cost += cost; return from_blk; }