Disk manufacturers are fond of quoting sizes in powers of 10,
rather than powers of 2 (after all, 2.1 GB sounds larger than
2.0 GiB, even though the exact opposite is true). So, we might
as well follow coreutils lead in supporting three types of
suffix: single letter ${u} (which we already had) and ${u}iB
for the power of 2, and ${u}B for power of 10.
Additionally, it is impossible to create a file with more than
2**63 bytes, since off_t is signed (if you have enough storage
to even create one 8EiB file, I'm jealous). This now reports
failure up front rather than down the road when the kernel
finally refuses an impossible size.
* docs/schemas/basictypes.rng (unit): Add suffixes.
* src/conf/storage_conf.c (virStorageSize): Use new function.
* docs/formatstorage.html.in: Document it.
---
v2: new
docs/formatstorage.html.in | 21 +++++---
docs/schemas/basictypes.rng | 2 +-
src/conf/storage_conf.c | 61 +++---------------------
tests/storagevolxml2xmlin/vol-file-backing.xml | 4 +-
tests/storagevolxml2xmlin/vol-file.xml | 4 +-
5 files changed, 26 insertions(+), 66 deletions(-)
diff --git a/docs/formatstorage.html.in b/docs/formatstorage.html.in
index 93d8ab2..b0acaf3 100644
--- a/docs/formatstorage.html.in
+++ b/docs/formatstorage.html.in
@@ -236,13 +236,20 @@
<br/>
By default this is specified in bytes, but an optional
<code>unit</code> can be specified to adjust the passed value.
- Values can be: 'K' (kibibytes, 2<sup>10</sup> or 1024),
'M'
- (mebibytes, 2<sup>20</sup> or 1,048,576), 'G' (gibibytes,
- 2<sup>30</sup> or 1,073,741,824), 'T' (tebibytes,
- 2<sup>40</sup> or 1,099,511,627,776), 'P' (pebibytes,
- 2<sup>50</sup> or 1,125,899,906,842,624), or 'E' (exbibytes,
- 2<sup>60</sup> or 1,152,921,504,606,846,976).
- <span class="since">Since 0.4.1</span></dd>
+ Values can be: 'B' or 'bytes' for bytes, 'KB'
(kilobytes,
+ 10<sup>3</sup> or 1000), 'K' or 'KiB' (kibibytes,
+ 2<sup>10</sup> or 1024), 'MB' (megabytes,
10<sup>6</sup> or
+ 1,000,000), 'M' or 'MiB' (mebibytes, 2<sup>20</sup>
or
+ 1,048,576), 'GB' (gigabytes, 10<sup>9</sup> or
1,000,000,000),
+ 'G' or 'GiB' (gibibytes, 2<sup>30</sup> or
1,073,741,824),
+ 'TB' (terabytes, 10<sup>12</sup> or 1,000,000,000,000),
'T' or
+ 'TiB' (tebibytes, 2<sup>40</sup> or 1,099,511,627,776),
'PB'
+ (petabytes, 10<sup>15</sup> or 1,000,000,000,000,000), 'P'
or
+ 'PiB' (pebibytes, 2<sup>50</sup> or 1,125,899,906,842,624),
+ 'EB' (exabytes, 10<sup>18</sup> or
1,000,000,000,000,000,000),
+ or 'E' or 'EiB' (exbibytes, 2<sup>60</sup> or
+ 1,152,921,504,606,846,976). <span class="since">Since 0.4.1,
+ multi-character <code>unit</code> since
0.9.11</span></dd>
<dt><code>capacity</code></dt>
<dd>Providing the logical capacity for the volume. This value is
in bytes by default, but a <code>unit</code> attribute can be
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index a50349c..cc0bc12 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -140,7 +140,7 @@
<define name='unit'>
<data type='string'>
- <param name='pattern'>(bytes)|[kKmMgGtTpPeE]</param>
+ <param
name='pattern'>([bB]([yY][tT][eE][sS]?)?)|([kKmMgGtTpPeE]([iI]?[bB])?)</param>
</data>
</define>
<define name='scaledInteger'>
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index 07f3f5b..d1558ee 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -944,64 +944,17 @@ virStoragePoolDefFormat(virStoragePoolDefPtr def) {
static int
virStorageSize(const char *unit,
const char *val,
- unsigned long long *ret) {
- unsigned long long mult;
- char *end;
-
- if (!unit) {
- mult = 1;
- } else {
- switch (unit[0]) {
- case 'k':
- case 'K':
- mult = 1024ull;
- break;
-
- case 'm':
- case 'M':
- mult = 1024ull * 1024ull;
- break;
-
- case 'g':
- case 'G':
- mult = 1024ull * 1024ull * 1024ull;
- break;
-
- case 't':
- case 'T':
- mult = 1024ull * 1024ull * 1024ull * 1024ull;
- break;
-
- case 'p':
- case 'P':
- mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull;
- break;
-
- case 'e':
- case 'E':
- mult = 1024ull * 1024ull * 1024ull * 1024ull * 1024ull *
- 1024ull;
- break;
-
- default:
- virStorageReportError(VIR_ERR_XML_ERROR,
- _("unknown size units '%s'"), unit);
- return -1;
- }
- }
-
- if (virStrToLong_ull (val, &end, 10, ret) < 0) {
+ unsigned long long *ret)
+{
+ if (virStrToLong_ull(val, NULL, 10, ret) < 0) {
virStorageReportError(VIR_ERR_XML_ERROR,
"%s", _("malformed capacity
element"));
return -1;
}
- if (*ret > (ULLONG_MAX / mult)) {
- virStorageReportError(VIR_ERR_XML_ERROR,
- "%s", _("capacity element value too
large"));
- return -1;
- }
-
- *ret *= mult;
+ /* off_t is signed, so you cannot create a file larger than 2^^63
+ * bytes in the first place. */
+ if (virScaleInteger(ret, unit, 1, LLONG_MAX) < 0)
+ return -1;
return 0;
}
diff --git a/tests/storagevolxml2xmlin/vol-file-backing.xml
b/tests/storagevolxml2xmlin/vol-file-backing.xml
index c1a5837..d23349e 100644
--- a/tests/storagevolxml2xmlin/vol-file-backing.xml
+++ b/tests/storagevolxml2xmlin/vol-file-backing.xml
@@ -1,8 +1,8 @@
<volume>
<name>sparse.img</name>
<source/>
- <capacity>10000000000</capacity>
- <allocation>0</allocation>
+ <capacity unit='GB'>10</capacity>
+ <allocation unit='MiB'>0</allocation>
<target>
<path>/var/lib/libvirt/images/sparse.img</path>
<permissions>
diff --git a/tests/storagevolxml2xmlin/vol-file.xml
b/tests/storagevolxml2xmlin/vol-file.xml
index d7de0aa..fdca510 100644
--- a/tests/storagevolxml2xmlin/vol-file.xml
+++ b/tests/storagevolxml2xmlin/vol-file.xml
@@ -1,8 +1,8 @@
<volume>
<name>sparse.img</name>
<source/>
- <capacity unit="T">1</capacity>
- <allocation>0</allocation>
+ <capacity unit="TiB">1</capacity>
+ <allocation unit="bytes">0</allocation>
<target>
<path>/var/lib/libvirt/images/sparse.img</path>
<permissions>
--
1.7.7.6