WIP dump/load heap

This commit is contained in:
Vitaliy Filippov
2025-11-23 19:08:24 +03:00
parent 3bad0f6fa8
commit 7a894efcb7
16 changed files with 1161 additions and 218 deletions
+8 -8
View File
@@ -228,11 +228,11 @@ void blockstore_disk_t::calc_lengths()
{
// data
data_len = data_device_size - data_offset;
if (data_fd == meta_fd && data_offset < meta_offset)
if (data_device == meta_device && data_offset < meta_offset)
{
data_len = meta_offset - data_offset;
}
if (data_fd == journal_fd && data_offset < journal_offset)
if (data_device == journal_device && data_offset < journal_offset)
{
data_len = data_len < journal_offset-data_offset
? data_len : journal_offset-data_offset;
@@ -247,23 +247,23 @@ void blockstore_disk_t::calc_lengths()
data_len = cfg_data_size;
}
// meta
meta_area_size = (meta_fd == data_fd ? data_device_size : meta_device_size) - meta_offset;
if (meta_fd == data_fd && meta_offset <= data_offset)
meta_area_size = (meta_device == data_device ? data_device_size : meta_device_size) - meta_offset;
if (meta_device == data_device && meta_offset <= data_offset)
{
meta_area_size = data_offset - meta_offset;
}
if (meta_fd == journal_fd && meta_offset <= journal_offset)
if (meta_device == journal_device && meta_offset <= journal_offset)
{
meta_area_size = meta_area_size < journal_offset-meta_offset
? meta_area_size : journal_offset-meta_offset;
}
// journal
journal_len = (journal_fd == data_fd ? data_device_size : (journal_fd == meta_fd ? meta_device_size : journal_device_size)) - journal_offset;
if (journal_fd == data_fd && journal_offset <= data_offset)
journal_len = (journal_device == data_device ? data_device_size : (journal_device == meta_device ? meta_device_size : journal_device_size)) - journal_offset;
if (journal_device == data_device && journal_offset <= data_offset)
{
journal_len = data_offset - journal_offset;
}
if (journal_fd == meta_fd && journal_offset <= meta_offset)
if (journal_device == meta_device && journal_offset <= meta_offset)
{
journal_len = journal_len < meta_offset-journal_offset
? journal_len : meta_offset-journal_offset;
+52 -20
View File
@@ -1285,18 +1285,11 @@ void blockstore_heap_t::allocate_block(heap_block_info_t & inf)
}
}
int blockstore_heap_t::add_object(object_id oid, heap_write_t *wr, uint32_t *modified_block)
int blockstore_heap_t::allocate_new_object(object_id oid, uint32_t full_object_size, uint32_t *modified_block, heap_object_t **new_obj)
{
// By now, initial small_writes are not allowed
if (wr->type() != BS_HEAP_BIG_WRITE &&
wr->type() != BS_HEAP_TOMBSTONE)
{
return EINVAL;
}
const uint32_t wr_size = wr->get_size(this);
// Allocate block (always leave at least <max_write_entry_size> free_space in the block)
uint32_t block_num = 0;
int res = get_block_for_new_object(block_num, sizeof(heap_object_t)+wr_size+max_write_entry_size);
// Allocate block (always leave at least <max_write_entry_size> free_space in the block)
int res = get_block_for_new_object(block_num, full_object_size+max_write_entry_size);
if (res != 0)
{
return res;
@@ -1307,27 +1300,66 @@ int blockstore_heap_t::add_object(object_id oid, heap_write_t *wr, uint32_t *mod
{
*modified_block = block_num;
}
const uint32_t offset = find_block_space(block_num, sizeof(heap_object_t)+wr_size);
const uint32_t offset = find_block_space(block_num, full_object_size);
if (offset == UINT32_MAX)
{
return ENOSPC;
}
add_used_space(block_num, full_object_size);
block_index[get_pg_id(oid.inode, oid.stripe)][oid.inode][oid.stripe] = (uint64_t)block_num*dsk->meta_block_size + offset;
// and just append the object entry
heap_object_t *new_entry = (heap_object_t *)(inf.data + offset);
new_entry->write_pos = sizeof(heap_object_t);
new_entry->inode = oid.inode;
new_entry->stripe = oid.stripe;
heap_write_t *new_wr = new_entry->get_writes();
*new_obj = (heap_object_t *)(inf.data + offset);
return 0;
}
int blockstore_heap_t::add_object(object_id oid, heap_write_t *wr, uint32_t *modified_block)
{
// By now, initial small_writes are not allowed
if (wr->type() != BS_HEAP_BIG_WRITE &&
wr->type() != BS_HEAP_TOMBSTONE)
{
return EINVAL;
}
const uint32_t wr_size = wr->get_size(this);
heap_object_t *new_obj = NULL;
int res = allocate_new_object(oid, sizeof(heap_object_t)+wr_size, modified_block, &new_obj);
if (res != 0)
{
return res;
}
// Fill the object entry
new_obj->size = sizeof(heap_object_t);
new_obj->write_pos = sizeof(heap_object_t);
new_obj->inode = oid.inode;
new_obj->stripe = oid.stripe;
heap_write_t *new_wr = new_obj->get_writes();
memcpy(new_wr, wr, wr_size);
new_wr->next_pos = 0;
new_wr->size = wr_size;
new_wr->lsn = ++next_lsn;
wr->lsn = new_wr->lsn;
push_inflight_lsn(oid, new_wr->lsn, new_wr->needs_compact(this) ? HEAP_INFLIGHT_COMPACTABLE : 0);
new_entry->size = sizeof(heap_object_t);
new_entry->crc32c = new_entry->calc_crc32c();
add_used_space(block_num, sizeof(heap_object_t) + wr_size);
new_obj->crc32c = new_obj->calc_crc32c();
return 0;
}
int blockstore_heap_t::copy_object(heap_object_t *obj, uint32_t *modified_block)
{
// Allocate block (always leave at least <max_write_entry_size> free_space in the block)
auto oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
assert(!read_entry(oid, NULL));
uint32_t full_object_size = obj->size;
for (auto wr = obj->get_writes(); wr; wr = wr->next())
{
full_object_size += wr->size;
}
heap_object_t *new_obj = NULL;
int res = allocate_new_object(oid, full_object_size, modified_block, &new_obj);
if (res != 0)
{
return res;
}
copy_full_object((uint8_t*)new_obj, obj);
new_obj->crc32c = new_obj->calc_crc32c();
return 0;
}
+3
View File
@@ -215,6 +215,7 @@ class blockstore_heap_t
bool mvcc_check_tracking(object_id oid);
void free_mvcc(heap_mvcc_map_t::iterator mvcc_it);
void allocate_block(heap_block_info_t & inf);
int allocate_new_object(object_id oid, uint32_t full_object_size, uint32_t *modified_block, heap_object_t **new_obj);
int add_object(object_id oid, heap_write_t *wr, uint32_t *modified_block);
void mark_overwritten(uint64_t over_lsn, uint64_t inode, heap_write_t *wr, heap_write_t *end_wr, bool tracking_active);
int update_object(uint32_t block_num, heap_object_t *obj, heap_write_t *wr, uint32_t *modified_block, uint32_t *moved_from_block);
@@ -268,6 +269,8 @@ public:
bool calc_block_checksums(uint32_t *block_csums, uint8_t *bitmap,
uint32_t start, uint32_t end, std::function<uint8_t*(uint32_t start, uint32_t & len)> next,
bool set, std::function<void(uint32_t, uint32_t, uint32_t)> bad_block_cb);
// copy an object as is
int copy_object(heap_object_t *obj, uint32_t *modified_block);
// auto-compacts the object, then adds a write entry to it and to the compaction queue
// return 0 if OK, or maybe ENOSPC
int post_write(object_id oid, heap_write_t *wr, uint32_t *modified_block, uint32_t *moved_from_block);
+2 -1
View File
@@ -355,7 +355,8 @@ void blockstore_impl_t::dump_diagnostics()
void blockstore_meta_header_v3_t::set_crc32c()
{
header_csum = 0;
uint32_t calc = crc32c(0, this, sizeof(*this));
uint32_t calc = crc32c(0, this, version == BLOCKSTORE_META_FORMAT_HEAP
? sizeof(blockstore_meta_header_v3_t) : sizeof(blockstore_meta_header_v2_t));
header_csum = calc;
}
+2 -1
View File
@@ -7,7 +7,8 @@ add_executable(vitastor-disk
disk_tool.cpp disk_simple_offsets.cpp
disk_tool_discard.cpp disk_tool_journal.cpp disk_tool_meta.cpp disk_tool_prepare.cpp disk_tool_resize.cpp
disk_tool_resize_auto.cpp disk_tool_udev.cpp disk_tool_utils.cpp disk_tool_upgrade.cpp
../util/crc32c.c ../util/str_util.cpp ../util/json_util.cpp ../../json11/json11.cpp ../util/rw_blocking.cpp ../util/allocator.cpp ../util/ringloop.cpp ../blockstore/blockstore_disk.cpp
../util/crc32c.c ../util/str_util.cpp ../util/json_util.cpp ../../json11/json11.cpp ../util/rw_blocking.cpp ../util/allocator.cpp ../util/ringloop.cpp
../blockstore/blockstore_disk.cpp ../blockstore/blockstore_heap.cpp ../blockstore/multilist.cpp
)
target_link_libraries(vitastor-disk
tcmalloc_minimal
+1
View File
@@ -12,6 +12,7 @@
#include "blockstore.h"
#include "blockstore_disk.h"
#include "blockstore_heap.h"
#include "ondisk_formats.h"
// Calculate offsets for a block device and print OSD command line parameters
void disk_tool_simple_offsets(json11::Json cfg, bool json_output)
+34 -18
View File
@@ -192,12 +192,12 @@ static const char *help_text =
" You can specify any OSD device (data, metadata or journal), or the layout manually.\n"
"\n"
"vitastor-disk dump-meta <osd_device>\n"
"vitastor-disk dump-meta <meta_file> <meta_block_size> <offset> <size>\n"
"vitastor-disk dump-meta [osd_options...]\n"
" Dump metadata in JSON format.\n"
" You can specify any OSD device (data, metadata or journal), or the layout manually.\n"
"\n"
"vitastor-disk write-meta <osd_device>\n"
"vitastor-disk write-meta <meta_file> <offset> <size>\n"
"vitastor-disk write-meta [osd_options...]\n"
" Write metadata from JSON taken from standard input in the same format as produced by `dump-meta`.\n"
" You can specify any OSD device (data, metadata or journal), or the layout manually.\n"
"\n"
@@ -364,48 +364,64 @@ int main(int argc, char *argv[])
}
else if (!strcmp(cmd[0], "dump-meta"))
{
if (cmd.size() != 2 && cmd.size() < 5)
{
print_help(help_text, "vitastor-disk", cmd[0], false);
return 1;
}
self.dsk.meta_device = cmd[1];
if (cmd.size() > 2)
if (cmd.size() == 5)
{
// Old format
self.dsk.meta_device = cmd[1];
self.dsk.meta_block_size = strtoul(cmd[2], NULL, 10);
self.dsk.meta_offset = strtoull(cmd[3], NULL, 10);
self.dsk.meta_area_size = strtoull(cmd[4], NULL, 10);
}
else
else if (cmd.size() == 2)
{
// First argument is an OSD device - take metadata layout parameters from it
self.dsk.meta_device = cmd[1];
if (self.dump_load_check_superblock(self.dsk.meta_device))
return 1;
}
else
{
// Parse all OSD options from cmdline
self.dsk.parse_config(self.options);
if (self.options["io"] != "")
self.dsk.data_io = self.dsk.meta_io = self.dsk.journal_io = self.options["io"];
// FIXME: This is a really repeated pattern, move it somewhere
self.dsk.open_data();
self.dsk.open_meta();
self.dsk.open_journal();
self.dsk.calc_lengths();
self.dsk.close_all();
}
return self.dump_meta();
}
else if (!strcmp(cmd[0], "write-meta"))
{
if (cmd.size() != 2 && cmd.size() < 4)
{
print_help(help_text, "vitastor-disk", cmd[0], false);
return 1;
}
self.new_meta_device = cmd[1];
if (cmd.size() > 2)
if (cmd.size() == 4)
{
self.new_meta_device = cmd[1];
self.new_meta_offset = strtoull(cmd[2], NULL, 10);
self.new_meta_len = strtoull(cmd[3], NULL, 10);
}
else
else if (cmd.size() == 2)
{
// First argument is an OSD device - take metadata layout parameters from it
self.new_meta_device = cmd[1];
if (self.dump_load_check_superblock(self.new_meta_device))
return 1;
self.new_meta_device = self.dsk.meta_device;
self.new_meta_offset = self.dsk.meta_offset;
self.new_meta_len = self.dsk.meta_area_size;
}
else
{
// Parse all OSD options from cmdline
self.dsk.parse_config(self.options);
self.dsk.open_data();
self.dsk.open_meta();
self.dsk.open_journal();
self.dsk.calc_lengths();
self.dsk.close_all();
}
std::string json_err;
json11::Json meta = json11::Json::parse(read_all_fd(0), json_err);
if (json_err != "")
+32 -13
View File
@@ -16,6 +16,7 @@
#include "json11/json11.hpp"
#include "blockstore_disk.h"
#include "blockstore.h"
#include "blockstore_heap.h"
#include "ondisk_formats.h"
#include "crc32c.h"
#include "allocator.h"
@@ -46,7 +47,9 @@ struct disk_tool_t
std::map<std::string, std::string> options;
bool test_mode = false;
bool all = false, json = false, now = false;
bool dump_with_blocks, dump_with_data;
bool dump_with_blocks = false, dump_with_data = false;
bool dump_as_old = false;
int log_level = 1;
blockstore_disk_t dsk;
// resize data and/or move metadata and journal
@@ -61,25 +64,30 @@ struct disk_tool_t
uint64_t meta_pos;
uint64_t journal_pos, journal_calc_data_pos;
uint8_t *buffer_area = NULL;
bool first_block, first_entry;
allocator_t *data_alloc;
allocator_t *data_alloc = NULL;
std::map<uint64_t, uint64_t> data_remap;
std::map<uint64_t, uint64_t>::iterator remap_it;
ring_loop_t *ringloop;
ring_loop_t *ringloop = NULL;
ring_consumer_t ring_consumer;
int remap_active;
journal_entry_start je_start;
uint8_t *new_journal_buf, *new_meta_buf, *new_journal_ptr, *new_journal_data;
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;
blockstore_disk_t new_dsk;
blockstore_heap_t *new_heap = 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;
int new_journal_fd, new_meta_fd;
resizer_data_moving_t *moving_blocks;
uint32_t new_meta_format = 0;
int new_journal_fd = -1, new_meta_fd = -1;
resizer_data_moving_t *moving_blocks = NULL;
bool started;
void *small_write_data;
void *small_write_data = NULL;
uint32_t data_crc32;
bool data_csum_valid;
uint32_t crc32_last;
@@ -91,17 +99,24 @@ struct disk_tool_t
void dump_journal_entry(int num, journal_entry *je, bool json);
int process_journal(std::function<int(void*)> block_fn, bool do_open = true);
int process_journal_block(void *buf, std::function<void(int, journal_entry*)> iter_fn);
int process_meta(std::function<void(blockstore_meta_header_v2_t *)> hdr_fn,
std::function<void(uint64_t, clean_disk_entry*, uint8_t*)> record_fn, bool do_open = true);
int process_meta(std::function<void(blockstore_meta_header_v3_t *)> hdr_fn,
std::function<void(blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)> obj_fn,
std::function<void(uint64_t block_num, clean_disk_entry *entry_v1, uint8_t *bitmap)> record_fn,
bool with_data, bool do_open);
int dump_meta();
void dump_meta_header(blockstore_meta_header_v2_t *hdr);
void dump_meta_header(blockstore_meta_header_v3_t *hdr);
void dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap);
void dump_heap_entry_as_old(blockstore_heap_t *heap, heap_object_t *obj);
void dump_heap_entry(blockstore_heap_t *heap, heap_object_t *obj);
int dump_load_check_superblock(const std::string & device);
int write_json_journal(json11::Json entries);
int write_json_meta(json11::Json meta);
int write_json_heap(json11::Json meta, json11::Json journal);
int index_journal_by_object(json11::Json journal,
std::map<object_id, std::vector<json11::Json::object>> & journal_by_object);
int resize_data(std::string device);
int resize_parse_move_journal(std::map<std::string, std::string> & move_options, bool dry_run);
@@ -109,13 +124,17 @@ struct disk_tool_t
int raw_resize();
int resize_parse_params();
void resize_init(blockstore_meta_header_v2_t *hdr);
void resize_init(blockstore_meta_header_v3_t *hdr);
int resize_remap_blocks();
int resize_copy_data();
int resize_rewrite_journal();
void resize_alloc_journal();
void build_journal_start();
void choose_journal_block(uint32_t je_size);
int resize_rebuild_journal();
int resize_write_new_journal();
int resize_rewrite_meta();
int resize_rebuild_meta();
int resize_write_new_meta();
void free_new_meta();
int udev_import(std::string device);
int read_sb(std::string device);
+12 -2
View File
@@ -54,12 +54,22 @@ int disk_tool_t::trim_data(std::string device)
fprintf(stderr, "Reading metadata\n");
data_alloc = new allocator_t(dsk.block_count);
r = process_meta(
[this](blockstore_meta_header_v2_t *hdr) {},
[this](blockstore_meta_header_v3_t *hdr) {},
[this](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
{
for (auto wr = obj->get_writes(); wr; wr = wr->next())
{
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE)
{
data_alloc->set(wr->location / dsk.data_block_size, true);
}
}
},
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
{
data_alloc->set(block_num, true);
},
false
false, false
);
if (r != 0)
{
+620 -34
View File
@@ -7,37 +7,116 @@
#include "json_util.h"
#include "malloc_or_die.h"
int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)> hdr_fn,
std::function<void(uint64_t, clean_disk_entry*, uint8_t*)> record_fn, bool do_open)
#define FREE_SPACE_BIT 0x8000
int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v3_t *)> hdr_fn,
std::function<void(blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)> obj_fn,
std::function<void(uint64_t block_num, clean_disk_entry *entry_v1, uint8_t *bitmap)> record_fn,
bool with_data, bool do_open)
{
int r = 0;
if (dsk.meta_block_size % DIRECT_IO_ALIGNMENT)
{
fprintf(stderr, "Invalid metadata block size: is not a multiple of %d\n", DIRECT_IO_ALIGNMENT);
return 1;
}
int buf_size = 1024*1024;
if (buf_size % dsk.meta_block_size)
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;
if (do_open)
{
if (dsk.meta_fd >= 0)
{
fprintf(stderr, "Bug: Metadata device is already opened\n");
return 1;
close_error:
r = 1;
goto close_free;
}
dsk.meta_fd = open(dsk.meta_device.c_str(), (options["io"] == "cached" ? 0 : O_DIRECT) | O_RDONLY);
if (dsk.meta_fd < 0)
{
fprintf(stderr, "Failed to open metadata device %s: %s\n", dsk.meta_device.c_str(), strerror(errno));
return 1;
goto close_error;
}
}
int buf_size = 1024*1024;
if (buf_size % dsk.meta_block_size)
buf_size = 8*dsk.meta_block_size;
void *data = memalign_or_die(MEM_ALIGNMENT, buf_size);
else if (dsk.meta_fd < 0)
{
fprintf(stderr, "Bug: Metadata device is not opened\n");
goto close_error;
}
// Check superblock
blockstore_meta_header_v2_t *hdr = (blockstore_meta_header_v2_t *)data;
lseek64(dsk.meta_fd, dsk.meta_offset, 0);
read_blocking(dsk.meta_fd, hdr, dsk.meta_block_size);
if (hdr->zero == 0 && hdr->magic == BLOCKSTORE_META_MAGIC_V1)
if (hdr->zero == 0 && hdr->magic == BLOCKSTORE_META_MAGIC_V1 && hdr->version == BLOCKSTORE_META_FORMAT_HEAP)
{
if (hdr->data_csum_type != 0 &&
hdr->data_csum_type != BLOCKSTORE_CSUM_CRC32C)
{
goto csum_unknown;
}
if (!dsk.journal_len && !with_data)
{
fprintf(stderr, "Buffer area (former journal) location must be specified to dump \"heap\" with data\n");
goto close_error;
}
// Load buffer_area
if (with_data)
{
buffer_area = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, dsk.journal_len);
if (dsk.journal_device == dsk.meta_device || dsk.journal_device == "")
{
dsk.journal_fd = dsk.meta_fd;
}
else if (do_open)
{
if (dsk.journal_fd >= 0)
{
fprintf(stderr, "Bug: Metadata device is already opened\n");
goto close_error;
}
dsk.journal_fd = open(dsk.journal_device.c_str(), (options["io"] == "cached" ? 0 : O_DIRECT) | O_RDONLY);
if (dsk.journal_fd < 0)
{
fprintf(stderr, "Failed to open journal device %s: %s\n", dsk.journal_device.c_str(), strerror(errno));
goto close_error;
}
}
else if (dsk.journal_fd < 0)
{
fprintf(stderr, "Bug: journal device is not opened\n");
goto close_error;
}
uint64_t journal_pos = 0;
lseek64(dsk.journal_fd, dsk.journal_offset+journal_pos, 0);
while (journal_pos < dsk.journal_len)
{
uint64_t read_len = buf_size < dsk.journal_len-journal_pos ? buf_size : dsk.journal_len-journal_pos;
read_blocking(dsk.journal_fd, buffer_area+journal_pos, read_len);
journal_pos += read_len;
}
}
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;
meta_pos = dsk.meta_block_size;
lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0);
while (meta_pos < dsk.meta_area_size)
{
uint64_t read_len = buf_size < dsk.meta_area_size-meta_pos ? buf_size : dsk.meta_area_size-meta_pos;
read_blocking(dsk.meta_fd, data, read_len);
heap->read_blocks(meta_pos-dsk.meta_block_size, read_len, data, [&](heap_object_t *obj)
{
obj_fn(heap, obj, ((uint8_t*)obj-data+meta_pos)/dsk.meta_block_size);
}, [](uint32_t, uint32_t, uint8_t*){});
meta_pos += read_len;
}
delete heap;
}
else if (hdr->zero == 0 && hdr->magic == BLOCKSTORE_META_MAGIC_V1)
{
dsk.meta_format = hdr->version;
dsk.calc_lengths();
@@ -55,27 +134,16 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
if (hdr->data_csum_type != 0 &&
hdr->data_csum_type != BLOCKSTORE_CSUM_CRC32C)
{
csum_unknown:
fprintf(stderr, "I don't know checksum format %u, the only supported format is crc32c = %u.\n", hdr->data_csum_type, BLOCKSTORE_CSUM_CRC32C);
free(data);
if (do_open)
{
close(dsk.meta_fd);
dsk.meta_fd = -1;
}
return 1;
goto close_error;
}
}
else
{
// Unsupported version
fprintf(stderr, "Metadata format is too new for me (stored version is %ju, max supported %u).\n", hdr->version, BLOCKSTORE_META_FORMAT_V2);
free(data);
if (do_open)
{
close(dsk.meta_fd);
dsk.meta_fd = -1;
}
return 1;
goto close_error;
}
if (hdr->meta_block_size != dsk.meta_block_size)
{
@@ -100,9 +168,9 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
hdr = NULL;
meta_pos = dsk.meta_block_size;
lseek64(dsk.meta_fd, dsk.meta_offset+meta_pos, 0);
while (meta_pos < dsk.meta_area_size)
while (meta_pos < dsk.min_meta_len)
{
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 < dsk.min_meta_len-meta_pos ? buf_size : dsk.min_meta_len-meta_pos;
read_blocking(dsk.meta_fd, data, read_len);
meta_pos += read_len;
for (uint64_t blk = 0; blk < read_len; blk += dsk.meta_block_size)
@@ -117,7 +185,7 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
uint32_t *entry_csum = (uint32_t*)((uint8_t*)entry + dsk.clean_entry_size - 4);
if (*entry_csum != crc32c(0, entry, dsk.clean_entry_size - 4))
{
fprintf(stderr, "Metadata entry %ju is corrupt (checksum mismatch), skipping\n", block_num);
fprintf(stderr, "Metadata entry %lu is corrupt (checksum mismatch), skipping\n", block_num);
continue;
}
}
@@ -153,13 +221,25 @@ int disk_tool_t::process_meta(std::function<void(blockstore_meta_header_v2_t *)>
}
}
}
close_free:
free(data);
if (buffer_area)
{
free(buffer_area);
buffer_area = NULL;
}
if (do_open)
{
close(dsk.meta_fd);
dsk.meta_fd = -1;
if (dsk.journal_fd >= 0)
{
if (dsk.journal_fd != dsk.meta_fd)
close(dsk.journal_fd);
dsk.journal_fd = -1;
}
}
return 0;
return r;
}
int disk_tool_t::dump_load_check_superblock(const std::string & device)
@@ -190,15 +270,33 @@ int disk_tool_t::dump_load_check_superblock(const std::string & device)
int disk_tool_t::dump_meta()
{
int r = process_meta(
[this](blockstore_meta_header_v2_t *hdr) { dump_meta_header(hdr); },
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap) { dump_meta_entry(block_num, entry, bitmap); }
[this](blockstore_meta_header_v3_t *hdr)
{
if (dump_as_old)
{
hdr->version = BLOCKSTORE_META_FORMAT_V2;
hdr->compacted_lsn = 0;
hdr->header_csum = 0;
hdr->header_csum = crc32c(0, hdr, sizeof(blockstore_meta_header_v2_t));
}
dump_meta_header(hdr);
},
[this](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
{
if (dump_as_old)
dump_heap_entry_as_old(heap, obj);
else
dump_heap_entry(heap, obj);
},
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap) { dump_meta_entry(block_num, entry, bitmap); },
true, true
);
if (r == 0)
printf("\n]}\n");
return r;
}
void disk_tool_t::dump_meta_header(blockstore_meta_header_v2_t *hdr)
void disk_tool_t::dump_meta_header(blockstore_meta_header_v3_t *hdr)
{
if (hdr)
{
@@ -219,6 +317,15 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v2_t *hdr)
csum_type_str(hdr->data_csum_type).c_str(), hdr->csum_block_size
);
}
else if (hdr->version == BLOCKSTORE_META_FORMAT_HEAP)
{
printf(
"{\"version\":\"3.0\",\"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
);
}
}
else
{
@@ -227,6 +334,125 @@ void disk_tool_t::dump_meta_header(blockstore_meta_header_v2_t *hdr)
first_entry = true;
}
void disk_tool_t::dump_heap_entry_as_old(blockstore_heap_t *heap, heap_object_t *obj)
{
heap_write_t *wr = NULL;
for (wr = obj->get_writes(); wr && wr->flags != (BS_HEAP_BIG_WRITE|BS_HEAP_STABLE) &&
wr->flags != (BS_HEAP_TOMBSTONE|BS_HEAP_STABLE); wr = wr->next())
{
}
if (!wr || wr->flags != (BS_HEAP_BIG_WRITE|BS_HEAP_STABLE))
{
return;
}
printf(
#define ENTRY_FMT "{\"block\":%ju,\"pool\":%u,\"inode\":\"0x%jx\",\"stripe\":\"0x%jx\",\"version\":%ju"
(first_entry ? ENTRY_FMT : (",\n" ENTRY_FMT)),
#undef ENTRY_FMT
wr->location/dsk.data_block_size, INODE_POOL(obj->inode), INODE_NO_POOL(obj->inode),
obj->stripe, wr->version
);
printf(",\"bitmap\":\"");
uint8_t* bitmap = wr->get_int_bitmap(heap);
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
{
printf("%02x", bitmap[i]);
}
bitmap = wr->get_ext_bitmap(heap);
printf("\",\"ext_bitmap\":\"");
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
{
printf("%02x", bitmap[i]);
}
uint8_t *csums = wr->get_checksums(heap);
uint32_t csum_size = wr->get_csum_size(heap);
if (csums)
{
printf("\",\"block_csums\":\"");
for (uint32_t i = 0; i < csum_size; i++)
{
printf("%02x", csums[i]);
}
}
if (wr->get_checksum(heap))
{
printf("\",\"crc32c\":\"%08x", *wr->get_checksum(heap));
}
printf("\"}");
first_entry = false;
}
void disk_tool_t::dump_heap_entry(blockstore_heap_t *heap, heap_object_t *obj)
{
printf(
#define ENTRY_FMT "{\"pool\":%u,\"inode\":\"0x%jx\",\"stripe\":\"0x%jx\",\"writes\":["
(first_entry ? ENTRY_FMT : (",\n" ENTRY_FMT)),
#undef ENTRY_FMT
INODE_POOL(obj->inode), INODE_NO_POOL(obj->inode), obj->stripe
);
heap_write_t *wr = NULL;
bool first_wr = true;
for (wr = obj->get_writes(); wr; wr = wr->next())
{
printf(
#define ENTRY_FMT "{\"lsn\":%ju,\"version\":%ju,\"type\":\"%s\",\"stable\":%s,\"offset\":%u,\"len\":%u"
(first_wr ? ENTRY_FMT : ("," ENTRY_FMT)),
#undef ENTRY_FMT
wr->lsn, wr->version, (wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE ? "small" : (
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE ? "big" : (
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_INTENT_WRITE ? "intent" : (
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_TOMBSTONE ? "tombstone" : "unknown"))),
(wr->flags & BS_HEAP_STABLE) ? "true" : "false",
wr->offset, wr->len
);
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE ||
(wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE && !dump_with_data)
{
printf(",\"location\":%ju", wr->location);
}
else if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE && dump_with_data)
{
printf(",\"data\":\"");
for (uint32_t i = 0; i < wr->len; i++)
printf("%02x", buffer_area[wr->location + i]);
printf("\"");
}
uint8_t* bitmap = wr->get_int_bitmap(heap);
if (bitmap)
{
printf(",\"bitmap\":\"");
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
printf("%02x", bitmap[i]);
printf("\"");
}
bitmap = wr->get_ext_bitmap(heap);
if (bitmap)
{
printf(",\"ext_bitmap\":\"");
for (uint64_t i = 0; i < dsk.clean_entry_bitmap_size; i++)
printf("%02x", bitmap[i]);
printf("\"");
}
uint8_t *csums = wr->get_checksums(heap);
if (csums)
{
printf(",\"block_csums\":\"");
uint32_t csum_size = wr->get_csum_size(heap);
for (uint32_t i = 0; i < csum_size; i++)
printf("%02x", csums[i]);
printf("\"");
}
if (wr->get_checksum(heap))
{
printf(",\"data_crc32c\":\"%08x\"", *wr->get_checksum(heap));
}
printf("}");
first_wr = false;
}
printf("]}");
first_entry = false;
}
void disk_tool_t::dump_meta_entry(uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
{
printf(
@@ -289,7 +515,7 @@ int disk_tool_t::write_json_meta(json11::Json meta)
? BLOCKSTORE_CSUM_CRC32C
: BLOCKSTORE_CSUM_NONE);
new_hdr->csum_block_size = meta["csum_block_size"].uint64_value();
new_hdr->header_csum = crc32c(0, new_hdr, sizeof(*new_hdr));
new_hdr->header_csum = crc32c(0, new_hdr, sizeof(blockstore_meta_header_v2_t));
}
uint32_t new_clean_entry_header_size = (new_hdr->version == BLOCKSTORE_META_FORMAT_V1
? sizeof(clean_disk_entry) : sizeof(clean_disk_entry) + 4 /*entry_csum*/);
@@ -299,6 +525,7 @@ int disk_tool_t::write_json_meta(json11::Json meta)
: 0);
new_clean_entry_size = new_clean_entry_header_size + 2*new_clean_entry_bitmap_size + new_data_csum_size;
new_entries_per_block = new_hdr->meta_block_size / new_clean_entry_size;
// FIXME: Use a streaming json parser
for (const auto & e: meta["entries"].array_items())
{
uint64_t data_block = e["block"].uint64_value();
@@ -332,7 +559,366 @@ int disk_tool_t::write_json_meta(json11::Json meta)
}
}
int r = resize_write_new_meta();
free(new_meta_buf);
new_meta_buf = NULL;
free_new_meta();
return r;
}
int disk_tool_t::write_json_heap(json11::Json meta, json11::Json journal)
{
new_meta_hdr->zero = 0;
new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
new_meta_hdr->version = BLOCKSTORE_META_FORMAT_HEAP;
new_meta_hdr->meta_block_size = meta["meta_block_size"].uint64_value()
? meta["meta_block_size"].uint64_value() : 4096;
new_meta_hdr->data_block_size = meta["data_block_size"].uint64_value()
? meta["data_block_size"].uint64_value() : 131072;
new_meta_hdr->bitmap_granularity = meta["bitmap_granularity"].uint64_value()
? meta["bitmap_granularity"].uint64_value() : 4096;
new_meta_hdr->data_csum_type = meta["data_csum_type"].is_number()
? meta["data_csum_type"].uint64_value()
: (meta["data_csum_type"].string_value() == "crc32c"
? BLOCKSTORE_CSUM_CRC32C
: 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_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;
if (new_journal_len)
{
memset(new_journal_buf, 0, new_journal_len);
}
uint64_t total_used_space = 0;
uint32_t used_space = 0;
// FIXME: Use a streaming json parser
if (meta["version"] == "3.0")
{
// New format
std::vector<uint8_t> object_buf;
new_heap = new blockstore_heap_t(&dsk, new_journal_buf, 0);
for (const auto & meta_entry: meta["entries"].array_items())
{
bool invalid = false;
object_id oid = {
.inode = (sscanf_json(NULL, meta_entry["pool"]) << (64-POOL_ID_BITS)) | sscanf_json(NULL, meta_entry["inode"]),
.stripe = sscanf_json(NULL, meta_entry["stripe"]),
};
object_buf.clear();
object_buf.resize(sizeof(heap_object_t));
heap_object_t *obj = (heap_object_t*)object_buf.data();
obj->size = sizeof(heap_object_t);
obj->write_pos = meta_entry["writes"].array_items().size() ? sizeof(heap_object_t) : 0;
obj->inode = oid.inode;
obj->stripe = oid.stripe;
size_t pos = sizeof(heap_object_t);
heap_write_t *last_wr = NULL;
for (auto & write_entry: meta_entry["writes"].array_items())
{
object_buf.resize(object_buf.size() + new_heap->get_max_write_entry_size());
heap_write_t *wr = (heap_write_t*)(object_buf.data() + pos);
last_wr = wr;
uint8_t wr_type = 0;
if (write_entry["type"] == "small")
wr_type = BS_HEAP_SMALL_WRITE;
else if (write_entry["type"] == "intent")
wr_type = BS_HEAP_INTENT_WRITE;
else if (write_entry["type"] == "big")
wr_type = BS_HEAP_BIG_WRITE;
else if (write_entry["type"] == "tombstone")
wr_type = BS_HEAP_TOMBSTONE;
else
{
fprintf(stderr, "Write entry in %s has invalid type: %s, skipping object\n", meta_entry.dump().c_str(), write_entry["type"].dump().c_str());
invalid = true;
break;
}
wr->flags = wr_type | (write_entry["stable"].bool_value() ? BS_HEAP_STABLE : 0);
wr->lsn = write_entry["lsn"].uint64_value();
wr->version = write_entry["version"].uint64_value();
wr->offset = write_entry["offset"].uint64_value();
wr->len = write_entry["len"].uint64_value();
wr->location = write_entry["location"].uint64_value();
wr->size = wr->get_size(new_heap);
wr->next_pos = wr->size;
if (wr_type == BS_HEAP_SMALL_WRITE && write_entry["data"].is_string() && wr->len > 0)
{
if (!new_journal_buf)
{
fprintf(stderr, "Loading small write data requires overwriting buffer area\n");
free_new_meta();
return 1;
}
wr->location = new_heap->find_free_buffer_area(wr->len);
fromhexstr(write_entry["data"].string_value(), wr->len, new_journal_buf + wr->location);
}
if (write_entry["bitmap"].is_string() && wr->get_int_bitmap(new_heap))
{
fromhexstr(write_entry["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_int_bitmap(new_heap));
}
if (write_entry["ext_bitmap"].is_string() && wr->get_ext_bitmap(new_heap))
{
fromhexstr(write_entry["ext_bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(new_heap));
}
if (write_entry["block_csums"].is_string() && wr->get_checksums(new_heap))
{
fromhexstr(write_entry["block_csums"].string_value(), wr->get_csum_size(new_heap), wr->get_ext_bitmap(new_heap));
}
if (write_entry["data_crc32c"].is_string() && wr->get_checksum(new_heap))
{
*wr->get_checksum(new_heap) = sscanf_json("%jx", write_entry["data_crc32c"]);
}
}
if (invalid)
{
continue;
}
last_wr->next_pos = 0;
new_heap->copy_object(obj, NULL);
}
}
else
{
if (!journal.is_array())
{
fprintf(stderr, "Metadata should include journal in you want to convert it to the \"heap\" format\n");
close_err:
free(new_meta_buf);
new_meta_buf = NULL;
return 1;
}
std::map<object_id, std::vector<json11::Json::object>> journal_by_object;
if (index_journal_by_object(journal, journal_by_object) != 0)
{
goto close_err;
}
journal = json11::Json();
// Convert old format to the new format
uint64_t next_lsn = 0;
uint64_t meta_offset = 0;
const uint32_t space_per_object = sizeof(heap_object_t) + sizeof(heap_write_t) +
new_clean_entry_bitmap_size*2 + new_data_csum_size;
uint64_t buffer_pos = 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;
dsk.meta_block_target_free_space = 800;
blockstore_heap_t heap(&dsk, NULL, 0);
for (const auto & meta_entry: meta["entries"].array_items())
{
object_id oid = {
.inode = (sscanf_json(NULL, meta_entry["pool"]) << (64-POOL_ID_BITS)) | sscanf_json(NULL, meta_entry["inode"]),
.stripe = sscanf_json(NULL, meta_entry["stripe"]),
};
uint32_t space_for_this = space_per_object;
auto j_it = journal_by_object.find(oid);
if (j_it != journal_by_object.end())
{
for (auto & rec: j_it->second)
{
if (rec["type"] == "small_write" || rec["type"] == "small_write_instant")
{
uint64_t off = rec["offset"].uint64_value();
uint64_t len = rec["len"].uint64_value();
if (off+len > new_meta_hdr->data_block_size)
{
fprintf(stderr, "Journal entry has too large offset or length: %s\n", json11::Json(rec).dump().c_str());
goto close_err;
}
space_for_this += sizeof(heap_write_t) + new_clean_entry_bitmap_size +
((off+len+new_meta_hdr->csum_block_size-1)/new_meta_hdr->csum_block_size - off/new_meta_hdr->csum_block_size) * (new_meta_hdr->data_csum_type & 0xFF);
}
else /*if (rec["type"] == "big_write" || rec["type"] == "big_write_instant")*/
{
space_for_this += sizeof(heap_write_t) + 2*new_clean_entry_bitmap_size + new_data_csum_size;
}
}
}
if (space_for_this > new_meta_hdr->meta_block_size)
{
fprintf(stderr, "Object doesn't fit in a single metadata block. Object meta: %s, object journal: %s\n",
meta_entry.dump().c_str(), json11::Json(j_it->second).dump().c_str());
goto close_err;
}
if (used_space + space_for_this > new_meta_hdr->meta_block_size-dsk.meta_block_target_free_space)
{
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);
}
meta_offset += new_meta_hdr->meta_block_size;
used_space = 0;
if (meta_offset >= new_meta_len)
{
fprintf(stderr, "Metadata doesn't fit into the new area (total used space: %ju, minimum free space in block: %u/%u)\n",
total_used_space, dsk.meta_block_target_free_space, new_meta_hdr->meta_block_size);
goto close_err;
}
}
heap_object_t *obj = (heap_object_t*)(new_meta_buf + meta_offset + used_space);
obj->size = sizeof(heap_object_t);
obj->write_pos = sizeof(heap_object_t);
obj->inode = oid.inode;
obj->stripe = oid.stripe;
heap_write_t *wr = obj->get_writes();
wr->next_pos = 0;
wr->flags = BS_HEAP_BIG_WRITE|BS_HEAP_STABLE;
wr->lsn = ++next_lsn;
wr->version = sscanf_json(NULL, meta_entry["version"]);
wr->offset = 0;
wr->len = new_meta_hdr->data_block_size;
wr->location = meta_entry["block"].uint64_value() * new_meta_hdr->data_block_size;
wr->size = wr->get_size(&heap);
fromhexstr(meta_entry["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_int_bitmap(&heap));
fromhexstr(meta_entry["ext_bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(&heap));
if (new_meta_hdr->data_csum_type != 0)
fromhexstr(meta_entry["data_csum"].string_value(), new_data_csum_size, wr->get_checksums(&heap));
if (j_it != journal_by_object.end())
{
for (auto & rec: j_it->second)
{
wr->next_pos = wr->get_size(&heap);
wr = wr->next();
wr->next_pos = 0;
wr->lsn = ++next_lsn;
wr->version = rec["ver"].uint64_value();
wr->offset = rec["offset"].uint64_value();
wr->len = rec["len"].uint64_value();
if (rec["type"] == "small_write" || rec["type"] == "small_write_instant")
{
if (wr->len > 0 && !rec["data"].is_string())
{
fprintf(stderr, "Error: entry data is missing, please generate the dump with --json --format data\n");
goto close_err;
}
wr->flags = BS_HEAP_SMALL_WRITE | (rec["type"] == "small_write_instant" ? BS_HEAP_STABLE : 0);
fromhexstr(rec["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(&heap));
fromhexstr(rec["data"].string_value(), wr->len, new_journal_buf+buffer_pos);
if (wr->len > 0)
{
if (!new_meta_hdr->data_csum_type)
*wr->get_checksum(&heap) = crc32c(0, new_journal_buf+buffer_pos, wr->len);
else
heap.calc_block_checksums((uint32_t*)wr->get_checksums(&heap), new_journal_buf+buffer_pos, NULL, wr->offset, wr->offset+wr->len, true, NULL);
}
buffer_pos += wr->len;
}
else if (rec["type"] == "big_write" || rec["type"] == "big_write_instant")
{
wr->flags = BS_HEAP_BIG_WRITE | (rec["type"] == "big_write_instant" ? BS_HEAP_STABLE : 0);
wr->location = sscanf_json(NULL, rec["loc"]);
bitmap_set(wr->get_int_bitmap(&heap), wr->offset, wr->len, new_meta_hdr->bitmap_granularity);
fromhexstr(rec["bitmap"].string_value(), new_clean_entry_bitmap_size, wr->get_ext_bitmap(&heap));
if (new_meta_hdr->data_csum_type != 0)
{
if ((wr->offset % new_meta_hdr->csum_block_size) || (wr->len % new_meta_hdr->csum_block_size))
{
fprintf(stderr,
"Error: big_write journal entries not aligned to csum_block_size can't be converted between v0.9 and v3.0 metadata\n"
"Stop writes and flush the journal or convert OSDs one by one without the journal if you still want to do it.\n");
goto close_err;
}
fromhexstr(rec["block_csums"].string_value(),
((wr->offset+wr->len+new_meta_hdr->csum_block_size-1)/new_meta_hdr->csum_block_size
- wr->offset/new_meta_hdr->csum_block_size) * (new_meta_hdr->data_csum_type & 0xFF),
wr->get_checksums(&heap));
}
}
else
{
assert(0);
}
wr->size = wr->get_size(&heap);
}
}
obj->crc32c = obj->calc_crc32c();
assert(((uint8_t*)wr + wr->size - (uint8_t*)obj) == space_for_this);
used_space += space_for_this;
total_used_space += space_for_this;
}
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);
}
}
int r = resize_write_new_meta();
if (r == 0)
{
r = resize_write_new_journal();
}
free_new_meta();
return r;
}
int disk_tool_t::index_journal_by_object(json11::Json journal,
std::map<object_id, std::vector<json11::Json::object>> & journal_by_object)
{
for (const auto & rec: journal.array_items())
{
object_id oid = {
.inode = sscanf_json(NULL, rec["inode"]),
.stripe = sscanf_json(NULL, rec["stripe"]),
};
auto & jbo = journal_by_object[oid];
if (rec["type"] == "small_write" || rec["type"] == "small_write_instant")
{
jbo.push_back(rec.object_items());
}
else if (rec["type"] == "big_write" || rec["type"] == "big_write_instant")
{
if (rec["type"] == "big_write_instant")
jbo.clear();
jbo.push_back(rec.object_items());
}
else if (rec["type"] == "delete")
{
jbo.clear();
}
else if (rec["type"] == "stable")
{
uint64_t commit_to = rec["version"].uint64_value();
for (size_t i = 0; i < jbo.size(); i++)
{
if (jbo[i]["version"].uint64_value() <= commit_to)
{
if (jbo[i]["type"] == "big_write")
{
jbo.erase(jbo.begin(), jbo.begin()+i);
i = 0;
jbo[i]["type"] = "big_write_instant";
}
else if (jbo[i]["type"] == "small_write")
{
jbo[i]["type"] = "small_write_instant";
}
}
}
}
else if (rec["type"] == "rollback")
{
uint64_t rollback_to = rec["version"].uint64_value();
for (size_t i = jbo.size()-1; i >= 0; i--)
{
if (jbo[i]["version"].uint64_value() > rollback_to)
jbo.erase(jbo.begin()+i, jbo.begin()+i+1);
}
}
else
{
fprintf(stderr, "Unknown journal entry type: %s\n", rec.dump().c_str());
return -1;
}
}
return 0;
}
+3 -1
View File
@@ -9,6 +9,7 @@
int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_hdd, json11::Json::object & result)
{
static const char *allow_additional_params[] = {
"meta_format",
"data_csum_type",
"csum_block_size",
"autosync_writes",
@@ -128,7 +129,8 @@ int disk_tool_t::prepare_one(std::map<std::string, std::string> options, int is_
dsk.open_meta();
dsk.open_journal();
dsk.calc_lengths();
dsk.data_offset += (new_meta_len ? 0 : (dsk.meta_format == BLOCKSTORE_META_FORMAT_HEAP ? dsk.min_meta_len*2 : dsk.min_meta_len));
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);
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"] },
+358 -98
View File
@@ -1,6 +1,9 @@
// Copyright (c) Vitaliy Filippov, 2019+
// License: VNPL-1.1 (see README.md for details)
#define _XOPEN_SOURCE
#include <limits.h>
#include "disk_tool.h"
#include "rw_blocking.h"
#include "str_util.h"
@@ -25,65 +28,87 @@ int disk_tool_t::raw_resize()
// Parse parameters
r = resize_parse_params();
if (r != 0)
return r;
goto ret;
// Fill allocator
fprintf(stderr, "Reading metadata\n");
data_alloc = new allocator_t((new_data_len < dsk.data_len ? dsk.data_len : new_data_len) / dsk.data_block_size);
r = process_meta(
[this](blockstore_meta_header_v2_t *hdr)
[this](blockstore_meta_header_v3_t *hdr)
{
resize_init(hdr);
},
[this](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
{
for (auto wr = obj->get_writes(); wr; wr = wr->next())
{
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE)
{
data_alloc->set(wr->location / dsk.data_block_size, true);
}
}
},
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
{
data_alloc->set(block_num, true);
}
},
true, true
);
if (r != 0)
return r;
fprintf(stderr, "Reading journal\n");
r = process_journal([this](void *buf)
goto ret;
if (dsk.meta_format != BLOCKSTORE_META_FORMAT_HEAP)
{
return process_journal_block(buf, [this](int num, journal_entry *je)
fprintf(stderr, "Reading journal\n");
r = process_journal([this](void *buf)
{
if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
return process_journal_block(buf, [this](int num, journal_entry *je)
{
data_alloc->set(je->big_write.location / dsk.data_block_size, true);
}
if (je->type == JE_BIG_WRITE || je->type == JE_BIG_WRITE_INSTANT)
{
data_alloc->set(je->big_write.location / dsk.data_block_size, true);
}
});
});
});
if (r != 0)
return r;
if (r != 0)
goto ret;
}
// Remap blocks
r = resize_remap_blocks();
if (r != 0)
return r;
goto ret;
// Copy data blocks into new places
fprintf(stderr, "Moving data blocks\n");
r = resize_copy_data();
if (r != 0)
return r;
// Rewrite journal
fprintf(stderr, "Rebuilding journal\n");
r = resize_rewrite_journal();
if (r != 0)
return r;
goto ret;
// Rewrite metadata
resize_alloc_journal();
fprintf(stderr, "Rebuilding metadata\n");
r = resize_rewrite_meta();
r = resize_rebuild_meta();
if (r != 0)
return r;
goto ret;
if (new_meta_format != BLOCKSTORE_META_FORMAT_HEAP)
{
// Rewrite journal
fprintf(stderr, "Rebuilding journal\n");
r = resize_rebuild_journal();
if (r != 0)
goto ret;
fprintf(stderr, "Writing new journal\n");
}
else
fprintf(stderr, "Writing new buffer area\n");
// Write new journal
fprintf(stderr, "Writing new journal\n");
r = resize_write_new_journal();
if (r != 0)
return r;
goto ret;
// Write new metadata
fprintf(stderr, "Writing new metadata\n");
r = resize_write_new_meta();
if (r != 0)
return r;
goto ret;
fprintf(stderr, "Done\n");
ret:
free_new_meta();
return 0;
}
@@ -127,6 +152,8 @@ int disk_tool_t::resize_parse_params()
? parse_size(options["new_journal_offset"]) : dsk.journal_offset;
new_journal_len = options.find("new_journal_len") != options.end()
? parse_size(options["new_journal_len"]) : dsk.journal_len;
new_meta_format = options.find("new_meta_format") != options.end()
? stoull_full(options["new_meta_format"]) : 0;
if (new_data_len+new_data_offset > dsk.data_device_size)
new_data_len = dsk.data_device_size-new_data_offset;
if (new_meta_device == dsk.data_device && new_data_offset < new_meta_offset &&
@@ -152,7 +179,7 @@ int disk_tool_t::resize_parse_params()
return 0;
}
void disk_tool_t::resize_init(blockstore_meta_header_v2_t *hdr)
void disk_tool_t::resize_init(blockstore_meta_header_v3_t *hdr)
{
if (hdr && dsk.data_block_size != hdr->data_block_size)
{
@@ -171,6 +198,15 @@ void disk_tool_t::resize_init(blockstore_meta_header_v2_t *hdr)
dsk.data_csum_type = hdr->data_csum_type;
dsk.csum_block_size = hdr->csum_block_size;
}
if (hdr && dsk.meta_format != hdr->version)
{
dsk.meta_format = hdr->version;
}
if (new_meta_format == 0)
{
new_meta_format = hdr && hdr->version == BLOCKSTORE_META_FORMAT_HEAP ? BLOCKSTORE_META_FORMAT_HEAP : BLOCKSTORE_META_FORMAT_V2;
}
dsk.calc_lengths();
if (((new_data_offset-dsk.data_offset) % dsk.data_block_size))
{
fprintf(stderr, "Data alignment mismatch: old data offset is 0x%jx, new is 0x%jx, but alignment on %x should be equal\n",
@@ -360,15 +396,57 @@ int disk_tool_t::resize_copy_data()
return 0;
}
int disk_tool_t::resize_rewrite_journal()
void disk_tool_t::resize_alloc_journal()
{
// Simply overwriting on the fly may be impossible because old and new areas may overlap
// For now, just build new journal data in memory
new_journal_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_journal_len);
memset(new_journal_buf, 0, new_journal_len);
new_journal_ptr = new_journal_buf;
new_journal_data = new_journal_ptr + dsk.journal_block_size;
new_journal_in_pos = 0;
memset(new_journal_buf, 0, new_journal_len);
}
void disk_tool_t::build_journal_start()
{
journal_entry *ne = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
*((journal_entry_start*)ne) = (journal_entry_start){
.magic = JOURNAL_MAGIC,
.type = JE_START,
.size = sizeof(journal_entry_start),
.journal_start = dsk.journal_block_size,
.version = JOURNAL_VERSION_V2,
.data_csum_type = dsk.data_csum_type,
.csum_block_size = dsk.csum_block_size,
};
ne->crc32 = je_crc32(ne);
new_journal_ptr += dsk.journal_block_size;
new_journal_data = new_journal_ptr+dsk.journal_block_size;
new_journal_in_pos = 0;
}
void disk_tool_t::choose_journal_block(uint32_t je_size)
{
if (dsk.journal_block_size < new_journal_in_pos+je_size)
{
new_journal_ptr = new_journal_data;
if (new_journal_ptr-new_journal_buf >= new_journal_len)
{
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
exit(1);
}
new_journal_data = new_journal_ptr+dsk.journal_block_size;
new_journal_in_pos = 0;
if (dsk.journal_block_size < je_size)
{
fprintf(stderr, "Error: journal entry too large (%u bytes)\n", je_size);
exit(1);
}
}
}
int disk_tool_t::resize_rebuild_journal()
{
// Simply overwriting on the fly may be impossible because old and new areas may overlap
// For now, just build new journal data in memory
process_journal([this](void *buf)
{
return process_journal_block(buf, [this](int num, journal_entry *je)
@@ -385,39 +463,11 @@ int disk_tool_t::resize_rewrite_journal()
);
exit(1);
}
journal_entry *ne = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
*((journal_entry_start*)ne) = (journal_entry_start){
.magic = JOURNAL_MAGIC,
.type = JE_START,
.size = sizeof(journal_entry_start),
.journal_start = dsk.journal_block_size,
.version = JOURNAL_VERSION_V2,
.data_csum_type = dsk.data_csum_type,
.csum_block_size = dsk.csum_block_size,
};
ne->crc32 = je_crc32(ne);
new_journal_ptr += dsk.journal_block_size;
new_journal_data = new_journal_ptr+dsk.journal_block_size;
new_journal_in_pos = 0;
build_journal_start();
}
else
{
if (dsk.journal_block_size < new_journal_in_pos+je->size)
{
new_journal_ptr = new_journal_data;
if (new_journal_ptr-new_journal_buf >= new_journal_len)
{
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
exit(1);
}
new_journal_data = new_journal_ptr+dsk.journal_block_size;
new_journal_in_pos = 0;
if (dsk.journal_block_size < je->size)
{
fprintf(stderr, "Error: journal entry too large (%u bytes)\n", je->size);
exit(1);
}
}
choose_journal_block(je->size);
journal_entry *ne = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
memcpy(ne, je, je->size);
ne->crc32_prev = new_crc32_prev;
@@ -464,30 +514,173 @@ int disk_tool_t::resize_write_new_journal()
fsync(new_journal_fd);
close(new_journal_fd);
new_journal_fd = -1;
free(new_journal_buf);
new_journal_buf = NULL;
return 0;
}
int disk_tool_t::resize_rewrite_meta()
int disk_tool_t::resize_rebuild_meta()
{
new_meta_buf = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, new_meta_len);
memset(new_meta_buf, 0, new_meta_len);
if (new_meta_format == BLOCKSTORE_META_FORMAT_HEAP)
{
new_dsk = dsk;
new_dsk.data_offset = new_data_offset;
new_dsk.data_len = new_data_len;
new_dsk.block_count = new_data_len / dsk.data_block_size;
new_dsk.journal_device = new_journal_device;
new_dsk.journal_offset = new_journal_offset;
new_dsk.journal_len = new_journal_len;
new_dsk.meta_device = new_meta_device;
new_dsk.meta_offset = new_meta_offset;
new_dsk.meta_area_size = new_meta_len;
new_dsk.meta_format = new_meta_format;
new_heap = new blockstore_heap_t(&new_dsk, NULL, 0);
new_meta_hdr = (blockstore_meta_header_v3_t *)memalign_or_die(MEM_ALIGNMENT, dsk.meta_block_size);
memset(new_meta_hdr, 0, dsk.meta_block_size);
}
else
{
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;
}
std::vector<heap_write_t*> writes;
int r = process_meta(
[this](blockstore_meta_header_v2_t *hdr)
[&](blockstore_meta_header_v3_t *hdr)
{
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 = BLOCKSTORE_META_FORMAT_V2;
new_hdr->meta_block_size = dsk.meta_block_size;
new_hdr->data_block_size = dsk.data_block_size;
new_hdr->bitmap_granularity = dsk.bitmap_granularity ? dsk.bitmap_granularity : 4096;
new_hdr->data_csum_type = dsk.data_csum_type;
new_hdr->csum_block_size = dsk.csum_block_size;
new_hdr->header_csum = crc32c(0, new_hdr, sizeof(*new_hdr));
new_meta_hdr->zero = 0;
new_meta_hdr->magic = BLOCKSTORE_META_MAGIC_V1;
new_meta_hdr->version = new_meta_format == 0 ? BLOCKSTORE_META_FORMAT_HEAP : new_meta_format;
new_meta_hdr->meta_block_size = dsk.meta_block_size;
new_meta_hdr->data_block_size = dsk.data_block_size;
new_meta_hdr->bitmap_granularity = dsk.bitmap_granularity ? dsk.bitmap_granularity : 4096;
new_meta_hdr->data_csum_type = dsk.data_csum_type;
new_meta_hdr->csum_block_size = dsk.csum_block_size;
new_meta_hdr->compacted_lsn = hdr->compacted_lsn;
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));
if (hdr->version == BLOCKSTORE_META_FORMAT_HEAP && new_meta_format != BLOCKSTORE_META_FORMAT_HEAP)
{
build_journal_start();
}
},
[this](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
[&](blockstore_heap_t *heap, heap_object_t *obj, uint32_t meta_block_num)
{
for (auto wr = obj->get_writes(); wr; wr = wr->next())
{
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_BIG_WRITE)
{
if (wr->next() && new_meta_hdr->data_csum_type != 0 &&
((wr->offset % new_meta_hdr->csum_block_size) || (wr->len % new_meta_hdr->csum_block_size)))
{
fprintf(stderr, "Error: big_write journal entries not aligned to csum_block_size can't be converted between v0.9 and v3.0 metadata\n");
exit(1);
}
auto block_num = wr->location / dsk.data_block_size;
auto remap_it = data_remap.find(block_num);
if (remap_it != data_remap.end())
block_num = remap_it->second;
if (block_num < free_first || block_num >= total_blocks-free_last)
{
fprintf(stderr, "BUG: remapped block %ju not in range %ju..%ju\n", block_num, free_first, total_blocks-free_last);
exit(1);
}
block_num += data_idx_diff;
wr->location = block_num * dsk.data_block_size;
}
else if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE)
{
if (new_heap && wr->len > 0)
{
if (new_journal_ptr-new_journal_buf+wr->len > new_journal_len)
{
fprintf(stderr, "Small write data doesn't fit into the new buffer area\n");
exit(1);
}
memcpy(new_journal_ptr, buffer_area+wr->location, wr->len);
wr->location = new_journal_ptr-new_journal_buf;
new_journal_ptr += wr->len;
}
}
else if (!new_heap)
{
fprintf(stderr, "Object %jx:%jx can't be converted to the old format because it contains %s\n",
obj->inode, obj->stripe, (wr->flags & BS_HEAP_TYPE) == BS_HEAP_TOMBSTONE
? "a tombstone" : ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_INTENT_WRITE ? "an intent_write entry" : "an unknown entry"));
exit(1);
}
}
if (new_heap)
{
// New -> New
new_heap->copy_object(obj, NULL);
}
else
{
// Fill journal
writes.clear();
for (auto wr = obj->get_writes(); wr; wr = wr->next())
{
writes.push_back(wr);
}
for (ssize_t i = writes.size()-2; i >= 0; i--)
{
auto wr = writes[i];
assert((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE || wr->flags == BS_HEAP_BIG_WRITE);
uint32_t je_size = dsk.dirty_dyn_size(wr->offset, wr->len) +
((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE ? sizeof(journal_entry_small_write) : sizeof(journal_entry_big_write));
choose_journal_block(je_size);
journal_entry *je = (journal_entry*)(new_journal_ptr + new_journal_in_pos);
je->magic = JOURNAL_MAGIC;
je->type = (wr->flags & BS_HEAP_STABLE) ? JE_SMALL_WRITE_INSTANT : JE_SMALL_WRITE;
je->size = je_size;
je->crc32_prev = new_crc32_prev;
je->small_write.oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
je->small_write.version = wr->version;
je->small_write.offset = wr->offset;
je->small_write.len = wr->len;
if ((wr->flags & BS_HEAP_TYPE) == BS_HEAP_SMALL_WRITE)
{
je->small_write.data_offset = new_journal_data-new_journal_buf;
if (je->small_write.data_offset + je->small_write.len > new_journal_len)
{
fprintf(stderr, "Error: live entries don't fit to the new journal\n");
exit(1);
}
memcpy(new_journal_data, buffer_area+wr->location, je->small_write.len);
new_journal_data += je->small_write.len;
if (dsk.data_csum_type == 0 && wr->get_checksum(heap))
je->small_write.crc32_data = *wr->get_checksum(heap);
}
else
{
je->big_write.location = wr->location;
}
memcpy((uint8_t*)je + je->size, wr->get_ext_bitmap(heap), new_clean_entry_bitmap_size);
if (dsk.data_csum_type != 0 && wr->get_checksums(heap))
memcpy((uint8_t*)je + je->size + new_clean_entry_bitmap_size, wr->get_checksums(heap), new_data_csum_size);
je->crc32 = je_crc32(je);
new_journal_in_pos += je->size;
new_crc32_prev = je->crc32;
}
// New -> Old
if (writes[writes.size()-1]->flags == BS_HEAP_BIG_WRITE|BS_HEAP_STABLE)
{
auto big_wr = writes[writes.size()-1];
uint64_t block_num = big_wr->location / dsk.data_block_size;
clean_disk_entry *new_entry = (clean_disk_entry*)(new_meta_buf + dsk.meta_block_size +
dsk.meta_block_size*(block_num / new_entries_per_block) +
new_clean_entry_size*(block_num % new_entries_per_block));
new_entry->oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
new_entry->version = big_wr->version;
memcpy(new_entry->bitmap, big_wr->get_ext_bitmap(heap), new_clean_entry_bitmap_size);
memcpy(new_entry->bitmap + new_clean_entry_bitmap_size, big_wr->get_int_bitmap(heap), new_clean_entry_bitmap_size);
memcpy(new_entry->bitmap + 2*new_clean_entry_bitmap_size, big_wr->get_checksums(heap), new_data_csum_size);
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
*new_entry_csum = crc32c(0, new_entry, new_clean_entry_size - 4);
}
}
},
[&](uint64_t block_num, clean_disk_entry *entry, uint8_t *bitmap)
{
auto remap_it = data_remap.find(block_num);
if (remap_it != data_remap.end())
@@ -498,26 +691,44 @@ int disk_tool_t::resize_rewrite_meta()
exit(1);
}
block_num += data_idx_diff;
clean_disk_entry *new_entry = (clean_disk_entry*)(new_meta_buf + dsk.meta_block_size +
dsk.meta_block_size*(block_num / new_entries_per_block) +
new_clean_entry_size*(block_num % new_entries_per_block));
new_entry->oid = entry->oid;
new_entry->version = entry->version;
if (bitmap)
memcpy(new_entry->bitmap, bitmap, 2*new_clean_entry_bitmap_size + new_data_csum_size);
if (new_heap)
{
// Old -> New
uint8_t wr_buf[new_heap->get_max_write_entry_size()];
heap_write_t *wr = (heap_write_t*)wr_buf;
wr->flags = BS_HEAP_BIG_WRITE|BS_HEAP_STABLE;
wr->location = block_num * dsk.data_block_size;
wr->next_pos = 0;
wr->offset = 0;
wr->len = 0;
wr->size = wr->get_size(new_heap);
if (bitmap)
{
memcpy(wr->get_ext_bitmap(new_heap), bitmap, new_clean_entry_bitmap_size);
memcpy(wr->get_int_bitmap(new_heap), bitmap+new_clean_entry_bitmap_size, new_clean_entry_bitmap_size);
memcpy(wr->get_checksums(new_heap), bitmap+2*new_clean_entry_bitmap_size, new_data_csum_size);
}
new_heap->post_write(entry->oid, wr, NULL, NULL);
}
else
memset(new_entry->bitmap, 0xff, 2*new_clean_entry_bitmap_size);
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
*new_entry_csum = crc32c(0, new_entry, new_clean_entry_size - 4);
}
{
// Old -> Old
clean_disk_entry *new_entry = (clean_disk_entry*)(new_meta_buf + dsk.meta_block_size +
dsk.meta_block_size*(block_num / new_entries_per_block) +
new_clean_entry_size*(block_num % new_entries_per_block));
new_entry->oid = entry->oid;
new_entry->version = entry->version;
if (bitmap)
memcpy(new_entry->bitmap, bitmap, 2*new_clean_entry_bitmap_size + new_data_csum_size);
else
memset(new_entry->bitmap, 0xff, 2*new_clean_entry_bitmap_size);
uint32_t *new_entry_csum = (uint32_t*)(((uint8_t*)new_entry) + new_clean_entry_size - 4);
*new_entry_csum = crc32c(0, new_entry, new_clean_entry_size - 4);
}
},
true, true
);
if (r != 0)
{
free(new_meta_buf);
new_meta_buf = NULL;
return r;
}
return 0;
return r;
}
int disk_tool_t::resize_write_new_meta()
@@ -529,11 +740,60 @@ int disk_tool_t::resize_write_new_meta()
return 1;
}
lseek64(new_meta_fd, new_meta_offset, 0);
write_blocking(new_meta_fd, new_meta_buf, new_meta_len);
if (new_meta_buf)
{
write_blocking(new_meta_fd, new_meta_buf, new_meta_len);
}
else
{
assert(new_heap);
uint32_t new_meta_blocks = new_meta_len / dsk.meta_block_size - 1;
uint8_t *zero_block = (uint8_t*)memalign_or_die(MEM_ALIGNMENT, dsk.meta_block_size);
memset(zero_block, 0, dsk.meta_block_size);
std::vector<iovec> iov;
iov.reserve(IOV_MAX);
iov.push_back((iovec){ .iov_base = new_meta_hdr, .iov_len = dsk.meta_block_size });
for (uint32_t i = 0; i < new_meta_blocks; i++)
{
uint8_t *data = new_heap->get_meta_block(i);
iov.push_back((iovec){ .iov_base = data ? data : zero_block, .iov_len = dsk.meta_block_size });
if (iov.size() >= IOV_MAX)
{
writev_blocking(new_meta_fd, iov.data(), iov.size());
iov.clear();
}
}
if (iov.size() > 0)
writev_blocking(new_meta_fd, iov.data(), iov.size());
free(zero_block);
zero_block = NULL;
}
fsync(new_meta_fd);
close(new_meta_fd);
new_meta_fd = -1;
free(new_meta_buf);
new_meta_buf = NULL;
return 0;
}
void disk_tool_t::free_new_meta()
{
if (new_heap)
{
delete new_heap;
new_heap = NULL;
}
if ((uint8_t*)new_meta_hdr != new_meta_buf)
{
free(new_meta_hdr);
new_meta_hdr = NULL;
}
if (new_meta_buf)
{
free(new_meta_buf);
new_meta_buf = NULL;
}
if (new_journal_buf)
{
free(new_journal_buf);
new_journal_buf = NULL;
}
}
+4 -3
View File
@@ -82,8 +82,10 @@ int disk_tool_t::resize_data(std::string device)
auto new_meta_device = move_options.find("new_meta_device") != move_options.end()
? 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_data_offset = 4096 + (new_journal_device == dsk.data_device ? new_journal_len : 0) +
(new_meta_device == dsk.data_device ? dsk.meta_area_size : 0);
(new_meta_device == dsk.data_device ? new_meta_len : 0);
new_data_offset += ((dsk.data_offset-new_data_offset) % dsk.data_block_size);
if (new_data_offset != dsk.data_offset)
move_options["new_data_offset"] = std::to_string(new_data_offset);
@@ -236,7 +238,7 @@ int disk_tool_t::resize_parse_move_meta(std::map<std::string, std::string> & mov
auto new_journal_device = move_options.find("new_journal_device") != move_options.end()
? move_options["new_journal_device"] : dsk.journal_device;
move_options["new_meta_device"] = dsk.data_device;
move_options["new_meta_len"] = std::to_string(dsk.meta_area_size);
move_options["new_meta_len"] = std::to_string(new_meta_len);
}
else
{
@@ -246,7 +248,6 @@ int disk_tool_t::resize_parse_move_meta(std::map<std::string, std::string> & mov
std::string parent_dev = get_parent_device(real_dev);
if (parent_dev == "")
return 1;
uint64_t new_meta_len = 0;
if (parent_dev == real_dev)
{
// whole disk - create partition
+10 -6
View File
@@ -145,6 +145,9 @@ void _test_init(blockstore_disk_t & dsk, bool csum)
if (csum)
config["data_csum_type"] = "crc32c";
dsk.parse_config(config);
dsk.data_device = "data";
dsk.meta_device = "meta";
dsk.journal_device = "journal";
dsk.data_device_size = 1*1024*1024*1024;
dsk.meta_device_size = 4*1024*1024;
dsk.journal_device_size = 4*1024*1024;
@@ -1236,6 +1239,7 @@ void test_alloc_buffer()
heap.use_buffer_area(1, pos, 64*1024);
assert(heap.get_buffer_area_used_space() == (i+1)*64*1024);
assert(!heap.is_buffer_area_free(i*64*1024+4096, 4096));
assert(heap.is_buffer_area_free(i*64*1024+4096, 0)); // zero length is always free
if (i < 4096/64-1)
assert(heap.is_buffer_area_free((i+1)*64*1024, 64*1024));
}
@@ -1280,9 +1284,9 @@ void test_full_alloc()
dsk.data_device_size = 8*1024*1024;
dsk.meta_device_size = 5*4096;
dsk.journal_device_size = 4*1024*1024;
dsk.data_fd = 0;
dsk.meta_fd = 1;
dsk.journal_fd = 2;
dsk.data_device = "data";
dsk.meta_device = "meta";
dsk.journal_device = "journal";
dsk.calc_lengths();
std::vector<uint8_t> buffer_area(dsk.journal_device_size);
@@ -1581,9 +1585,9 @@ void test_move()
dsk.data_device_size = 8*1024*1024;
dsk.meta_device_size = 5*4096;
dsk.journal_device_size = 4*1024*1024;
dsk.data_fd = 0;
dsk.meta_fd = 1;
dsk.journal_fd = 2;
dsk.data_device = "data";
dsk.meta_device = "meta";
dsk.journal_device = "journal";
dsk.calc_lengths();
std::vector<uint8_t> buffer_area(dsk.journal_device_size);
+19 -12
View File
@@ -25,27 +25,34 @@ done
for i in $(seq 1 $OSD_COUNT); do
offsets=$(build/src/disk_tool/vitastor-disk simple-offsets --format json ./testdata/bin/test_osd$i.bin)
opts=$(build/src/disk_tool/vitastor-disk simple-offsets --format options ./testdata/bin/test_osd$i.bin)
meta_format=$(echo $offsets | jq -r .meta_format)
meta_offset=$(echo $offsets | jq -r .meta_offset)
data_offset=$(echo $offsets | jq -r .data_offset)
build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 0 $meta_offset >./testdata/journal_before_resize.json
build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd$i.bin 4096 $meta_offset $((data_offset-meta_offset)) >./testdata/meta_before_resize.json
#build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 0 $meta_offset >./testdata/journal_before_resize.json
#build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd$i.bin 4096 $meta_offset $((data_offset-meta_offset)) >./testdata/meta_before_resize.json
build/src/disk_tool/vitastor-disk dump-meta --io cached $opts >./testdata/meta_before_resize.json
new_data_offset=$((128*1024*1024+data_offset%131072))
build/src/disk_tool/vitastor-disk raw-resize --io cached \
$(build/src/disk_tool/vitastor-disk simple-offsets --format options ./testdata/bin/test_osd$i.bin 2>/dev/null) \
$opts \
--new_meta_offset 0 \
--new_meta_len $((1024*1024)) \
--new_journal_offset $((1024*1024)) \
--new_data_offset $((128*1024*1024+32768))
build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 $((1024*1024)) $((127*1024*1024)) >./testdata/journal_after_resize.json
build/src/disk_tool/vitastor-disk dump-meta --io cached ./testdata/bin/test_osd$i.bin 4096 0 $((1024*1024)) >./testdata/meta_after_resize.json
--new_data_offset $new_data_offset
#build/src/disk_tool/vitastor-disk dump-journal --io cached --json ./testdata/bin/test_osd$i.bin 4096 $((1024*1024)) $((127*1024*1024)) >./testdata/journal_after_resize.json
build/src/disk_tool/vitastor-disk dump-meta --io cached $opts \
--meta_offset 0 \
--meta_len $((1024*1024)) \
--journal_offset $((1024*1024)) \
--data_offset $new_data_offset >./testdata/meta_after_resize.json
if ! (cat ./testdata/meta_before_resize.json ./testdata/meta_after_resize.json | \
jq -e -s 'map([ .entries[] | del(.block) ] | sort_by(.pool, .inode, .stripe)) | .[0] == .[1] and (.[0] | length) > 1000'); then
jq -e -s 'map([ .entries[] | del(.block, .writes[].location) ] | sort_by(.pool, .inode, .stripe)) | .[0] == .[1] and (.[0] | length) > 1000'); then
format_error "OSD $i metadata corrupted after resizing"
fi
if ! (cat ./testdata/journal_before_resize.json ./testdata/journal_after_resize.json | \
jq -e -s 'map([ .[] | del(.crc32, .crc32_prev, .valid, .loc, .start) ]) | .[0] == .[1] and (.[0] | length) > 1'); then
format_error "OSD $i journal corrupted after resizing"
fi
#if ! (cat ./testdata/journal_before_resize.json ./testdata/journal_after_resize.json | \
# jq -e -s 'map([ .[] | del(.crc32, .crc32_prev, .valid, .loc, .start) ]) | .[0] == .[1] and (.[0] | length) > 1'); then
# format_error "OSD $i journal corrupted after resizing"
#fi
done
$ETCDCTL del --prefix /vitastor/osd/state/
@@ -56,7 +63,7 @@ for i in $(seq 1 $OSD_COUNT); do
--data_device ./testdata/bin/test_osd$i.bin \
--meta_offset 0 \
--journal_offset $((1024*1024)) \
--data_offset $((128*1024*1024+32768)) >>./testdata/osd$i.log 2>&1 &
--data_offset $new_data_offset >>./testdata/osd$i.log 2>&1 &
eval OSD${i}_PID=$!
done
+1 -1
View File
@@ -15,7 +15,7 @@ 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 --no_init 1 --meta_reserve 1x,1M \
sudo build/src/disk_tool/vitastor-disk-test prepare --meta_format 2 --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