diff --git a/src/blockstore/blockstore_init.cpp b/src/blockstore/blockstore_init.cpp index a9195814..54e20a13 100644 --- a/src/blockstore/blockstore_init.cpp +++ b/src/blockstore/blockstore_init.cpp @@ -86,6 +86,10 @@ resume_1: hdr->data_csum_type = bs->dsk.data_csum_type; hdr->csum_block_size = bs->dsk.csum_block_size; } + if (bs->dsk.meta_format >= BLOCKSTORE_META_FORMAT_HEAP) + { + hdr->meta_area_size = bs->dsk.meta_area_size; + } hdr->set_crc32c(); } if (bs->readonly) @@ -136,19 +140,21 @@ resume_1: hdr->data_block_size != bs->dsk.data_block_size || hdr->bitmap_granularity != bs->dsk.bitmap_granularity || hdr->data_csum_type != bs->dsk.data_csum_type || - hdr->csum_block_size != bs->dsk.csum_block_size) + hdr->csum_block_size != bs->dsk.csum_block_size || + hdr->meta_area_size > bs->dsk.meta_area_size) { printf( "Configuration stored in metadata superblock" - " (meta_block_size=%u, data_block_size=%u, bitmap_granularity=%u, data_csum_type=%u, csum_block_size=%u)" - " differs from OSD configuration (%u/%u/%u, %u/%u).\n", + " (meta_block_size=%u, data_block_size=%u, bitmap_granularity=%u, data_csum_type=%u, csum_block_size=%u, meta_area_size=%ju)" + " differs from OSD configuration (%u/%u/%u, %u/%u, %ju).\n", hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity, - hdr->data_csum_type, hdr->csum_block_size, + hdr->data_csum_type, hdr->csum_block_size, hdr->meta_area_size, bs->dsk.meta_block_size, bs->dsk.data_block_size, bs->dsk.bitmap_granularity, - bs->dsk.data_csum_type, bs->dsk.csum_block_size + bs->dsk.data_csum_type, bs->dsk.csum_block_size, bs->dsk.meta_area_size ); exit(1); } + bs->dsk.meta_area_size = hdr->meta_area_size; if (bs->dsk.meta_format != hdr->version) { bs->dsk.meta_format = hdr->version; diff --git a/src/blockstore/ondisk_formats.h b/src/blockstore/ondisk_formats.h index 86aeb3af..071e9b8d 100644 --- a/src/blockstore/ondisk_formats.h +++ b/src/blockstore/ondisk_formats.h @@ -185,6 +185,7 @@ struct __attribute__((__packed__)) blockstore_meta_header_v3_t uint32_t data_csum_type; uint32_t csum_block_size; uint32_t header_csum; + uint64_t meta_area_size; uint64_t completed_lsn; void set_crc32c(); diff --git a/src/disk_tool/disk_tool.h b/src/disk_tool/disk_tool.h index b3a801d9..07cf41be 100644 --- a/src/disk_tool/disk_tool.h +++ b/src/disk_tool/disk_tool.h @@ -27,6 +27,9 @@ #define VITASTOR_PART_TYPE "e7009fac-a5a1-4d72-af72-53de13059903" #define DEFAULT_HYBRID_JOURNAL "1G" #define DEFAULT_HYBRID_SSD_JOURNAL "128M" +#define VITASTOR_META_FORMAT_NAME_V1 "0.6" +#define VITASTOR_META_FORMAT_NAME_V2 "0.9" +#define VITASTOR_META_FORMAT_NAME_HEAP "3.0" struct resizer_data_moving_t; @@ -51,18 +54,20 @@ struct disk_tool_t bool dump_as_old = false; bool skip_obsolete = false; int log_level = 1; + double meta_reserve_multiple = 2; + uint64_t meta_reserve_min_size = (uint64_t)1024*1024*1024; blockstore_disk_t dsk; // resize data and/or move metadata and journal int iodepth; std::string new_meta_device, new_journal_device; - uint64_t new_data_offset, new_data_len; - uint64_t new_journal_offset, new_journal_len; - uint64_t new_meta_offset, new_meta_len; + uint64_t new_data_offset = 0, new_data_len = 0; + uint64_t new_journal_offset = 0, new_journal_len = 0; + uint64_t new_meta_offset = 0, new_meta_len = 0; /**** State ****/ - uint64_t journal_pos, journal_calc_data_pos; + uint64_t journal_pos = 0, journal_calc_data_pos = 0; uint8_t *buffer_area = NULL; bool first_block, first_entry; @@ -72,24 +77,24 @@ struct disk_tool_t std::map::iterator remap_it; ring_loop_t *ringloop = NULL; ring_consumer_t ring_consumer; - int remap_active; + int remap_active = 0; journal_entry_start je_start; uint8_t *new_journal_buf = NULL, *new_meta_buf = NULL, *new_journal_ptr = NULL, *new_journal_data = NULL; blockstore_meta_header_v3_t *new_meta_hdr = NULL; - uint64_t new_journal_in_pos; - int64_t data_idx_diff; - uint64_t total_blocks, free_first, free_last; - uint64_t new_clean_entry_bitmap_size, new_data_csum_size, new_clean_entry_size, new_entries_per_block; + uint64_t new_journal_in_pos = 0; + int64_t data_idx_diff = 0; + uint64_t total_blocks = 0, free_first = 0, free_last = 0; + uint64_t new_clean_entry_bitmap_size = 0, new_data_csum_size = 0, new_clean_entry_size = 0, new_entries_per_block = 0; uint32_t new_meta_format = 0; int new_journal_fd = -1, new_meta_fd = -1; resizer_data_moving_t *moving_blocks = NULL; - bool started; + bool started = false; void *small_write_data = NULL; - uint32_t data_crc32; - bool data_csum_valid; - uint32_t crc32_last; - uint32_t new_crc32_prev; + uint32_t data_crc32 = 0; + bool data_csum_valid = false; + uint32_t crc32_last = 0; + uint32_t new_crc32_prev = 0; ~disk_tool_t(); @@ -152,6 +157,7 @@ struct disk_tool_t json11::Json read_osd_superblock(std::string device, bool expect_exist = true, bool ignore_nonref = false); uint32_t write_osd_superblock(std::string device, json11::Json params); + void parse_meta_reserve(); int prepare_one(std::map options, int is_hdd, json11::Json::object & result); int check_existing_partition(std::string & dev_by_uuid); int fix_partition_type(std::string & dev_by_uuid); diff --git a/src/disk_tool/disk_tool_meta.cpp b/src/disk_tool/disk_tool_meta.cpp index 4bf16f71..60edfa5f 100644 --- a/src/disk_tool/disk_tool_meta.cpp +++ b/src/disk_tool/disk_tool_meta.cpp @@ -7,8 +7,6 @@ #include "json_util.h" #include "malloc_or_die.h" -#define FREE_SPACE_BIT 0x8000 - int disk_tool_t::process_meta(std::function hdr_fn, std::function obj_fn, std::function record_fn, @@ -25,7 +23,7 @@ int disk_tool_t::process_meta(std::function buf_size = 8*dsk.meta_block_size; uint8_t *data = NULL; data = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, buf_size); - blockstore_meta_header_v3_t *hdr = (blockstore_meta_header_v3_t *)data; + blockstore_meta_header_v3_t *hdr = (blockstore_meta_header_v3_t *)memalign_or_die(MEM_ALIGNMENT, dsk.meta_block_size); if (do_open) { if (dsk.meta_fd >= 0) @@ -101,13 +99,12 @@ close_error: blockstore_heap_t *heap = new blockstore_heap_t(&dsk, buffer_area, log_level); // Load heap and just iterate it in memory hdr_fn(hdr); - hdr = NULL; uint64_t meta_pos = dsk.meta_block_size; lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0); uint64_t entries_loaded = 0; - while (meta_pos < dsk.meta_area_size) + while (meta_pos < hdr->meta_area_size) { - uint64_t read_len = buf_size < dsk.meta_area_size-meta_pos ? buf_size : dsk.meta_area_size-meta_pos; + uint64_t read_len = buf_size < hdr->meta_area_size-meta_pos ? buf_size : hdr->meta_area_size-meta_pos; read_blocking(dsk.meta_fd, data, read_len); r = heap->load_blocks(meta_pos-dsk.meta_block_size, read_len, data, true, entries_loaded); meta_pos += read_len; @@ -165,7 +162,6 @@ csum_unknown: // Read uint64_t block_num = 0; hdr_fn(hdr); - hdr = NULL; uint64_t meta_pos = dsk.meta_block_size; lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0); while (meta_pos < dsk.min_meta_len) @@ -224,6 +220,7 @@ csum_unknown: } close_free: free(data); + free(hdr); if (buffer_area) { free(buffer_area); @@ -308,7 +305,7 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr) if (hdr->version == BLOCKSTORE_META_FORMAT_V1) { printf( - "{\"version\":\"0.6\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u," + "{\"version\":\"" VITASTOR_META_FORMAT_NAME_V1 "\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u," "\"entries\":[\n", hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity ); @@ -316,7 +313,7 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr) else if (hdr->version == BLOCKSTORE_META_FORMAT_V2) { printf( - "{\"version\":\"0.9\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u," + "{\"version\":\"" VITASTOR_META_FORMAT_NAME_V2 "\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u," "\"data_csum_type\":\"%s\",\"csum_block_size\":%u,\"entries\":[\n", hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity, csum_type_str(hdr->data_csum_type).c_str(), hdr->csum_block_size @@ -325,7 +322,7 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr) else if (hdr->version == BLOCKSTORE_META_FORMAT_HEAP) { printf( - "{\"version\":\"3.0\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u," + "{\"version\":\"" VITASTOR_META_FORMAT_NAME_HEAP "\",\"meta_block_size\":%u,\"data_block_size\":%u,\"bitmap_granularity\":%u," "\"data_csum_type\":\"%s\",\"csum_block_size\":%u,\"entries\":[\n", hdr->meta_block_size, hdr->data_block_size, hdr->bitmap_granularity, csum_type_str(hdr->data_csum_type).c_str(), hdr->csum_block_size @@ -517,12 +514,16 @@ void disk_tool_t::dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, u int disk_tool_t::write_json_meta(json11::Json meta) { + if (meta["version"].string_value() == VITASTOR_META_FORMAT_NAME_HEAP) + { + return write_json_heap(meta, meta["journal"]); + } new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len); memset(new_meta_buf, 0, new_meta_len); blockstore_meta_header_v2_t *new_hdr = (blockstore_meta_header_v2_t *)new_meta_buf; new_hdr->zero = 0; new_hdr->magic = BLOCKSTORE_META_MAGIC_V1; - new_hdr->version = meta["version"].uint64_value() == BLOCKSTORE_META_FORMAT_V1 + new_hdr->version = meta["version"].string_value() == VITASTOR_META_FORMAT_NAME_V1 ? BLOCKSTORE_META_FORMAT_V1 : BLOCKSTORE_META_FORMAT_V2; new_hdr->meta_block_size = meta["meta_block_size"].uint64_value() ? meta["meta_block_size"].uint64_value() : 4096; @@ -588,6 +589,9 @@ int disk_tool_t::write_json_meta(json11::Json meta) int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal) { + new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len); + memset(new_meta_buf, 0, new_meta_len); + new_meta_hdr = (blockstore_meta_header_v3_t *)new_meta_buf; new_meta_hdr->zero = 0; new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1; new_meta_hdr->version = BLOCKSTORE_META_FORMAT_HEAP; @@ -604,41 +608,29 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal) : BLOCKSTORE_CSUM_NONE); new_meta_hdr->csum_block_size = meta["csum_block_size"].uint64_value(); new_meta_hdr->header_csum = crc32c(0, new_meta_hdr, sizeof(blockstore_meta_header_v3_t)); + new_meta_hdr->meta_area_size = new_meta_len; new_clean_entry_bitmap_size = (new_meta_hdr->data_block_size / new_meta_hdr->bitmap_granularity + 7) / 8; new_clean_entry_size = 0; new_entries_per_block = 0; new_data_csum_size = (new_meta_hdr->data_csum_type ? ((new_meta_hdr->data_block_size+new_meta_hdr->csum_block_size-1)/new_meta_hdr->csum_block_size*(new_meta_hdr->data_csum_type & 0xFF)) : 0); - new_journal_buf = new_journal_len ? (uint8_t*)memalign(MEM_ALIGNMENT, new_journal_len) : NULL; + new_journal_buf = NULL; if (new_journal_len) { + new_journal_buf = (uint8_t*)memalign(MEM_ALIGNMENT, new_journal_len); memset(new_journal_buf, 0, new_journal_len); } uint64_t total_used_space = 0; uint32_t used_space = 0; - uint64_t meta_offset = 0; - // FIXME: Rather ugly. Remove the dependency on dsk from heap? - blockstore_disk_t dsk; - dsk.bitmap_granularity = new_meta_hdr->bitmap_granularity; - dsk.block_count = 16; - dsk.data_block_size = new_meta_hdr->data_block_size; - dsk.clean_entry_bitmap_size = new_clean_entry_bitmap_size; - dsk.csum_block_size = new_meta_hdr->csum_block_size; - dsk.data_csum_type = new_meta_hdr->data_csum_type; - dsk.journal_len = 4096; - dsk.meta_area_size = new_meta_len; - dsk.meta_block_size = new_meta_hdr->meta_block_size; + uint64_t meta_offset = dsk.meta_block_size; blockstore_heap_t heap(&dsk, NULL, 0); heap_entry_t *wr = NULL; auto get_wr = [&](uint32_t entry_size) { if (used_space > new_meta_hdr->meta_block_size-entry_size) { - if (used_space < new_meta_hdr->meta_block_size-2) - { - *((uint16_t*)(new_meta_buf + meta_offset + used_space)) = FREE_SPACE_BIT | (uint16_t)(new_meta_hdr->meta_block_size-used_space); - } + heap.fill_block_empty_space(new_meta_buf + meta_offset, used_space); meta_offset += new_meta_hdr->meta_block_size; used_space = 0; if (meta_offset >= new_meta_len) @@ -652,7 +644,7 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal) return wr; }; // FIXME: Use a streaming json parser - if (meta["version"] == "3.0") + if (meta["version"].string_value() == VITASTOR_META_FORMAT_NAME_HEAP) { // New format for (const auto & meta_entry: meta["entries"].array_items()) @@ -680,7 +672,8 @@ int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal) wr_type = BS_HEAP_ROLLBACK; else { - fprintf(stderr, "Write entry in %s has invalid type: %s, skipping\n", write_entry.dump().c_str(), write_entry["type"].dump().c_str()); + fprintf(stderr, "Write entry %s has invalid type: %s, aborting\n", + write_entry.dump().c_str(), write_entry["type"].dump().c_str()); close_err0: free(new_meta_buf); new_meta_buf = NULL; @@ -723,8 +716,13 @@ close_err0: else if (wr_type == BS_HEAP_BIG_WRITE) { uint64_t loc = write_entry["location"].uint64_value(); - assert(!(loc % dsk.data_block_size)); - assert((loc / dsk.data_block_size) < 0xFFFF0000); + if ((loc % dsk.data_block_size) || (loc / dsk.data_block_size) >= 0xFFFF0000) + { + fprintf(stderr, "Write entry %s has invalid location: 0x%jx, aborting\n", + write_entry.dump().c_str(), loc); + free_new_meta(); + return 1; + } wr->set_big_location(&heap, loc); } else if (wr_type == BS_HEAP_BIG_INTENT) @@ -867,13 +865,15 @@ close_err: } } } - if (used_space > 0 && used_space < new_meta_hdr->meta_block_size-2) - { - *((uint16_t*)(new_meta_buf + meta_offset + used_space)) = FREE_SPACE_BIT | (uint16_t)(new_meta_hdr->meta_block_size-used_space); - } + } + while (meta_offset < new_meta_len) + { + heap.fill_block_empty_space(new_meta_buf + meta_offset, used_space); + meta_offset += dsk.meta_block_size; + used_space = 0; } int r = resize_write_new_meta(); - if (r == 0) + if (new_journal_buf && r == 0) { r = resize_write_new_journal(); } diff --git a/src/disk_tool/disk_tool_prepare.cpp b/src/disk_tool/disk_tool_prepare.cpp index abb60845..92bcd1e6 100644 --- a/src/disk_tool/disk_tool_prepare.cpp +++ b/src/disk_tool/disk_tool_prepare.cpp @@ -6,6 +6,25 @@ #include "json_util.h" #include "osd_id.h" +void disk_tool_t::parse_meta_reserve() +{ + meta_reserve_multiple = 2; + meta_reserve_min_size = (uint64_t)1024*1024*1024; + if (options.find("meta_reserve") != options.end()) + { + int p1 = options["meta_reserve"].find("x"), p2 = options["meta_reserve"].find(","); + if (p1 >= 0 && p2 >= 0) + { + sscanf(options["meta_reserve"].c_str()+(p1 < p2 ? 0 : p2), "%lf", &meta_reserve_multiple); + meta_reserve_min_size = parse_size(options["meta_reserve"].substr(p1 < p2 ? p2 : 0, p1 < p2 ? options["meta_reserve"].size()-p2 : p2)); + } + else if (p1 >= 0) + sscanf(options["meta_reserve"].c_str(), "%lf", &meta_reserve_multiple); + else + meta_reserve_min_size = parse_size(options["meta_reserve"]); + } +} + int disk_tool_t::prepare_one(std::map options, int is_hdd, json11::Json::object & result) { static const char *allow_additional_params[] = { @@ -144,7 +163,17 @@ int disk_tool_t::prepare_one(std::map options, int is_ dsk.open_journal(); dsk.calc_lengths(); if (dsk.data_device == dsk.meta_device && !new_meta_len) - dsk.data_offset += (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.min_meta_len*2 : dsk.min_meta_len); + { + uint64_t new_meta_len = dsk.min_meta_len; + if (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP) + { + new_meta_len = dsk.min_meta_len*meta_reserve_multiple; + if (new_meta_len < meta_reserve_min_size) + new_meta_len = meta_reserve_min_size; + new_meta_len = (new_meta_len + dsk.meta_block_size-1) & ~((uint64_t)dsk.meta_block_size-1); + } + dsk.data_offset += new_meta_len; + } dsk.meta_area_size = (dsk.data_device == dsk.meta_device ? dsk.data_offset : dsk.meta_device_size) - dsk.meta_offset; sb = json11::Json::object { { "meta_format", options["meta_format"] }, @@ -562,24 +591,10 @@ int disk_tool_t::get_meta_partition(std::vector & ssds, std return 1; } // Leave some extra space for future metadata formats and round metadata area size to multiples of 1 MB - uint64_t meta_reserve_multiple = 2, min_meta_size = (uint64_t)1024*1024*1024; - if (options.find("meta_reserve") != options.end()) - { - int p1 = options["meta_reserve"].find("x"), p2 = options["meta_reserve"].find(","); - if (p1 >= 0 && p2 >= 0) - { - meta_reserve_multiple = stoull_full(options["meta_reserve"].substr(p1 < p2 ? 0 : p2, p1 - (p1 < p2 ? 0 : p2))); - min_meta_size = parse_size(options["meta_reserve"].substr(p1 < p2 ? p2 : 0, p1 < p2 ? options["meta_reserve"].size()-p2 : p2)); - } - else if (p1 >= 0) - meta_reserve_multiple = stoull_full(options["meta_reserve"].substr(0, p1)); - else - min_meta_size = parse_size(options["meta_reserve"]); - } meta_size = ((meta_size+1024*1024-1)/1024/1024)*1024*1024; meta_size *= meta_reserve_multiple; - if (meta_size < min_meta_size) - meta_size = min_meta_size; + if (meta_size < meta_reserve_min_size) + meta_size = meta_reserve_min_size; // Pick an SSD for journal&meta, balancing the number of serviced OSDs across SSDs int sel = -1; for (int i = 0; i < ssds.size(); i++) @@ -610,6 +625,7 @@ int disk_tool_t::get_meta_partition(std::vector & ssds, std int disk_tool_t::prepare(std::vector devices) { + parse_meta_reserve(); if (options.find("data_device") != options.end() && options["data_device"] != "") { if (options.find("hybrid") != options.end() || diff --git a/src/disk_tool/disk_tool_resize.cpp b/src/disk_tool/disk_tool_resize.cpp index c71069c8..0640c998 100644 --- a/src/disk_tool/disk_tool_resize.cpp +++ b/src/disk_tool/disk_tool_resize.cpp @@ -25,6 +25,7 @@ struct resizer_data_moving_t int disk_tool_t::raw_resize() { int r; + parse_meta_reserve(); // Parse parameters r = resize_parse_params(); if (r != 0) @@ -225,17 +226,28 @@ void disk_tool_t::resize_init(blockstore_meta_header_v3_t *hdr) new_data_csum_size = (dsk.data_csum_type ? ((dsk.data_block_size+dsk.csum_block_size-1)/dsk.csum_block_size*(dsk.data_csum_type & 0xFF)) : 0); - new_clean_entry_size = new_clean_entry_header_size + 2*new_clean_entry_bitmap_size + new_data_csum_size; - new_entries_per_block = dsk.meta_block_size/new_clean_entry_size; - uint64_t new_meta_blocks = 1 + (new_data_len/dsk.data_block_size + new_entries_per_block-1) / new_entries_per_block; - if (!new_meta_len) + if (new_meta_format != BLOCKSTORE_META_FORMAT_HEAP) { - new_meta_len = dsk.meta_block_size*new_meta_blocks; + new_clean_entry_size = new_clean_entry_header_size + 2*new_clean_entry_bitmap_size + new_data_csum_size; + new_entries_per_block = dsk.meta_block_size/new_clean_entry_size; + uint64_t new_meta_blocks = 1 + (new_data_len/dsk.data_block_size + new_entries_per_block-1) / new_entries_per_block; + if (!new_meta_len) + { + new_meta_len = dsk.meta_block_size*new_meta_blocks; + } + if (new_meta_len < dsk.meta_block_size*new_meta_blocks) + { + fprintf(stderr, "New metadata area size is too small, should be at least %ju bytes\n", dsk.meta_block_size*new_meta_blocks); + exit(1); + } } - if (new_meta_len < dsk.meta_block_size*new_meta_blocks) + else { - fprintf(stderr, "New metadata area size is too small, should be at least %ju bytes\n", dsk.meta_block_size*new_meta_blocks); - exit(1); + new_clean_entry_size = new_entries_per_block = 0; + if (!new_meta_len) + { + new_meta_len = dsk.meta_area_size; + } } // Check that new metadata, journal and data areas don't overlap if (new_meta_device == dsk.data_device && new_meta_offset < new_data_offset+new_data_len && @@ -631,6 +643,7 @@ int disk_tool_t::resize_rebuild_meta() new_meta_hdr->data_csum_type = dsk.data_csum_type; new_meta_hdr->csum_block_size = dsk.csum_block_size; new_meta_hdr->completed_lsn = hdr->completed_lsn; + new_meta_hdr->meta_area_size = new_meta_len; new_meta_hdr->header_csum = 0; new_meta_hdr->header_csum = crc32c(0, new_meta_hdr, new_meta_hdr->version == BLOCKSTORE_META_FORMAT_HEAP ? sizeof(blockstore_meta_header_v3_t) : sizeof(blockstore_meta_header_v2_t)); diff --git a/src/disk_tool/disk_tool_resize_auto.cpp b/src/disk_tool/disk_tool_resize_auto.cpp index e7c7dc63..ce07cc2d 100644 --- a/src/disk_tool/disk_tool_resize_auto.cpp +++ b/src/disk_tool/disk_tool_resize_auto.cpp @@ -8,6 +8,7 @@ int disk_tool_t::resize_data(std::string device) { + parse_meta_reserve(); if (options.find("move_journal") == options.end() && options.find("move_data") == options.end() && options.find("journal_size") == options.end() && @@ -83,7 +84,8 @@ int disk_tool_t::resize_data(std::string device) ? move_options["new_meta_device"] : dsk.meta_device; // Calculate new data & meta offsets if (!new_meta_len) - new_meta_len = (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.min_meta_len*2 : dsk.min_meta_len); + new_meta_len = (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.meta_area_size : dsk.min_meta_len); + move_options["new_meta_len"] = std::to_string(new_meta_len); new_data_offset = 4096 + (new_journal_device == dsk.data_device ? new_journal_len : 0) + (new_meta_device == dsk.data_device ? new_meta_len : 0); new_data_offset += ((dsk.data_offset-new_data_offset) % dsk.data_block_size); diff --git a/tests/test_resize_auto.sh b/tests/test_resize_auto.sh index f905e271..d99abeef 100755 --- a/tests/test_resize_auto.sh +++ b/tests/test_resize_auto.sh @@ -15,26 +15,29 @@ trap "kill -9 $(jobs -p) || true; sudo losetup -d $LOOP1 $LOOP2"' || true' EXIT # also test prepare --hybrid :) # non-vitastor random type UUID to prevent udev activation mount | grep '/dev type devtmpfs' || sudo mount udev /dev/ -t devtmpfs -sudo build/src/disk_tool/vitastor-disk-test prepare --meta_format 2 --no_init 1 --meta_reserve 1x,1M \ +sudo build/src/disk_tool/vitastor-disk-test prepare $OFFSET_ARGS --no_init 1 --meta_reserve 1x,1M \ --block_size 131072 --osd_num 987654 --part_type_uuid 0df42ae0-3695-4395-a957-7d5ff3645c56 \ --hybrid --fast-devices $LOOP2 $LOOP1 -# write almost empty journal -node < ./testdata/journal.json +if [[ -n "$OLD" ]]; then + # write almost empty journal + node < ./testdata/journal.json console.log(JSON.stringify([ {"type":"start","start":"0x1000"}, {"type":"big_write_instant","inode":"0x1000000000001","stripe":"0xc60000","ver":"10","offset":0,"len":131072,"loc":"0x18ffdc0000","bitmap":"ffffffff"} ])); EOF -sudo build/src/disk_tool/vitastor-disk write-journal ${LOOP1}p1 < ./testdata/journal.json -sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json -jq -S '[ .[] + {"valid":true} ]' < ./testdata/journal.json > ./testdata/j1.json -diff ./testdata/j1.json ./testdata/j2.json + sudo build/src/disk_tool/vitastor-disk write-journal ${LOOP1}p1 < ./testdata/journal.json + sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json + jq -S '[ .[] + {"valid":true} ]' < ./testdata/journal.json > ./testdata/j1.json + diff ./testdata/j1.json ./testdata/j2.json +fi # write fake metadata items in the end DATA_DEV_SIZE=$(sudo blockdev --getsize64 ${LOOP1}p1) BLOCK_COUNT=$(((DATA_DEV_SIZE-4096)/128/1024)) -node < ./testdata/meta.json +if [[ -n "$OLD" ]]; then + node < ./testdata/meta.json console.log(JSON.stringify({ version: "0.9", meta_block_size: 4096, @@ -53,42 +56,84 @@ console.log(JSON.stringify({ })), })); EOF +else + node < ./testdata/meta.json +console.log(JSON.stringify({ + version: "3.0", + meta_block_size: 4096, + data_block_size: 131072, + bitmap_granularity: 4096, + data_csum_type: "none", + csum_block_size: 0, + entries: [ ...new Array(100).keys() ].map(i => ({ + pool: 1, + inode: "0x1", + stripe: "0x"+Number(i*0x20000).toString(16), + writes: [ { + lsn: (1+i), + version: 10, + type: 'big', + stable: true, + location: 128*1024*(($BLOCK_COUNT-100)+i), + bitmap: "ffffffff", + ext_bitmap: "ffffffff", + } ], + })), +})); +EOF +fi # also test write & dump sudo build/src/disk_tool/vitastor-disk write-meta ${LOOP1}p1 < ./testdata/meta.json sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 > ./testdata/compare.json -jq -S < ./testdata/meta.json > ./testdata/1.json -jq -S < ./testdata/compare.json > ./testdata/2.json +jq -S '. + {"entries": (.entries | sort_by(.stripe)) }' < ./testdata/meta.json > ./testdata/1.json +jq -S '. + {"entries": (.entries | sort_by(.stripe)) }' < ./testdata/compare.json > ./testdata/2.json diff ./testdata/1.json ./testdata/2.json # move journal & meta back, data will become smaller; end indexes should be shifted by -1251 sudo build/src/disk_tool/vitastor-disk-test resize --move-journal '' --move-meta '' ${LOOP1}p1 -sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S > ./testdata/2.json -jq -S '. + {"entries": [ .entries[] | (. + { "block": (.block-1251) }) ]}' < ./testdata/meta.json > ./testdata/1.json +sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S '. + {"entries": (.entries | sort_by(.stripe)) }' > ./testdata/2.json +if [[ -n "$OLD" ]]; then + jq -S '. + {"entries": ([ .entries[] | (. + { "block": (.block-1251) }) ] | sort_by(.stripe))}' < ./testdata/meta.json > ./testdata/1.json +else + jq -S '. + {"entries": ([ .entries[] | (. + { "writes": [ .writes[0] + { "location": (.writes[0].location-1360*128*1024) } ] }) ] | sort_by(.stripe))}' < ./testdata/meta.json > ./testdata/1.json +fi diff ./testdata/1.json ./testdata/2.json -sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json -jq -S '[ (.[] + {"valid":true}) | (if .type == "big_write_instant" then . + {"loc":"0x18f6160000"} else . end) ]' < ./testdata/journal.json > ./testdata/j1.json -diff ./testdata/j1.json ./testdata/j2.json +if [[ -n "$OLD" ]]; then + sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json + jq -S '[ (.[] + {"valid":true}) | (if .type == "big_write_instant" then . + {"loc":"0x18f6160000"} else . end) ]' < ./testdata/journal.json > ./testdata/j1.json + diff ./testdata/j1.json ./testdata/j2.json +fi # move journal & meta out, data will become larger; end indexes should be shifted back by +1251 sudo build/src/disk_tool/vitastor-disk-test resize --move-journal ${LOOP2}p1 --move-meta ${LOOP2}p2 ${LOOP1}p1 -sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S > ./testdata/2.json -jq -S < ./testdata/meta.json > ./testdata/1.json +sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S '. + {"entries": (.entries | sort_by(.stripe)) }' > ./testdata/2.json +jq -S '. + {"entries": (.entries | sort_by(.stripe)) }' < ./testdata/meta.json > ./testdata/1.json diff ./testdata/1.json ./testdata/2.json -jq -S '[ .[] + {"valid":true} ]' < ./testdata/journal.json > ./testdata/j1.json -sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json +if [[ -n "$OLD" ]]; then + jq -S '[ .[] + {"valid":true} ]' < ./testdata/journal.json > ./testdata/j1.json + sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json +fi # reduce data device size by exactly 128k * 99 (occupied blocks); exactly 1 should be left in place :) sudo build/src/disk_tool/vitastor-disk-test resize --data-size $((DATA_DEV_SIZE-128*1024*99)) ${LOOP1}p1 -sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S > ./testdata/2.json -jq -S '. + {"entries": ([ .entries[] | (. + { "block": (.block | if . > '$BLOCK_COUNT'-100 then .-('$BLOCK_COUNT'-100+1) else '$BLOCK_COUNT'-100 end) }) ] | .[1:] + [ .[0] ])}' < ./testdata/meta.json > ./testdata/1.json +sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S '. + {"entries": (.entries | sort_by(.stripe)) }' > ./testdata/2.json +if [[ -n "$OLD" ]]; then + jq -S '. + {"entries": ([ .entries[] | (. + { "block": (.block | if . > '$BLOCK_COUNT'-100 then .-('$BLOCK_COUNT'-100+1) else '$BLOCK_COUNT'-100 end) }) ] + | .[1:] + [ .[0] ]) | sort_by(.stripe)}' < ./testdata/meta.json > ./testdata/1.json +else + jq -S '. + {"entries": ([ .entries[] | (. + { "writes": [ .writes[0] + { "location": (.writes[0].location/128/1024 + | if . > '$BLOCK_COUNT'-100 then .-('$BLOCK_COUNT'-100+1) else '$BLOCK_COUNT'-100 end | .*128*1024) } ] }) ]) | sort_by(.stripe)}' < ./testdata/meta.json > ./testdata/1.json +fi diff ./testdata/1.json ./testdata/2.json -jq -S '[ .[] + {"valid":true} ]' < ./testdata/journal.json > ./testdata/j1.json -sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json +if [[ -n "$OLD" ]]; then + jq -S '[ .[] + {"valid":true} ]' < ./testdata/journal.json > ./testdata/j1.json + sudo build/src/disk_tool/vitastor-disk dump-journal --json --format data ${LOOP1}p1 | jq -S '[ .[] | del(.crc32, .crc32_prev) ]' > ./testdata/j2.json +fi # extend data device size to maximum sudo build/src/disk_tool/vitastor-disk-test resize --data-size max ${LOOP1}p1 -sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S > ./testdata/2.json +sudo build/src/disk_tool/vitastor-disk dump-meta ${LOOP1}p1 | jq -S '. + {"entries": (.entries | sort_by(.stripe)) }' > ./testdata/2.json diff ./testdata/1.json ./testdata/2.json format_green OK