|
|
@ -39,12 +39,14 @@ void copy_blocks(int src, int dst, off64_t start, off64_t length) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size) |
|
|
|
void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size, int print_progress) |
|
|
|
{ |
|
|
|
// read input XML
|
|
|
|
char buf[XML_BUFSIZE] = { 0 }; |
|
|
|
char c = 0; |
|
|
|
long long start = 0, length = 0, total = 0; |
|
|
|
long long *offsets = NULL; |
|
|
|
int i, offsets_alloc = 0, offsets_len = 0; |
|
|
|
if (fgets(buf, XML_BUFSIZE, fp) == NULL) |
|
|
|
{ |
|
|
|
fprintf(stderr, "Input block list is empty\n"); |
|
|
@ -71,32 +73,51 @@ void read_era_invalidate_and_copy(FILE *fp, int src, int era_block_size) |
|
|
|
} |
|
|
|
start = start*era_block_size*512; |
|
|
|
length = length*era_block_size*512; |
|
|
|
if (src >= 0) |
|
|
|
if (offsets_len >= offsets_alloc) |
|
|
|
{ |
|
|
|
// write a very simple binary format: SIGNATURE, start, length, data, ...
|
|
|
|
write(1, SIGNATURE, 8); |
|
|
|
write(1, &start, 8); |
|
|
|
write(1, &length, 8); |
|
|
|
copy_blocks(src, 1, start, length); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
// calculate diff size
|
|
|
|
total += length; |
|
|
|
offsets_alloc += 4096/sizeof(long long); |
|
|
|
offsets = (long long*)realloc(offsets, offsets_alloc*2*sizeof(long long)); |
|
|
|
} |
|
|
|
offsets[offsets_len++] = start; |
|
|
|
offsets[offsets_len++] = length; |
|
|
|
// calculate diff size
|
|
|
|
total += length; |
|
|
|
} |
|
|
|
if (sscanf(buf, " </blocks > %c", &c) == 0 || c != 0) |
|
|
|
{ |
|
|
|
fprintf(stderr, "</blocks> expected, but \"%s\" found\n", buf); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
if (src < 0) |
|
|
|
if (src >= 0) |
|
|
|
{ |
|
|
|
long long copied = 0, prev_copied = 0; |
|
|
|
if (print_progress) |
|
|
|
{ |
|
|
|
setvbuf(stderr, NULL, _IONBF, 0); |
|
|
|
} |
|
|
|
for (i = 0; i < offsets_len; i += 2) |
|
|
|
{ |
|
|
|
if (print_progress && (!copied || copied >= prev_copied + 1048576)) |
|
|
|
{ |
|
|
|
fprintf(stderr, "\rDone %lld MB / %lld MB, copying next %lld MB...", copied/1048576, total/1048576, offsets[i+1]/1048576); |
|
|
|
prev_copied = copied; |
|
|
|
} |
|
|
|
// write a very simple binary format: SIGNATURE, start, length, data, ...
|
|
|
|
write(1, SIGNATURE, 8); |
|
|
|
write(1, offsets+i, 8); |
|
|
|
write(1, offsets+i+1, 8); |
|
|
|
copy_blocks(src, 1, offsets[i], offsets[i+1]); |
|
|
|
copied += offsets[i+1]; |
|
|
|
} |
|
|
|
fprintf(stderr, "\n"); |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
printf("%lld bytes\n", total); |
|
|
|
printf("%lld bytes to copy\n", total); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void era_copy(char *src_path, int era_block_size) |
|
|
|
void era_copy(char *src_path, int era_block_size, int print_progress) |
|
|
|
{ |
|
|
|
int src = -1; |
|
|
|
if (src_path != NULL) |
|
|
@ -108,7 +129,7 @@ void era_copy(char *src_path, int era_block_size) |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
} |
|
|
|
read_era_invalidate_and_copy(stdin, src, era_block_size); |
|
|
|
read_era_invalidate_and_copy(stdin, src, era_block_size, print_progress); |
|
|
|
if (src_path != NULL) |
|
|
|
{ |
|
|
|
close(src); |
|
|
@ -117,29 +138,30 @@ void era_copy(char *src_path, int era_block_size) |
|
|
|
|
|
|
|
int main(int narg, char *args[]) |
|
|
|
{ |
|
|
|
if (narg < 2) |
|
|
|
int print_progress = 0; |
|
|
|
if (narg < 2 || ((print_progress = !strcmp(args[1], "--progress")) && narg < 3)) |
|
|
|
{ |
|
|
|
fprintf(stderr, |
|
|
|
"era_copy - parses era_invalidate output and saves changed blocks to a stream\n" |
|
|
|
"(c) Vitaliy Filippov, 2019+, distributed under the terms of GNU GPLv3.0 or later license\n" |
|
|
|
"\n" |
|
|
|
"USAGE:\nera_invalidate --metadata-snapshot --written-since <ERA> <META_DEVICE> |\\\n" |
|
|
|
" era_copy <ERA_BLOCK_SIZE> [<DATA_DEVICE>] > era_copy.bin\n" |
|
|
|
" era_copy [--progress] <ERA_BLOCK_SIZE> [<DATA_DEVICE>] > era_copy.bin\n" |
|
|
|
"\n" |
|
|
|
"When invoked without <DATA_DEVICE>, era_copy only calculates the future diff size and prints it\n" |
|
|
|
"\n" |
|
|
|
"ERA_BLOCK_SIZE is dm-era's granularity in 512-byte sectors you used when creating dm-era device\n" |
|
|
|
"You can take it from `dmsetup table <DATA_DEVICE>`: it's the last number in DM table\n" |
|
|
|
"For example, in `0 3625546496 era 259:3 259:2 65536` it's 65536\n" |
|
|
|
"For example, in `0 3625546496 era 259:3 259:2 1024` it's 1024\n" |
|
|
|
); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
int bs = atoi(args[1]); |
|
|
|
int bs = atoi(args[print_progress ? 2 : 1]); |
|
|
|
if (bs < 1) |
|
|
|
{ |
|
|
|
fprintf(stderr, "Incorrect era_block_size = %d\n", bs); |
|
|
|
exit(1); |
|
|
|
} |
|
|
|
era_copy(narg == 2 ? NULL : args[2], bs); |
|
|
|
era_copy(narg == (print_progress ? 3 : 2) ? NULL : args[print_progress ? 3 : 2], bs, print_progress); |
|
|
|
return 0; |
|
|
|
} |
|
|
|