qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

vpc: Require aligned size in .bdrv_co_create

Perform the rounding to match a CHS geometry only in the legacy code
path in .bdrv_co_create_opts. QMP now requires that the user already
passes a CHS aligned image size, unless force-size=true is given.

CHS alignment is required to make the image compatible with Virtual PC,
but not for use with newer Microsoft hypervisors.

Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Reviewed-by: Max Reitz <mreitz@redhat.com>

+82 -31
+82 -31
block/vpc.c
··· 902 902 return ret; 903 903 } 904 904 905 + static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts, 906 + uint16_t *out_cyls, 907 + uint8_t *out_heads, 908 + uint8_t *out_secs_per_cyl, 909 + int64_t *out_total_sectors, 910 + Error **errp) 911 + { 912 + int64_t total_size = vpc_opts->size; 913 + uint16_t cyls = 0; 914 + uint8_t heads = 0; 915 + uint8_t secs_per_cyl = 0; 916 + int64_t total_sectors; 917 + int i; 918 + 919 + /* 920 + * Calculate matching total_size and geometry. Increase the number of 921 + * sectors requested until we get enough (or fail). This ensures that 922 + * qemu-img convert doesn't truncate images, but rather rounds up. 923 + * 924 + * If the image size can't be represented by a spec conformant CHS geometry, 925 + * we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use 926 + * the image size from the VHD footer to calculate total_sectors. 927 + */ 928 + if (vpc_opts->force_size) { 929 + /* This will force the use of total_size for sector count, below */ 930 + cyls = VHD_CHS_MAX_C; 931 + heads = VHD_CHS_MAX_H; 932 + secs_per_cyl = VHD_CHS_MAX_S; 933 + } else { 934 + total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE); 935 + for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) { 936 + calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl); 937 + } 938 + } 939 + 940 + if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) { 941 + total_sectors = total_size / BDRV_SECTOR_SIZE; 942 + /* Allow a maximum disk size of 2040 GiB */ 943 + if (total_sectors > VHD_MAX_SECTORS) { 944 + error_setg(errp, "Disk size is too large, max size is 2040 GiB"); 945 + return -EFBIG; 946 + } 947 + } else { 948 + total_sectors = (int64_t) cyls * heads * secs_per_cyl; 949 + } 950 + 951 + *out_total_sectors = total_sectors; 952 + if (out_cyls) { 953 + *out_cyls = cyls; 954 + *out_heads = heads; 955 + *out_secs_per_cyl = secs_per_cyl; 956 + } 957 + 958 + return 0; 959 + } 960 + 905 961 static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts, 906 962 Error **errp) 907 963 { ··· 911 967 912 968 uint8_t buf[1024]; 913 969 VHDFooter *footer = (VHDFooter *) buf; 914 - int i; 915 970 uint16_t cyls = 0; 916 971 uint8_t heads = 0; 917 972 uint8_t secs_per_cyl = 0; ··· 953 1008 } 954 1009 blk_set_allow_write_beyond_eof(blk, true); 955 1010 956 - /* 957 - * Calculate matching total_size and geometry. Increase the number of 958 - * sectors requested until we get enough (or fail). This ensures that 959 - * qemu-img convert doesn't truncate images, but rather rounds up. 960 - * 961 - * If the image size can't be represented by a spec conformant CHS geometry, 962 - * we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use 963 - * the image size from the VHD footer to calculate total_sectors. 964 - */ 965 - if (vpc_opts->force_size) { 966 - /* This will force the use of total_size for sector count, below */ 967 - cyls = VHD_CHS_MAX_C; 968 - heads = VHD_CHS_MAX_H; 969 - secs_per_cyl = VHD_CHS_MAX_S; 970 - } else { 971 - total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE); 972 - for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) { 973 - calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl); 974 - } 1011 + /* Get geometry and check that it matches the image size*/ 1012 + ret = calculate_rounded_image_size(vpc_opts, &cyls, &heads, &secs_per_cyl, 1013 + &total_sectors, errp); 1014 + if (ret < 0) { 1015 + goto out; 975 1016 } 976 1017 977 - if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) { 978 - total_sectors = total_size / BDRV_SECTOR_SIZE; 979 - /* Allow a maximum disk size of 2040 GiB */ 980 - if (total_sectors > VHD_MAX_SECTORS) { 981 - error_setg(errp, "Disk size is too large, max size is 2040 GiB"); 982 - ret = -EFBIG; 983 - goto out; 984 - } 985 - } else { 986 - total_sectors = (int64_t)cyls * heads * secs_per_cyl; 987 - total_size = total_sectors * BDRV_SECTOR_SIZE; 1018 + if (total_size != total_sectors * BDRV_SECTOR_SIZE) { 1019 + error_setg(errp, "The requested image size cannot be represented in " 1020 + "CHS geometry"); 1021 + error_append_hint(errp, "Try size=%llu or force-size=on (the " 1022 + "latter makes the image incompatible with " 1023 + "Virtual PC)", 1024 + total_sectors * BDRV_SECTOR_SIZE); 1025 + ret = -EINVAL; 1026 + goto out; 988 1027 } 989 1028 990 1029 /* Prepare the Hard Disk Footer */ ··· 1101 1140 assert(create_options->driver == BLOCKDEV_DRIVER_VPC); 1102 1141 create_options->u.vpc.size = 1103 1142 ROUND_UP(create_options->u.vpc.size, BDRV_SECTOR_SIZE); 1143 + 1144 + if (!create_options->u.vpc.force_size) { 1145 + int64_t total_sectors; 1146 + ret = calculate_rounded_image_size(&create_options->u.vpc, NULL, NULL, 1147 + NULL, &total_sectors, errp); 1148 + if (ret < 0) { 1149 + goto fail; 1150 + } 1151 + 1152 + create_options->u.vpc.size = total_sectors * BDRV_SECTOR_SIZE; 1153 + } 1154 + 1104 1155 1105 1156 /* Create the vpc image (format layer) */ 1106 1157 ret = vpc_co_create(create_options, errp);