2
0

compatibility.rst 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. Backwards compatibility
  2. =======================
  3. How backwards compatibility works
  4. ---------------------------------
  5. When we do migration, we have two QEMU processes: the source and the
  6. target. There are two cases, they are the same version or they are
  7. different versions. The easy case is when they are the same version.
  8. The difficult one is when they are different versions.
  9. There are two things that are different, but they have very similar
  10. names and sometimes get confused:
  11. - QEMU version
  12. - machine type version
  13. Let's start with a practical example, we start with:
  14. - qemu-system-x86_64 (v5.2), from now on qemu-5.2.
  15. - qemu-system-x86_64 (v5.1), from now on qemu-5.1.
  16. Related to this are the "latest" machine types defined on each of
  17. them:
  18. - pc-q35-5.2 (newer one in qemu-5.2) from now on pc-5.2
  19. - pc-q35-5.1 (newer one in qemu-5.1) from now on pc-5.1
  20. First of all, migration is only supposed to work if you use the same
  21. machine type in both source and destination. The QEMU hardware
  22. configuration needs to be the same also on source and destination.
  23. Most aspects of the backend configuration can be changed at will,
  24. except for a few cases where the backend features influence frontend
  25. device feature exposure. But that is not relevant for this section.
  26. I am going to list the number of combinations that we can have. Let's
  27. start with the trivial ones, QEMU is the same on source and
  28. destination:
  29. 1 - qemu-5.2 -M pc-5.2 -> migrates to -> qemu-5.2 -M pc-5.2
  30. This is the latest QEMU with the latest machine type.
  31. This have to work, and if it doesn't work it is a bug.
  32. 2 - qemu-5.1 -M pc-5.1 -> migrates to -> qemu-5.1 -M pc-5.1
  33. Exactly the same case than the previous one, but for 5.1.
  34. Nothing to see here either.
  35. This are the easiest ones, we will not talk more about them in this
  36. section.
  37. Now we start with the more interesting cases. Consider the case where
  38. we have the same QEMU version in both sides (qemu-5.2) but we are using
  39. the latest machine type for that version (pc-5.2) but one of an older
  40. QEMU version, in this case pc-5.1.
  41. 3 - qemu-5.2 -M pc-5.1 -> migrates to -> qemu-5.2 -M pc-5.1
  42. It needs to use the definition of pc-5.1 and the devices as they
  43. were configured on 5.1, but this should be easy in the sense that
  44. both sides are the same QEMU and both sides have exactly the same
  45. idea of what the pc-5.1 machine is.
  46. 4 - qemu-5.1 -M pc-5.2 -> migrates to -> qemu-5.1 -M pc-5.2
  47. This combination is not possible as the qemu-5.1 doesn't understand
  48. pc-5.2 machine type. So nothing to worry here.
  49. Now it comes the interesting ones, when both QEMU processes are
  50. different. Notice also that the machine type needs to be pc-5.1,
  51. because we have the limitation than qemu-5.1 doesn't know pc-5.2. So
  52. the possible cases are:
  53. 5 - qemu-5.2 -M pc-5.1 -> migrates to -> qemu-5.1 -M pc-5.1
  54. This migration is known as newer to older. We need to make sure
  55. when we are developing 5.2 we need to take care about not to break
  56. migration to qemu-5.1. Notice that we can't make updates to
  57. qemu-5.1 to understand whatever qemu-5.2 decides to change, so it is
  58. in qemu-5.2 side to make the relevant changes.
  59. 6 - qemu-5.1 -M pc-5.1 -> migrates to -> qemu-5.2 -M pc-5.1
  60. This migration is known as older to newer. We need to make sure
  61. than we are able to receive migrations from qemu-5.1. The problem is
  62. similar to the previous one.
  63. If qemu-5.1 and qemu-5.2 were the same, there will not be any
  64. compatibility problems. But the reason that we create qemu-5.2 is to
  65. get new features, devices, defaults, etc.
  66. If we get a device that has a new feature, or change a default value,
  67. we have a problem when we try to migrate between different QEMU
  68. versions.
  69. So we need a way to tell qemu-5.2 that when we are using machine type
  70. pc-5.1, it needs to **not** use the feature, to be able to migrate to
  71. real qemu-5.1.
  72. And the equivalent part when migrating from qemu-5.1 to qemu-5.2.
  73. qemu-5.2 has to expect that it is not going to get data for the new
  74. feature, because qemu-5.1 doesn't know about it.
  75. How do we tell QEMU about these device feature changes? In
  76. hw/core/machine.c:hw_compat_X_Y arrays.
  77. If we change a default value, we need to put back the old value on
  78. that array. And the device, during initialization needs to look at
  79. that array to see what value it needs to get for that feature. And
  80. what are we going to put in that array, the value of a property.
  81. To create a property for a device, we need to use one of the
  82. DEFINE_PROP_*() macros. See include/hw/qdev-properties.h to find the
  83. macros that exist. With it, we set the default value for that
  84. property, and that is what it is going to get in the latest released
  85. version. But if we want a different value for a previous version, we
  86. can change that in the hw_compat_X_Y arrays.
  87. hw_compat_X_Y is an array of registers that have the format:
  88. - name_device
  89. - name_property
  90. - value
  91. Let's see a practical example.
  92. In qemu-5.2 virtio-blk-device got multi queue support. This is a
  93. change that is not backward compatible. In qemu-5.1 it has one
  94. queue. In qemu-5.2 it has the same number of queues as the number of
  95. cpus in the system.
  96. When we are doing migration, if we migrate from a device that has 4
  97. queues to a device that have only one queue, we don't know where to
  98. put the extra information for the other 3 queues, and we fail
  99. migration.
  100. Similar problem when we migrate from qemu-5.1 that has only one queue
  101. to qemu-5.2, we only sent information for one queue, but destination
  102. has 4, and we have 3 queues that are not properly initialized and
  103. anything can happen.
  104. So, how can we address this problem. Easy, just convince qemu-5.2
  105. that when it is running pc-5.1, it needs to set the number of queues
  106. for virtio-blk-devices to 1.
  107. That way we fix the cases 5 and 6.
  108. 5 - qemu-5.2 -M pc-5.1 -> migrates to -> qemu-5.1 -M pc-5.1
  109. qemu-5.2 -M pc-5.1 sets number of queues to be 1.
  110. qemu-5.1 -M pc-5.1 expects number of queues to be 1.
  111. correct. migration works.
  112. 6 - qemu-5.1 -M pc-5.1 -> migrates to -> qemu-5.2 -M pc-5.1
  113. qemu-5.1 -M pc-5.1 sets number of queues to be 1.
  114. qemu-5.2 -M pc-5.1 expects number of queues to be 1.
  115. correct. migration works.
  116. And now the other interesting case, case 3. In this case we have:
  117. 3 - qemu-5.2 -M pc-5.1 -> migrates to -> qemu-5.2 -M pc-5.1
  118. Here we have the same QEMU in both sides. So it doesn't matter a
  119. lot if we have set the number of queues to 1 or not, because
  120. they are the same.
  121. WRONG!
  122. Think what happens if we do one of this double migrations:
  123. A -> migrates -> B -> migrates -> C
  124. where:
  125. A: qemu-5.1 -M pc-5.1
  126. B: qemu-5.2 -M pc-5.1
  127. C: qemu-5.2 -M pc-5.1
  128. migration A -> B is case 6, so number of queues needs to be 1.
  129. migration B -> C is case 3, so we don't care. But actually we
  130. care because we haven't started the guest in qemu-5.2, it came
  131. migrated from qemu-5.1. So to be in the safe place, we need to
  132. always use number of queues 1 when we are using pc-5.1.
  133. Now, how was this done in reality? The following commit shows how it
  134. was done::
  135. commit 9445e1e15e66c19e42bea942ba810db28052cd05
  136. Author: Stefan Hajnoczi <stefanha@redhat.com>
  137. Date: Tue Aug 18 15:33:47 2020 +0100
  138. virtio-blk-pci: default num_queues to -smp N
  139. The relevant parts for migration are::
  140. @@ -1281,7 +1284,8 @@ static const Property virtio_blk_properties[] = {
  141. #endif
  142. DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
  143. true),
  144. - DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues, 1),
  145. + DEFINE_PROP_UINT16("num-queues", VirtIOBlock, conf.num_queues,
  146. + VIRTIO_BLK_AUTO_NUM_QUEUES),
  147. DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 256),
  148. It changes the default value of num_queues. But it fishes it for old
  149. machine types to have the right value::
  150. @@ -31,6 +31,7 @@
  151. GlobalProperty hw_compat_5_1[] = {
  152. ...
  153. + { "virtio-blk-device", "num-queues", "1"},
  154. ...
  155. };
  156. A device with different features on both sides
  157. ----------------------------------------------
  158. Let's assume that we are using the same QEMU binary on both sides,
  159. just to make the things easier. But we have a device that has
  160. different features on both sides of the migration. That can be
  161. because the devices are different, because the kernel driver of both
  162. devices have different features, whatever.
  163. How can we get this to work with migration. The way to do that is
  164. "theoretically" easy. You have to get the features that the device
  165. has in the source of the migration. The features that the device has
  166. on the target of the migration, you get the intersection of the
  167. features of both sides, and that is the way that you should launch
  168. QEMU.
  169. Notice that this is not completely related to QEMU. The most
  170. important thing here is that this should be handled by the managing
  171. application that launches QEMU. If QEMU is configured correctly, the
  172. migration will succeed.
  173. That said, actually doing it is complicated. Almost all devices are
  174. bad at being able to be launched with only some features enabled.
  175. With one big exception: cpus.
  176. You can read the documentation for QEMU x86 cpu models here:
  177. https://qemu-project.gitlab.io/qemu/system/qemu-cpu-models.html
  178. See when they talk about migration they recommend that one chooses the
  179. newest cpu model that is supported for all cpus.
  180. Let's say that we have:
  181. Host A:
  182. Device X has the feature Y
  183. Host B:
  184. Device X has not the feature Y
  185. If we try to migrate without any care from host A to host B, it will
  186. fail because when migration tries to load the feature Y on
  187. destination, it will find that the hardware is not there.
  188. Doing this would be the equivalent of doing with cpus:
  189. Host A:
  190. $ qemu-system-x86_64 -cpu host
  191. Host B:
  192. $ qemu-system-x86_64 -cpu host
  193. When both hosts have different cpu features this is guaranteed to
  194. fail. Especially if Host B has less features than host A. If host A
  195. has less features than host B, sometimes it works. Important word of
  196. last sentence is "sometimes".
  197. So, forgetting about cpu models and continuing with the -cpu host
  198. example, let's see that the differences of the cpus is that Host A and
  199. B have the following features:
  200. Features: 'pcid' 'stibp' 'taa-no'
  201. Host A: X X
  202. Host B: X
  203. And we want to migrate between them, the way configure both QEMU cpu
  204. will be:
  205. Host A:
  206. $ qemu-system-x86_64 -cpu host,pcid=off,stibp=off
  207. Host B:
  208. $ qemu-system-x86_64 -cpu host,taa-no=off
  209. And you would be able to migrate between them. It is responsibility
  210. of the management application or of the user to make sure that the
  211. configuration is correct. QEMU doesn't know how to look at this kind
  212. of features in general.
  213. Notice that we don't recommend to use -cpu host for migration. It is
  214. used in this example because it makes the example simpler.
  215. Other devices have worse control about individual features. If they
  216. want to be able to migrate between hosts that show different features,
  217. the device needs a way to configure which ones it is going to use.
  218. In this section we have considered that we are using the same QEMU
  219. binary in both sides of the migration. If we use different QEMU
  220. versions process, then we need to have into account all other
  221. differences and the examples become even more complicated.
  222. How to mitigate when we have a backward compatibility error
  223. -----------------------------------------------------------
  224. We broke migration for old machine types continuously during
  225. development. But as soon as we find that there is a problem, we fix
  226. it. The problem is what happens when we detect after we have done a
  227. release that something has gone wrong.
  228. Let see how it worked with one example.
  229. After the release of qemu-8.0 we found a problem when doing migration
  230. of the machine type pc-7.2.
  231. - $ qemu-7.2 -M pc-7.2 -> qemu-7.2 -M pc-7.2
  232. This migration works
  233. - $ qemu-8.0 -M pc-7.2 -> qemu-8.0 -M pc-7.2
  234. This migration works
  235. - $ qemu-8.0 -M pc-7.2 -> qemu-7.2 -M pc-7.2
  236. This migration fails
  237. - $ qemu-7.2 -M pc-7.2 -> qemu-8.0 -M pc-7.2
  238. This migration fails
  239. So clearly something fails when migration between qemu-7.2 and
  240. qemu-8.0 with machine type pc-7.2. The error messages, and git bisect
  241. pointed to this commit.
  242. In qemu-8.0 we got this commit::
  243. commit 010746ae1db7f52700cb2e2c46eb94f299cfa0d2
  244. Author: Jonathan Cameron <Jonathan.Cameron@huawei.com>
  245. Date: Thu Mar 2 13:37:02 2023 +0000
  246. hw/pci/aer: Implement PCI_ERR_UNCOR_MASK register
  247. The relevant bits of the commit for our example are this ones::
  248. --- a/hw/pci/pcie_aer.c
  249. +++ b/hw/pci/pcie_aer.c
  250. @@ -112,6 +112,10 @@ int pcie_aer_init(PCIDevice *dev,
  251. pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
  252. PCI_ERR_UNC_SUPPORTED);
  253. + pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
  254. + PCI_ERR_UNC_MASK_DEFAULT);
  255. + pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
  256. + PCI_ERR_UNC_SUPPORTED);
  257. pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
  258. PCI_ERR_UNC_SEVERITY_DEFAULT);
  259. The patch changes how we configure PCI space for AER. But QEMU fails
  260. when the PCI space configuration is different between source and
  261. destination.
  262. The following commit shows how this got fixed::
  263. commit 5ed3dabe57dd9f4c007404345e5f5bf0e347317f
  264. Author: Leonardo Bras <leobras@redhat.com>
  265. Date: Tue May 2 21:27:02 2023 -0300
  266. hw/pci: Disable PCI_ERR_UNCOR_MASK register for machine type < 8.0
  267. [...]
  268. The relevant parts of the fix in QEMU are as follow:
  269. First, we create a new property for the device to be able to configure
  270. the old behaviour or the new behaviour::
  271. diff --git a/hw/pci/pci.c b/hw/pci/pci.c
  272. index 8a87ccc8b0..5153ad63d6 100644
  273. --- a/hw/pci/pci.c
  274. +++ b/hw/pci/pci.c
  275. @@ -79,6 +79,8 @@ static const Property pci_props[] = {
  276. DEFINE_PROP_STRING("failover_pair_id", PCIDevice,
  277. failover_pair_id),
  278. DEFINE_PROP_UINT32("acpi-index", PCIDevice, acpi_index, 0),
  279. + DEFINE_PROP_BIT("x-pcie-err-unc-mask", PCIDevice, cap_present,
  280. + QEMU_PCIE_ERR_UNC_MASK_BITNR, true),
  281. };
  282. Notice that we enable the feature for new machine types.
  283. Now we see how the fix is done. This is going to depend on what kind
  284. of breakage happens, but in this case it is quite simple::
  285. diff --git a/hw/pci/pcie_aer.c b/hw/pci/pcie_aer.c
  286. index 103667c368..374d593ead 100644
  287. --- a/hw/pci/pcie_aer.c
  288. +++ b/hw/pci/pcie_aer.c
  289. @@ -112,10 +112,13 @@ int pcie_aer_init(PCIDevice *dev, uint8_t cap_ver,
  290. uint16_t offset,
  291. pci_set_long(dev->w1cmask + offset + PCI_ERR_UNCOR_STATUS,
  292. PCI_ERR_UNC_SUPPORTED);
  293. - pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
  294. - PCI_ERR_UNC_MASK_DEFAULT);
  295. - pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
  296. - PCI_ERR_UNC_SUPPORTED);
  297. +
  298. + if (dev->cap_present & QEMU_PCIE_ERR_UNC_MASK) {
  299. + pci_set_long(dev->config + offset + PCI_ERR_UNCOR_MASK,
  300. + PCI_ERR_UNC_MASK_DEFAULT);
  301. + pci_set_long(dev->wmask + offset + PCI_ERR_UNCOR_MASK,
  302. + PCI_ERR_UNC_SUPPORTED);
  303. + }
  304. pci_set_long(dev->config + offset + PCI_ERR_UNCOR_SEVER,
  305. PCI_ERR_UNC_SEVERITY_DEFAULT);
  306. I.e. If the property bit is enabled, we configure it as we did for
  307. qemu-8.0. If the property bit is not set, we configure it as it was in 7.2.
  308. And now, everything that is missing is disabling the feature for old
  309. machine types::
  310. diff --git a/hw/core/machine.c b/hw/core/machine.c
  311. index 47a34841a5..07f763eb2e 100644
  312. --- a/hw/core/machine.c
  313. +++ b/hw/core/machine.c
  314. @@ -48,6 +48,7 @@ GlobalProperty hw_compat_7_2[] = {
  315. { "e1000e", "migrate-timadj", "off" },
  316. { "virtio-mem", "x-early-migration", "false" },
  317. { "migration", "x-preempt-pre-7-2", "true" },
  318. + { TYPE_PCI_DEVICE, "x-pcie-err-unc-mask", "off" },
  319. };
  320. const size_t hw_compat_7_2_len = G_N_ELEMENTS(hw_compat_7_2);
  321. And now, when qemu-8.0.1 is released with this fix, all combinations
  322. are going to work as supposed.
  323. - $ qemu-7.2 -M pc-7.2 -> qemu-7.2 -M pc-7.2 (works)
  324. - $ qemu-8.0.1 -M pc-7.2 -> qemu-8.0.1 -M pc-7.2 (works)
  325. - $ qemu-8.0.1 -M pc-7.2 -> qemu-7.2 -M pc-7.2 (works)
  326. - $ qemu-7.2 -M pc-7.2 -> qemu-8.0.1 -M pc-7.2 (works)
  327. So the normality has been restored and everything is ok, no?
  328. Not really, now our matrix is much bigger. We started with the easy
  329. cases, migration from the same version to the same version always
  330. works:
  331. - $ qemu-7.2 -M pc-7.2 -> qemu-7.2 -M pc-7.2
  332. - $ qemu-8.0 -M pc-7.2 -> qemu-8.0 -M pc-7.2
  333. - $ qemu-8.0.1 -M pc-7.2 -> qemu-8.0.1 -M pc-7.2
  334. Now the interesting ones. When the QEMU processes versions are
  335. different. For the 1st set, their fail and we can do nothing, both
  336. versions are released and we can't change anything.
  337. - $ qemu-7.2 -M pc-7.2 -> qemu-8.0 -M pc-7.2
  338. - $ qemu-8.0 -M pc-7.2 -> qemu-7.2 -M pc-7.2
  339. This two are the ones that work. The whole point of making the
  340. change in qemu-8.0.1 release was to fix this issue:
  341. - $ qemu-7.2 -M pc-7.2 -> qemu-8.0.1 -M pc-7.2
  342. - $ qemu-8.0.1 -M pc-7.2 -> qemu-7.2 -M pc-7.2
  343. But now we found that qemu-8.0 neither can migrate to qemu-7.2 not
  344. qemu-8.0.1.
  345. - $ qemu-8.0 -M pc-7.2 -> qemu-8.0.1 -M pc-7.2
  346. - $ qemu-8.0.1 -M pc-7.2 -> qemu-8.0 -M pc-7.2
  347. So, if we start a pc-7.2 machine in qemu-8.0 we can't migrate it to
  348. anything except to qemu-8.0.
  349. Can we do better?
  350. Yeap. If we know that we are going to do this migration:
  351. - $ qemu-8.0 -M pc-7.2 -> qemu-8.0.1 -M pc-7.2
  352. We can launch the appropriate devices with::
  353. --device...,x-pci-e-err-unc-mask=on
  354. And now we can receive a migration from 8.0. And from now on, we can
  355. do that migration to new machine types if we remember to enable that
  356. property for pc-7.2. Notice that we need to remember, it is not
  357. enough to know that the source of the migration is qemu-8.0. Think of
  358. this example:
  359. $ qemu-8.0 -M pc-7.2 -> qemu-8.0.1 -M pc-7.2 -> qemu-8.2 -M pc-7.2
  360. In the second migration, the source is not qemu-8.0, but we still have
  361. that "problem" and have that property enabled. Notice that we need to
  362. continue having this mark/property until we have this machine
  363. rebooted. But it is not a normal reboot (that don't reload QEMU) we
  364. need the machine to poweroff/poweron on a fixed QEMU. And from now
  365. on we can use the proper real machine.