Revision a22f123c qemu-img.c
b/qemu-img.c | ||
---|---|---|
82 | 82 |
" rebasing in this case (useful for renaming the backing file)\n" |
83 | 83 |
" '-h' with or without a command shows this help and lists the supported formats\n" |
84 | 84 |
" '-p' show progress of command (only certain commands)\n" |
85 |
" '-S' indicates the consecutive number of bytes that must contain only zeros\n" |
|
86 |
" for qemu-img to create a sparse image during conversion\n" |
|
85 | 87 |
"\n" |
86 | 88 |
"Parameters to snapshot subcommand:\n" |
87 | 89 |
" 'snapshot' is the name of the snapshot to create, apply or delete\n" |
... | ... | |
571 | 573 |
} |
572 | 574 |
|
573 | 575 |
/* |
576 |
* Like is_allocated_sectors, but if the buffer starts with a used sector, |
|
577 |
* up to 'min' consecutive sectors containing zeros are ignored. This avoids |
|
578 |
* breaking up write requests for only small sparse areas. |
|
579 |
*/ |
|
580 |
static int is_allocated_sectors_min(const uint8_t *buf, int n, int *pnum, |
|
581 |
int min) |
|
582 |
{ |
|
583 |
int ret; |
|
584 |
int num_checked, num_used; |
|
585 |
|
|
586 |
if (n < min) { |
|
587 |
min = n; |
|
588 |
} |
|
589 |
|
|
590 |
ret = is_allocated_sectors(buf, n, pnum); |
|
591 |
if (!ret) { |
|
592 |
return ret; |
|
593 |
} |
|
594 |
|
|
595 |
num_used = *pnum; |
|
596 |
buf += BDRV_SECTOR_SIZE * *pnum; |
|
597 |
n -= *pnum; |
|
598 |
num_checked = num_used; |
|
599 |
|
|
600 |
while (n > 0) { |
|
601 |
ret = is_allocated_sectors(buf, n, pnum); |
|
602 |
|
|
603 |
buf += BDRV_SECTOR_SIZE * *pnum; |
|
604 |
n -= *pnum; |
|
605 |
num_checked += *pnum; |
|
606 |
if (ret) { |
|
607 |
num_used = num_checked; |
|
608 |
} else if (*pnum >= min) { |
|
609 |
break; |
|
610 |
} |
|
611 |
} |
|
612 |
|
|
613 |
*pnum = num_used; |
|
614 |
return 1; |
|
615 |
} |
|
616 |
|
|
617 |
/* |
|
574 | 618 |
* Compares two buffers sector by sector. Returns 0 if the first sector of both |
575 | 619 |
* buffers matches, non-zero otherwise. |
576 | 620 |
* |
... | ... | |
620 | 664 |
char *options = NULL; |
621 | 665 |
const char *snapshot_name = NULL; |
622 | 666 |
float local_progress; |
667 |
int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */ |
|
623 | 668 |
|
624 | 669 |
fmt = NULL; |
625 | 670 |
out_fmt = "raw"; |
... | ... | |
627 | 672 |
out_baseimg = NULL; |
628 | 673 |
compress = 0; |
629 | 674 |
for(;;) { |
630 |
c = getopt(argc, argv, "f:O:B:s:hce6o:pt:"); |
|
675 |
c = getopt(argc, argv, "f:O:B:s:hce6o:pS:t:");
|
|
631 | 676 |
if (c == -1) { |
632 | 677 |
break; |
633 | 678 |
} |
... | ... | |
662 | 707 |
case 's': |
663 | 708 |
snapshot_name = optarg; |
664 | 709 |
break; |
710 |
case 'S': |
|
711 |
{ |
|
712 |
int64_t sval; |
|
713 |
sval = strtosz_suffix(optarg, NULL, STRTOSZ_DEFSUFFIX_B); |
|
714 |
if (sval < 0) { |
|
715 |
error_report("Invalid minimum zero buffer size for sparse output specified"); |
|
716 |
return 1; |
|
717 |
} |
|
718 |
|
|
719 |
min_sparse = sval / BDRV_SECTOR_SIZE; |
|
720 |
break; |
|
721 |
} |
|
665 | 722 |
case 'p': |
666 | 723 |
progress = 1; |
667 | 724 |
break; |
... | ... | |
970 | 1027 |
sectors that are entirely 0, since whatever data was |
971 | 1028 |
already there is garbage, not 0s. */ |
972 | 1029 |
if (!has_zero_init || out_baseimg || |
973 |
is_allocated_sectors(buf1, n, &n1)) {
|
|
1030 |
is_allocated_sectors_min(buf1, n, &n1, min_sparse)) {
|
|
974 | 1031 |
ret = bdrv_write(out_bs, sector_num, buf1, n1); |
975 | 1032 |
if (ret < 0) { |
976 | 1033 |
error_report("error while writing sector %" PRId64 |
Also available in: Unified diff