Fix unaligned last block read/write in cli_dd

This commit is contained in:
Vitaliy Filippov
2024-09-04 11:05:56 +03:00
parent 9f25bb059b
commit 9c2132882c
+70 -52
View File
@@ -44,7 +44,7 @@ struct dd_in_info_t
inode_watch_t *iwatch = NULL; inode_watch_t *iwatch = NULL;
int ifd = -1; int ifd = -1;
uint64_t in_size = 0; uint64_t in_size = 0;
uint32_t in_granularity = 0; uint32_t in_granularity = 1;
bool in_seekable = false; bool in_seekable = false;
void open_input(cli_tool_t *parent) void open_input(cli_tool_t *parent)
@@ -154,9 +154,10 @@ struct dd_out_info_t
uint64_t out_size = 0; uint64_t out_size = 0;
cli_result_t result; cli_result_t result;
bool old_progress = false;
inode_watch_t *owatch = NULL; inode_watch_t *owatch = NULL;
int ofd = -1; int ofd = -1;
uint32_t out_granularity = 0; uint32_t out_granularity = 1;
bool out_seekable = false; bool out_seekable = false;
std::function<bool(cli_result_t &)> sub_cb; std::function<bool(cli_result_t &)> sub_cb;
@@ -217,6 +218,7 @@ struct dd_out_info_t
{ {
out_size += (4096 - (out_size % 4096)); out_size += (4096 - (out_size % 4096));
} }
old_progress = parent->progress;
if (!owatch->cfg.num) if (!owatch->cfg.num)
{ {
if (!out_create) if (!out_create)
@@ -250,7 +252,8 @@ struct dd_out_info_t
return true; return true;
} }
// Resize output image // Resize output image
sub_cb = parent->start_create(json11::Json::object { parent->progress = false;
sub_cb = parent->start_modify(json11::Json::object {
{ "image", oimg }, { "image", oimg },
{ "resize", out_size }, { "resize", out_size },
}); });
@@ -267,6 +270,7 @@ resume_1:
state = base_state; state = base_state;
return false; return false;
} }
parent->progress = old_progress;
sub_cb = NULL; sub_cb = NULL;
if (result.err) if (result.err)
{ {
@@ -375,6 +379,7 @@ struct cli_dd_t
uint64_t in_iodepth = 0, out_iodepth = 0; uint64_t in_iodepth = 0, out_iodepth = 0;
uint64_t read_offset = 0, read_end = 0; uint64_t read_offset = 0, read_end = 0;
std::vector<dd_buf_t*> read_buffers, short_reads, short_writes; std::vector<dd_buf_t*> read_buffers, short_reads, short_writes;
std::vector<uint8_t*> zero_buf;
bool in_eof = false; bool in_eof = false;
uint64_t written_size = 0; uint64_t written_size = 0;
uint64_t written_progress = 0; uint64_t written_progress = 0;
@@ -405,6 +410,11 @@ struct cli_dd_t
return 0; return 0;
} }
uint64_t round_up(uint64_t n, uint64_t align)
{
return (n % align) ? (n + align - (n % align)) : n;
}
void vitastor_read_bitmap(dd_buf_t *cur_read) void vitastor_read_bitmap(dd_buf_t *cur_read)
{ {
cluster_op_t *read_op = new cluster_op_t; cluster_op_t *read_op = new cluster_op_t;
@@ -412,22 +422,19 @@ struct cli_dd_t
read_op->inode = iinfo.iwatch->cfg.num; read_op->inode = iinfo.iwatch->cfg.num;
// FIXME: Support unaligned read? // FIXME: Support unaligned read?
read_op->offset = cur_read->offset + iseek; read_op->offset = cur_read->offset + iseek;
read_op->len = cur_read->max; read_op->len = round_up(round_up(cur_read->max, iinfo.in_granularity), oinfo.out_granularity);
in_waiting++; in_waiting++;
read_op->callback = [this, cur_read](cluster_op_t *read_op) read_op->callback = [this, cur_read](cluster_op_t *read_op)
{ {
in_waiting--; in_waiting--;
if (read_op->retval < 0) if (read_op->retval < 0)
{ {
if (ignore_errors) fprintf(
{ stderr, "Failed to read bitmap for %lu bytes from image %s at offset %lu: %s (code %d)\n",
fprintf( read_op->len, iinfo.iimg.c_str(), read_op->offset,
stderr, "Failed to read bitmap for %lu bytes from image %s at offset %lu: %s (code %d)\n", strerror(read_op->retval < 0 ? -read_op->retval : EIO), read_op->retval
read_op->len, iinfo.iimg.c_str(), read_op->offset, );
strerror(read_op->retval < 0 ? -read_op->retval : EIO), read_op->retval if (!ignore_errors)
);
}
else
{ {
copy_error = read_op->retval < 0 ? -read_op->retval : EIO; copy_error = read_op->retval < 0 ? -read_op->retval : EIO;
} }
@@ -454,23 +461,25 @@ struct cli_dd_t
read_op->inode = iinfo.iwatch->cfg.num; read_op->inode = iinfo.iwatch->cfg.num;
// FIXME: Support unaligned read? // FIXME: Support unaligned read?
read_op->offset = cur_read->offset + iseek; read_op->offset = cur_read->offset + iseek;
read_op->len = cur_read->max; read_op->len = round_up(round_up(cur_read->max, iinfo.in_granularity), oinfo.out_granularity);
read_op->iov.push_back(cur_read->buf, cur_read->max); read_op->iov.push_back(cur_read->buf, cur_read->max);
if (cur_read->max < read_op->len)
{
// Zero pad
read_op->iov.push_back(zero_buf.data(), read_op->len - cur_read->max);
}
in_waiting++; in_waiting++;
read_op->callback = [this, cur_read](cluster_op_t *read_op) read_op->callback = [this, cur_read](cluster_op_t *read_op)
{ {
in_waiting--; in_waiting--;
if (read_op->retval != read_op->len) if (read_op->retval != read_op->len)
{ {
if (ignore_errors) fprintf(
{ stderr, "Failed to read %lu bytes from image %s at offset %lu: %s (code %d)\n",
fprintf( read_op->len, iinfo.iimg.c_str(), read_op->offset,
stderr, "Failed to read %lu bytes from image %s at offset %lu: %s (code %d)\n", strerror(read_op->retval < 0 ? -read_op->retval : EIO), read_op->retval
read_op->len, iinfo.iimg.c_str(), read_op->offset, );
strerror(read_op->retval < 0 ? -read_op->retval : EIO), read_op->retval if (!ignore_errors)
);
}
else
{ {
copy_error = read_op->retval < 0 ? -read_op->retval : EIO; copy_error = read_op->retval < 0 ? -read_op->retval : EIO;
} }
@@ -536,15 +545,12 @@ struct cli_dd_t
in_waiting--; in_waiting--;
if (data->res < 0) if (data->res < 0)
{ {
if (ignore_errors) fprintf(
{ stderr, "Failed to read %lu bytes from %s at offset %lu: %s (code %d)\n",
fprintf( data->iov.iov_len, iinfo.ifile == "" ? "stdin" : iinfo.ifile.c_str(), cur_read->offset,
stderr, "Failed to read %lu bytes from %s at offset %lu: %s (code %d)\n", strerror(-data->res), data->res
data->iov.iov_len, iinfo.ifile == "" ? "stdin" : iinfo.ifile.c_str(), cur_read->offset, );
strerror(-data->res), data->res if (!ignore_errors)
);
}
else
{ {
copy_error = -data->res; copy_error = -data->res;
} }
@@ -623,23 +629,25 @@ struct cli_dd_t
write_op->inode = oinfo.owatch->cfg.num; write_op->inode = oinfo.owatch->cfg.num;
// FIXME: Support unaligned write? // FIXME: Support unaligned write?
write_op->offset = cur_read->offset + oseek; write_op->offset = cur_read->offset + oseek;
write_op->len = cur_read->max; write_op->len = round_up(cur_read->max, oinfo.out_granularity);
write_op->iov.push_back(cur_read->buf, cur_read->max); write_op->iov.push_back(cur_read->buf, cur_read->max);
if (cur_read->max < write_op->len)
{
// Zero pad
write_op->iov.push_back(zero_buf.data(), write_op->len - cur_read->max);
}
out_waiting++; out_waiting++;
write_op->callback = [this, cur_read](cluster_op_t *write_op) write_op->callback = [this, cur_read](cluster_op_t *write_op)
{ {
out_waiting--; out_waiting--;
if (write_op->retval != write_op->len) if (write_op->retval != write_op->len)
{ {
if (ignore_errors) fprintf(
{ stderr, "Failed to write %lu bytes to image %s at offset %lu: %s (code %d)\n",
fprintf( write_op->len, oinfo.oimg.c_str(), write_op->offset,
stderr, "Failed to write %lu bytes to image %s at offset %lu: %s (code %d)\n", strerror(write_op->retval < 0 ? -write_op->retval : EIO), write_op->retval
write_op->len, oinfo.oimg.c_str(), write_op->offset, );
strerror(write_op->retval < 0 ? -write_op->retval : EIO), write_op->retval if (!ignore_errors)
);
}
else
{ {
copy_error = write_op->retval < 0 ? -write_op->retval : EIO; copy_error = write_op->retval < 0 ? -write_op->retval : EIO;
} }
@@ -670,16 +678,13 @@ struct cli_dd_t
out_waiting--; out_waiting--;
if (data->res < 0) if (data->res < 0)
{ {
if (ignore_errors) fprintf(
{ stderr, "Failed to write %lu bytes to %s at offset %lu: %s (code %d)\n",
fprintf( data->iov.iov_len, oinfo.ofile == "" ? "stdout" : oinfo.ofile.c_str(),
stderr, "Failed to write %lu bytes to %s at offset %lu: %s (code %d)\n", oinfo.out_seekable ? cur_read->offset+cur_read->len+oseek : 0,
data->iov.iov_len, oinfo.ofile == "" ? "stdout" : oinfo.ofile.c_str(), strerror(-data->res), data->res
oinfo.out_seekable ? cur_read->offset+cur_read->len+oseek : 0, );
strerror(-data->res), data->res if (!ignore_errors)
);
}
else
{ {
copy_error = -data->res; copy_error = -data->res;
} }
@@ -773,6 +778,7 @@ struct cli_dd_t
state = 100; state = 100;
return; return;
} }
zero_buf.resize(blocksize);
// Open input and output // Open input and output
iinfo.open_input(parent); iinfo.open_input(parent);
if (iinfo.result.err) if (iinfo.result.err)
@@ -781,6 +787,13 @@ struct cli_dd_t
state = 100; state = 100;
return; return;
} }
if (iinfo.iwatch && ((iseek % iinfo.in_granularity) || (blocksize % iinfo.in_granularity)))
{
iinfo.close_input(parent);
result = (cli_result_t){ .err = EINVAL, .text = "Unaligned read from Vitastor is not supported" };
state = 100;
return;
}
if (!oinfo.out_size) if (!oinfo.out_size)
{ {
oinfo.out_size = oseek + (iinfo.in_seekable && (!bytelimit || iinfo.in_size-iseek < bytelimit) ? iinfo.in_size-iseek : bytelimit); oinfo.out_size = oseek + (iinfo.in_seekable && (!bytelimit || iinfo.in_size-iseek < bytelimit) ? iinfo.in_size-iseek : bytelimit);
@@ -798,6 +811,11 @@ resume_2:
state = 100; state = 100;
return; return;
} }
if (oinfo.owatch && ((oseek % oinfo.out_granularity) || (blocksize % oinfo.out_granularity)))
{
result = (cli_result_t){ .err = EINVAL, .text = "Unaligned write to Vitastor is not supported" };
goto close_end;
}
// Copy data // Copy data
if (iinfo.in_seekable && iseek >= iinfo.in_size) if (iinfo.in_seekable && iseek >= iinfo.in_size)
{ {