:p
atchew
Login
The following changes since commit b455ce4c2f300c8ba47cba7232dd03261368a4cb: Merge tag 'q800-for-8.1-pull-request' of https://github.com/vivier/qemu-m68k into staging (2023-06-22 10:18:32 +0200) are available in the Git repository at: https://gitlab.com/juan.quintela/qemu.git tags/next-pull-request for you to fetch changes up to 23e4307eadc1497bd0a11ca91041768f15963b68: migration/rdma: Split qemu_fopen_rdma() into input/output functions (2023-06-22 18:11:58 +0200) ---------------------------------------------------------------- Migration Pull request (20230621) take 2 In this pull request the only change is fixing 32 bits complitaion issue. Please apply. [take 1] - fix for multifd thread creation (fabiano) - dirtylimity (hyman) * migration-test will go on next PULL request, as it has failures. - Improve error description (tejus) - improve -incoming and set parameters before calling incoming (wei) - migration atomic counters reviewed patches (quintela) - migration-test refacttoring reviewed (quintela) ---------------------------------------------------------------- Fabiano Rosas (2): migration/multifd: Rename threadinfo.c functions migration/multifd: Protect accesses to migration_threads Hyman Huang(黄勇) (8): softmmu/dirtylimit: Add parameter check for hmp "set_vcpu_dirty_limit" qapi/migration: Introduce x-vcpu-dirty-limit-period parameter qapi/migration: Introduce vcpu-dirty-limit parameters migration: Introduce dirty-limit capability migration: Refactor auto-converge capability logic migration: Put the detection logic before auto-converge checking migration: Implement dirty-limit convergence algo migration: Extend query-migrate to provide dirty page limit info Juan Quintela (16): migration-test: Be consistent for ppc migration-test: Make machine_opts regular with other options migration-test: Create arch_opts migration-test: machine_opts is really arch specific migration-test: Create kvm_opts migration-test: bootpath is the same for all tests and for all archs migration-test: Add bootfile_create/delete() functions migration-test: dirtylimit checks for x86_64 arch before migration-test: simplify shmem_opts handling qemu-file: Rename qemu_file_transferred_ fast -> noflush migration: Change qemu_file_transferred to noflush migration: Use qemu_file_transferred_noflush() for block migration. qemu_file: Make qemu_file_is_writable() static qemu-file: Simplify qemu_file_shutdown() qemu-file: Make qemu_file_get_error_obj() static migration/rdma: Split qemu_fopen_rdma() into input/output functions Tejus GK (2): migration: Update error description whenever migration fails migration: Refactor repeated call of yank_unregister_instance Wei Wang (2): migration: enforce multifd and postcopy preempt to be set before incoming qtest/migration-tests.c: use "-incoming defer" for postcopy tests qapi/migration.json | 74 +++++++++++++++++--- include/sysemu/dirtylimit.h | 2 + migration/options.h | 1 + migration/qemu-file.h | 14 ++-- migration/threadinfo.h | 7 +- migration/block.c | 4 +- migration/migration-hmp-cmds.c | 26 +++++++ migration/migration.c | 40 +++++++---- migration/multifd.c | 4 +- migration/options.c | 87 +++++++++++++++++++++++ migration/qemu-file.c | 24 ++----- migration/ram.c | 59 +++++++++++++--- migration/rdma.c | 39 +++++------ migration/savevm.c | 6 +- migration/threadinfo.c | 19 ++++- migration/vmstate.c | 4 +- softmmu/dirtylimit.c | 97 +++++++++++++++++++++++--- tests/qtest/migration-test.c | 123 ++++++++++++++++++--------------- migration/trace-events | 1 + 19 files changed, 472 insertions(+), 159 deletions(-) base-commit: 5f9dd6a8ce3961db4ce47411ed2097ad88bdf5fc prerequisite-patch-id: 99c8bffa9428838925e330eb2881bab476122579 prerequisite-patch-id: 77ba427fd916aeb395e95aa0e7190f84e98e96ab prerequisite-patch-id: 9983d46fa438d7075a37be883529e37ae41e4228 prerequisite-patch-id: 207f7529924b12dcb57f6557d6db6f79ceb2d682 prerequisite-patch-id: 5ad1799a13845dbf893a28a202b51a6b50d95d90 prerequisite-patch-id: c51959aacd6d65ee84fcd4f1b2aed3dd6f6af879 prerequisite-patch-id: da9dbb6799b2da002c0896574334920097e4c50a prerequisite-patch-id: c1110ffafbaf5465fb277a20db809372291f7846 prerequisite-patch-id: 8307c92bedd07446214b35b40206eb6793a7384d prerequisite-patch-id: 0a6106cd4a508d5e700a7ff6c25edfdd03c8ca3d prerequisite-patch-id: 83205051de22382e75bf4acdf69e59315801fa0d prerequisite-patch-id: 8c9b3cba89d555c071a410041e6da41806106a7e prerequisite-patch-id: 0ff62a33b9a242226ccc1f5424a516de803c9fe5 prerequisite-patch-id: 25b8ae1ebe09ace14457c454cfcb23077c37346c prerequisite-patch-id: 466ea91d5be41fe345dacd4d17bbbe5ce13118c2 prerequisite-patch-id: d1045858f9729ac62eccf2e83ebf95cfebae2cb5 prerequisite-patch-id: 0276ec02073bda5426de39e2f2e81eef080b4f54 prerequisite-patch-id: 7afb4450a163cc1a63ea23831c50214966969131 prerequisite-patch-id: 06c053ce4f41db9675bd1778ae8f6a483641fcef prerequisite-patch-id: 13ea05d54d741ed08b3bfefa1fc8bedb9c81c782 prerequisite-patch-id: 99c4e2b7101bc8c4b9515129a1bbe6f068053dbf prerequisite-patch-id: 1e393a196dc7a1ee75f3cc3cebbb591c5422102f prerequisite-patch-id: 2cf497b41f5024ede0a224b1f5b172226067a534 prerequisite-patch-id: 2a70276ed61d33fc4f3b52560753c05d1cd413be prerequisite-patch-id: 17ec40f4388b62ba8bf3ac1546c6913f5d1f6079 prerequisite-patch-id: dba969ce9d6cf69c1319661a7d81b1c1c719804d prerequisite-patch-id: 8d800cda87167314f07320bdb3df936c323e4a40 prerequisite-patch-id: 25d4aaf54ea66f30e426fa38bdd4e0f47303c513 prerequisite-patch-id: 082c9d8584c1daff1e827e44ee3047178e7004a7 prerequisite-patch-id: 0ef73900899425ae2f00751347afdce3739aa954 prerequisite-patch-id: e7db4730b791b71aaf417ee0f65fb6304566aaf8 prerequisite-patch-id: 62d7f28f8196039507ffe362f97723395d7bb704 prerequisite-patch-id: ea8de47bcb54e33bcc67e59e9ed752a4d1fad703 prerequisite-patch-id: 497893ef92e1ea56bd8605e6990a05cb4c7f9293 prerequisite-patch-id: 3dc869c80ee568449bbfa2a9bc427524d0e8970b prerequisite-patch-id: 52c14b6fb14ed4ccd685385a9fbc6297b762c0ef prerequisite-patch-id: 23de8371e9e3277c374a47f9bd10de209a22fdd5 prerequisite-patch-id: d21f036dd106af3375fb920bf0a557fe2b86d98e prerequisite-patch-id: ca717076e9de83d6ce370f7374c4729a9f586fae prerequisite-patch-id: a235b6ab3237155f2b39e8e10d47ddd250f6b6cc prerequisite-patch-id: 6db2aa3d8a5804c85dd171864f5140fadf5f72da prerequisite-patch-id: a799b883f4cb41c34ad074220293f372c6e0a9c7 prerequisite-patch-id: 5e012c426aef7b2f07513cec68e7efa1cf85fe52 prerequisite-patch-id: 4e614e7e3395dda7bae5f9fa21257c57cce45a39 prerequisite-patch-id: 67f8e68622c9698280ff5c5dc7469f36daf9a012 prerequisite-patch-id: d86078331449a21499e3f955e27bc87294969346 prerequisite-patch-id: 3f30d10e0ac7f53307f6b462eaf5b47151b73631 prerequisite-patch-id: a5d84769b776873697b1eb18b6b170a168e68133 prerequisite-patch-id: e5058b3e0ca9f80886bd2c1667349bffc6949da6 prerequisite-patch-id: 669d7e2ef30468034acfa33d4da0404caae526a9 prerequisite-patch-id: 3276a659cbe45efca6a6d3a4579af3cf7ceda992 prerequisite-patch-id: 624657b1f538edfb852b09889d6583970665cad9 prerequisite-patch-id: d7d70d557970f203c288f153361c6782245ba9f9 prerequisite-patch-id: fcbab0e48ac1385d2de1be7852b2adb74f04acfc prerequisite-patch-id: 88e76e8dc51b054c84c497344424f24e877e325b prerequisite-patch-id: dc4c193c8571ae5969a6c498edc7cec8ef438bc1 prerequisite-patch-id: 39c1ee32082f6ce1dd088d5a8340ca9b3e2434a4 prerequisite-patch-id: 28deb0caf0f5eac3fc0a866d2901667a56870f6d prerequisite-patch-id: 53b48b35c9b8217b2da5212d7ed48320d355a943 prerequisite-patch-id: 4469f3663714a65a06b7c472ce9c92ab7502a00f prerequisite-patch-id: a75f08b401d251fc3465b65f94a8db8d32d8900a prerequisite-patch-id: 4b7ac86af078a260f656914089da8f43cdaab8ff prerequisite-patch-id: 398f62abad95f55181d2cf8a383f69000de97af4 prerequisite-patch-id: e102cdc3834018fa88f9fe98a78afb46ff316124 prerequisite-patch-id: 1c30c139ef694b9fd8314bffb4b9b2a02c6c9233 prerequisite-patch-id: d96c304f1c63fa840440508f5b3be70a922b2210 prerequisite-patch-id: a8be25a6b6834ac542d40eaec47a60caf2fe545c prerequisite-patch-id: d29aa52f7a6c5e61cf793addbbc7d7ea5f383725 prerequisite-patch-id: c7a6d171e568f4aba6f94126abc6a9a64caefcc2 prerequisite-patch-id: dcbf2e0e9b3b3cd985423993bdd411fc0cdf4646 prerequisite-patch-id: d5f1a450785cb6e8d74e152b7026621cd4077d04 prerequisite-patch-id: 6179fd2a7c7d6866906365b564fcef05428318b3 prerequisite-patch-id: 3f0e5189f1046e8fd37b2f104a5ee6c306438bed prerequisite-patch-id: 9b8f5520663a347e1981c46d1d72f6b7efeef222 prerequisite-patch-id: 6171b4310abc56d03a21f95848beff3f04c04333 prerequisite-patch-id: 93336ba3fd1e3875b644ec6007ef22480df750a2 prerequisite-patch-id: 9a76b6408f38b96af9ad91269a0fac8d1893bdef prerequisite-patch-id: 74c166a9a1ccafef04f3894085a3b3ed5215df7a prerequisite-patch-id: 71833e48cfa5875247770ac8b94ab957e4eab4fe prerequisite-patch-id: 9a14e6755e7d7605267abaeab62d70e651d622e3 prerequisite-patch-id: e0b2ce3211263007de8e2a2b60402cfea4a2f1c2 prerequisite-patch-id: bacccbe583a69dd0f081aa74822e92c23f344a64 prerequisite-patch-id: bee3183ab6c76123bc8795dfd5dd6eb19d417832 prerequisite-patch-id: eee73769e563ea8ad64f82473c235a4fef18ce83 prerequisite-patch-id: 5c2c95e068dc614a7708fe830d773e03e8cde4ec prerequisite-patch-id: deae58b435dc10d80f1ea754613e9ed3e7bd4fe1 prerequisite-patch-id: 1e6e138aeb18a51b6496a265f84f5df1b98471b6 prerequisite-patch-id: 15865988ed0b88b1e28f0e16c50222f61db5ac35 prerequisite-patch-id: 7884031de035d910c1bddee4331a765c6a266243 prerequisite-patch-id: a2deb3751dec34448ab776b455a7b29bd6d8217f prerequisite-patch-id: d24167f841efc3b8fd8afe06ae02da4d4a594fdc prerequisite-patch-id: 4f23aea0e73aa0933a53db59ed716a19dcbd575c prerequisite-patch-id: f54b42bfeb4241cb96b2490e1261e2bc44e7cc07 prerequisite-patch-id: 7e3f3e34be720b25f3db15d2a878bce23b99353c prerequisite-patch-id: fc91b48c6593c862aa17b221663d2bbed9261f16 prerequisite-patch-id: f20dbadd1962f16e7f4fc4a2b8747443ada94f80 prerequisite-patch-id: 78de9ba010ec43b9ebbc998f4d3afb38fed6be8e prerequisite-patch-id: 013c99f721a9a0a4af86772cb8d1d40f6942f16f prerequisite-patch-id: 7ee4a5b056b343ba2d7491158965023af84f56ad prerequisite-patch-id: d489b42dc81bf9dd7a51381c06182ddffb2230e5 prerequisite-patch-id: fcf1400a8d8b417801baf1450c8c10efa06f4481 prerequisite-patch-id: e475e1e9cd7ce746410ef9839d02ba242cb72090 prerequisite-patch-id: 68d24ec2081c2224a1c133f2c07544177e693a53 prerequisite-patch-id: 6e70864f4065b79db49a206523bcc8b4afded934 prerequisite-patch-id: 0d259c5d3ebb259d36c5d059a82df3b0ffbf1429 prerequisite-patch-id: 392a9fa483070625cad85778e4742c4fc5a2ac5d prerequisite-patch-id: 62804c908c4abe71d644f18303780084a4c224e8 prerequisite-patch-id: 3f3f1eed1a6150df53aba846237329cf24bb9548 prerequisite-patch-id: 4d1387c6e00b9c62e638ce955cd5d9681754bfb5 prerequisite-patch-id: 3382e00119d0ecd997ae6f99855c74e3eed9237c prerequisite-patch-id: 95fcef043070fc902f1cad42ef47a94744624530 prerequisite-patch-id: 5b6737d17f3ef9a4ae5d33343125bc597ad2fa62 prerequisite-patch-id: acc0a1e809cb0639e16d4b05cccfd809f8e299b5 prerequisite-patch-id: aa5c2db287402596e20ef0f935aea67007484f58 prerequisite-patch-id: a0318b66bb3f1f096f7d77c3f03e2018f68430b4 prerequisite-patch-id: 4d709e0d8ac627462de259723ac4fcb8efcc5342 prerequisite-patch-id: 811deca81c0cbdc5a3e977dd282f46427e79dbe2 prerequisite-patch-id: 8f66923ad1790ee9e567b9b1d155c7836c3e7cb8 prerequisite-patch-id: c0f2a71d9835e66a216af2ff3b3d434eec44ab0d prerequisite-patch-id: 5e1a47e077d7bd22b1af9439e1cf1ae38830f763 prerequisite-patch-id: 04bd404d9e3268cbc399458be5bd69190852884a prerequisite-patch-id: 6d630be7173e6e8da9a14739d32701f76bdf32a3 prerequisite-patch-id: 463c4f52f60b2c8fbf165caedbbc1bfa3bd2a265 prerequisite-patch-id: 67403a8553d60ec8938906f28319176f2ef0ecc4 prerequisite-patch-id: 18443a910e260eed010a2d4cd8f255678476eb0a prerequisite-patch-id: cf8d1aab1c343ad9bb6de1b980bf7a8aa7479e79 prerequisite-patch-id: cb8ee956876a21478178d46383e760f2a29ec60a prerequisite-patch-id: 0384e88e9105ce6907f44a55ae0d22bb57b11701 prerequisite-patch-id: 010b9094c8a9b1b41dc49fc07d9704a7be6374c0 prerequisite-patch-id: 3e96fcf9486ad8decca891534d4d2b41f786087a prerequisite-patch-id: d77c491a6a5760ca828ecbb1445a77dcf9bebf0b prerequisite-patch-id: 5c2e9b005429bca543ac6dd39912731d9388eb10 prerequisite-patch-id: 741c7b38494d42817d2d71adb6f267268c9cb208 prerequisite-patch-id: b97fb8b1e5848e8561fc599ef7173b2b07782918 prerequisite-patch-id: cca04ee447a117242679dc946638dd876bbaf931 prerequisite-patch-id: 7e7784bd5ec5ecfdb8d7130975a915fb88e8c26b prerequisite-patch-id: 5a5137d28df7153718ef924d49a821fc1482b220 prerequisite-patch-id: 3d010e879709b5540948b11c2692a28fd5bdd1ea prerequisite-patch-id: 3d418aca0f2a4a5a3e8cbd3c9da2a5229dd26f61 prerequisite-patch-id: 423c72136d6c85888dfac083efb54b518323f0dd prerequisite-patch-id: 099453248d834931415e431e1bb470c1f99cdfa2 prerequisite-patch-id: 9fde172c51e107415194ecce2a3e218d2fab7f60 prerequisite-patch-id: 602a0f6b0121ef0296a3fe14872d59b8a0673b24 prerequisite-patch-id: ded33eb3b89b9da9e7a32ca5c6da3da2b65d3a83 prerequisite-patch-id: 56baaaf053e49e6306c076a80c5e7759a7c27805 prerequisite-patch-id: ec1ace1ef1e30d4c56143b3148b4f70c123ddd85 prerequisite-patch-id: da789135fed934d00e9020a90ec700a273fb18fa prerequisite-patch-id: ca5e644043851df5c7472b4149806ac98b6cce5c prerequisite-patch-id: d4f92797793802ce3021c4d1b45d2d0a94c51f07 prerequisite-patch-id: 992ab3fb9e82572494ff6f8af494ffbe8ba5cc6e prerequisite-patch-id: 8baf34ed9789ac6a26f1d84648869131cea522fa prerequisite-patch-id: 63f23c96115916e7707201d828fcab42ceeea385 prerequisite-patch-id: 7c166511597619b0f03043ce3a0a7237032bf7e0 prerequisite-patch-id: 35e2044bb5d5ea5d041ed01579943f6cffa6ee41 prerequisite-patch-id: 497b25db87c4c64173167f70d3a48154e44ca655 prerequisite-patch-id: d78941852e275e8b8ed03254a89324fef00fcf18 prerequisite-patch-id: 3cc8bd3f0886b6dca9197bfdba4bfa6ff360bf24 prerequisite-patch-id: 61890eaa88bcab4ac0aa2ef9a131d56ef8376f1d prerequisite-patch-id: 097b002021ddd12f7b5180ccaa744ecce925f04b prerequisite-patch-id: f599ecb06efafb8954fc9ad6d08a9819da860d28 prerequisite-patch-id: 484f86ad1f4fb5d8b2debfb1e7a8c7b6d0610f77 prerequisite-patch-id: 52db9f2823a1ad78ffb91f84911cd9963b295465 prerequisite-patch-id: d936469bba0e3720bf957995c0f842e56c815e85 prerequisite-patch-id: 9bfb8fba3a480dd5c8878fd307d96cbaaf521cff prerequisite-patch-id: 13798977298ceb264b789af0eae36c714b0d17c1 prerequisite-patch-id: fc68338d9f90388d062471e46e9b691b00302c69 prerequisite-patch-id: 25e5e3c9ec0a10aa564b3cf32fe793aaf1e705b7 prerequisite-patch-id: 9160fde4ddf465965328264e443638a3ab0d09d9 prerequisite-patch-id: 20d490f27f569e5784d5501d842b4be8a4931127 prerequisite-patch-id: 9b7866c753c962fa8107eeff4d25ff40a546f329 prerequisite-patch-id: 653af78a35e216c7dc891a2d46849bdde83a5dfd prerequisite-patch-id: f27f61687c1f423d4ad8f690a5114644364d26c5 prerequisite-patch-id: 705f5636837961012d4ad7cef93e3c06bf2828ad prerequisite-patch-id: cf18ec6cc3cfb012e68e34f5319e5ca5fc08b04f prerequisite-patch-id: 496d56c7025c252650cef84afef17c1cbe761011 prerequisite-patch-id: 849633dc3d51365926008341078b46e05349daf3 prerequisite-patch-id: bdd1c3731521ab2bec54b5757a1b1460ffa8a76b prerequisite-patch-id: 7a4af5cc7a8d0c73fac182936c3034b8b97a1d81 prerequisite-patch-id: b6640f64140c35ef6614a47ac213d815eaacc385 prerequisite-patch-id: 619f2ef543c43d0e537cc5ec16a88aff8d08f7ee prerequisite-patch-id: 5b7d7481f225dd506c53bc58d913b3dcf670ab3b prerequisite-patch-id: 76b2c41e04d00656cff256f72fb81617baf75004 prerequisite-patch-id: e1e44b6305e28dc040a7495749756d39f086b407 prerequisite-patch-id: 23b6508f200dc43698cc460285ec47fef2e54a45 prerequisite-patch-id: b225a20694d23a03f11eab8c86a0a4b7b640a302 prerequisite-patch-id: e630536287ec238942c1948f8b966e15384fd3ff prerequisite-patch-id: 327ccf1526eb31e0899de28c42c6bc687e274be5 prerequisite-patch-id: 6b4ab77555a60de86ad045538ea19460e0f65a27 prerequisite-patch-id: e9766937f032e867e3953ea53c47a5c385c68feb prerequisite-patch-id: b6f9c8b0ac1722d3809bc48d89ace7070e1c447a prerequisite-patch-id: e72efe42eec650c70433a02ce9c97ddeaef02d0d prerequisite-patch-id: 9f17b908169ba05390869f3e35b69df00bd46d41 prerequisite-patch-id: b9a82d490d17914a2f80b0430cf4973dd93ccd2f prerequisite-patch-id: 2563a1dcb7798936aa2c4a83dc1e1ddd585af241 prerequisite-patch-id: d4e0829e923f60dbf80b39493879280c8da2ff4e prerequisite-patch-id: e42a585260f999d56d222e7b2f44405f6cfbc406 prerequisite-patch-id: e163a8cb28f70824dcde6295354df58a9ece12c0 prerequisite-patch-id: fb1ecde59655a27c8d3fdff20a66cbbe3f00bd6d prerequisite-patch-id: 8cb6ee4b61ec57e6972ac1ee1253e85a7765deaa prerequisite-patch-id: 499ac0cc3c1b5a08c8609ecc7d210c35edf01370 prerequisite-patch-id: 8434161ce61b9b53baf7c2643709e08bede8891d prerequisite-patch-id: bf01608b5710ec0f4d041056988bf42e8785b7be prerequisite-patch-id: 31a846018ddc61b29dffd1c56e8ef29c5aeb164b prerequisite-patch-id: 1a0ab80ff0cde1bf49af90be105764d6504c42e2 prerequisite-patch-id: 4463e631ff73f48de1f761fa08fc2d3a0d02d2e3 prerequisite-patch-id: 1ef269c11829325108dc950ebb6ebbb0413f491d prerequisite-patch-id: 244d96e340cb984ccaeb47ba1fc32c093df85877 prerequisite-patch-id: 6490e0a9923c2341d6aa355576fc178e830a10ef prerequisite-patch-id: 73099e3b819e51e70cedf57b5de2da94161a789b prerequisite-patch-id: 49c793919ad92fe3162b6cc8efac6762037534e1 prerequisite-patch-id: 53796f63653ecdf3f2a66d9cb3181546441d4ac0 prerequisite-patch-id: aa6fbd949a032b6fce2b599309f633393bc0bb08 prerequisite-patch-id: eb33de06c18bd23ef820d12cd5e340eda4fc15dc prerequisite-patch-id: 9acaaae21935bd460bd45f89ac9e5b3c7be398fc prerequisite-patch-id: d00c2306f14a27317918b63539f65df88ee08222 prerequisite-patch-id: 87cb389190ca57ff8250be430e3470b39575271d prerequisite-patch-id: 2eaee2a99c51fd5a0df72b5253e8064d9facbcd0 prerequisite-patch-id: fa319f93ccd1f3f07955a69b793d0c3ca697fe56 prerequisite-patch-id: 8541186582e59ab7fc5b8242042d068b5ff344ec prerequisite-patch-id: 02406627f62825a368975d64a3da2c68fafeccea prerequisite-patch-id: 5ff0c64a0f40ad9c17a67f3ec4af3c24ca81ba7c prerequisite-patch-id: 7f2ccb5fa7573dd10b4dec4d9b3dda8c5416e77e prerequisite-patch-id: f32307884ffd5b79bb333fffbf7a1a1fb11e1077 prerequisite-patch-id: dc6d9a25a341dbd7ec34453b5692f0c4ee0e5ebd prerequisite-patch-id: fdc3da57663352fd762b6ea8b3fb39545cd86f69 prerequisite-patch-id: 93933d68c7698bf5c66aaff4b9e61b8a7cd49deb prerequisite-patch-id: 601286c6aae0c275b6ebc489197c21f6425d1dea prerequisite-patch-id: b6bd48dfa8f1d956be0a63ccc27e0f2648ea6188 prerequisite-patch-id: d7bc5f0deb3489e698b5d93d756bb41fe334229e prerequisite-patch-id: 3f3d8b03dc8e39e30049f94c234fb32333bea7ab prerequisite-patch-id: e7e5398f510b2490efec81bc227ab3a66fda6db0 prerequisite-patch-id: db92723389041e01bed4d3cab7d800bd0060d44d prerequisite-patch-id: 7ba892dca22bd88cb2b4f03e9c7ec3ab4828f365 prerequisite-patch-id: 56aac78c79b3a4329e7014d173c8f6edea4ebee1 prerequisite-patch-id: 10e17f897a2bb483d2cd0038598e5e2f08514e4a prerequisite-patch-id: dfb16a3bd2e302f02dd89fd4337446b454100ed4 prerequisite-patch-id: 145f9e823ba743c9bf1c3f9abcdd1d4648a82d53 prerequisite-patch-id: f7152653caf4f759f0537fc8f7898261e839261a prerequisite-patch-id: e727e63dd83f98fc829b6b74a11d7f936950aa14 prerequisite-patch-id: c5e20e303c45ddc096195a9d7c5c2cc2432f0290 prerequisite-patch-id: f448aa53083685570eb21b735641430a91610921 -- 2.40.1
From: Fabiano Rosas <farosas@suse.de> We're about to add more functions to this file so make it use the same coding style as the rest of the code. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Juan Quintela <quintela@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Peter Xu <peterx@redhat.com> Message-Id: <20230607161306.31425-2-farosas@suse.de> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/threadinfo.h | 5 ++--- migration/migration.c | 4 ++-- migration/multifd.c | 4 ++-- migration/threadinfo.c | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/migration/threadinfo.h b/migration/threadinfo.h index XXXXXXX..XXXXXXX 100644 --- a/migration/threadinfo.h +++ b/migration/threadinfo.h @@ -XXX,XX +XXX,XX @@ struct MigrationThread { QLIST_ENTRY(MigrationThread) node; }; -MigrationThread *MigrationThreadAdd(const char *name, int thread_id); - -void MigrationThreadDel(MigrationThread *info); +MigrationThread *migration_threads_add(const char *name, int thread_id); +void migration_threads_remove(MigrationThread *info); diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ static void *migration_thread(void *opaque) MigThrError thr_error; bool urgent = false; - thread = MigrationThreadAdd("live_migration", qemu_get_thread_id()); + thread = migration_threads_add("live_migration", qemu_get_thread_id()); rcu_register_thread(); @@ -XXX,XX +XXX,XX @@ static void *migration_thread(void *opaque) migration_iteration_finish(s); object_unref(OBJECT(s)); rcu_unregister_thread(); - MigrationThreadDel(thread); + migration_threads_remove(thread); return NULL; } diff --git a/migration/multifd.c b/migration/multifd.c index XXXXXXX..XXXXXXX 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -XXX,XX +XXX,XX @@ static void *multifd_send_thread(void *opaque) int ret = 0; bool use_zero_copy_send = migrate_zero_copy_send(); - thread = MigrationThreadAdd(p->name, qemu_get_thread_id()); + thread = migration_threads_add(p->name, qemu_get_thread_id()); trace_multifd_send_thread_start(p->id); rcu_register_thread(); @@ -XXX,XX +XXX,XX @@ out: qemu_mutex_unlock(&p->mutex); rcu_unregister_thread(); - MigrationThreadDel(thread); + migration_threads_remove(thread); trace_multifd_send_thread_end(p->id, p->num_packets, p->total_normal_pages); return NULL; diff --git a/migration/threadinfo.c b/migration/threadinfo.c index XXXXXXX..XXXXXXX 100644 --- a/migration/threadinfo.c +++ b/migration/threadinfo.c @@ -XXX,XX +XXX,XX @@ static QLIST_HEAD(, MigrationThread) migration_threads; -MigrationThread *MigrationThreadAdd(const char *name, int thread_id) +MigrationThread *migration_threads_add(const char *name, int thread_id) { MigrationThread *thread = g_new0(MigrationThread, 1); thread->name = name; @@ -XXX,XX +XXX,XX @@ MigrationThread *MigrationThreadAdd(const char *name, int thread_id) return thread; } -void MigrationThreadDel(MigrationThread *thread) +void migration_threads_remove(MigrationThread *thread) { if (thread) { QLIST_REMOVE(thread, node); -- 2.40.1
From: Fabiano Rosas <farosas@suse.de> This doubly linked list is common for all the multifd and migration threads so we need to avoid concurrent access. Add a mutex to protect the data from concurrent access. This fixes a crash when removing two MigrationThread objects from the list at the same time during cleanup of multifd threads. Fixes: 671326201d ("migration: Introduce interface query-migrationthreads") Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-Id: <20230607161306.31425-3-farosas@suse.de> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/threadinfo.h | 2 -- migration/threadinfo.c | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/migration/threadinfo.h b/migration/threadinfo.h index XXXXXXX..XXXXXXX 100644 --- a/migration/threadinfo.h +++ b/migration/threadinfo.h @@ -XXX,XX +XXX,XX @@ * See the COPYING file in the top-level directory. */ -#include "qemu/queue.h" -#include "qemu/osdep.h" #include "qapi/error.h" #include "qapi/qapi-commands-migration.h" diff --git a/migration/threadinfo.c b/migration/threadinfo.c index XXXXXXX..XXXXXXX 100644 --- a/migration/threadinfo.c +++ b/migration/threadinfo.c @@ -XXX,XX +XXX,XX @@ * See the COPYING file in the top-level directory. */ +#include "qemu/osdep.h" +#include "qemu/queue.h" +#include "qemu/lockable.h" #include "threadinfo.h" +QemuMutex migration_threads_lock; static QLIST_HEAD(, MigrationThread) migration_threads; +static void __attribute__((constructor)) migration_threads_init(void) +{ + qemu_mutex_init(&migration_threads_lock); +} + MigrationThread *migration_threads_add(const char *name, int thread_id) { MigrationThread *thread = g_new0(MigrationThread, 1); thread->name = name; thread->thread_id = thread_id; - QLIST_INSERT_HEAD(&migration_threads, thread, node); + WITH_QEMU_LOCK_GUARD(&migration_threads_lock) { + QLIST_INSERT_HEAD(&migration_threads, thread, node); + } return thread; } void migration_threads_remove(MigrationThread *thread) { + QEMU_LOCK_GUARD(&migration_threads_lock); if (thread) { QLIST_REMOVE(thread, node); g_free(thread); @@ -XXX,XX +XXX,XX @@ MigrationThreadInfoList *qmp_query_migrationthreads(Error **errp) MigrationThreadInfoList **tail = &head; MigrationThread *thread = NULL; + QEMU_LOCK_GUARD(&migration_threads_lock); QLIST_FOREACH(thread, &migration_threads, node) { MigrationThreadInfo *info = g_new0(MigrationThreadInfo, 1); info->name = g_strdup(thread->name); -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> dirty_rate paraemter of hmp command "set_vcpu_dirty_limit" is invalid if less than 0, so add parameter check for it. Note that this patch also delete the unsolicited help message and clean up the code. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-Id: <168618975839.6361.17407633874747688653-1@git.sr.ht> Signed-off-by: Juan Quintela <quintela@redhat.com> --- softmmu/dirtylimit.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -XXX,XX +XXX,XX @@ void hmp_set_vcpu_dirty_limit(Monitor *mon, const QDict *qdict) int64_t cpu_index = qdict_get_try_int(qdict, "cpu_index", -1); Error *err = NULL; + if (dirty_rate < 0) { + error_setg(&err, "invalid dirty page limit %" PRId64, dirty_rate); + goto out; + } + qmp_set_vcpu_dirty_limit(!!(cpu_index != -1), cpu_index, dirty_rate, &err); - if (err) { - hmp_handle_error(mon, err); - return; - } - monitor_printf(mon, "[Please use 'info vcpu_dirty_limit' to query " - "dirty limit for virtual CPU]\n"); +out: + hmp_handle_error(mon, err); } static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index) -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> Introduce "x-vcpu-dirty-limit-period" migration experimental parameter, which is in the range of 1 to 1000ms and used to make dirtyrate calculation period configurable. Currently with the "x-vcpu-dirty-limit-period" varies, the total time of live migration changes, test results show the optimal value of "x-vcpu-dirty-limit-period" ranges from 500ms to 1000 ms. "x-vcpu-dirty-limit-period" should be made stable once it proves best value can not be determined with developer's experiments. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-Id: <168618975839.6361.17407633874747688653-2@git.sr.ht> Signed-off-by: Juan Quintela <quintela@redhat.com> --- qapi/migration.json | 34 +++++++++++++++++++++++++++------- migration/migration-hmp-cmds.c | 8 ++++++++ migration/options.c | 28 ++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/qapi/migration.json b/qapi/migration.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -XXX,XX +XXX,XX @@ # Nodes are mapped to their block device name if there is one, and # to their node name otherwise. (Since 5.2) # +# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty limit during +# live migration. Should be in the range 1 to 1000ms, +# defaults to 1000ms. (Since 8.1) +# # Features: # -# @unstable: Member @x-checkpoint-delay is experimental. +# @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period +# are experimental. # # Since: 2.4 ## @@ -XXX,XX +XXX,XX @@ 'multifd-channels', 'xbzrle-cache-size', 'max-postcopy-bandwidth', 'max-cpu-throttle', 'multifd-compression', - 'multifd-zlib-level' ,'multifd-zstd-level', - 'block-bitmap-mapping' ] } + 'multifd-zlib-level', 'multifd-zstd-level', + 'block-bitmap-mapping', + { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] } ] } ## # @MigrateSetParameters: @@ -XXX,XX +XXX,XX @@ # Nodes are mapped to their block device name if there is one, and # to their node name otherwise. (Since 5.2) # +# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty limit during +# live migration. Should be in the range 1 to 1000ms, +# defaults to 1000ms. (Since 8.1) +# # Features: # -# @unstable: Member @x-checkpoint-delay is experimental. +# @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period +# are experimental. # # TODO: either fuse back into MigrationParameters, or make # MigrationParameters members mandatory @@ -XXX,XX +XXX,XX @@ '*multifd-compression': 'MultiFDCompression', '*multifd-zlib-level': 'uint8', '*multifd-zstd-level': 'uint8', - '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], + '*x-vcpu-dirty-limit-period': { 'type': 'uint64', + 'features': [ 'unstable' ] } } } ## # @migrate-set-parameters: @@ -XXX,XX +XXX,XX @@ # Nodes are mapped to their block device name if there is one, and # to their node name otherwise. (Since 5.2) # +# @x-vcpu-dirty-limit-period: Periodic time (in milliseconds) of dirty limit during +# live migration. Should be in the range 1 to 1000ms, +# defaults to 1000ms. (Since 8.1) +# # Features: # -# @unstable: Member @x-checkpoint-delay is experimental. +# @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period +# are experimental. # # Since: 2.4 ## @@ -XXX,XX +XXX,XX @@ '*multifd-compression': 'MultiFDCompression', '*multifd-zlib-level': 'uint8', '*multifd-zstd-level': 'uint8', - '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ] } } + '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], + '*x-vcpu-dirty-limit-period': { 'type': 'uint64', + 'features': [ 'unstable' ] } } } ## # @query-migrate-parameters: diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) } } } + + monitor_printf(mon, "%s: %" PRIu64 " ms\n", + MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD), + params->x_vcpu_dirty_limit_period); } qapi_free_MigrationParameters(params); @@ -XXX,XX +XXX,XX @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) error_setg(&err, "The block-bitmap-mapping parameter can only be set " "through QMP"); break; + case MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD: + p->has_x_vcpu_dirty_limit_period = true; + visit_type_size(v, param, &p->x_vcpu_dirty_limit_period, &err); + break; default: assert(0); } diff --git a/migration/options.c b/migration/options.c index XXXXXXX..XXXXXXX 100644 --- a/migration/options.c +++ b/migration/options.c @@ -XXX,XX +XXX,XX @@ #define DEFINE_PROP_MIG_CAP(name, x) \ DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false) +#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 1000 /* milliseconds */ + Property migration_properties[] = { DEFINE_PROP_BOOL("store-global-state", MigrationState, store_global_state, true), @@ -XXX,XX +XXX,XX @@ Property migration_properties[] = { DEFINE_PROP_STRING("tls-creds", MigrationState, parameters.tls_creds), DEFINE_PROP_STRING("tls-hostname", MigrationState, parameters.tls_hostname), DEFINE_PROP_STRING("tls-authz", MigrationState, parameters.tls_authz), + DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState, + parameters.x_vcpu_dirty_limit_period, + DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD), /* Migration capabilities */ DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), @@ -XXX,XX +XXX,XX @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) s->parameters.block_bitmap_mapping); } + params->has_x_vcpu_dirty_limit_period = true; + params->x_vcpu_dirty_limit_period = s->parameters.x_vcpu_dirty_limit_period; + return params; } @@ -XXX,XX +XXX,XX @@ void migrate_params_init(MigrationParameters *params) params->has_announce_max = true; params->has_announce_rounds = true; params->has_announce_step = true; + params->has_x_vcpu_dirty_limit_period = true; } /* @@ -XXX,XX +XXX,XX @@ bool migrate_params_check(MigrationParameters *params, Error **errp) } #endif + if (params->has_x_vcpu_dirty_limit_period && + (params->x_vcpu_dirty_limit_period < 1 || + params->x_vcpu_dirty_limit_period > 1000)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "x-vcpu-dirty-limit-period", + "a value between 1 and 1000"); + return false; + } + return true; } @@ -XXX,XX +XXX,XX @@ static void migrate_params_test_apply(MigrateSetParameters *params, dest->has_block_bitmap_mapping = true; dest->block_bitmap_mapping = params->block_bitmap_mapping; } + + if (params->has_x_vcpu_dirty_limit_period) { + dest->x_vcpu_dirty_limit_period = + params->x_vcpu_dirty_limit_period; + } } static void migrate_params_apply(MigrateSetParameters *params, Error **errp) @@ -XXX,XX +XXX,XX @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) QAPI_CLONE(BitmapMigrationNodeAliasList, params->block_bitmap_mapping); } + + if (params->has_x_vcpu_dirty_limit_period) { + s->parameters.x_vcpu_dirty_limit_period = + params->x_vcpu_dirty_limit_period; + } } void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> Introduce "vcpu-dirty-limit" migration parameter used to limit dirty page rate during live migration. "vcpu-dirty-limit" and "x-vcpu-dirty-limit-period" are two dirty-limit-related migration parameters, which can be set before and during live migration by qmp migrate-set-parameters. This two parameters are used to help implement the dirty page rate limit algo of migration. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Acked-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-Id: <168618975839.6361.17407633874747688653-3@git.sr.ht> Signed-off-by: Juan Quintela <quintela@redhat.com> --- qapi/migration.json | 18 +++++++++++++++--- migration/migration-hmp-cmds.c | 8 ++++++++ migration/options.c | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/qapi/migration.json b/qapi/migration.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -XXX,XX +XXX,XX @@ # live migration. Should be in the range 1 to 1000ms, # defaults to 1000ms. (Since 8.1) # +# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration. +# Defaults to 1. (Since 8.1) +# # Features: # # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period @@ -XXX,XX +XXX,XX @@ 'max-cpu-throttle', 'multifd-compression', 'multifd-zlib-level', 'multifd-zstd-level', 'block-bitmap-mapping', - { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] } ] } + { 'name': 'x-vcpu-dirty-limit-period', 'features': ['unstable'] }, + 'vcpu-dirty-limit'] } ## # @MigrateSetParameters: @@ -XXX,XX +XXX,XX @@ # live migration. Should be in the range 1 to 1000ms, # defaults to 1000ms. (Since 8.1) # +# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration. +# Defaults to 1. (Since 8.1) +# # Features: # # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period @@ -XXX,XX +XXX,XX @@ '*multifd-zstd-level': 'uint8', '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], '*x-vcpu-dirty-limit-period': { 'type': 'uint64', - 'features': [ 'unstable' ] } } } + 'features': [ 'unstable' ] }, + '*vcpu-dirty-limit': 'uint64'} } ## # @migrate-set-parameters: @@ -XXX,XX +XXX,XX @@ # live migration. Should be in the range 1 to 1000ms, # defaults to 1000ms. (Since 8.1) # +# @vcpu-dirty-limit: Dirtyrate limit (MB/s) during live migration. +# Defaults to 1. (Since 8.1) +# # Features: # # @unstable: Members @x-checkpoint-delay and @x-vcpu-dirty-limit-period @@ -XXX,XX +XXX,XX @@ '*multifd-zstd-level': 'uint8', '*block-bitmap-mapping': [ 'BitmapMigrationNodeAlias' ], '*x-vcpu-dirty-limit-period': { 'type': 'uint64', - 'features': [ 'unstable' ] } } } + 'features': [ 'unstable' ] }, + '*vcpu-dirty-limit': 'uint64'} } ## # @query-migrate-parameters: diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_info_migrate_parameters(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%s: %" PRIu64 " ms\n", MigrationParameter_str(MIGRATION_PARAMETER_X_VCPU_DIRTY_LIMIT_PERIOD), params->x_vcpu_dirty_limit_period); + + monitor_printf(mon, "%s: %" PRIu64 " MB/s\n", + MigrationParameter_str(MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT), + params->vcpu_dirty_limit); } qapi_free_MigrationParameters(params); @@ -XXX,XX +XXX,XX @@ void hmp_migrate_set_parameter(Monitor *mon, const QDict *qdict) p->has_x_vcpu_dirty_limit_period = true; visit_type_size(v, param, &p->x_vcpu_dirty_limit_period, &err); break; + case MIGRATION_PARAMETER_VCPU_DIRTY_LIMIT: + p->has_vcpu_dirty_limit = true; + visit_type_size(v, param, &p->vcpu_dirty_limit, &err); + break; default: assert(0); } diff --git a/migration/options.c b/migration/options.c index XXXXXXX..XXXXXXX 100644 --- a/migration/options.c +++ b/migration/options.c @@ -XXX,XX +XXX,XX @@ DEFINE_PROP_BOOL(name, MigrationState, capabilities[x], false) #define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD 1000 /* milliseconds */ +#define DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT 1 /* MB/s */ Property migration_properties[] = { DEFINE_PROP_BOOL("store-global-state", MigrationState, @@ -XXX,XX +XXX,XX @@ Property migration_properties[] = { DEFINE_PROP_UINT64("x-vcpu-dirty-limit-period", MigrationState, parameters.x_vcpu_dirty_limit_period, DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT_PERIOD), + DEFINE_PROP_UINT64("vcpu-dirty-limit", MigrationState, + parameters.vcpu_dirty_limit, + DEFAULT_MIGRATE_VCPU_DIRTY_LIMIT), /* Migration capabilities */ DEFINE_PROP_MIG_CAP("x-xbzrle", MIGRATION_CAPABILITY_XBZRLE), @@ -XXX,XX +XXX,XX @@ MigrationParameters *qmp_query_migrate_parameters(Error **errp) params->has_x_vcpu_dirty_limit_period = true; params->x_vcpu_dirty_limit_period = s->parameters.x_vcpu_dirty_limit_period; + params->has_vcpu_dirty_limit = true; + params->vcpu_dirty_limit = s->parameters.vcpu_dirty_limit; return params; } @@ -XXX,XX +XXX,XX @@ void migrate_params_init(MigrationParameters *params) params->has_announce_rounds = true; params->has_announce_step = true; params->has_x_vcpu_dirty_limit_period = true; + params->has_vcpu_dirty_limit = true; } /* @@ -XXX,XX +XXX,XX @@ bool migrate_params_check(MigrationParameters *params, Error **errp) return false; } + if (params->has_vcpu_dirty_limit && + (params->vcpu_dirty_limit < 1)) { + error_setg(errp, QERR_INVALID_PARAMETER_VALUE, + "vcpu_dirty_limit", + "is invalid, it must greater then 1 MB/s"); + return false; + } + return true; } @@ -XXX,XX +XXX,XX @@ static void migrate_params_test_apply(MigrateSetParameters *params, dest->x_vcpu_dirty_limit_period = params->x_vcpu_dirty_limit_period; } + if (params->has_vcpu_dirty_limit) { + dest->vcpu_dirty_limit = params->vcpu_dirty_limit; + } } static void migrate_params_apply(MigrateSetParameters *params, Error **errp) @@ -XXX,XX +XXX,XX @@ static void migrate_params_apply(MigrateSetParameters *params, Error **errp) s->parameters.x_vcpu_dirty_limit_period = params->x_vcpu_dirty_limit_period; } + if (params->has_vcpu_dirty_limit) { + s->parameters.vcpu_dirty_limit = params->vcpu_dirty_limit; + } } void qmp_migrate_set_parameters(MigrateSetParameters *params, Error **errp) -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> Introduce migration dirty-limit capability, which can be turned on before live migration and limit dirty page rate durty live migration. Introduce migrate_dirty_limit function to help check if dirty-limit capability enabled during live migration. Meanwhile, refactor vcpu_dirty_rate_stat_collect so that period can be configured instead of hardcoded. dirty-limit capability is kind of like auto-converge but using dirty limit instead of traditional cpu-throttle to throttle guest down. To enable this feature, turn on the dirty-limit capability before live migration using migrate-set-capabilities, and set the parameters "x-vcpu-dirty-limit-period", "vcpu-dirty-limit" suitably to speed up convergence. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Acked-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-Id: <168618975839.6361.17407633874747688653-4@git.sr.ht> Signed-off-by: Juan Quintela <quintela@redhat.com> --- qapi/migration.json | 12 +++++++++++- migration/options.h | 1 + migration/options.c | 23 +++++++++++++++++++++++ softmmu/dirtylimit.c | 18 ++++++++++++++---- 4 files changed, 49 insertions(+), 5 deletions(-) diff --git a/qapi/migration.json b/qapi/migration.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -XXX,XX +XXX,XX @@ # and should not affect the correctness of postcopy migration. # (since 7.1) # +# @dirty-limit: If enabled, migration will use the dirty-limit algo to +# throttle down guest instead of auto-converge algo. +# Throttle algo only works when vCPU's dirtyrate greater +# than 'vcpu-dirty-limit', read processes in guest os +# aren't penalized any more, so this algo can improve +# performance of vCPU during live migration. This is an +# optional performance feature and should not affect the +# correctness of the existing auto-converge algo. +# (since 8.1) +# # Features: # # @unstable: Members @x-colo and @x-ignore-shared are experimental. @@ -XXX,XX +XXX,XX @@ 'dirty-bitmaps', 'postcopy-blocktime', 'late-block-activate', { 'name': 'x-ignore-shared', 'features': [ 'unstable' ] }, 'validate-uuid', 'background-snapshot', - 'zero-copy-send', 'postcopy-preempt'] } + 'zero-copy-send', 'postcopy-preempt', 'dirty-limit'] } ## # @MigrationCapabilityStatus: diff --git a/migration/options.h b/migration/options.h index XXXXXXX..XXXXXXX 100644 --- a/migration/options.h +++ b/migration/options.h @@ -XXX,XX +XXX,XX @@ bool migrate_block(void); bool migrate_colo(void); bool migrate_compress(void); bool migrate_dirty_bitmaps(void); +bool migrate_dirty_limit(void); bool migrate_events(void); bool migrate_ignore_shared(void); bool migrate_late_block_activate(void); diff --git a/migration/options.c b/migration/options.c index XXXXXXX..XXXXXXX 100644 --- a/migration/options.c +++ b/migration/options.c @@ -XXX,XX +XXX,XX @@ #include "qemu-file.h" #include "ram.h" #include "options.h" +#include "sysemu/kvm.h" /* Maximum migrate downtime set to 2000 seconds */ #define MAX_MIGRATE_DOWNTIME_SECONDS 2000 @@ -XXX,XX +XXX,XX @@ Property migration_properties[] = { DEFINE_PROP_MIG_CAP("x-zero-copy-send", MIGRATION_CAPABILITY_ZERO_COPY_SEND), #endif + DEFINE_PROP_MIG_CAP("x-dirty-limit", MIGRATION_CAPABILITY_DIRTY_LIMIT), DEFINE_PROP_END_OF_LIST(), }; @@ -XXX,XX +XXX,XX @@ bool migrate_dirty_bitmaps(void) return s->capabilities[MIGRATION_CAPABILITY_DIRTY_BITMAPS]; } +bool migrate_dirty_limit(void) +{ + MigrationState *s = migrate_get_current(); + + return s->capabilities[MIGRATION_CAPABILITY_DIRTY_LIMIT]; +} + bool migrate_events(void) { MigrationState *s = migrate_get_current(); @@ -XXX,XX +XXX,XX @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) } } + if (new_caps[MIGRATION_CAPABILITY_DIRTY_LIMIT]) { + if (new_caps[MIGRATION_CAPABILITY_AUTO_CONVERGE]) { + error_setg(errp, "dirty-limit conflicts with auto-converge" + " either of then available currently"); + return false; + } + + if (!kvm_enabled() || !kvm_dirty_ring_enabled()) { + error_setg(errp, "dirty-limit requires KVM with accelerator" + " property 'dirty-ring-size' set"); + return false; + } + } + return true; } diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -XXX,XX +XXX,XX @@ #include "hw/boards.h" #include "sysemu/kvm.h" #include "trace.h" +#include "migration/misc.h" +#include "migration/migration.h" +#include "migration/options.h" /* * Dirtylimit stop working if dirty page rate error @@ -XXX,XX +XXX,XX @@ static bool dirtylimit_quit; static void vcpu_dirty_rate_stat_collect(void) { + MigrationState *s = migrate_get_current(); VcpuStat stat; int i = 0; + int64_t period = DIRTYLIMIT_CALC_TIME_MS; + + if (migrate_dirty_limit() && + migration_is_active(s)) { + period = s->parameters.x_vcpu_dirty_limit_period; + } /* calculate vcpu dirtyrate */ - vcpu_calculate_dirtyrate(DIRTYLIMIT_CALC_TIME_MS, - &stat, - GLOBAL_DIRTY_LIMIT, - false); + vcpu_calculate_dirtyrate(period, + &stat, + GLOBAL_DIRTY_LIMIT, + false); for (i = 0; i < stat.nvcpu; i++) { vcpu_dirty_rate_stat->stat.rates[i].id = i; -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> Check if block migration is running before throttling guest down in auto-converge way. Note that this modification is kind of like code clean, because block migration does not depend on auto-converge capability, so the order of checks can be adjusted. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Acked-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-Id: <168618975839.6361.17407633874747688653-5@git.sr.ht> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/ram.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/migration/ram.c b/migration/ram.c index XXXXXXX..XXXXXXX 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -XXX,XX +XXX,XX @@ static void migration_trigger_throttle(RAMState *rs) /* During block migration the auto-converge logic incorrectly detects * that ram migration makes no progress. Avoid this by disabling the * throttling logic during the bulk phase of block migration. */ - if (migrate_auto_converge() && !blk_mig_bulk_active()) { + if (blk_mig_bulk_active()) { + return; + } + + if (migrate_auto_converge()) { /* The following detection logic can be refined later. For now: Check to see if the ratio between dirtied bytes and the approx. amount of bytes that just got transferred since the last time -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> This commit is prepared for the implementation of dirty-limit convergence algo. The detection logic of throttling condition can apply to both auto-converge and dirty-limit algo, putting it's position before the checking logic for auto-converge feature. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-ID: <168733225273.5845.15871826788879741674-6@git.sr.ht> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/ram.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index XXXXXXX..XXXXXXX 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -XXX,XX +XXX,XX @@ static void migration_trigger_throttle(RAMState *rs) return; } - if (migrate_auto_converge()) { - /* The following detection logic can be refined later. For now: - Check to see if the ratio between dirtied bytes and the approx. - amount of bytes that just got transferred since the last time - we were in this routine reaches the threshold. If that happens - twice, start or increase throttling. */ - - if ((bytes_dirty_period > bytes_dirty_threshold) && - (++rs->dirty_rate_high_cnt >= 2)) { + /* + * The following detection logic can be refined later. For now: + * Check to see if the ratio between dirtied bytes and the approx. + * amount of bytes that just got transferred since the last time + * we were in this routine reaches the threshold. If that happens + * twice, start or increase throttling. + */ + if ((bytes_dirty_period > bytes_dirty_threshold) && + (++rs->dirty_rate_high_cnt >= 2)) { + rs->dirty_rate_high_cnt = 0; + if (migrate_auto_converge()) { trace_migration_throttle(); - rs->dirty_rate_high_cnt = 0; mig_throttle_guest_down(bytes_dirty_period, bytes_dirty_threshold); } -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> Implement dirty-limit convergence algo for live migration, which is kind of like auto-converge algo but using dirty-limit instead of cpu throttle to make migration convergent. Enable dirty page limit if dirty_rate_high_cnt greater than 2 when dirty-limit capability enabled, Disable dirty-limit if migration be canceled. Note that "set_vcpu_dirty_limit", "cancel_vcpu_dirty_limit" commands are not allowed during dirty-limit live migration. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Message-ID: <168733225273.5845.15871826788879741674-7@git.sr.ht> Reviewed-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/migration.c | 3 +++ migration/ram.c | 36 ++++++++++++++++++++++++++++++++++++ softmmu/dirtylimit.c | 29 +++++++++++++++++++++++++++++ migration/trace-events | 1 + 4 files changed, 69 insertions(+) diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ void migration_cancel(const Error *error) if (error) { migrate_set_error(current_migration, error); } + if (migrate_dirty_limit()) { + qmp_cancel_vcpu_dirty_limit(false, -1, NULL); + } migrate_fd_cancel(current_migration); } diff --git a/migration/ram.c b/migration/ram.c index XXXXXXX..XXXXXXX 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -XXX,XX +XXX,XX @@ #include "qapi/error.h" #include "qapi/qapi-types-migration.h" #include "qapi/qapi-events-migration.h" +#include "qapi/qapi-commands-migration.h" #include "qapi/qmp/qerror.h" #include "trace.h" #include "exec/ram_addr.h" @@ -XXX,XX +XXX,XX @@ #include "multifd.h" #include "sysemu/runstate.h" #include "options.h" +#include "sysemu/dirtylimit.h" +#include "sysemu/kvm.h" #include "hw/boards.h" /* for machine_dump_guest_core() */ @@ -XXX,XX +XXX,XX @@ static void migration_update_rates(RAMState *rs, int64_t end_time) } } +/* + * Enable dirty-limit to throttle down the guest + */ +static void migration_dirty_limit_guest(void) +{ + /* + * dirty page rate quota for all vCPUs fetched from + * migration parameter 'vcpu_dirty_limit' + */ + static int64_t quota_dirtyrate; + MigrationState *s = migrate_get_current(); + + /* + * If dirty limit already enabled and migration parameter + * vcpu-dirty-limit untouched. + */ + if (dirtylimit_in_service() && + quota_dirtyrate == s->parameters.vcpu_dirty_limit) { + return; + } + + quota_dirtyrate = s->parameters.vcpu_dirty_limit; + + /* + * Set all vCPU a quota dirtyrate, note that the second + * parameter will be ignored if setting all vCPU for the vm + */ + qmp_set_vcpu_dirty_limit(false, -1, quota_dirtyrate, NULL); + trace_migration_dirty_limit_guest(quota_dirtyrate); +} + static void migration_trigger_throttle(RAMState *rs) { uint64_t threshold = migrate_throttle_trigger_threshold(); @@ -XXX,XX +XXX,XX @@ static void migration_trigger_throttle(RAMState *rs) trace_migration_throttle(); mig_throttle_guest_down(bytes_dirty_period, bytes_dirty_threshold); + } else if (migrate_dirty_limit()) { + migration_dirty_limit_guest(); } } } diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -XXX,XX +XXX,XX @@ static void dirtylimit_cleanup(void) dirtylimit_state_finalize(); } +/* + * dirty page rate limit is not allowed to set if migration + * is running with dirty-limit capability enabled. + */ +static bool dirtylimit_is_allowed(void) +{ + MigrationState *ms = migrate_get_current(); + + if (migration_is_running(ms->state) && + (!qemu_thread_is_self(&ms->thread)) && + migrate_dirty_limit() && + dirtylimit_in_service()) { + return false; + } + return true; +} + void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, int64_t cpu_index, Error **errp) @@ -XXX,XX +XXX,XX @@ void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index, return; } + if (!dirtylimit_is_allowed()) { + error_setg(errp, "can't cancel dirty page rate limit while" + " migration is running"); + return; + } + if (!dirtylimit_in_service()) { return; } @@ -XXX,XX +XXX,XX @@ void qmp_set_vcpu_dirty_limit(bool has_cpu_index, return; } + if (!dirtylimit_is_allowed()) { + error_setg(errp, "can't set dirty page rate limit while" + " migration is running"); + return; + } + if (!dirty_rate) { qmp_cancel_vcpu_dirty_limit(has_cpu_index, cpu_index, errp); return; diff --git a/migration/trace-events b/migration/trace-events index XXXXXXX..XXXXXXX 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -XXX,XX +XXX,XX @@ migration_bitmap_sync_start(void) "" migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64 migration_bitmap_clear_dirty(char *str, uint64_t start, uint64_t size, unsigned long page) "rb %s start 0x%"PRIx64" size 0x%"PRIx64" page 0x%lx" migration_throttle(void) "" +migration_dirty_limit_guest(int64_t dirtyrate) "guest dirty page rate limit %" PRIi64 " MB/s" ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx" ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: addr: 0x%" PRIx64 " flags: 0x%x host: %p" ram_load_postcopy_loop(int channel, uint64_t addr, int flags) "chan=%d addr=0x%" PRIx64 " flags=0x%x" -- 2.40.1
From: Hyman Huang(黄勇) <yong.huang@smartx.com> Extend query-migrate to provide throttle time and estimated ring full time with dirty-limit capability enabled, through which we can observe if dirty limit take effect during live migration. Signed-off-by: Hyman Huang(黄勇) <yong.huang@smartx.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-ID: <168733225273.5845.15871826788879741674-8@git.sr.ht> Signed-off-by: Juan Quintela <quintela@redhat.com> --- qapi/migration.json | 16 +++++++++++++- include/sysemu/dirtylimit.h | 2 ++ migration/migration-hmp-cmds.c | 10 +++++++++ migration/migration.c | 10 +++++++++ softmmu/dirtylimit.c | 39 ++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 1 deletion(-) diff --git a/qapi/migration.json b/qapi/migration.json index XXXXXXX..XXXXXXX 100644 --- a/qapi/migration.json +++ b/qapi/migration.json @@ -XXX,XX +XXX,XX @@ # blocked. Present and non-empty when migration is blocked. # (since 6.0) # +# @dirty-limit-throttle-time-per-round: Maximum throttle time (in microseconds) of virtual +# CPUs each dirty ring full round, which shows how +# MigrationCapability dirty-limit affects the guest +# during live migration. (since 8.1) +# +# @dirty-limit-ring-full-time: Estimated average dirty ring full time (in microseconds) +# each dirty ring full round, note that the value equals +# dirty ring memory size divided by average dirty page rate +# of virtual CPU, which can be used to observe the average +# memory load of virtual CPU indirectly. Note that zero +# means guest doesn't dirty memory (since 8.1) +# # Since: 0.14 ## { 'struct': 'MigrationInfo', @@ -XXX,XX +XXX,XX @@ '*postcopy-blocktime' : 'uint32', '*postcopy-vcpu-blocktime': ['uint32'], '*compression': 'CompressionStats', - '*socket-address': ['SocketAddress'] } } + '*socket-address': ['SocketAddress'], + '*dirty-limit-throttle-time-per-round': 'uint64', + '*dirty-limit-ring-full-time': 'uint64'} } ## # @query-migrate: diff --git a/include/sysemu/dirtylimit.h b/include/sysemu/dirtylimit.h index XXXXXXX..XXXXXXX 100644 --- a/include/sysemu/dirtylimit.h +++ b/include/sysemu/dirtylimit.h @@ -XXX,XX +XXX,XX @@ void dirtylimit_set_vcpu(int cpu_index, void dirtylimit_set_all(uint64_t quota, bool enable); void dirtylimit_vcpu_execute(CPUState *cpu); +uint64_t dirtylimit_throttle_time_per_round(void); +uint64_t dirtylimit_ring_full_time(void); #endif diff --git a/migration/migration-hmp-cmds.c b/migration/migration-hmp-cmds.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration-hmp-cmds.c +++ b/migration/migration-hmp-cmds.c @@ -XXX,XX +XXX,XX @@ void hmp_info_migrate(Monitor *mon, const QDict *qdict) info->cpu_throttle_percentage); } + if (info->has_dirty_limit_throttle_time_per_round) { + monitor_printf(mon, "dirty-limit throttle time: %" PRIu64 " us\n", + info->dirty_limit_throttle_time_per_round); + } + + if (info->has_dirty_limit_ring_full_time) { + monitor_printf(mon, "dirty-limit ring full time: %" PRIu64 " us\n", + info->dirty_limit_ring_full_time); + } + if (info->has_postcopy_blocktime) { monitor_printf(mon, "postcopy blocktime: %u\n", info->postcopy_blocktime); diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ #include "yank_functions.h" #include "sysemu/qtest.h" #include "options.h" +#include "sysemu/dirtylimit.h" static NotifierList migration_state_notifiers = NOTIFIER_LIST_INITIALIZER(migration_state_notifiers); @@ -XXX,XX +XXX,XX @@ static void populate_ram_info(MigrationInfo *info, MigrationState *s) info->ram->dirty_pages_rate = stat64_get(&mig_stats.dirty_pages_rate); } + + if (migrate_dirty_limit() && dirtylimit_in_service()) { + info->has_dirty_limit_throttle_time_per_round = true; + info->dirty_limit_throttle_time_per_round = + dirtylimit_throttle_time_per_round(); + + info->has_dirty_limit_ring_full_time = true; + info->dirty_limit_ring_full_time = dirtylimit_ring_full_time(); + } } static void populate_disk_info(MigrationInfo *info) diff --git a/softmmu/dirtylimit.c b/softmmu/dirtylimit.c index XXXXXXX..XXXXXXX 100644 --- a/softmmu/dirtylimit.c +++ b/softmmu/dirtylimit.c @@ -XXX,XX +XXX,XX @@ out: hmp_handle_error(mon, err); } +/* Return the max throttle time of each virtual CPU */ +uint64_t dirtylimit_throttle_time_per_round(void) +{ + CPUState *cpu; + int64_t max = 0; + + CPU_FOREACH(cpu) { + if (cpu->throttle_us_per_full > max) { + max = cpu->throttle_us_per_full; + } + } + + return max; +} + +/* + * Estimate average dirty ring full time of each virtaul CPU. + * Return 0 if guest doesn't dirty memory. + */ +uint64_t dirtylimit_ring_full_time(void) +{ + CPUState *cpu; + uint64_t curr_rate = 0; + int nvcpus = 0; + + CPU_FOREACH(cpu) { + if (cpu->running) { + nvcpus++; + curr_rate += vcpu_dirty_rate_get(cpu->cpu_index); + } + } + + if (!curr_rate || !nvcpus) { + return 0; + } + + return dirtylimit_dirty_ring_full_time(curr_rate / nvcpus); +} + static struct DirtyLimitInfo *dirtylimit_query_vcpu(int cpu_index) { DirtyLimitInfo *info = NULL; -- 2.40.1
It makes no sense that we don't have the same configuration on both sides. Reviewed-by: Laurent Vivier <lvivier@redhat.com> Message-ID: <20230608224943.3877-2-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "'nvramrc=hex .\" _\" begin %x %x " "do i c@ 1 + i c! 1000 +loop .\" B\" 0 " "until'", end_address, start_address); - arch_target = g_strdup(""); + arch_target = g_strdup("-nodefaults"); } else if (strcmp(arch, "aarch64") == 0) { init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel)); machine_opts = "virt,gic-version=max"; -- 2.40.1
Reviewed-by: Peter Xu <peterx@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> Message-ID: <20230608224943.3877-5-quintela@redhat.com> --- tests/qtest/migration-test.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, start_address = S390_TEST_MEM_START; end_address = S390_TEST_MEM_END; } else if (strcmp(arch, "ppc64") == 0) { - machine_opts = "vsmt=8"; + machine_opts = "-machine vsmt=8"; memory_size = "256M"; start_address = PPC_TEST_MEM_START; end_address = PPC_TEST_MEM_END; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, arch_target = g_strdup("-nodefaults"); } else if (strcmp(arch, "aarch64") == 0) { init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel)); - machine_opts = "virt,gic-version=max"; + machine_opts = "-machine virt,gic-version=max"; memory_size = "150M"; arch_source = g_strdup_printf("-cpu max " "-kernel %s", @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, shmem_opts = g_strdup(""); } - cmd_source = g_strdup_printf("-accel kvm%s -accel tcg%s%s " + cmd_source = g_strdup_printf("-accel kvm%s -accel tcg %s " "-name source,debug-threads=on " "-m %s " "-serial file:%s/src_serial " "%s %s %s %s", args->use_dirty_ring ? ",dirty-ring-size=4096" : "", - machine_opts ? " -machine " : "", machine_opts ? machine_opts : "", memory_size, tmpfs, arch_source, shmem_opts, @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, &got_src_stop); } - cmd_target = g_strdup_printf("-accel kvm%s -accel tcg%s%s " + cmd_target = g_strdup_printf("-accel kvm%s -accel tcg %s " "-name target,debug-threads=on " "-m %s " "-serial file:%s/dest_serial " @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "%s %s %s %s", args->use_dirty_ring ? ",dirty-ring-size=4096" : "", - machine_opts ? " -machine " : "", machine_opts ? machine_opts : "", memory_size, tmpfs, uri, arch_target, shmem_opts, -- 2.40.1
This will contain the options needed for both source and target. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230608224943.3877-6-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, { g_autofree gchar *arch_source = NULL; g_autofree gchar *arch_target = NULL; + /* options for source and target */ + g_autofree gchar *arch_opts = NULL; g_autofree gchar *cmd_source = NULL; g_autofree gchar *cmd_target = NULL; const gchar *ignore_stderr; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, assert(sizeof(x86_bootsect) == 512); init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); memory_size = "150M"; - arch_source = g_strdup_printf("-drive file=%s,format=raw", bootpath); - arch_target = g_strdup(arch_source); + arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); start_address = X86_TEST_MEM_START; end_address = X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf)); memory_size = "128M"; - arch_source = g_strdup_printf("-bios %s", bootpath); - arch_target = g_strdup(arch_source); + arch_opts = g_strdup_printf("-bios %s", bootpath); start_address = S390_TEST_MEM_START; end_address = S390_TEST_MEM_END; } else if (strcmp(arch, "ppc64") == 0) { @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size = "256M"; start_address = PPC_TEST_MEM_START; end_address = PPC_TEST_MEM_END; - arch_source = g_strdup_printf("-nodefaults " - "-prom-env 'use-nvramrc?=true' -prom-env " + arch_source = g_strdup_printf("-prom-env 'use-nvramrc?=true' -prom-env " "'nvramrc=hex .\" _\" begin %x %x " "do i c@ 1 + i c! 1000 +loop .\" B\" 0 " "until'", end_address, start_address); - arch_target = g_strdup("-nodefaults"); + arch_opts = g_strdup("-nodefaults"); } else if (strcmp(arch, "aarch64") == 0) { init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel)); machine_opts = "-machine virt,gic-version=max"; memory_size = "150M"; - arch_source = g_strdup_printf("-cpu max " - "-kernel %s", - bootpath); - arch_target = g_strdup(arch_source); + arch_opts = g_strdup_printf("-cpu max -kernel %s", bootpath); start_address = ARM_TEST_MEM_START; end_address = ARM_TEST_MEM_END; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "-name source,debug-threads=on " "-m %s " "-serial file:%s/src_serial " - "%s %s %s %s", + "%s %s %s %s %s", args->use_dirty_ring ? ",dirty-ring-size=4096" : "", machine_opts ? machine_opts : "", memory_size, tmpfs, - arch_source, shmem_opts, + arch_opts ? arch_opts : "", + arch_source ? arch_source : "", + shmem_opts, args->opts_source ? args->opts_source : "", ignore_stderr); if (!args->only_target) { @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "-m %s " "-serial file:%s/dest_serial " "-incoming %s " - "%s %s %s %s", + "%s %s %s %s %s", args->use_dirty_ring ? ",dirty-ring-size=4096" : "", machine_opts ? machine_opts : "", memory_size, tmpfs, uri, - arch_target, shmem_opts, + arch_opts ? arch_opts : "", + arch_target ? arch_target : "", + shmem_opts, args->opts_target ? args->opts_target : "", ignore_stderr); *to = qtest_init(cmd_target); -- 2.40.1
And it needs to be in both source and target, so put it on arch_opts. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230608224943.3877-7-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, g_autofree char *shmem_opts = NULL; g_autofree char *shmem_path = NULL; const char *arch = qtest_get_arch(); - const char *machine_opts = NULL; const char *memory_size; if (args->use_shmem) { @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, start_address = S390_TEST_MEM_START; end_address = S390_TEST_MEM_END; } else if (strcmp(arch, "ppc64") == 0) { - machine_opts = "-machine vsmt=8"; memory_size = "256M"; start_address = PPC_TEST_MEM_START; end_address = PPC_TEST_MEM_END; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "'nvramrc=hex .\" _\" begin %x %x " "do i c@ 1 + i c! 1000 +loop .\" B\" 0 " "until'", end_address, start_address); - arch_opts = g_strdup("-nodefaults"); + arch_opts = g_strdup("-nodefaults -machine vsmt=8"); } else if (strcmp(arch, "aarch64") == 0) { init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel)); - machine_opts = "-machine virt,gic-version=max"; memory_size = "150M"; - arch_opts = g_strdup_printf("-cpu max -kernel %s", bootpath); + arch_opts = g_strdup_printf("-machine virt,gic-version=max -cpu max " + "-kernel %s", bootpath); start_address = ARM_TEST_MEM_START; end_address = ARM_TEST_MEM_END; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, shmem_opts = g_strdup(""); } - cmd_source = g_strdup_printf("-accel kvm%s -accel tcg %s " + cmd_source = g_strdup_printf("-accel kvm%s -accel tcg " "-name source,debug-threads=on " "-m %s " "-serial file:%s/src_serial " "%s %s %s %s %s", args->use_dirty_ring ? ",dirty-ring-size=4096" : "", - machine_opts ? machine_opts : "", memory_size, tmpfs, arch_opts ? arch_opts : "", arch_source ? arch_source : "", @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, &got_src_stop); } - cmd_target = g_strdup_printf("-accel kvm%s -accel tcg %s " + cmd_target = g_strdup_printf("-accel kvm%s -accel tcg " "-name target,debug-threads=on " "-m %s " "-serial file:%s/dest_serial " @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "%s %s %s %s %s", args->use_dirty_ring ? ",dirty-ring-size=4096" : "", - machine_opts ? machine_opts : "", memory_size, tmpfs, uri, arch_opts ? arch_opts : "", arch_target ? arch_target : "", -- 2.40.1
So arch_dirty_ring option becomes one option like the others. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230608224943.3877-8-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, g_autofree char *bootpath = NULL; g_autofree char *shmem_opts = NULL; g_autofree char *shmem_path = NULL; + const char *kvm_opts = NULL; const char *arch = qtest_get_arch(); const char *memory_size; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, shmem_opts = g_strdup(""); } + if (args->use_dirty_ring) { + kvm_opts = ",dirty-ring-size=4096"; + } + cmd_source = g_strdup_printf("-accel kvm%s -accel tcg " "-name source,debug-threads=on " "-m %s " "-serial file:%s/src_serial " "%s %s %s %s %s", - args->use_dirty_ring ? - ",dirty-ring-size=4096" : "", + kvm_opts ? kvm_opts : "", memory_size, tmpfs, arch_opts ? arch_opts : "", arch_source ? arch_source : "", @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "-serial file:%s/dest_serial " "-incoming %s " "%s %s %s %s %s", - args->use_dirty_ring ? - ",dirty-ring-size=4096" : "", + kvm_opts ? kvm_opts : "", memory_size, tmpfs, uri, arch_opts ? arch_opts : "", arch_target ? arch_target : "", -- 2.40.1
So just make it a global variable. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230608224943.3877-9-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static bool ufd_version_check(void) #endif static char *tmpfs; +static char *bootpath; /* The boot file modifies memory area in [start_address, end_address) * repeatedly. It outputs a 'B' at a fixed rate while it's still running. @@ -XXX,XX +XXX,XX @@ static char *tmpfs; #include "tests/migration/aarch64/a-b-kernel.h" #include "tests/migration/s390x/a-b-bios.h" -static void init_bootfile(const char *bootpath, void *content, size_t len) +static void init_bootfile(void *content, size_t len) { FILE *bootfile = fopen(bootpath, "wb"); @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, g_autofree gchar *cmd_source = NULL; g_autofree gchar *cmd_target = NULL; const gchar *ignore_stderr; - g_autofree char *bootpath = NULL; g_autofree char *shmem_opts = NULL; g_autofree char *shmem_path = NULL; const char *kvm_opts = NULL; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, got_src_stop = false; got_dst_resume = false; - bootpath = g_strdup_printf("%s/bootsect", tmpfs); if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { /* the assembled x86 boot sector should be exactly one sector large */ assert(sizeof(x86_bootsect) == 512); - init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); + init_bootfile(x86_bootsect, sizeof(x86_bootsect)); memory_size = "150M"; arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); start_address = X86_TEST_MEM_START; end_address = X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { - init_bootfile(bootpath, s390x_elf, sizeof(s390x_elf)); + init_bootfile(s390x_elf, sizeof(s390x_elf)); memory_size = "128M"; arch_opts = g_strdup_printf("-bios %s", bootpath); start_address = S390_TEST_MEM_START; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "until'", end_address, start_address); arch_opts = g_strdup("-nodefaults -machine vsmt=8"); } else if (strcmp(arch, "aarch64") == 0) { - init_bootfile(bootpath, aarch64_kernel, sizeof(aarch64_kernel)); + init_bootfile(aarch64_kernel, sizeof(aarch64_kernel)); memory_size = "150M"; arch_opts = g_strdup_printf("-machine virt,gic-version=max -cpu max " "-kernel %s", bootpath); @@ -XXX,XX +XXX,XX @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest) qtest_quit(to); - cleanup("bootsect"); cleanup("migsocket"); cleanup("src_serial"); cleanup("dest_serial"); @@ -XXX,XX +XXX,XX @@ static QTestState *dirtylimit_start_vm(void) QTestState *vm = NULL; g_autofree gchar *cmd = NULL; const char *arch = qtest_get_arch(); - g_autofree char *bootpath = NULL; assert((strcmp(arch, "x86_64") == 0)); - bootpath = g_strdup_printf("%s/bootsect", tmpfs); assert(sizeof(x86_bootsect) == 512); - init_bootfile(bootpath, x86_bootsect, sizeof(x86_bootsect)); + init_bootfile(x86_bootsect, sizeof(x86_bootsect)); cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " "-name dirtylimit-test,debug-threads=on " @@ -XXX,XX +XXX,XX @@ static QTestState *dirtylimit_start_vm(void) static void dirtylimit_stop_vm(QTestState *vm) { qtest_quit(vm); - cleanup("bootsect"); cleanup("vm_serial"); } @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) g_get_tmp_dir(), err->message); } g_assert(tmpfs); + bootpath = g_strdup_printf("%s/bootsect", tmpfs); module_call_init(MODULE_INIT_QOM); @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) g_assert_cmpint(ret, ==, 0); + cleanup("bootsect"); + g_free(bootpath); ret = rmdir(tmpfs); if (ret != 0) { g_test_message("unable to rmdir: path (%s): %s", -- 2.40.1
The bootsector code is read only from the guest (otherwise we are going to have problems with it being read from both source and destination). Create a single copy for all the tests. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230608224943.3877-10-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 50 ++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static char *bootpath; #include "tests/migration/aarch64/a-b-kernel.h" #include "tests/migration/s390x/a-b-bios.h" -static void init_bootfile(void *content, size_t len) +static void bootfile_create(char *dir) { + const char *arch = qtest_get_arch(); + unsigned char *content; + size_t len; + + bootpath = g_strdup_printf("%s/bootsect", dir); + if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { + /* the assembled x86 boot sector should be exactly one sector large */ + g_assert(sizeof(x86_bootsect) == 512); + content = x86_bootsect; + len = sizeof(x86_bootsect); + } else if (g_str_equal(arch, "s390x")) { + content = s390x_elf; + len = sizeof(s390x_elf); + } else if (strcmp(arch, "ppc64") == 0) { + /* + * sane architectures can be programmed at the boot prompt + */ + return; + } else if (strcmp(arch, "aarch64") == 0) { + content = aarch64_kernel; + len = sizeof(aarch64_kernel); + g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE); + } else { + g_assert_not_reached(); + } + FILE *bootfile = fopen(bootpath, "wb"); g_assert_cmpint(fwrite(content, len, 1, bootfile), ==, 1); fclose(bootfile); } +static void bootfile_delete(void) +{ + unlink(bootpath); + g_free(bootpath); + bootpath = NULL; +} + /* * Wait for some output in the serial output file, * we get an 'A' followed by an endless string of 'B's @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, got_src_stop = false; got_dst_resume = false; if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) { - /* the assembled x86 boot sector should be exactly one sector large */ - assert(sizeof(x86_bootsect) == 512); - init_bootfile(x86_bootsect, sizeof(x86_bootsect)); memory_size = "150M"; arch_opts = g_strdup_printf("-drive file=%s,format=raw", bootpath); start_address = X86_TEST_MEM_START; end_address = X86_TEST_MEM_END; } else if (g_str_equal(arch, "s390x")) { - init_bootfile(s390x_elf, sizeof(s390x_elf)); memory_size = "128M"; arch_opts = g_strdup_printf("-bios %s", bootpath); start_address = S390_TEST_MEM_START; @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "until'", end_address, start_address); arch_opts = g_strdup("-nodefaults -machine vsmt=8"); } else if (strcmp(arch, "aarch64") == 0) { - init_bootfile(aarch64_kernel, sizeof(aarch64_kernel)); memory_size = "150M"; arch_opts = g_strdup_printf("-machine virt,gic-version=max -cpu max " "-kernel %s", bootpath); start_address = ARM_TEST_MEM_START; end_address = ARM_TEST_MEM_END; - - g_assert(sizeof(aarch64_kernel) <= ARM_TEST_MAX_KERNEL_SIZE); } else { g_assert_not_reached(); } @@ -XXX,XX +XXX,XX @@ static QTestState *dirtylimit_start_vm(void) const char *arch = qtest_get_arch(); assert((strcmp(arch, "x86_64") == 0)); - assert(sizeof(x86_bootsect) == 512); - init_bootfile(x86_bootsect, sizeof(x86_bootsect)); - cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " "-name dirtylimit-test,debug-threads=on " "-m 150M -smp 1 " @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) g_get_tmp_dir(), err->message); } g_assert(tmpfs); - bootpath = g_strdup_printf("%s/bootsect", tmpfs); + bootfile_create(tmpfs); module_call_init(MODULE_INIT_QOM); @@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv) g_assert_cmpint(ret, ==, 0); - cleanup("bootsect"); - g_free(bootpath); + bootfile_delete(); ret = rmdir(tmpfs); if (ret != 0) { g_test_message("unable to rmdir: path (%s): %s", -- 2.40.1
So no need to assert we are in x86_64. Once there, refactor the function to remove useless variables. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230608224943.3877-11-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int64_t get_limit_rate(QTestState *who) static QTestState *dirtylimit_start_vm(void) { QTestState *vm = NULL; - g_autofree gchar *cmd = NULL; - const char *arch = qtest_get_arch(); - - assert((strcmp(arch, "x86_64") == 0)); + g_autofree gchar * cmd = g_strdup_printf("-accel kvm,dirty-ring-size=4096 " "-name dirtylimit-test,debug-threads=on " "-m 150M -smp 1 " -- 2.40.1
Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230608224943.3877-4-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, "-object memory-backend-file,id=mem0,size=%s" ",mem-path=%s,share=on -numa node,memdev=mem0", memory_size, shmem_path); - } else { - shmem_path = NULL; - shmem_opts = g_strdup(""); } if (args->use_dirty_ring) { @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, arch_opts ? arch_opts : "", arch_source ? arch_source : "", - shmem_opts, + shmem_opts ? shmem_opts : "", args->opts_source ? args->opts_source : "", ignore_stderr); if (!args->only_target) { @@ -XXX,XX +XXX,XX @@ static int test_migrate_start(QTestState **from, QTestState **to, memory_size, tmpfs, uri, arch_opts ? arch_opts : "", arch_target ? arch_target : "", - shmem_opts, + shmem_opts ? shmem_opts : "", args->opts_target ? args->opts_target : "", ignore_stderr); *to = qtest_init(cmd_target); -- 2.40.1
From: Tejus GK <tejus.gk@nutanix.com> There are places in migration.c where the migration is marked failed with MIGRATION_STATUS_FAILED, but the failure reason is never updated. Hence libvirt doesn't know why the migration failed when it queries for it. Reviewed-by: Daniel P. Berrangé <berrange@redhat.com Reviewed-by: Juan Quintela <quintela@redhat.com> Signed-off-by: Tejus GK <tejus.gk@nutanix.com> Message-ID: <20230621130940.178659-2-tejus.gk@nutanix.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/migration.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, if (!(has_resume && resume)) { yank_unregister_instance(MIGRATION_YANK_INSTANCE); } - error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "uri", + error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); migrate_set_state(&s->state, MIGRATION_STATUS_SETUP, MIGRATION_STATUS_FAILED); @@ -XXX,XX +XXX,XX @@ migration_wait_main_channel(MigrationState *ms) * Switch from normal iteration to postcopy * Returns non-0 on error */ -static int postcopy_start(MigrationState *ms) +static int postcopy_start(MigrationState *ms, Error **errp) { int ret; QIOChannelBuffer *bioc; @@ -XXX,XX +XXX,XX @@ static int postcopy_start(MigrationState *ms) */ ret = qemu_file_get_error(ms->to_dst_file); if (ret) { - error_report("postcopy_start: Migration stream errored (pre package)"); + error_setg(errp, "postcopy_start: Migration stream errored (pre package)"); goto fail_closefb; } @@ -XXX,XX +XXX,XX @@ static int postcopy_start(MigrationState *ms) ret = qemu_file_get_error(ms->to_dst_file); if (ret) { - error_report("postcopy_start: Migration stream errored"); + error_setg(errp, "postcopy_start: Migration stream errored"); migrate_set_state(&ms->state, MIGRATION_STATUS_POSTCOPY_ACTIVE, MIGRATION_STATUS_FAILED); } @@ -XXX,XX +XXX,XX @@ typedef enum { static MigIterateState migration_iteration_run(MigrationState *s) { uint64_t must_precopy, can_postcopy; + Error *local_err = NULL; bool in_postcopy = s->state == MIGRATION_STATUS_POSTCOPY_ACTIVE; qemu_savevm_state_pending_estimate(&must_precopy, &can_postcopy); @@ -XXX,XX +XXX,XX @@ static MigIterateState migration_iteration_run(MigrationState *s) /* Still a significant amount to transfer */ if (!in_postcopy && must_precopy <= s->threshold_size && qatomic_read(&s->start_postcopy)) { - if (postcopy_start(s)) { - error_report("%s: postcopy failed to start", __func__); + if (postcopy_start(s, &local_err)) { + migrate_set_error(s, local_err); + error_report_err(local_err); } return MIG_ITERATE_SKIP; } @@ -XXX,XX +XXX,XX @@ void migrate_fd_connect(MigrationState *s, Error *error_in) */ if (migrate_postcopy_ram() || migrate_return_path()) { if (open_return_path_on_source(s, !resume)) { - error_report("Unable to open return-path for postcopy"); + error_setg(&local_err, "Unable to open return-path for postcopy"); migrate_set_state(&s->state, s->state, MIGRATION_STATUS_FAILED); + migrate_set_error(s, local_err); + error_report_err(local_err); migrate_fd_cleanup(s); return; } @@ -XXX,XX +XXX,XX @@ void migrate_fd_connect(MigrationState *s, Error *error_in) } if (multifd_save_setup(&local_err) != 0) { + migrate_set_error(s, local_err); error_report_err(local_err); migrate_set_state(&s->state, MIGRATION_STATUS_SETUP, MIGRATION_STATUS_FAILED); -- 2.40.1
From: Tejus GK <tejus.gk@nutanix.com> In the function qmp_migrate(), yank_unregister_instance() gets called twice which isn't required. Hence, refactoring it so that it gets called during the local_error cleanup. Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Acked-by: Peter Xu <peterx@redhat.com> Signed-off-by: Tejus GK <tejus.gk@nutanix.com> Message-ID: <20230621130940.178659-3-tejus.gk@nutanix.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/migration.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ void qmp_migrate(const char *uri, bool has_blk, bool blk, } else if (strstart(uri, "fd:", &p)) { fd_start_outgoing_migration(s, p, &local_err); } else { - if (!(has_resume && resume)) { - yank_unregister_instance(MIGRATION_YANK_INSTANCE); - } error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "uri", "a valid migration protocol"); migrate_set_state(&s->state, MIGRATION_STATUS_SETUP, MIGRATION_STATUS_FAILED); block_cleanup_parameters(); - return; } if (local_err) { -- 2.40.1
From: Wei Wang <wei.w.wang@intel.com> qemu_start_incoming_migration needs to check the number of multifd channels or postcopy ram channels to configure the backlog parameter (i.e. the maximum length to which the queue of pending connections for sockfd may grow) of listen(). So enforce the usage of postcopy-preempt and multifd as below: - need to use "-incoming defer" on the destination; and - set_capability and set_parameter need to be done before migrate_incoming Otherwise, disable the use of the features and report error messages to remind users to adjust the commands. Signed-off-by: Wei Wang <wei.w.wang@intel.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-ID: <20230606101910.20456-2-wei.w.wang@intel.com> Signed-off-by: Juan Quintela <quintela@redhat.com> Acked-by: Juan Quintela <quintela@redhat.com> --- migration/options.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/migration/options.c b/migration/options.c index XXXXXXX..XXXXXXX 100644 --- a/migration/options.c +++ b/migration/options.c @@ -XXX,XX +XXX,XX @@ INITIALIZE_MIGRATE_CAPS_SET(check_caps_background_snapshot, MIGRATION_CAPABILITY_VALIDATE_UUID, MIGRATION_CAPABILITY_ZERO_COPY_SEND); +static bool migrate_incoming_started(void) +{ + return !!migration_incoming_get_current()->transport_data; +} + /** * @migration_caps_check - check capability compatibility * @@ -XXX,XX +XXX,XX @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) error_setg(errp, "Postcopy preempt not compatible with compress"); return false; } + + if (migrate_incoming_started()) { + error_setg(errp, + "Postcopy preempt must be set before incoming starts"); + return false; + } } if (new_caps[MIGRATION_CAPABILITY_MULTIFD]) { @@ -XXX,XX +XXX,XX @@ bool migrate_caps_check(bool *old_caps, bool *new_caps, Error **errp) error_setg(errp, "Multifd is not compatible with compress"); return false; } + if (migrate_incoming_started()) { + error_setg(errp, "Multifd must be set before incoming starts"); + return false; + } } if (new_caps[MIGRATION_CAPABILITY_DIRTY_LIMIT]) { -- 2.40.1
From: Wei Wang <wei.w.wang@intel.com> The Postcopy preempt capability is expected to be set before incoming starts, so change the postcopy tests to start with deferred incoming and call migrate-incoming after the cap has been set. Why the existing tests (without this patch) didn't fail? There could be two reasons: 1) "backlog" specifies the number of pending connections. As long as the server accepts the connections faster than the clients side connecting, connection will succeed. For the preempt test, it uses only 2 channels, so very likely to not have pending connections. 2) per my tests (on kernel 6.2), the number of pending connections allowed is actually "backlog + 1", which is 2 in this case. That said, the implementation of socket_start_incoming_migration_internal expects "migrate defer" to be used, and for safety, change the test to work with the expected usage. Signed-off-by: Wei Wang <wei.w.wang@intel.com> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Juan Quintela <quintela@redhat.com> Message-ID: <20230606101910.20456-3-wei.w.wang@intel.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- tests/qtest/migration-test.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration-test.c +++ b/tests/qtest/migration-test.c @@ -XXX,XX +XXX,XX @@ static int migrate_postcopy_prepare(QTestState **from_ptr, QTestState **to_ptr, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + g_autofree char *uri = NULL; QTestState *from, *to; - if (test_migrate_start(&from, &to, uri, &args->start)) { + if (test_migrate_start(&from, &to, "defer", &args->start)) { return -1; } @@ -XXX,XX +XXX,XX @@ static int migrate_postcopy_prepare(QTestState **from_ptr, migrate_ensure_non_converge(from); + qtest_qmp_assert_success(to, "{ 'execute': 'migrate-incoming'," + " 'arguments': { 'uri': 'tcp:127.0.0.1:0' }}"); + /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); + uri = migrate_get_socket_address(to, "socket-address"); migrate_qmp(from, uri, "{}"); wait_for_migration_pass(from); -- 2.40.1
Fast don't say much. Noflush indicates more clearly that it is like qemu_file_transferred but without the flush. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20230530183941.7223-2-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/qemu-file.h | 11 +++++------ migration/qemu-file.c | 2 +- migration/savevm.c | 4 ++-- migration/vmstate.c | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/migration/qemu-file.h b/migration/qemu-file.h index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -XXX,XX +XXX,XX @@ int qemu_fclose(QEMUFile *f); uint64_t qemu_file_transferred(QEMUFile *f); /* - * qemu_file_transferred_fast: + * qemu_file_transferred_noflush: * - * As qemu_file_transferred except for writable - * files, where no flush is performed and the reported - * amount will include the size of any queued buffers, - * on top of the amount actually transferred. + * As qemu_file_transferred except for writable files, where no flush + * is performed and the reported amount will include the size of any + * queued buffers, on top of the amount actually transferred. * * Returns: the total bytes transferred and queued */ -uint64_t qemu_file_transferred_fast(QEMUFile *f); +uint64_t qemu_file_transferred_noflush(QEMUFile *f); /* * put_buffer without copying the buffer. diff --git a/migration/qemu-file.c b/migration/qemu-file.c index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -XXX,XX +XXX,XX @@ int coroutine_mixed_fn qemu_get_byte(QEMUFile *f) return result; } -uint64_t qemu_file_transferred_fast(QEMUFile *f) +uint64_t qemu_file_transferred_noflush(QEMUFile *f) { uint64_t ret = f->total_transferred; int i; diff --git a/migration/savevm.c b/migration/savevm.c index XXXXXXX..XXXXXXX 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -XXX,XX +XXX,XX @@ static int vmstate_load(QEMUFile *f, SaveStateEntry *se) static void vmstate_save_old_style(QEMUFile *f, SaveStateEntry *se, JSONWriter *vmdesc) { - uint64_t old_offset = qemu_file_transferred_fast(f); + uint64_t old_offset = qemu_file_transferred_noflush(f); se->ops->save_state(f, se->opaque); - uint64_t size = qemu_file_transferred_fast(f) - old_offset; + uint64_t size = qemu_file_transferred_noflush(f) - old_offset; if (vmdesc) { json_writer_int64(vmdesc, "size", size); diff --git a/migration/vmstate.c b/migration/vmstate.c index XXXXXXX..XXXXXXX 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -XXX,XX +XXX,XX @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, void *curr_elem = first_elem + size * i; vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems); - old_offset = qemu_file_transferred_fast(f); + old_offset = qemu_file_transferred_noflush(f); if (field->flags & VMS_ARRAY_OF_POINTER) { assert(curr_elem); curr_elem = *(void **)curr_elem; @@ -XXX,XX +XXX,XX @@ int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, return ret; } - written_bytes = qemu_file_transferred_fast(f) - old_offset; + written_bytes = qemu_file_transferred_noflush(f) - old_offset; vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i); /* Compressed arrays only care about the first element */ -- 2.40.1
We do a qemu_fclose() just after that, that also does a qemu_fflush(), so remove one qemu_fflush(). Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-ID: <20230530183941.7223-3-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/savevm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/savevm.c b/migration/savevm.c index XXXXXXX..XXXXXXX 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -XXX,XX +XXX,XX @@ bool save_snapshot(const char *name, bool overwrite, const char *vmstate, goto the_end; } ret = qemu_savevm_state(f, errp); - vm_state_size = qemu_file_transferred(f); + vm_state_size = qemu_file_transferred_noflush(f); ret2 = qemu_fclose(f); if (ret < 0) { goto the_end; -- 2.40.1
We only care about the amount of bytes transferred. Flushing is done by the system somewhere else. Reviewed-by: Fabiano Rosas <farosas@suse.de> Signed-off-by: Juan Quintela <quintela@redhat.com> Message-ID: <20230530183941.7223-4-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/block.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migration/block.c b/migration/block.c index XXXXXXX..XXXXXXX 100644 --- a/migration/block.c +++ b/migration/block.c @@ -XXX,XX +XXX,XX @@ static int block_save_setup(QEMUFile *f, void *opaque) static int block_save_iterate(QEMUFile *f, void *opaque) { int ret; - uint64_t last_bytes = qemu_file_transferred(f); + uint64_t last_bytes = qemu_file_transferred_noflush(f); trace_migration_block_save("iterate", block_mig_state.submitted, block_mig_state.transferred); @@ -XXX,XX +XXX,XX @@ static int block_save_iterate(QEMUFile *f, void *opaque) } qemu_put_be64(f, BLK_MIG_FLAG_EOS); - uint64_t delta_bytes = qemu_file_transferred(f) - last_bytes; + uint64_t delta_bytes = qemu_file_transferred_noflush(f) - last_bytes; return (delta_bytes > 0); } -- 2.40.1
It is not used outside of qemu_file, and it shouldn't. Signed-off-by: Juan Quintela <quintela@redhat.com> Message-ID: <20230530183941.7223-19-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/qemu-file.h | 1 - migration/qemu-file.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/migration/qemu-file.h b/migration/qemu-file.h index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -XXX,XX +XXX,XX @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f); void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size, bool may_free); bool qemu_file_mode_is_not_valid(const char *mode); -bool qemu_file_is_writable(QEMUFile *f); #include "migration/qemu-file-types.h" diff --git a/migration/qemu-file.c b/migration/qemu-file.c index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -XXX,XX +XXX,XX @@ void qemu_file_set_error(QEMUFile *f, int ret) qemu_file_set_error_obj(f, ret, NULL); } -bool qemu_file_is_writable(QEMUFile *f) +static bool qemu_file_is_writable(QEMUFile *f) { return f->is_writable; } -- 2.40.1
Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230530183941.7223-20-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/qemu-file.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/migration/qemu-file.c b/migration/qemu-file.c index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -XXX,XX +XXX,XX @@ struct QEMUFile { */ int qemu_file_shutdown(QEMUFile *f) { - int ret = 0; - /* * We must set qemufile error before the real shutdown(), otherwise * there can be a race window where we thought IO all went though @@ -XXX,XX +XXX,XX @@ int qemu_file_shutdown(QEMUFile *f) } if (qio_channel_shutdown(f->ioc, QIO_CHANNEL_SHUTDOWN_BOTH, NULL) < 0) { - ret = -EIO; + return -EIO; } - return ret; + return 0; } bool qemu_file_mode_is_not_valid(const char *mode) -- 2.40.1
It was not used outside of qemu_file.c anyways. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230530183941.7223-21-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/qemu-file.h | 1 - migration/qemu-file.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/migration/qemu-file.h b/migration/qemu-file.h index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -XXX,XX +XXX,XX @@ void qemu_file_skip(QEMUFile *f, int size); * accounting information tracks the total migration traffic. */ void qemu_file_credit_transfer(QEMUFile *f, size_t size); -int qemu_file_get_error_obj(QEMUFile *f, Error **errp); int qemu_file_get_error_obj_any(QEMUFile *f1, QEMUFile *f2, Error **errp); void qemu_file_set_error_obj(QEMUFile *f, int ret, Error *err); void qemu_file_set_error(QEMUFile *f, int ret); diff --git a/migration/qemu-file.c b/migration/qemu-file.c index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -XXX,XX +XXX,XX @@ void qemu_file_set_hooks(QEMUFile *f, const QEMUFileHooks *hooks) * is not 0. * */ -int qemu_file_get_error_obj(QEMUFile *f, Error **errp) +static int qemu_file_get_error_obj(QEMUFile *f, Error **errp) { if (errp) { *errp = f->last_error_obj ? error_copy(f->last_error_obj) : NULL; -- 2.40.1
This is how everything else in QEMUFile is structured. As a bonus they are three less lines of code. Reviewed-by: Peter Xu <peterx@redhat.com> Message-ID: <20230530183941.7223-17-quintela@redhat.com> Signed-off-by: Juan Quintela <quintela@redhat.com> --- migration/qemu-file.h | 1 - migration/qemu-file.c | 12 ------------ migration/rdma.c | 39 +++++++++++++++++++-------------------- 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/migration/qemu-file.h b/migration/qemu-file.h index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.h +++ b/migration/qemu-file.h @@ -XXX,XX +XXX,XX @@ uint64_t qemu_file_transferred_noflush(QEMUFile *f); */ void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size, bool may_free); -bool qemu_file_mode_is_not_valid(const char *mode); #include "migration/qemu-file-types.h" diff --git a/migration/qemu-file.c b/migration/qemu-file.c index XXXXXXX..XXXXXXX 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -XXX,XX +XXX,XX @@ int qemu_file_shutdown(QEMUFile *f) return 0; } -bool qemu_file_mode_is_not_valid(const char *mode) -{ - if (mode == NULL || - (mode[0] != 'r' && mode[0] != 'w') || - mode[1] != 'b' || mode[2] != 0) { - fprintf(stderr, "qemu_fopen: Argument validity check failed\n"); - return true; - } - - return false; -} - static QEMUFile *qemu_file_new_impl(QIOChannel *ioc, bool is_writable) { QEMUFile *f; diff --git a/migration/rdma.c b/migration/rdma.c index XXXXXXX..XXXXXXX 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -XXX,XX +XXX,XX @@ static void qio_channel_rdma_register_types(void) type_init(qio_channel_rdma_register_types); -static QEMUFile *qemu_fopen_rdma(RDMAContext *rdma, const char *mode) +static QEMUFile *rdma_new_input(RDMAContext *rdma) { - QIOChannelRDMA *rioc; + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA)); - if (qemu_file_mode_is_not_valid(mode)) { - return NULL; - } + rioc->file = qemu_file_new_input(QIO_CHANNEL(rioc)); + rioc->rdmain = rdma; + rioc->rdmaout = rdma->return_path; + qemu_file_set_hooks(rioc->file, &rdma_read_hooks); - rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA)); + return rioc->file; +} - if (mode[0] == 'w') { - rioc->file = qemu_file_new_output(QIO_CHANNEL(rioc)); - rioc->rdmaout = rdma; - rioc->rdmain = rdma->return_path; - qemu_file_set_hooks(rioc->file, &rdma_write_hooks); - } else { - rioc->file = qemu_file_new_input(QIO_CHANNEL(rioc)); - rioc->rdmain = rdma; - rioc->rdmaout = rdma->return_path; - qemu_file_set_hooks(rioc->file, &rdma_read_hooks); - } +static QEMUFile *rdma_new_output(RDMAContext *rdma) +{ + QIOChannelRDMA *rioc = QIO_CHANNEL_RDMA(object_new(TYPE_QIO_CHANNEL_RDMA)); + + rioc->file = qemu_file_new_output(QIO_CHANNEL(rioc)); + rioc->rdmaout = rdma; + rioc->rdmain = rdma->return_path; + qemu_file_set_hooks(rioc->file, &rdma_write_hooks); return rioc->file; } @@ -XXX,XX +XXX,XX @@ static void rdma_accept_incoming_migration(void *opaque) return; } - f = qemu_fopen_rdma(rdma, "rb"); + f = rdma_new_input(rdma); if (f == NULL) { - fprintf(stderr, "RDMA ERROR: could not qemu_fopen_rdma\n"); + fprintf(stderr, "RDMA ERROR: could not open RDMA for input\n"); qemu_rdma_cleanup(rdma); return; } @@ -XXX,XX +XXX,XX @@ void rdma_start_outgoing_migration(void *opaque, trace_rdma_start_outgoing_migration_after_rdma_connect(); - s->to_dst_file = qemu_fopen_rdma(rdma, "wb"); + s->to_dst_file = rdma_new_output(rdma); migrate_fd_connect(s, NULL); return; return_path_err: -- 2.40.1
The following changes since commit 343a88cb022e5cdb1d839a0499f9a33f8614598d: Merge tag 'firmware-20260519-pull-request' of https://gitlab.com/kraxel/qemu into staging (2026-05-19 09:28:07 -0400) are available in the Git repository at: https://gitlab.com/peterx/qemu.git tags/next-pull-request for you to fetch changes up to 7a4b1c333ffe8358664430e1f5a676e1dee7175c: MAINTAINERS: Update email of Yong Huang (2026-05-20 17:01:37 -0400) ---------------------------------------------------------------- Migration and mem pull request - Peter's fix on 2nd migration crashing if the 1st migration cancelled early - Phil's patch to remove VMS_MULTIPLY_ELEMENTS across tree - Peter's fix on possible division by zero in recent query-migrate change - Aadeshveer's cleanup for current_migration references - Fabiano's fix of auto-converge test - Maciej's maintainer file update for CPR - Fabiano's migration qtest refactor to stick with -incoming defer - Bin's cleanup / fix series all over migration (part of) - hongmianquan's cpr optimization to use ghash for fd bookkeeping - Yong's email address update ---------------------------------------------------------------- Aadeshveer Singh (1): migration: Replace current_migration with migrate_get_current() Bin Guo (6): migration/global_state: replace strcpy("") with explicit NUL termination migration/vmstate: avoid per-element heap churn in vmsd ptr marker field migration/savevm: use stack-allocated bitmap in configuration_validate_capabilities migration/multifd: fix off-by-one in recv channel ID validation migration/multifd: cache migrate_multifd_channels() in send/recv hot paths migration/multifd: cache channel count in multifd_send_sync_main Fabiano Rosas (16): tests/qtest/migration: Fix auto-converge test tests/qtest/migration: Move cpr transfer logic into cpr-tests.c tests/qtest/migration: Make file-tests defer by default tests/qtest/migration: Set file URI by default tests/qtest/migration: Group unix migration tests tests/qtest/migration: Use precopy_unix_common for ignore-shared test tests/qtest/migration: Use a default TCP URI for precopy tests/qtest/migration: Defer by default in precopy_common tests/qtest/migration: Set compression method in compression-tests tests/qtest/migration: Remove multifd compression hook tests/qtest/migration: Use defer for all tests tests/qtest/migration: Use defer for cpr-tests tests/qtest/migration: Use defer for auto-converge tests/qtest/migration: Use defer in dirty_limit test tests/qtest/migration: Stop passing URI into migrate_start tests/qtest/migration: Unify URIs Hyman Huang (1): MAINTAINERS: Update email of Yong Huang Maciej S. Szmigiero (1): MAINTAINERS: Make Maciej CPR maintainer Peter Xu (2): migration: Fix crash on second migration when cancel early migration: Fix possible division by zero on calc expected downtime Philippe Mathieu-Daudé (1): migration: Remove VMS_MULTIPLY_ELEMENTS and VMSTATE_VARRAY_MULTIPLY() hongmianquan (1): migration/cpr: use hashtable for cpr fds MAINTAINERS | 5 +- include/migration/cpr.h | 1 + include/migration/vmstate.h | 22 +--- migration/migration.h | 5 + tests/qtest/migration/framework.h | 26 ++-- migration/cpr-transfer.c | 10 ++ migration/cpr.c | 116 ++++++++++++++--- migration/global_state.c | 2 +- migration/migration.c | 57 +++++++-- migration/multifd.c | 27 ++-- migration/savevm.c | 5 +- migration/vmstate.c | 45 +++---- tests/qtest/migration/colo-tests.c | 16 +-- tests/qtest/migration/compression-tests.c | 34 ++--- tests/qtest/migration/cpr-tests.c | 85 ++++++++++--- tests/qtest/migration/file-tests.c | 56 +-------- tests/qtest/migration/framework.c | 91 +++++--------- tests/qtest/migration/misc-tests.c | 62 ++++------ tests/qtest/migration/precopy-tests.c | 144 ++++------------------ tests/qtest/migration/tls-tests.c | 110 ++--------------- rust/bindings/migration-sys/lib.rs | 8 -- rust/migration/src/vmstate.rs | 3 +- rust/tests/tests/vmstate_tests.rs | 55 --------- 23 files changed, 396 insertions(+), 589 deletions(-) -- 2.53.0
Marc-André reported an issue on QEMU crash when retrying a cancelled migration during early setup phase, see "Link:" for more information, and also easy way to reproduce. This patch is a replacement of the prior fix proposed by not only switching to migration_cleanup(), but also fixing it from CPR side, so that we track hup_source properly to know if src QEMU is waiting or the HUP signal. To put it simple: this chunk of special casing in migration_cancel() should not affect normal migration, but only cpr-transfer migration to cover the small window when the src QEMU is waiting for a HUP signal on cpr channel (so that src QEMU can continue the migration on the main channel). To achieve that, we'll also need to remember to detach the hup_source whenenver invoked: after that point, we should always be able to cleanup the migration. It's not a generic operation to explicitly detach a gsource from its context while in its dispatch() function. But it should be safe, because gsource disptch() will only happen with a boosted refcount for the dispatcher so that the gsource will not be freed until the callback completes. It's also safe to return G_SOURCE_REMOVE after the gsource is detached, as glib will simply ignore the G_SOURCE_REMOVE. One can refer to latest 2.86.5 glib code in g_main_dispatch() for that: https://github.com/GNOME/glib/blob/2.86.5/glib/gmain.c#L3592 When at this, add a bunch of assertions to make sure nothing surprises us. After this patch applied, the 2nd migration will not crash QEMU, instead it'll be in CANCELLING until the socket connection times out (it will take ~2min on my Fedora default kernel). During this process no 2nd migration will be allowed, and after it timed out migration can be restarted. It's because so far we don't have control over socket_connect_outgoing(), or anything yet managed by a task executed in qio_task_run_in_thread(). Speeding up the cancellation to be left for future. I also tested cpr-transfer by only providing cpr channel not the main channel (with -incoming defer), kickoff migration on source, then cancel it on source directly without providing the main channel. It keeps working. I wanted to add an unit test for that but it'll need to refactor current cpr-transfer tests first; let's leave it for later. Link: https://lore.kernel.org/r/20260417184742.293061-1-marcandre.lureau@redhat.com Reported-by: Marc-André Lureau <marcandre.lureau@redhat.com> Tested-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260421175820.302795-1-peterx@redhat.com Signed-off-by: Peter Xu <peterx@redhat.com> --- include/migration/cpr.h | 1 + migration/migration.h | 5 +++++ migration/cpr-transfer.c | 10 ++++++++++ migration/migration.c | 31 +++++++++++++++++++++++-------- 4 files changed, 39 insertions(+), 8 deletions(-) diff --git a/include/migration/cpr.h b/include/migration/cpr.h index XXXXXXX..XXXXXXX 100644 --- a/include/migration/cpr.h +++ b/include/migration/cpr.h @@ -XXX,XX +XXX,XX @@ QEMUFile *cpr_transfer_input(MigrationChannel *channel, Error **errp); void cpr_transfer_add_hup_watch(MigrationState *s, QIOChannelFunc func, void *opaque); void cpr_transfer_source_destroy(MigrationState *s); +bool cpr_transfer_source_active(MigrationState *s); void cpr_exec_init(void); QEMUFile *cpr_exec_output(Error **errp); diff --git a/migration/migration.h b/migration/migration.h index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.h +++ b/migration/migration.h @@ -XXX,XX +XXX,XX @@ struct MigrationState { bool postcopy_package_loaded; + /* + * When set, it means cpr-transfer is waiting for the HUP signal from + * destination to continue the 2nd step of migration via the main + * channel. + */ GSource *hup_source; /* diff --git a/migration/cpr-transfer.c b/migration/cpr-transfer.c index XXXXXXX..XXXXXXX 100644 --- a/migration/cpr-transfer.c +++ b/migration/cpr-transfer.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" +#include "qemu/main-loop.h" #include "qapi/clone-visitor.h" #include "qapi/error.h" #include "qapi/qapi-visit-migration.h" @@ -XXX,XX +XXX,XX @@ QEMUFile *cpr_transfer_input(MigrationChannel *channel, Error **errp) void cpr_transfer_add_hup_watch(MigrationState *s, QIOChannelFunc func, void *opaque) { + assert(bql_locked()); s->hup_source = qio_channel_create_watch(cpr_state_ioc(), G_IO_HUP); g_source_set_callback(s->hup_source, (GSourceFunc)func, @@ -XXX,XX +XXX,XX @@ void cpr_transfer_add_hup_watch(MigrationState *s, QIOChannelFunc func, void cpr_transfer_source_destroy(MigrationState *s) { + assert(bql_locked()); if (s->hup_source) { g_source_destroy(s->hup_source); g_source_unref(s->hup_source); s->hup_source = NULL; } } + +bool cpr_transfer_source_active(MigrationState *s) +{ + /* Whenever the HUP gsource is available, it's active. */ + assert(bql_locked()); + return s->hup_source; +} diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ void migration_cancel(void) } /* - * If migration_connect_outgoing has not been called, then there - * is no path that will complete the cancellation. Do it now. - */ - if (setup && !s->to_dst_file) { - migrate_set_state(&s->state, MIGRATION_STATUS_CANCELLING, - MIGRATION_STATUS_CANCELLED); - cpr_state_close(); - cpr_transfer_source_destroy(s); + * This is cpr-transfer specific processing. + * + * If this is true, it means cpr-transfer migration is waiting for the + * destination to send HUP event on CPR channel to continue the next + * phase. If so, do the cleanup proactively to avoid get stuck in + * CANCELLING state. + */ + if (cpr_transfer_source_active(s)) { + assert(migrate_mode() == MIG_MODE_CPR_TRANSFER); + assert(setup && !s->to_dst_file); + migration_cleanup(s); + /* Now all things should have been released */ + assert(!cpr_transfer_source_active(s)); } } @@ -XXX,XX +XXX,XX @@ static gboolean migration_connect_outgoing_cb(QIOChannel *channel, MigrationState *s = migrate_get_current(); Error *local_err = NULL; + /* + * Detach and release the GSource right after use. We rely on this to + * detect this small cpr-transfer window of "waiting for HUP event". + */ + cpr_transfer_source_destroy(s); + migration_connect_outgoing(s, opaque, &local_err); if (local_err) { migration_connect_error_propagate(s, local_err); } + /* + * This is redundant as we do cpr_transfer_source_destroy() at the + * entry, but it's benign; glib will just skip the detach. + */ return G_SOURCE_REMOVE; } -- 2.53.0
From: Philippe Mathieu-Daudé <philmd@linaro.org> Commit c1eb3ac3468 ("target/sparc: Replace VMSTATE_VARRAY_MULTIPLY -> VMSTATE_UINTTL_ARRAY") removed the last use of the VMSTATE_VARRAY_MULTIPLY() macro. We can now remove it as unnecessary, along with the VMS_MULTIPLY_ELEMENTS flag and the associated tests. Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org> Reviewed-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Acked-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org> Link: https://lore.kernel.org/r/20260507070228.48877-1-philmd@linaro.org Signed-off-by: Peter Xu <peterx@redhat.com> --- include/migration/vmstate.h | 22 ++---------- migration/vmstate.c | 4 --- rust/bindings/migration-sys/lib.rs | 8 ----- rust/migration/src/vmstate.rs | 3 +- rust/tests/tests/vmstate_tests.rs | 55 ------------------------------ 5 files changed, 4 insertions(+), 88 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index XXXXXXX..XXXXXXX 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -XXX,XX +XXX,XX @@ enum VMStateFlags { VMS_ARRAY_OF_POINTER = 0x040, /* The field is an array of variable size. The uint16_t at opaque - * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * + VMStateField.num_offset * contains the number of entries in the array. See the VMS_ARRAY * description regarding array handling in general. May not be * combined with VMS_ARRAY or any other VMS_VARRAY*. */ @@ -XXX,XX +XXX,XX @@ enum VMStateFlags { VMS_MULTIPLY = 0x200, /* The field is an array of variable size. The uint8_t at opaque + - * VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * VMStateField.num_offset * contains the number of entries in the array. See the VMS_ARRAY * description regarding array handling in general. May not be * combined with VMS_ARRAY or any other VMS_VARRAY*. */ VMS_VARRAY_UINT8 = 0x400, /* The field is an array of variable size. The uint32_t at opaque - * + VMStateField.num_offset (subject to VMS_MULTIPLY_ELEMENTS) + * + VMStateField.num_offset * contains the number of entries in the array. See the VMS_ARRAY * description regarding array handling in general. May not be * combined with VMS_ARRAY or any other VMS_VARRAY*. */ @@ -XXX,XX +XXX,XX @@ enum VMStateFlags { * cause the individual entries to be allocated. */ VMS_ALLOC = 0x2000, - /* Multiply the number of entries given by the integer at opaque + - * VMStateField.num_offset (see VMS_VARRAY*) with VMStateField.num - * to determine the number of entries in the array. Only valid in - * combination with one of VMS_VARRAY*. */ - VMS_MULTIPLY_ELEMENTS = 0x4000, - /* A structure field that is like VMS_STRUCT, but uses * VMStateField.struct_version_id to tell which version of the * structure we are referencing to use. */ @@ -XXX,XX +XXX,XX @@ extern const VMStateInfo vmstate_info_qlist; .offset = vmstate_offset_2darray(_state, _field, _type, _n1, _n2), \ } -#define VMSTATE_VARRAY_MULTIPLY(_field, _state, _field_num, _multiply, _info, _type) { \ - .name = (stringify(_field)), \ - .num_offset = vmstate_offset_value(_state, _field_num, uint32_t),\ - .num = (_multiply), \ - .info = &(_info), \ - .size = sizeof(_type), \ - .flags = VMS_VARRAY_UINT32|VMS_MULTIPLY_ELEMENTS, \ - .offset = vmstate_offset_varray(_state, _field, _type), \ -} - #define VMSTATE_SUB_ARRAY(_field, _state, _start, _num, _version, _info, _type) { \ .name = (stringify(_field)), \ .version_id = (_version), \ diff --git a/migration/vmstate.c b/migration/vmstate.c index XXXXXXX..XXXXXXX 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -XXX,XX +XXX,XX @@ static int vmstate_n_elems(void *opaque, const VMStateField *field) n_elems = *(uint8_t *)(opaque + field->num_offset); } - if (field->flags & VMS_MULTIPLY_ELEMENTS) { - n_elems *= field->num; - } - trace_vmstate_n_elems(field->name, n_elems); return n_elems; } diff --git a/rust/bindings/migration-sys/lib.rs b/rust/bindings/migration-sys/lib.rs index XXXXXXX..XXXXXXX 100644 --- a/rust/bindings/migration-sys/lib.rs +++ b/rust/bindings/migration-sys/lib.rs @@ -XXX,XX +XXX,XX @@ pub const fn with_varray_flag(mut self, flag: VMStateFlags) -> Self { assert!((self.flags.0 & VMStateFlags::VMS_ARRAY.0) != 0); self.with_varray_flag_unchecked(flag) } - - #[must_use] - pub const fn with_varray_multiply(mut self, num: u32) -> Self { - assert!(num <= 0x7FFF_FFFFu32); - self.flags = VMStateFlags(self.flags.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0); - self.num = num as i32; - self - } } diff --git a/rust/migration/src/vmstate.rs b/rust/migration/src/vmstate.rs index XXXXXXX..XXXXXXX 100644 --- a/rust/migration/src/vmstate.rs +++ b/rust/migration/src/vmstate.rs @@ -XXX,XX +XXX,XX @@ macro_rules! vmstate_of { )$(.with_varray_flag($crate::call_func_with_field!( $crate::vmstate::vmstate_varray_flag, $struct_name, - $($num).+)) - $(.with_varray_multiply($factor))?)? + $($num).+)))? } }; } diff --git a/rust/tests/tests/vmstate_tests.rs b/rust/tests/tests/vmstate_tests.rs index XXXXXXX..XXXXXXX 100644 --- a/rust/tests/tests/vmstate_tests.rs +++ b/rust/tests/tests/vmstate_tests.rs @@ -XXX,XX +XXX,XX @@ fn test_vmstate_varray_uint16_unsafe() { assert!(foo_fields[2].field_exists.is_none()); } -#[test] -fn test_vmstate_varray_multiply() { - let foo_fields: &[VMStateField] = - unsafe { slice::from_raw_parts(VMSTATE_FOOA.as_ref().fields, 5) }; - - // 4th VMStateField ("arr_mul") in VMSTATE_FOOA (corresponding to - // VMSTATE_VARRAY_MULTIPLY) - assert_eq!( - unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), - b"arr_mul\0" - ); - assert_eq!(foo_fields[3].offset, 6); - assert_eq!(foo_fields[3].num_offset, 12); - assert_eq!(foo_fields[3].info, unsafe { &vmstate_info_int8 }); - assert_eq!(foo_fields[3].version_id, 0); - assert_eq!(foo_fields[3].size, 1); - assert_eq!(foo_fields[3].num, 16); - assert_eq!( - foo_fields[3].flags.0, - VMStateFlags::VMS_VARRAY_UINT32.0 | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 - ); - assert!(foo_fields[3].vmsd.is_null()); - assert!(foo_fields[3].field_exists.is_none()); - - // The last VMStateField in VMSTATE_FOOA. - assert_eq!(foo_fields[4].flags, VMStateFlags::VMS_END); -} - // =========================== Test VMSTATE_FOOB =========================== // Test the use cases of the vmstate macro, corresponding to the following C // macro variants: @@ -XXX,XX +XXX,XX @@ fn test_vmstate_struct_varray_uint8() { assert!(foo_fields[2].field_exists.is_none()); } -#[test] -fn test_vmstate_struct_varray_uint32_multiply() { - let foo_fields: &[VMStateField] = - unsafe { slice::from_raw_parts(VMSTATE_FOOB.as_ref().fields, 7) }; - - // 4th VMStateField ("arr_a_mul") in VMSTATE_FOOB (corresponding to - // (no C version) MULTIPLY variant of VMSTATE_STRUCT_VARRAY_UINT32) - assert_eq!( - unsafe { CStr::from_ptr(foo_fields[3].name) }.to_bytes_with_nul(), - b"arr_a_mul\0" - ); - assert_eq!(foo_fields[3].offset, 64); - assert_eq!(foo_fields[3].num_offset, 124); - assert!(foo_fields[3].info.is_null()); // VMSTATE_STRUCT_VARRAY_UINT8 doesn't set info field. - assert_eq!(foo_fields[3].version_id, 2); - assert_eq!(foo_fields[3].size, 20); - assert_eq!(foo_fields[3].num, 32); - assert_eq!( - foo_fields[3].flags.0, - VMStateFlags::VMS_STRUCT.0 - | VMStateFlags::VMS_VARRAY_UINT32.0 - | VMStateFlags::VMS_MULTIPLY_ELEMENTS.0 - ); - assert_eq!(foo_fields[3].vmsd, VMSTATE_FOOA.as_ref()); - assert!(foo_fields[3].field_exists.is_none()); -} - #[test] fn test_vmstate_macro_array() { let foo_fields: &[VMStateField] = -- 2.53.0
Commit dd4fe8844b changed the reporting of expected downtime behavior, so that the value will be calculated on-demand. One side effect on the change is QEMU will allow the calculation to happen anytime even if there's no transfer happening for a short while. PeterM reported an ubsan report from clang when running migration-test with aarch64 binary on x86_64 hosts. I can also reproduce if I run the test concurrently so some of the src QEMU may not get chance to push any data, causing mbps to be 0: ../migration/migration.c:1051:12: runtime error: -nan is outside the range of representable values of type 'long' Fix it by properly handle both Inf and Nan to return INT64_MAX. Add a rich comment, per PeterM's suggestion. Link: https://lore.kernel.org/r/CAFEAcA-MYH6C39xO0OLx4-M5pKurJpurwRsMqZe9q=W-NShAbw@mail.gmail.com Reported-by: Peter Maydell <peter.maydell@linaro.org> Fixes: dd4fe8844b ("migration: Calculate expected downtime on demand") Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Link: https://lore.kernel.org/r/20260511182432.1333467-1-peterx@redhat.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/migration.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ #include "system/dirtylimit.h" #include "qemu/sockets.h" #include "system/kvm.h" +#include "math.h" #define NOTIFIER_ELEM_INIT(array, elem) \ [elem] = NOTIFIER_WITH_RETURN_LIST_INITIALIZER((array)[elem]) @@ -XXX,XX +XXX,XX @@ static bool migrate_show_downtime(MigrationState *s) /* Return expected downtime (unit: milliseconds) */ int64_t migration_downtime_calc_expected(MigrationState *s) { + double expected_ms; + if (mig_stats.dirty_sync_count <= 1) { return migrate_downtime_limit(); } - return mig_stats.dirty_bytes_last_sync / + expected_ms = mig_stats.dirty_bytes_last_sync / migration_get_switchover_bw(s) * 1000; + + /* + * If we haven't been able to transfer any data, the result here could + * be NaN (for 0 / 0) or infinity (something else / 0). + * + * Return INT64_MAX as our best approximation to "this will take + * forever to complete". If the problem is transient (e.g. we just + * haven't started to transfer yet) we'll recalculate to a more + * accurate figure later. + */ + if (isnan(expected_ms) || expected_ms >= (double)INT64_MAX) { + return INT64_MAX; + } + + return (int64_t) expected_ms; } static void populate_time_info(MigrationInfo *info, MigrationState *s) -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> We fixed the cpu throttling sync thread affecting the dirty-sync-count, but the test still relies on it to gauge for progress. Remove that block from the test with no replacement. While here remove several incorrect or redundant comments. Fixes: 9519d3667a ("migration: Move iteration counter out of RAM") Signed-off-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260512141338.10089-1-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/precopy-tests.c | 62 ++------------------------- 1 file changed, 3 insertions(+), 59 deletions(-) diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_fd_socket(char *name, MigrateCommon *args) } #endif /* _WIN32 */ -/* - * The way auto_converge works, we need to do too many passes to - * run this test. Auto_converge logic is only run once every - * three iterations, so: - * - * - 3 iterations without auto_converge enabled - * - 3 iterations with pct = 5 - * - 3 iterations with pct = 30 - * - 3 iterations with pct = 55 - * - 3 iterations with pct = 80 - * - 3 iterations with pct = 95 (max(95, 80 + 25)) - * - * To make things even worse, we need to run the initial stage at - * 3MB/s so we enter autoconverge even when host is (over)loaded. - */ static void test_auto_converge(char *name, MigrateCommon *args) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; int64_t percentage; - - /* - * We want the test to be stable and as fast as possible. - * E.g., with 1Gb/s bandwidth migration may pass without throttling, - * so we need to decrease a bandwidth. - */ const int64_t init_pct = 5, inc_pct = 25, max_pct = 95; - uint64_t prev_dirty_sync_cnt, dirty_sync_cnt; - int max_try_count, hit = 0; if (migrate_start(&from, &to, uri, &args->start)) { return; @@ -XXX,XX +XXX,XX @@ static void test_auto_converge(char *name, MigrateCommon *args) migrate_set_parameter_int(from, "cpu-throttle-increment", inc_pct); migrate_set_parameter_int(from, "max-cpu-throttle", max_pct); - /* - * Set the initial parameters so that the migration could not converge - * without throttling. - */ migrate_ensure_non_converge(from); /* To check remaining size after precopy */ migrate_set_capability(from, "pause-before-switchover", true); - /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); migrate_qmp(from, to, uri, NULL, "{}"); - /* Wait for throttling begins */ + /* Wait until throttling begins */ percentage = 0; do { percentage = read_migrate_property_int(from, "cpu-throttle-percentage"); @@ -XXX,XX +XXX,XX @@ static void test_auto_converge(char *name, MigrateCommon *args) /* The first percentage of throttling should be at least init_pct */ g_assert_cmpint(percentage, >=, init_pct); - /* - * End the loop when the dirty sync count greater than 1. - */ - while ((dirty_sync_cnt = get_migration_pass(from)) < 2) { - usleep(1000 * 1000); - } - - prev_dirty_sync_cnt = dirty_sync_cnt; - - /* - * The RAMBlock dirty sync count must changes in 5 seconds, here we set - * the timeout to 10 seconds to ensure it changes. - * - * Note that migrate_ensure_non_converge set the max-bandwidth to 3MB/s, - * while the qtest mem is >= 100MB, one iteration takes at least 33s (100/3) - * to complete; this ensures that the RAMBlock dirty sync occurs. - */ - max_try_count = 10; - while (--max_try_count) { - dirty_sync_cnt = get_migration_pass(from); - if (dirty_sync_cnt != prev_dirty_sync_cnt) { - hit = 1; - break; - } - prev_dirty_sync_cnt = dirty_sync_cnt; - sleep(1); - } - g_assert_cmpint(hit, ==, 1); - - /* Now, when we tested that throttling works, let it converge */ + /* throttling always ignores the first pass */ + assert(get_migration_pass(from) == 2); migrate_ensure_converge(from); /* -- 2.53.0
From: Aadeshveer Singh <aadeshveer07@gmail.com> Replaces the direct accesses to global variable `current_migration` with `migrate_get_current()` to ensure consistency across systems. Note: Following this only direct access to `current_migration` will be * `migrate_get_current()` itself * `migration_object_init()` initializes `current_migration` * `migration_shutdown()` to pair up with initialization * `migration_is_running()`, as there might be a case where this function is called by a thread before object initialization Signed-off-by: Aadeshveer Singh <aadeshveer07@gmail.com> Link: https://lore.kernel.org/r/20260513063513.250911-1-aadeshveer07@gmail.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/migration.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index XXXXXXX..XXXXXXX 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -XXX,XX +XXX,XX @@ bool migration_is_running(void) static bool migration_is_active(void) { - MigrationState *s = current_migration; + MigrationState *s = migrate_get_current(); return (s->state == MIGRATION_STATUS_ACTIVE || s->state == MIGRATION_STATUS_POSTCOPY_DEVICE || @@ -XXX,XX +XXX,XX @@ bool migration_in_bg_snapshot(void) bool migration_thread_is_self(void) { - MigrationState *s = current_migration; + MigrationState *s = migrate_get_current(); return qemu_thread_is_self(&s->thread); } @@ -XXX,XX +XXX,XX @@ static MigThrError postcopy_pause(MigrationState *s) void migration_file_set_error(int ret, Error *err) { - MigrationState *s = current_migration; + MigrationState *s = migrate_get_current(); WITH_QEMU_LOCK_GUARD(&s->qemu_file_lock) { if (s->to_dst_file) { -- 2.53.0
From: "Maciej S. Szmigiero" <maciej.szmigiero@oracle.com> Since Steve has retired last year I will take the CPR maintainership - with kind help of Mark who remains a reviewer. Cc: Mark Kanda <mark.kanda@oracle.com> Signed-off-by: Maciej S. Szmigiero <maciej.szmigiero@oracle.com> Reviewed-by: Cédric Le Goater <clg@redhat.com> Link: https://lore.kernel.org/r/ebe67053f4bdf92eedab1e5839603b7137e36970.1778687091.git.maciej.szmigiero@oracle.com Signed-off-by: Peter Xu <peterx@redhat.com> --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ T: git https://gitlab.com/jsnow/qemu.git jobs T: git https://gitlab.com/vsementsov/qemu.git block CheckPoint and Restart (CPR) +M: Maciej S. Szmigiero <maciej.szmigiero@oracle.com> R: Peter Xu <peterx@redhat.com> R: Fabiano Rosas <farosas@suse.de> R: Mark Kanda <mark.kanda@oracle.com> -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> There's some amount of cpr-transfer logic at precopy_common, which in retrospect was a bad idea. For just two tests, that's too much code to be in the common function. Move it to the cpr file. We'll need this cleanup for subsequent improvements. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-2-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/framework.h | 3 -- tests/qtest/migration/cpr-tests.c | 57 ++++++++++++++++++++++++++++--- tests/qtest/migration/framework.c | 36 +++---------------- 3 files changed, 56 insertions(+), 40 deletions(-) diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -XXX,XX +XXX,XX @@ typedef struct { */ const char *connect_channels; - /* Optional: the cpr migration channel, in JSON or dotted keys format */ - const char *cpr_channel; - /* Optional: callback to run at start to set migration parameters */ TestMigrateStartHook start_hook; /* Optional: callback to run at finish to cleanup */ diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -XXX,XX +XXX,XX @@ #include "migration/framework.h" #include "migration/migration-qmp.h" #include "migration/migration-util.h" +#include "qapi/error.h" +#include "qobject/qjson.h" +#include "qobject/qlist.h" static char *tmpfs; @@ -XXX,XX +XXX,XX @@ static void test_mode_reboot(char *name, MigrateCommon *args) test_file_common(args, true); } -static void *test_mode_transfer_start(QTestState *from, QTestState *to) +static int test_transfer(MigrateCommon *args, const char *cpr_channel, + bool incoming_defer) { + QTestState *from, *to; + QObject *obj, *out_channels = qobject_from_json(args->connect_channels, + &error_abort); + QList *channels_list; + + /* + * The cpr channel must be included in outgoing channels, but not in + * migrate-incoming channels. + */ + channels_list = qobject_to(QList, out_channels); + obj = migrate_str_to_channel(cpr_channel); + qlist_append(channels_list, obj); + + if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + return -1; + } + migrate_set_parameter_str(from, "mode", "cpr-transfer"); - return NULL; + + wait_for_serial("src_serial"); + + qtest_qmp_assert_success(from, "{ 'execute' : 'stop'}"); + wait_for_stop(from, get_src()); + migrate_ensure_converge(from); + + migrate_qmp(from, to, NULL, out_channels, "{}"); + + qtest_connect(to); + qtest_qmp_handshake(to, NULL); + if (incoming_defer) { + QObject *in_channels = qobject_from_json(args->connect_channels, + &error_abort); + + migrate_incoming_qmp(to, NULL, in_channels, "{}"); + } + + wait_for_migration_complete(from); + wait_for_migration_complete(to); + + qtest_qmp_assert_success(to, "{ 'execute' : 'cont'}"); + + wait_for_resume(to, get_dst()); + wait_for_serial("dest_serial"); + + migrate_end(from, to, true); + + return 0; } /* @@ -XXX,XX +XXX,XX @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer) args->listen_uri = incoming_defer ? "defer" : uri; args->connect_channels = connect_channels; - args->cpr_channel = cpr_channel; - args->start_hook = test_mode_transfer_start; args->start.opts_source = opts; args->start.opts_target = opts_target; args->start.defer_target_connect = true; args->start.mem_type = MEM_TYPE_MEMFD; - if (test_precopy_common(args) < 0) { + if (test_transfer(args, cpr_channel, incoming_defer) < 0) { close(cpr_sockfd); unlink(cpr_path); } diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ #include "ppc-util.h" #include "qapi/error.h" #include "qobject/qjson.h" -#include "qobject/qlist.h" #include "qemu/bswap.h" #include "qemu/module.h" #include "qemu/option.h" @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) { QTestState *from, *to; void *data_hook = NULL; - QObject *in_channels = NULL; - QObject *out_channels = NULL; - - g_assert(!args->cpr_channel || args->connect_channels); + QObject *channels = NULL; if (migrate_start(&from, &to, args->listen_uri, &args->start)) { return -1; @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) } } - /* - * The cpr channel must be included in outgoing channels, but not in - * migrate-incoming channels. - */ if (args->connect_channels) { - if (args->start.defer_target_connect && - !strcmp(args->listen_uri, "defer")) { - in_channels = qobject_from_json(args->connect_channels, - &error_abort); - } - out_channels = qobject_from_json(args->connect_channels, &error_abort); - - if (args->cpr_channel) { - QList *channels_list = qobject_to(QList, out_channels); - QObject *obj = migrate_str_to_channel(args->cpr_channel); - - qlist_append(channels_list, obj); - } + channels = qobject_from_json(args->connect_channels, &error_abort); } if (args->result == MIG_TEST_QMP_ERROR) { - migrate_qmp_fail(from, args->connect_uri, out_channels, "{}"); + migrate_qmp_fail(from, args->connect_uri, channels, "{}"); goto finish; } - migrate_qmp(from, to, args->connect_uri, out_channels, "{}"); - - if (args->start.defer_target_connect) { - qtest_connect(to); - qtest_qmp_handshake(to, NULL); - if (!strcmp(args->listen_uri, "defer")) { - migrate_incoming_qmp(to, args->connect_uri, in_channels, "{}"); - } - } + migrate_qmp(from, to, args->connect_uri, channels, "{}"); if (args->result != MIG_TEST_SUCCEED) { bool allow_active = args->result == MIG_TEST_FAIL; -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> All file: tests use listen_uri="defer". Make this the default in the common function. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-3-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/cpr-tests.c | 1 - tests/qtest/migration/file-tests.c | 14 -------------- tests/qtest/migration/framework.c | 2 +- 3 files changed, 1 insertion(+), 16 deletions(-) diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -XXX,XX +XXX,XX @@ static void test_mode_reboot(char *name, MigrateCommon *args) FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_mode_reboot; args->start.mem_type = MEM_TYPE_SHMEM; diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/file-tests.c +++ b/tests/qtest/migration/file-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_file(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; - test_file_common(args, true); } @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_offset_fdset(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); args->connect_uri = uri; - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_file_offset_fdset; test_file_common(args, false); @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_offset(char *name, MigrateCommon *args) FILE_TEST_OFFSET); args->connect_uri = uri; - args->listen_uri = "defer"; - test_file_common(args, false); } @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_offset_bad(char *name, MigrateCommon *args) tmpfs, FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->result = MIG_TEST_QMP_ERROR; test_file_common(args, false); @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args) FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args) FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args) FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_mapped_ram_dio; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args) FILE_TEST_OFFSET); args->connect_uri = uri; - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset; args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset; @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram_fdset_dio(char *name, g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); args->connect_uri = uri; - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio; args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset; @@ -XXX,XX +XXX,XX @@ test_precopy_file_mapped_ram_ignore_shared(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); args->connect_uri = uri; - args->listen_uri = "defer"; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true; diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ void test_file_common(MigrateCommon *args, bool stop_src) void *data_hook = NULL; bool check_offset = false; - if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return; } -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Most file: tests use the same URI. Make it a default in the common function. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-4-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/file-tests.c | 29 ----------------------------- tests/qtest/migration/framework.c | 6 ++++++ 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/file-tests.c +++ b/tests/qtest/migration/file-tests.c @@ -XXX,XX +XXX,XX @@ static void test_file_connect_outgoing_fd_leak(char *name, MigrateCommon *args) static void test_precopy_file(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, - FILE_TEST_FILENAME); - args->connect_uri = uri; test_file_common(args, true); } @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_offset_bad(char *name, MigrateCommon *args) static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, - FILE_TEST_FILENAME); - - args->connect_uri = uri; - args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; test_file_common(args, false); @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_mapped_ram_live(char *name, MigrateCommon *args) static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, - FILE_TEST_FILENAME); - - args->connect_uri = uri; - args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; test_file_common(args, true); @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_mapped_ram(char *name, MigrateCommon *args) static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, - FILE_TEST_FILENAME); - args->connect_uri = uri; - args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram_live(char *name, MigrateCommon *args) static void test_multifd_file_mapped_ram(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, - FILE_TEST_FILENAME); - - args->connect_uri = uri; - args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void *migrate_hook_start_multifd_mapped_ram_dio(QTestState *from, static void test_multifd_file_mapped_ram_dio(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, - FILE_TEST_FILENAME); - args->connect_uri = uri; args->start_hook = migrate_hook_start_multifd_mapped_ram_dio; args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; @@ -XXX,XX +XXX,XX @@ static void migration_test_add_file_smoke(MigrationTestEnv *env) static void test_precopy_file_mapped_ram_ignore_shared(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, - FILE_TEST_FILENAME); - args->connect_uri = uri; - args->start.caps[MIGRATION_CAPABILITY_MAPPED_RAM] = true; args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true; diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ void test_file_common(MigrateCommon *args, bool stop_src) QTestState *from, *to; void *data_hook = NULL; bool check_offset = false; + g_autofree char *uri = NULL; if (migrate_start(&from, &to, "defer", &args->start)) { return; } + if (!args->connect_uri) { + uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); + args->connect_uri = uri; + } + /* * File migration is never live. We can keep the source VM running * during migration, but the destination will not be running -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Remove some repetition when defining unix: tests by introducing a _common function. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-5-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/framework.h | 1 + tests/qtest/migration/compression-tests.c | 6 +---- tests/qtest/migration/framework.c | 9 +++++++ tests/qtest/migration/precopy-tests.c | 30 +++-------------------- tests/qtest/migration/tls-tests.c | 12 ++------- 5 files changed, 17 insertions(+), 41 deletions(-) diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -XXX,XX +XXX,XX @@ void test_postcopy_common(MigrateCommon *args); void test_postcopy_recovery_common(MigrateCommon *args, PostcopyRecoveryFailStage fail_stage); int test_precopy_common(MigrateCommon *args); +void test_precopy_unix_common(MigrateCommon *args); void test_file_common(MigrateCommon *args, bool stop_src); void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from, QTestState *to, diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/compression-tests.c +++ b/tests/qtest/migration/compression-tests.c @@ -XXX,XX +XXX,XX @@ migrate_hook_start_xbzrle(QTestState *from, static void test_precopy_unix_xbzrle(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - - args->connect_uri = uri; - args->listen_uri = uri; args->start_hook = migrate_hook_start_xbzrle; args->iterations = 2; /* @@ -XXX,XX +XXX,XX @@ static void test_precopy_unix_xbzrle(char *name, MigrateCommon *args) args->start.caps[MIGRATION_CAPABILITY_XBZRLE] = true; - test_precopy_common(args); + test_precopy_unix_common(args); } static void * diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ finish: return 0; } +void test_precopy_unix_common(MigrateCommon *args) +{ + g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); + + args->listen_uri = uri; + args->connect_uri = uri; + test_precopy_common(args); +} + static void file_dirty_offset_region(void) { g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static char *tmpfs; static void test_precopy_unix_plain(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - - args->listen_uri = uri; - args->connect_uri = uri; /* * The simplest use case of precopy, covering smoke tests of * get-dirty-log dirty tracking. */ args->live = true; - - test_precopy_common(args); + test_precopy_unix_common(args); } static void test_precopy_unix_suspend_live(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - - args->listen_uri = uri; - args->connect_uri = uri; /* * despite being live, the test is fast because the src * suspends immediately. */ args->live = true; - args->start.suspend_me = true; - - test_precopy_common(args); + test_precopy_unix_common(args); } static void test_precopy_unix_suspend_notlive(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - - args->listen_uri = uri; - args->connect_uri = uri; args->start.suspend_me = true; - - test_precopy_common(args); + test_precopy_unix_common(args); } static void test_precopy_unix_dirty_ring(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - - args->listen_uri = uri; - args->connect_uri = uri; /* * Besides the precopy/unix basic test, cover dirty ring interface * rather than get-dirty-log. */ args->live = true; - args->start.use_dirty_ring = true; - - test_precopy_common(args); + test_precopy_unix_common(args); } #ifdef CONFIG_RDMA diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -XXX,XX +XXX,XX @@ static void test_multifd_postcopy_preempt_recovery_tls_psk(char *name, static void test_precopy_unix_tls_psk(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - - args->connect_uri = uri; - args->listen_uri = uri; args->start_hook = migrate_hook_start_tls_psk_match; args->end_hook = migrate_hook_end_tls_psk; - test_precopy_common(args); + test_precopy_unix_common(args); } #ifdef CONFIG_TASN1 @@ -XXX,XX +XXX,XX @@ static void test_precopy_unix_tls_x509_default_host(char *name, static void test_precopy_unix_tls_x509_override_host(char *name, MigrateCommon *args) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - - args->connect_uri = uri; - args->listen_uri = uri; args->start_hook = migrate_hook_start_tls_x509_override_host; args->end_hook = migrate_hook_end_tls_x509; - test_precopy_common(args); + test_precopy_unix_common(args); } #endif /* CONFIG_TASN1 */ -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> The ignore-shared test has the same code as the precopy_common test but inverting (probably incorrectly) the order of a few event waits. Change it to use the common code instead. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-6-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/misc-tests.c | 40 ++++++++---------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/misc-tests.c +++ b/tests/qtest/migration/misc-tests.c @@ -XXX,XX +XXX,XX @@ static void test_analyze_script(char *name, MigrateCommon *args) } #endif -static void test_ignore_shared(char *name, MigrateCommon *args) +static void ignore_shared_assert_skipped(QTestState *from, QTestState *to, + void *data) { - g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - QTestState *from, *to; - - args->start.mem_type = MEM_TYPE_SHMEM; - args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true; - - if (migrate_start(&from, &to, uri, &args->start)) { - return; - } - - migrate_ensure_non_converge(from); - migrate_prepare_for_dirty_mem(from); - - /* Wait for the first serial output from the source */ - wait_for_serial("src_serial"); - - migrate_qmp(from, to, uri, NULL, "{}"); - - migrate_wait_for_dirty_mem(from, to); - - wait_for_stop(from, get_src()); - - qtest_qmp_eventwait(to, "RESUME"); - - wait_for_serial("dest_serial"); - wait_for_migration_complete(from); - /* Check whether shared RAM has been really skipped */ g_assert_cmpint( read_ram_property_int(from, "transferred"), <, 4 * 1024 * 1024); +} + +static void test_ignore_shared(char *name, MigrateCommon *args) +{ + args->live = true; + args->start.mem_type = MEM_TYPE_SHMEM; + args->start.caps[MIGRATION_CAPABILITY_X_IGNORE_SHARED] = true; + args->end_hook = ignore_shared_assert_skipped; - migrate_end(from, to, true); + test_precopy_unix_common(args); } static void do_test_validate_uuid(MigrateStart *args, bool should_fail) -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Using a localhost TCP URI for testing is quite common. Set it as a default for precopy tests that don't provide an URI. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-7-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/framework.c | 4 ++++ tests/qtest/migration/precopy-tests.c | 3 --- tests/qtest/migration/tls-tests.c | 9 --------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) void *data_hook = NULL; QObject *channels = NULL; + if (!args->listen_uri) { + args->listen_uri = "tcp:127.0.0.1:0"; + } + if (migrate_start(&from, &to, args->listen_uri, &args->start)) { return -1; } diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_rdma_plain_ipv6(char *name, MigrateCommon *args) static void test_precopy_tcp_plain(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; - test_precopy_common(args); } static void test_precopy_tcp_switchover_ack(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; /* * Source VM must be running in order to consider the switchover ACK * when deciding to do switchover or not. diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_unix_tls_x509_override_host(char *name, static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_psk_match; args->end_hook = migrate_hook_end_tls_psk; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_psk_match(char *name, MigrateCommon *args) static void test_precopy_tcp_tls_psk_mismatch(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_psk_mismatch; args->end_hook = migrate_hook_end_tls_psk; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ static void *migrate_hook_start_no_tls(QTestState *from, QTestState *to) static void test_precopy_tcp_no_tls(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_no_tls; /* the no_tls start hook requires no cleanup actions */ args->end_hook = NULL; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args) static void test_precopy_tcp_tls_x509_default_host(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_default_host; args->end_hook = migrate_hook_end_tls_x509; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_x509_default_host(char *name, static void test_precopy_tcp_tls_x509_override_host(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_override_host; args->end_hook = migrate_hook_end_tls_x509; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_x509_mismatch_host(char *name, static void test_precopy_tcp_tls_x509_friendly_client(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_friendly_client; args->end_hook = migrate_hook_end_tls_x509; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_x509_friendly_client(char *name, static void test_precopy_tcp_tls_x509_hostile_client(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_hostile_client; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_x509_hostile_client(char *name, static void test_precopy_tcp_tls_x509_allow_anon_client(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_allow_anon_client; args->end_hook = migrate_hook_end_tls_x509; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_x509_allow_anon_client(char *name, static void test_precopy_tcp_tls_x509_reject_anon_client(char *name, MigrateCommon *args) { - args->listen_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_reject_anon_client; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> As a design direction, we're restricting the usage of the command line option -incoming <URI>. The alternative -incoming defer should be used instead. Make all precopy_common tests defer by default. Using the defer option means that QEMU will not start the incoming migration automatically. Add the incoming QMP command. With the added command, the invocation at the multifd_common hook becomes redundant, so remove it. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Reviewed-by: Lukas Straub <lukasstraub2@web.de> Tested-by: Lukas Straub <lukasstraub2@web.de> Link: https://lore.kernel.org/r/20260505160915.25558-8-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/colo-tests.c | 12 ++++-------- tests/qtest/migration/compression-tests.c | 6 ------ tests/qtest/migration/framework.c | 15 ++++++++------- tests/qtest/migration/precopy-tests.c | 11 +---------- tests/qtest/migration/tls-tests.c | 15 +-------------- 5 files changed, 14 insertions(+), 45 deletions(-) diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/colo-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/colo-tests.c +++ b/tests/qtest/migration/colo-tests.c @@ -XXX,XX +XXX,XX @@ static int test_colo_common(MigrateCommon *args, args->start.caps[MIGRATION_CAPABILITY_RETURN_PATH] = true; args->start.caps[MIGRATION_CAPABILITY_X_COLO] = true; - if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return -1; } @@ -XXX,XX +XXX,XX @@ static int test_colo_common(MigrateCommon *args, data_hook = args->start_hook(from, to); } + migrate_incoming_qmp(to, args->listen_uri, NULL, "{}"); + migrate_ensure_converge(from); wait_for_serial("src_serial"); @@ -XXX,XX +XXX,XX @@ static void test_colo_plain_common(MigrateCommon *args, test_colo_common(args, failover_during_checkpoint, primary_failover); } -static void *hook_start_multifd(QTestState *from, QTestState *to) -{ - return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); -} - static void test_colo_multifd_common(MigrateCommon *args, bool failover_during_checkpoint, bool primary_failover) { - args->listen_uri = "defer"; - args->start_hook = hook_start_multifd; + args->listen_uri = "tcp:127.0.0.1:0"; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; test_colo_common(args, failover_during_checkpoint, primary_failover); } diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/compression-tests.c +++ b/tests/qtest/migration/compression-tests.c @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from, static void test_multifd_tcp_zstd(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_zstd(char *name, MigrateCommon *args) static void test_multifd_postcopy_tcp_zstd(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_zstd, args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from, static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_qatzip; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from, static void test_multifd_tcp_qpl(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_qpl; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from, static void test_multifd_tcp_uadk(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_uadk; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from, static void test_multifd_tcp_zlib(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_zlib; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) void *data_hook = NULL; QObject *channels = NULL; - if (!args->listen_uri) { + assert(!args->connect_uri); + + if (args->listen_uri) { + args->connect_uri = args->listen_uri; + } else { args->listen_uri = "tcp:127.0.0.1:0"; } - if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return -1; } @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) data_hook = args->start_hook(from, to); } + migrate_incoming_qmp(to, args->listen_uri, NULL, "{}"); + /* Wait for the first serial output from the source */ if (args->result == MIG_TEST_SUCCEED) { wait_for_serial("src_serial"); @@ -XXX,XX +XXX,XX @@ void test_precopy_unix_common(MigrateCommon *args) g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); args->listen_uri = uri; - args->connect_uri = uri; test_precopy_common(args); } @@ -XXX,XX +XXX,XX @@ void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from, { migrate_set_parameter_str(from, "multifd-compression", method); migrate_set_parameter_str(to, "multifd-compression", method); - - /* Start incoming migration from the 1st socket */ - migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); - return NULL; } diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void __test_precopy_rdma_plain(MigrateCommon *args, bool ipv6) g_autofree char *uri = g_strdup_printf("rdma:%s:29200", buffer); args->listen_uri = uri; - args->connect_uri = uri; test_precopy_common(args); } @@ -XXX,XX +XXX,XX @@ static void *migrate_hook_start_fd(QTestState *from, " 'arguments': { 'fdname': 'fd-mig' }}"); close(pair[0]); - /* Start incoming migration from the 1st socket */ - migrate_incoming_qmp(to, "fd:fd-mig", NULL, "{}"); - /* Send the 2nd socket to the target */ qtest_qmp_fds_assert_success(from, &pair[1], 1, "{ 'execute': 'getfd'," @@ -XXX,XX +XXX,XX @@ static void migrate_hook_end_fd(QTestState *from, static void test_precopy_fd_socket(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; - args->connect_uri = "fd:fd-mig"; + args->listen_uri = "fd:fd-mig"; args->start_hook = migrate_hook_start_fd; args->end_hook = migrate_hook_end_fd; @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from, static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd; /* * Multifd is more complicated than most of the features, it @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args) static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_zero_page_legacy; /* * Multifd is more complicated than most of the features, it @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_zero_page_legacy(char *name, MigrateCommon *args) static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd_no_zero_page; /* * Multifd is more complicated than most of the features, it @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args) static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_precopy_tcp_multifd; args->live = true; args->connect_channels = ("[ { 'channel-type': 'main'," diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_unix_tls_x509_default_host(char *name, { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - args->connect_uri = uri; - args->listen_uri = "defer"; + args->listen_uri = uri; args->start_hook = migrate_hook_start_tls_x509_default_host; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ migrate_hook_start_tls_x509_no_host(QTestState *from, QTestState *to) static void test_precopy_tcp_tls_no_hostname(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; - args->connect_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_no_host; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_x509_override_host(char *name, static void test_precopy_tcp_tls_x509_mismatch_host(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; - args->connect_uri = "tcp:127.0.0.1:0"; args->start_hook = migrate_hook_start_tls_x509_mismatch_host; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from, static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match; args->end_hook = migrate_hook_end_tls_psk; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args) static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch; args->end_hook = migrate_hook_end_tls_psk; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args) static void test_multifd_postcopy_tcp_tls_psk_match(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match; args->end_hook = migrate_hook_end_tls_psk; @@ -XXX,XX +XXX,XX @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name, static void test_multifd_tcp_tls_x509_default_host(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tls_x509_default_host; args->end_hook = migrate_hook_end_tls_x509; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_default_host(char *name, static void test_multifd_tcp_tls_x509_override_host(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tls_x509_override_host; args->end_hook = migrate_hook_end_tls_x509; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name, * to load migration state, and thus just aborts the migration * without exiting. */ - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name, static void test_multifd_tcp_tls_x509_allow_anon_client(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client; args->end_hook = migrate_hook_end_tls_x509; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name, static void test_multifd_tcp_tls_x509_reject_anon_client(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Stop calling a common function to set the multifd compression method. The default method is "none", so the common function is not necessary for tests that don't set compression and will be removed. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-9-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/compression-tests.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/qtest/migration/compression-tests.c b/tests/qtest/migration/compression-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/compression-tests.c +++ b/tests/qtest/migration/compression-tests.c @@ -XXX,XX +XXX,XX @@ static char *tmpfs; +static void set_multifd_compression(QTestState *from, QTestState *to, + const char *method) +{ + migrate_set_parameter_str(from, "multifd-compression", method); + migrate_set_parameter_str(to, "multifd-compression", method); +} + #ifdef CONFIG_ZSTD static void * migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from, @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_zstd(QTestState *from, { migrate_set_parameter_int(from, "multifd-zstd-level", 2); migrate_set_parameter_int(to, "multifd-zstd-level", 2); + set_multifd_compression(from, to, "zstd"); - return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zstd"); + return NULL; } static void test_multifd_tcp_zstd(char *name, MigrateCommon *args) @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_qatzip(QTestState *from, { migrate_set_parameter_int(from, "multifd-qatzip-level", 2); migrate_set_parameter_int(to, "multifd-qatzip-level", 2); + set_multifd_compression(from, to, "qatzip"); - return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qatzip"); + return NULL; } static void test_multifd_tcp_qatzip(char *name, MigrateCommon *args) @@ -XXX,XX +XXX,XX @@ static void * migrate_hook_start_precopy_tcp_multifd_qpl(QTestState *from, QTestState *to) { - return migrate_hook_start_precopy_tcp_multifd_common(from, to, "qpl"); + set_multifd_compression(from, to, "qpl"); + return NULL; } static void test_multifd_tcp_qpl(char *name, MigrateCommon *args) @@ -XXX,XX +XXX,XX @@ static void * migrate_hook_start_precopy_tcp_multifd_uadk(QTestState *from, QTestState *to) { - return migrate_hook_start_precopy_tcp_multifd_common(from, to, "uadk"); + set_multifd_compression(from, to, "uadk"); + return NULL; } static void test_multifd_tcp_uadk(char *name, MigrateCommon *args) @@ -XXX,XX +XXX,XX @@ migrate_hook_start_precopy_tcp_multifd_zlib(QTestState *from, */ migrate_set_parameter_int(from, "multifd-zlib-level", 2); migrate_set_parameter_int(to, "multifd-zlib-level", 2); + set_multifd_compression(from, to, "zlib"); - return migrate_hook_start_precopy_tcp_multifd_common(from, to, "zlib"); + return NULL; } static void test_multifd_tcp_zlib(char *name, MigrateCommon *args) -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Take advantage of the default compression method for multifd being "none" and remove the common compression hook. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-10-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/framework.h | 3 -- tests/qtest/migration/framework.c | 9 ---- tests/qtest/migration/precopy-tests.c | 11 ---- tests/qtest/migration/tls-tests.c | 74 +++------------------------ 4 files changed, 8 insertions(+), 89 deletions(-) diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -XXX,XX +XXX,XX @@ void test_postcopy_recovery_common(MigrateCommon *args, int test_precopy_common(MigrateCommon *args); void test_precopy_unix_common(MigrateCommon *args); void test_file_common(MigrateCommon *args, bool stop_src); -void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from, - QTestState *to, - const char *method); typedef struct QTestMigrationState QTestMigrationState; QTestMigrationState *get_src(void); diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ finish: migrate_end(from, to, args->result == MIG_TEST_SUCCEED); } -void *migrate_hook_start_precopy_tcp_multifd_common(QTestState *from, - QTestState *to, - const char *method) -{ - migrate_set_parameter_str(from, "multifd-compression", method); - migrate_set_parameter_str(to, "multifd-compression", method); - return NULL; -} - QTestMigrationState *get_src(void) { return &src_state; diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void test_auto_converge(char *name, MigrateCommon *args) migrate_end(from, to, true); } -static void * -migrate_hook_start_precopy_tcp_multifd(QTestState *from, - QTestState *to) -{ - return migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); -} - static void * migrate_hook_start_precopy_tcp_multifd_zero_page_legacy(QTestState *from, QTestState *to) { - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); migrate_set_parameter_str(from, "zero-page-detection", "legacy"); return NULL; } @@ -XXX,XX +XXX,XX @@ static void * migrate_hook_start_precopy_tcp_multifd_no_zero_page(QTestState *from, QTestState *to) { - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); migrate_set_parameter_str(from, "zero-page-detection", "none"); return NULL; } static void test_multifd_tcp_uri_none(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_precopy_tcp_multifd; /* * Multifd is more complicated than most of the features, it * directly takes guest page buffers when sending, make sure @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_no_zero_page(char *name, MigrateCommon *args) static void test_multifd_tcp_channels_none(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_precopy_tcp_multifd; args->live = true; args->connect_channels = ("[ { 'channel-type': 'main'," " 'addr': { 'transport': 'socket'," diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_tcp_tls_x509_reject_anon_client(char *name, } #endif /* CONFIG_TASN1 */ -static void * -migrate_hook_start_multifd_tcp_tls_psk_match(QTestState *from, - QTestState *to) -{ - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); - return migrate_hook_start_tls_psk_match(from, to); -} - -static void * -migrate_hook_start_multifd_tcp_tls_psk_mismatch(QTestState *from, - QTestState *to) -{ - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); - return migrate_hook_start_tls_psk_mismatch(from, to); -} - -#ifdef CONFIG_TASN1 -static void * -migrate_hook_start_multifd_tls_x509_default_host(QTestState *from, - QTestState *to) -{ - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); - return migrate_hook_start_tls_x509_default_host(from, to); -} - -static void * -migrate_hook_start_multifd_tls_x509_override_host(QTestState *from, - QTestState *to) -{ - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); - return migrate_hook_start_tls_x509_override_host(from, to); -} - -static void * -migrate_hook_start_multifd_tls_x509_mismatch_host(QTestState *from, - QTestState *to) -{ - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); - return migrate_hook_start_tls_x509_mismatch_host(from, to); -} - -static void * -migrate_hook_start_multifd_tls_x509_allow_anon_client(QTestState *from, - QTestState *to) -{ - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); - return migrate_hook_start_tls_x509_allow_anon_client(from, to); -} - -static void * -migrate_hook_start_multifd_tls_x509_reject_anon_client(QTestState *from, - QTestState *to) -{ - migrate_hook_start_precopy_tcp_multifd_common(from, to, "none"); - return migrate_hook_start_tls_x509_reject_anon_client(from, to); -} -#endif /* CONFIG_TASN1 */ - static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match; + args->start_hook = migrate_hook_start_tls_psk_match; args->end_hook = migrate_hook_end_tls_psk; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_psk_match(char *name, MigrateCommon *args) static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_mismatch; + args->start_hook = migrate_hook_start_tls_psk_mismatch; args->end_hook = migrate_hook_end_tls_psk; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_psk_mismatch(char *name, MigrateCommon *args) static void test_multifd_postcopy_tcp_tls_psk_match(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_multifd_tcp_tls_psk_match; + args->start_hook = migrate_hook_start_tls_psk_match; args->end_hook = migrate_hook_end_tls_psk; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_postcopy_tcp_tls_psk_match(char *name, static void test_multifd_tcp_tls_x509_default_host(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_multifd_tls_x509_default_host; + args->start_hook = migrate_hook_start_tls_x509_default_host; args->end_hook = migrate_hook_end_tls_x509; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_default_host(char *name, static void test_multifd_tcp_tls_x509_override_host(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_multifd_tls_x509_override_host; + args->start_hook = migrate_hook_start_tls_x509_override_host; args->end_hook = migrate_hook_end_tls_x509; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name, * to load migration state, and thus just aborts the migration * without exiting. */ - args->start_hook = migrate_hook_start_multifd_tls_x509_mismatch_host; + args->start_hook = migrate_hook_start_tls_x509_mismatch_host; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_mismatch_host(char *name, static void test_multifd_tcp_tls_x509_allow_anon_client(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_multifd_tls_x509_allow_anon_client; + args->start_hook = migrate_hook_start_tls_x509_allow_anon_client; args->end_hook = migrate_hook_end_tls_x509; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_tls_x509_allow_anon_client(char *name, static void test_multifd_tcp_tls_x509_reject_anon_client(char *name, MigrateCommon *args) { - args->start_hook = migrate_hook_start_multifd_tls_x509_reject_anon_client; + args->start_hook = migrate_hook_start_tls_x509_reject_anon_client; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Change all invocations of migrate_start to use defer. The uri parameter will be removed from that function in subsequent patches. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-11-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/misc-tests.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/misc-tests.c +++ b/tests/qtest/migration/misc-tests.c @@ -XXX,XX +XXX,XX @@ static void test_baddest(char *name, MigrateCommon *args) args->start.hide_stderr = true; - if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return; } + + migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); migrate_qmp(from, to, "tcp:127.0.0.1:0", NULL, "{}"); wait_for_migration_fail(from, false); migrate_end(from, to, false); @@ -XXX,XX +XXX,XX @@ static void test_analyze_script(char *name, MigrateCommon *args) return; } - /* dummy url */ - if (migrate_start(&from, &to, "tcp:127.0.0.1:0", &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_analyze_script(char *name, MigrateCommon *args) uri = g_strdup_printf("exec:cat > %s", file); migrate_ensure_converge(from); + migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); migrate_qmp(from, to, uri, NULL, "{}"); wait_for_migration_complete(from); @@ -XXX,XX +XXX,XX @@ static void do_test_validate_uri_channel(MigrateCommon *args) QTestState *from, *to; QObject *channels; - if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return; } /* Wait for the first serial output from the source */ wait_for_serial("src_serial"); + migrate_incoming_qmp(to, "tcp:127.0.0.1:0", NULL, "{}"); + /* * 'uri' and 'channels' validation is checked even before the migration * starts. @@ -XXX,XX +XXX,XX @@ static void test_validate_caps_pair(char *test_path, MigrateCommon *args) static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args) { - args->listen_uri = "defer", args->connect_uri = "tcp:127.0.0.1:0", args->connect_channels = ("[ { ""'channel-type': 'main'," " 'addr': { 'transport': 'socket'," @@ -XXX,XX +XXX,XX @@ static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args) static void test_validate_uri_channels_none_set(char *name, MigrateCommon *args) { - args->listen_uri = "defer"; args->start.hide_stderr = true; do_test_validate_uri_channel(args); -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-12-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/cpr-tests.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -XXX,XX +XXX,XX @@ static int test_transfer(MigrateCommon *args, const char *cpr_channel, obj = migrate_str_to_channel(cpr_channel); qlist_append(channels_list, obj); - if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return -1; } @@ -XXX,XX +XXX,XX @@ static void test_mode_transfer_common(MigrateCommon *args, bool incoming_defer) int cpr_sockfd = qtest_socket_server(cpr_path); g_assert(cpr_sockfd >= 0); - opts_target = g_strdup_printf("-incoming cpr,addr.transport=socket," - "addr.type=fd,addr.str=%d %s", - cpr_sockfd, opts); + if (incoming_defer) { + opts_target = g_strdup_printf("-incoming cpr,addr.transport=socket," + "addr.type=fd,addr.str=%d %s", + cpr_sockfd, opts); + } else { + opts_target = g_strdup_printf("-incoming %s " + "-incoming cpr,addr.transport=socket," + "addr.type=fd,addr.str=%d %s", + uri, cpr_sockfd, opts); + } - args->listen_uri = incoming_defer ? "defer" : uri; args->connect_channels = connect_channels; args->start.opts_source = opts; @@ -XXX,XX +XXX,XX @@ static void test_cpr_exec(MigrateCommon *args) g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); - if (migrate_start(&from, NULL, args->listen_uri, &args->start)) { + if (migrate_start(&from, NULL, "defer", &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_mode_exec(char *name, MigrateCommon *args) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); - g_autofree char *listen_uri = g_strdup_printf("defer"); - args->connect_uri = uri; - args->listen_uri = listen_uri; args->start_hook = test_mode_exec_start; args->start.only_source = true; -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-13-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/precopy-tests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void test_auto_converge(char *name, MigrateCommon *args) int64_t percentage; const int64_t init_pct = 5, inc_pct = 25, max_pct = 95; - if (migrate_start(&from, &to, uri, &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_auto_converge(char *name, MigrateCommon *args) wait_for_serial("src_serial"); + migrate_incoming_qmp(to, uri, NULL, "{}"); migrate_qmp(from, to, uri, NULL, "{}"); /* Wait until throttling begins */ -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-14-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/precopy-tests.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void test_dirty_limit(char *name, MigrateCommon *args) args->start.use_dirty_ring = true; /* Restart dst vm, src vm already show up so we needn't wait anymore */ - if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + if (migrate_start(&from, &to, "defer", &args->start)) { return; } /* Start migrate */ + migrate_incoming_qmp(to, args->listen_uri, NULL, "{}"); migrate_qmp(from, to, args->connect_uri, NULL, "{}"); /* Wait for dirty limit throttle begin */ -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> Don't allow changing the default -incoming URI via migrate_start. The default is now -incoming defer. If a test really needs to alter this (such as with CPR), the target_opts variable is still available to change the command line. (aside from the larger goal of using defer, this change is a step towards allowing migrate_start() to be invoked only once for all tests) Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Lukas Straub <lukasstraub2@web.de> Tested-by: Lukas Straub <lukasstraub2@web.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-15-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/framework.h | 5 ++--- tests/qtest/migration/colo-tests.c | 2 +- tests/qtest/migration/cpr-tests.c | 6 +++--- tests/qtest/migration/file-tests.c | 3 +-- tests/qtest/migration/framework.c | 17 ++++++++--------- tests/qtest/migration/misc-tests.c | 10 +++++----- tests/qtest/migration/precopy-tests.c | 12 ++++++------ 7 files changed, 26 insertions(+), 29 deletions(-) diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -XXX,XX +XXX,XX @@ void wait_for_serial(const char *side); void migrate_prepare_for_dirty_mem(QTestState *from); void migrate_wait_for_dirty_mem(QTestState *from, QTestState *to); -int migrate_args(char **from, char **to, const char *uri, MigrateStart *args); -int migrate_start(QTestState **from, QTestState **to, const char *uri, - MigrateStart *args); +int migrate_args(char **from, char **to, MigrateStart *args); +int migrate_start(QTestState **from, QTestState **to, MigrateStart *args); void migrate_end(QTestState *from, QTestState *to, bool test_dest); void test_postcopy_common(MigrateCommon *args); diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/colo-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/colo-tests.c +++ b/tests/qtest/migration/colo-tests.c @@ -XXX,XX +XXX,XX @@ static int test_colo_common(MigrateCommon *args, args->start.caps[MIGRATION_CAPABILITY_RETURN_PATH] = true; args->start.caps[MIGRATION_CAPABILITY_X_COLO] = true; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return -1; } diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -XXX,XX +XXX,XX @@ static int test_transfer(MigrateCommon *args, const char *cpr_channel, obj = migrate_str_to_channel(cpr_channel); qlist_append(channels_list, obj); - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return -1; } @@ -XXX,XX +XXX,XX @@ static void set_cpr_exec_args(QTestState *who, MigrateCommon *args) */ g_assert(args->start.hide_stderr == false); - ret = migrate_args(&from_args, &to_args, args->listen_uri, &args->start); + ret = migrate_args(&from_args, &to_args, &args->start); g_assert(!ret); qtest_from_args = qtest_qemu_args(from_args); @@ -XXX,XX +XXX,XX @@ static void test_cpr_exec(MigrateCommon *args) g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); - if (migrate_start(&from, NULL, "defer", &args->start)) { + if (migrate_start(&from, NULL, &args->start)) { return; } diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/file-tests.c +++ b/tests/qtest/migration/file-tests.c @@ -XXX,XX +XXX,XX @@ static void test_file_connect_outgoing_fd_leak(char *name, MigrateCommon *args) return; } - args->listen_uri = "defer"; - if (migrate_start(&from, &to, args->listen_uri, &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ static char *migrate_mem_type_get_opts(MemType type, const char *memory_size) return opts; } -int migrate_args(char **from, char **to, const char *uri, MigrateStart *args) +int migrate_args(char **from, char **to, MigrateStart *args) { /* options for source and target */ g_autofree gchar *arch_opts = NULL; @@ -XXX,XX +XXX,XX @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args) "-name target,debug-threads=on " "%s " "-serial file:%s/dest_serial " - "-incoming %s " + "-incoming defer " "%s %s %s %s", kvm_opts ? kvm_opts : "", machine, machine_opts, - memory_backend, tmpfs, uri, + memory_backend, tmpfs, events, arch_opts ? arch_opts : "", args->opts_target ? args->opts_target : "", @@ -XXX,XX +XXX,XX @@ static void migrate_mem_type_cleanup(MemType type) } } -int migrate_start(QTestState **from, QTestState **to, const char *uri, - MigrateStart *args) +int migrate_start(QTestState **from, QTestState **to, MigrateStart *args) { g_autofree gchar *cmd_source = NULL; g_autofree gchar *cmd_target = NULL; @@ -XXX,XX +XXX,XX @@ int migrate_start(QTestState **from, QTestState **to, const char *uri, bootfile_create(qtest_get_arch(), tmpfs, args->suspend_me); src_state.suspend_me = args->suspend_me; - if (migrate_args(&cmd_source, &cmd_target, uri, args)) { + if (migrate_args(&cmd_source, &cmd_target, args)) { return -1; } @@ -XXX,XX +XXX,XX @@ static int migrate_postcopy_prepare(QTestState **from_ptr, args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_BLOCKTIME] = true; args->start.caps[MIGRATION_CAPABILITY_POSTCOPY_RAM] = true; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return -1; } @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) args->listen_uri = "tcp:127.0.0.1:0"; } - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return -1; } @@ -XXX,XX +XXX,XX @@ void test_file_common(MigrateCommon *args, bool stop_src) bool check_offset = false; g_autofree char *uri = NULL; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/misc-tests.c +++ b/tests/qtest/migration/misc-tests.c @@ -XXX,XX +XXX,XX @@ static void test_baddest(char *name, MigrateCommon *args) args->start.hide_stderr = true; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_analyze_script(char *name, MigrateCommon *args) return; } - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void do_test_validate_uuid(MigrateStart *args, bool should_fail) g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); QTestState *from, *to; - if (migrate_start(&from, &to, "defer", args)) { + if (migrate_start(&from, &to, args)) { return; } @@ -XXX,XX +XXX,XX @@ static void do_test_validate_uri_channel(MigrateCommon *args) QTestState *from, *to; QObject *channels; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_validate_caps_pair(char *test_path, MigrateCommon *args) args->start.hide_stderr = true; args->start.only_source = true; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void test_auto_converge(char *name, MigrateCommon *args) int64_t percentage; const int64_t init_pct = 5, inc_pct = 25, max_pct = 95; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram) args->start.hide_stderr = true; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_multifd_tcp_cancel(MigrateCommon *args, bool postcopy_ram) args->start.only_target = true; - if (migrate_start(&from, &to2, "defer", &args->start)) { + if (migrate_start(&from, &to2, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_cancel_src_after_status(char *test_path, MigrateCommon *args) args->start.hide_stderr = true; - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_dirty_limit(char *name, MigrateCommon *args) args->connect_uri = uri; /* Start src, dst vm */ - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } @@ -XXX,XX +XXX,XX @@ static void test_dirty_limit(char *name, MigrateCommon *args) args->start.use_dirty_ring = true; /* Restart dst vm, src vm already show up so we needn't wait anymore */ - if (migrate_start(&from, &to, "defer", &args->start)) { + if (migrate_start(&from, &to, &args->start)) { return; } -- 2.53.0
From: Fabiano Rosas <farosas@suse.de> The migration tests have always used localhost migration and therefore the same URI for both sides of migration. Change the listen_uri and connect_uri into a single uri variable. For migrations using sockets, there's the possibility of detecting the socket address the destination side is using. For those, keep using different variables for migrate_qmp and migrate_incoming_qmp. Signed-off-by: Fabiano Rosas <farosas@suse.de> Reviewed-by: Lukas Straub <lukasstraub2@web.de> Tested-by: Lukas Straub <lukasstraub2@web.de> Reviewed-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/r/20260505160915.25558-16-farosas@suse.de Signed-off-by: Peter Xu <peterx@redhat.com> --- tests/qtest/migration/framework.h | 14 ++++++------- tests/qtest/migration/colo-tests.c | 8 ++++---- tests/qtest/migration/cpr-tests.c | 6 +++--- tests/qtest/migration/file-tests.c | 10 ++++----- tests/qtest/migration/framework.c | 29 ++++++++++----------------- tests/qtest/migration/misc-tests.c | 4 ++-- tests/qtest/migration/precopy-tests.c | 17 ++++++++-------- tests/qtest/migration/tls-tests.c | 2 +- 8 files changed, 40 insertions(+), 50 deletions(-) diff --git a/tests/qtest/migration/framework.h b/tests/qtest/migration/framework.h index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.h +++ b/tests/qtest/migration/framework.h @@ -XXX,XX +XXX,XX @@ typedef struct { /* Optional: fine tune start parameters */ MigrateStart start; - /* Required: the URI for the dst QEMU to listen on */ - const char *listen_uri; - /* - * Optional: the URI for the src QEMU to connect to - * If NULL, then it will query the dst QEMU for its actual - * listening address and use that as the connect address. - * This allows for dynamically picking a free TCP port. + * Optional: the migration URI. If NULL, the common code should + * provide a default. For socket migration, the source QEMU may + * query the dst QEMU for the listening address and use that as + * the connection address. This allows for dynamically picking a + * free TCP port. */ - const char *connect_uri; + const char *uri; /* * Optional: JSON-formatted list of src QEMU URIs. If a port is diff --git a/tests/qtest/migration/colo-tests.c b/tests/qtest/migration/colo-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/colo-tests.c +++ b/tests/qtest/migration/colo-tests.c @@ -XXX,XX +XXX,XX @@ static int test_colo_common(MigrateCommon *args, data_hook = args->start_hook(from, to); } - migrate_incoming_qmp(to, args->listen_uri, NULL, "{}"); + migrate_incoming_qmp(to, args->uri, NULL, "{}"); migrate_ensure_converge(from); wait_for_serial("src_serial"); - migrate_qmp(from, to, args->connect_uri, NULL, "{}"); + migrate_qmp(from, to, NULL, NULL, "{}"); wait_for_migration_status(from, "colo", NULL); wait_for_resume(to, get_dst()); @@ -XXX,XX +XXX,XX @@ static void test_colo_plain_common(MigrateCommon *args, bool failover_during_checkpoint, bool primary_failover) { - args->listen_uri = "tcp:127.0.0.1:0"; + args->uri = "tcp:127.0.0.1:0"; test_colo_common(args, failover_during_checkpoint, primary_failover); } @@ -XXX,XX +XXX,XX @@ static void test_colo_multifd_common(MigrateCommon *args, bool failover_during_checkpoint, bool primary_failover) { - args->listen_uri = "tcp:127.0.0.1:0"; + args->uri = "tcp:127.0.0.1:0"; args->start.caps[MIGRATION_CAPABILITY_MULTIFD] = true; test_colo_common(args, failover_during_checkpoint, primary_failover); } diff --git a/tests/qtest/migration/cpr-tests.c b/tests/qtest/migration/cpr-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/cpr-tests.c +++ b/tests/qtest/migration/cpr-tests.c @@ -XXX,XX +XXX,XX @@ static void test_mode_reboot(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); - args->connect_uri = uri; + args->uri = uri; args->start_hook = migrate_hook_start_mode_reboot; args->start.mem_type = MEM_TYPE_SHMEM; @@ -XXX,XX +XXX,XX @@ static void test_cpr_exec(MigrateCommon *args) { QTestState *from, *to; void *data_hook = NULL; - g_autofree char *connect_uri = g_strdup(args->connect_uri); + g_autofree char *connect_uri = g_strdup(args->uri); g_autofree char *filename = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME); @@ -XXX,XX +XXX,XX @@ static void test_mode_exec(char *name, MigrateCommon *args) { g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); - args->connect_uri = uri; + args->uri = uri; args->start_hook = test_mode_exec_start; args->start.only_source = true; diff --git a/tests/qtest/migration/file-tests.c b/tests/qtest/migration/file-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/file-tests.c +++ b/tests/qtest/migration/file-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_offset_fdset(char *name, MigrateCommon *args) { g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); - args->connect_uri = uri; + args->uri = uri; args->start_hook = migrate_hook_start_file_offset_fdset; test_file_common(args, false); @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_offset(char *name, MigrateCommon *args) FILE_TEST_FILENAME, FILE_TEST_OFFSET); - args->connect_uri = uri; + args->uri = uri; test_file_common(args, false); } @@ -XXX,XX +XXX,XX @@ static void test_precopy_file_offset_bad(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M", tmpfs, FILE_TEST_FILENAME); - args->connect_uri = uri; + args->uri = uri; args->result = MIG_TEST_QMP_ERROR; test_file_common(args, false); @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram_fdset(char *name, MigrateCommon *args) g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); - args->connect_uri = uri; + args->uri = uri; args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset; args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset; @@ -XXX,XX +XXX,XX @@ static void test_multifd_file_mapped_ram_fdset_dio(char *name, { g_autofree char *uri = g_strdup_printf("file:/dev/fdset/1,offset=%d", FILE_TEST_OFFSET); - args->connect_uri = uri; + args->uri = uri; args->start_hook = migrate_hook_start_multifd_mapped_ram_fdset_dio; args->end_hook = migrate_hook_end_multifd_mapped_ram_fdset; diff --git a/tests/qtest/migration/framework.c b/tests/qtest/migration/framework.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/framework.c +++ b/tests/qtest/migration/framework.c @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) QTestState *from, *to; void *data_hook = NULL; QObject *channels = NULL; - - assert(!args->connect_uri); - - if (args->listen_uri) { - args->connect_uri = args->listen_uri; - } else { - args->listen_uri = "tcp:127.0.0.1:0"; - } + const char *listen_uri = args->uri ?: "tcp:127.0.0.1:0"; if (migrate_start(&from, &to, &args->start)) { return -1; @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) data_hook = args->start_hook(from, to); } - migrate_incoming_qmp(to, args->listen_uri, NULL, "{}"); + migrate_incoming_qmp(to, listen_uri, NULL, "{}"); /* Wait for the first serial output from the source */ if (args->result == MIG_TEST_SUCCEED) { @@ -XXX,XX +XXX,XX @@ int test_precopy_common(MigrateCommon *args) } if (args->result == MIG_TEST_QMP_ERROR) { - migrate_qmp_fail(from, args->connect_uri, channels, "{}"); + migrate_qmp_fail(from, args->uri, channels, "{}"); goto finish; } - migrate_qmp(from, to, args->connect_uri, channels, "{}"); + migrate_qmp(from, to, args->uri, channels, "{}"); if (args->result != MIG_TEST_SUCCEED) { bool allow_active = args->result == MIG_TEST_FAIL; @@ -XXX,XX +XXX,XX @@ void test_precopy_unix_common(MigrateCommon *args) { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - args->listen_uri = uri; + args->uri = uri; test_precopy_common(args); } @@ -XXX,XX +XXX,XX @@ void test_file_common(MigrateCommon *args, bool stop_src) return; } - if (!args->connect_uri) { + if (!args->uri) { uri = g_strdup_printf("file:%s/%s", tmpfs, FILE_TEST_FILENAME); - args->connect_uri = uri; + args->uri = uri; } /* @@ -XXX,XX +XXX,XX @@ void test_file_common(MigrateCommon *args, bool stop_src) */ g_assert_false(args->live); - if (g_strrstr(args->connect_uri, "offset=")) { + if (g_strrstr(args->uri, "offset=")) { check_offset = true; /* * This comes before the start_hook because it's equivalent to @@ -XXX,XX +XXX,XX @@ void test_file_common(MigrateCommon *args, bool stop_src) } if (args->result == MIG_TEST_QMP_ERROR) { - migrate_qmp_fail(from, args->connect_uri, NULL, "{}"); + migrate_qmp_fail(from, args->uri, NULL, "{}"); goto finish; } - migrate_qmp(from, to, args->connect_uri, NULL, "{}"); + migrate_qmp(from, to, args->uri, NULL, "{}"); wait_for_migration_complete(from); /* * We need to wait for the source to finish before starting the * destination. */ - migrate_incoming_qmp(to, args->connect_uri, NULL, "{}"); + migrate_incoming_qmp(to, args->uri, NULL, "{}"); wait_for_migration_complete(to); if (stop_src) { diff --git a/tests/qtest/migration/misc-tests.c b/tests/qtest/migration/misc-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/misc-tests.c +++ b/tests/qtest/migration/misc-tests.c @@ -XXX,XX +XXX,XX @@ static void do_test_validate_uri_channel(MigrateCommon *args) channels = args->connect_channels ? qobject_from_json(args->connect_channels, &error_abort) : NULL; - migrate_qmp_fail(from, args->connect_uri, channels, "{}"); + migrate_qmp_fail(from, args->uri, channels, "{}"); migrate_end(from, to, false); } @@ -XXX,XX +XXX,XX @@ static void test_validate_caps_pair(char *test_path, MigrateCommon *args) static void test_validate_uri_channels_both_set(char *name, MigrateCommon *args) { - args->connect_uri = "tcp:127.0.0.1:0", + args->uri = "tcp:127.0.0.1:0", args->connect_channels = ("[ { ""'channel-type': 'main'," " 'addr': { 'transport': 'socket'," " 'type': 'inet'," diff --git a/tests/qtest/migration/precopy-tests.c b/tests/qtest/migration/precopy-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/precopy-tests.c +++ b/tests/qtest/migration/precopy-tests.c @@ -XXX,XX +XXX,XX @@ static void __test_precopy_rdma_plain(MigrateCommon *args, bool ipv6) **/ g_autofree char *uri = g_strdup_printf("rdma:%s:29200", buffer); - args->listen_uri = uri; + args->uri = uri; test_precopy_common(args); } @@ -XXX,XX +XXX,XX @@ static void migrate_hook_end_fd(QTestState *from, static void test_precopy_fd_socket(char *name, MigrateCommon *args) { - args->listen_uri = "fd:fd-mig"; + args->uri = "fd:fd-mig"; args->start_hook = migrate_hook_start_fd; args->end_hook = migrate_hook_end_fd; @@ -XXX,XX +XXX,XX @@ static void test_dirty_limit(char *name, MigrateCommon *args) args->start.hide_stderr = true; args->start.use_dirty_ring = true; - args->connect_uri = uri; + args->uri = uri; /* Start src, dst vm */ if (migrate_start(&from, &to, &args->start)) { @@ -XXX,XX +XXX,XX @@ static void test_dirty_limit(char *name, MigrateCommon *args) migrate_dirty_limit_wait_showup(from, dirtylimit_period, dirtylimit_value); /* Start migrate */ - migrate_incoming_qmp(to, args->connect_uri, NULL, "{}"); - migrate_qmp(from, to, args->connect_uri, NULL, "{}"); + migrate_incoming_qmp(to, args->uri, NULL, "{}"); + migrate_qmp(from, to, args->uri, NULL, "{}"); /* Wait for dirty limit throttle begin */ throttle_us_per_full = 0; @@ -XXX,XX +XXX,XX @@ static void test_dirty_limit(char *name, MigrateCommon *args) /* Assert dirty limit is not in service */ g_assert_cmpint(throttle_us_per_full, ==, 0); - args->listen_uri = uri; - args->connect_uri = uri; + args->uri = uri; args->start.only_target = true; args->start.use_dirty_ring = true; @@ -XXX,XX +XXX,XX @@ static void test_dirty_limit(char *name, MigrateCommon *args) } /* Start migrate */ - migrate_incoming_qmp(to, args->listen_uri, NULL, "{}"); - migrate_qmp(from, to, args->connect_uri, NULL, "{}"); + migrate_incoming_qmp(to, args->uri, NULL, "{}"); + migrate_qmp(from, to, args->uri, NULL, "{}"); /* Wait for dirty limit throttle begin */ throttle_us_per_full = 0; diff --git a/tests/qtest/migration/tls-tests.c b/tests/qtest/migration/tls-tests.c index XXXXXXX..XXXXXXX 100644 --- a/tests/qtest/migration/tls-tests.c +++ b/tests/qtest/migration/tls-tests.c @@ -XXX,XX +XXX,XX @@ static void test_precopy_unix_tls_x509_default_host(char *name, { g_autofree char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs); - args->listen_uri = uri; + args->uri = uri; args->start_hook = migrate_hook_start_tls_x509_default_host; args->end_hook = migrate_hook_end_tls_x509; args->result = MIG_TEST_FAIL; -- 2.53.0
From: Bin Guo <guobin@linux.alibaba.com> Drop the unnecessary strcpy of an empty literal (and its spurious (char *)& cast) in favor of a direct NUL store, which avoids the libc call and hides no bugs behind a cast. Signed-off-by: Bin Guo <guobin@linux.alibaba.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260518110112.21395-3-guobin@linux.alibaba.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/global_state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration/global_state.c b/migration/global_state.c index XXXXXXX..XXXXXXX 100644 --- a/migration/global_state.c +++ b/migration/global_state.c @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_globalstate = { void register_global_state(void) { /* We would use it independently that we receive it */ - strcpy((char *)&global_state.runstate, ""); + global_state.runstate[0] = '\0'; global_state.received = false; vmstate_register(NULL, 0, &vmstate_globalstate, &global_state); } -- 2.53.0
From: Bin Guo <guobin@linux.alibaba.com> For every NULL slot in a VMS_ARRAY_OF_POINTER (or every entry of a dynamic array), the saver allocates a 1-element fake VMStateField via g_new0 and frees it again right after the save. For arrays of thousands of entries this is thousands of malloc/free pairs on the hot save path. Replace the heap-allocated marker with a stack-resident field populated by an init helper. The caller passes a pointer to a local VMStateField, the helper fills it in (still asserting the precondition), and no g_free is needed. Signed-off-by: Bin Guo <guobin@linux.alibaba.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260518110112.21395-4-guobin@linux.alibaba.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/vmstate.c | 41 ++++++++++++++++------------------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/migration/vmstate.c b/migration/vmstate.c index XXXXXXX..XXXXXXX 100644 --- a/migration/vmstate.c +++ b/migration/vmstate.c @@ -XXX,XX +XXX,XX @@ vmstate_field_exists(const VMStateDescription *vmsd, const VMStateField *field, * array of a VMS_ARRAY_OF_POINTER VMSD field. It's needed because we * can't dereference the NULL pointer. */ -static const VMStateField * -vmsd_create_ptr_marker_field(const VMStateField *field) +static void +vmsd_init_ptr_marker_field(VMStateField *fake, const VMStateField *field) { - VMStateField *fake = g_new0(VMStateField, 1); - /* It can only happen on an array of pointers! */ assert(field->flags & VMS_ARRAY_OF_POINTER); - /* Some of fake's properties should match the original's */ - fake->name = field->name; - fake->version_id = field->version_id; - - /* Do not need "field_exists" check as it always exists */ - fake->field_exists = NULL; - - /* See vmstate_info_ptr_marker - use 1 byte to represent ptr status */ - fake->size = 1; - fake->info = &vmstate_info_ptr_marker; - fake->flags = VMS_SINGLE; - - /* All the rest fields shouldn't matter.. */ - - return (const VMStateField *)fake; + /* See vmstate_info_ptr_marker - 1 byte represents ptr status */ + *fake = (VMStateField) { + .name = field->name, + .version_id = field->version_id, + /* Marker always exists, no field_exists callback needed */ + .field_exists = NULL, + .size = 1, + .info = &vmstate_info_ptr_marker, + .flags = VMS_SINGLE, + /* All other fields stay zero-initialised */ + }; } static int vmstate_n_elems(void *opaque, const VMStateField *field) @@ -XXX,XX +XXX,XX @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd, for (i = 0; i < n_elems; i++) { void *curr_elem = first_elem + size * i; const VMStateField *inner_field; + VMStateField marker_field; /* maximum number of elements to compress in the JSON blob */ int max_elems = vmsd_can_compress(field) ? (n_elems - i) : 1; bool use_marker_field, is_null = false; @@ -XXX,XX +XXX,XX @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd, use_marker_field = use_dynamic_array || is_null; if (use_marker_field) { - inner_field = vmsd_create_ptr_marker_field(field); + vmsd_init_ptr_marker_field(&marker_field, field); + inner_field = &marker_field; } else { inner_field = field; } @@ -XXX,XX +XXX,XX @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd, inner_field, vmdesc_loop, i, max_elems, errp); - /* If we used a fake temp field.. free it now */ - if (use_marker_field) { - g_clear_pointer((gpointer *)&inner_field, g_free); - } - if (!ok) { goto out; } -- 2.53.0
From: Bin Guo <guobin@linux.alibaba.com> configuration_validate_capabilities() allocates a bitmap on the heap to track source capabilities via bitmap_new()/g_free(). Since MIGRATION_CAPABILITY__MAX is a small compile-time constant (< 64), a heap allocation for a bitmap this small is wasteful: it adds malloc/free overhead and a potential cache miss for a transient 8-byte allocation. Replace with DECLARE_BITMAP() on the stack and bitmap_zero() to initialize. This eliminates the heap round-trip entirely. Signed-off-by: Bin Guo <guobin@linux.alibaba.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260518110112.21395-5-guobin@linux.alibaba.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/savevm.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/migration/savevm.c b/migration/savevm.c index XXXXXXX..XXXXXXX 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -XXX,XX +XXX,XX @@ static bool configuration_validate_capabilities(SaveState *state) { bool ret = true; MigrationState *s = migrate_get_current(); - unsigned long *source_caps_bm; + DECLARE_BITMAP(source_caps_bm, MIGRATION_CAPABILITY__MAX); int i; - source_caps_bm = bitmap_new(MIGRATION_CAPABILITY__MAX); + bitmap_zero(source_caps_bm, MIGRATION_CAPABILITY__MAX); for (i = 0; i < state->caps_count; i++) { MigrationCapability capability = state->capabilities[i]; set_bit(capability, source_caps_bm); @@ -XXX,XX +XXX,XX @@ static bool configuration_validate_capabilities(SaveState *state) } } - g_free(source_caps_bm); return ret; } -- 2.53.0
From: Bin Guo <guobin@linux.alibaba.com> multifd_recv_initial_packet() validates the channel ID received from the source against the configured number of channels. The current check uses '>' which allows msg.id == N to pass through. This ID is then used to index multifd_recv_state->params[msg.id], which was allocated with g_new0(MultiFDRecvParams, N) -- an out-of-bounds access. A malicious or buggy source could send id == N and cause heap corruption on the destination. Fix by changing '>' to '>='. Also fix the error message to say "exceeds channel count" for accuracy. Signed-off-by: Bin Guo <guobin@linux.alibaba.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260518110112.21395-6-guobin@linux.alibaba.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/multifd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index XXXXXXX..XXXXXXX 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -XXX,XX +XXX,XX @@ static int multifd_recv_initial_packet(QIOChannel *c, Error **errp) return -1; } - if (msg.id > migrate_multifd_channels()) { - error_setg(errp, "multifd: received channel id %u is greater than " - "number of channels %u", msg.id, migrate_multifd_channels()); + if (msg.id >= migrate_multifd_channels()) { + error_setg(errp, "multifd: received channel id %u exceeds " + "channel count %u", msg.id, migrate_multifd_channels()); return -1; } -- 2.53.0
From: Bin Guo <guobin@linux.alibaba.com> multifd_send() and multifd_recv() are on the per-page-batch hot path of live migration. Both functions call migrate_multifd_channels() multiple times (3-4 calls each) for modulo arithmetic in the round-robin channel selection loop. Each call goes through migrate_get_current() -> dereference MigrationState -> read parameters.multifd_channels. While each individual call is cheap, these functions execute for every page batch during the entire migration, easily millions of times. Cache the return value in a local variable at function entry. The channel count is fixed for the duration of a migration and cannot change mid-flight. For multifd_send(): 3 calls reduced to 1. For multifd_recv(): 4 calls reduced to 1. Signed-off-by: Bin Guo <guobin@linux.alibaba.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260518110112.21395-8-guobin@linux.alibaba.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/multifd.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index XXXXXXX..XXXXXXX 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -XXX,XX +XXX,XX @@ bool multifd_send(MultiFDSendData **send_data) /* We wait here, until at least one channel is ready */ qemu_sem_wait(&multifd_send_state->channels_ready); + int thread_count = migrate_multifd_channels(); + /* * next_channel can remain from a previous migration that was * using more channels, so ensure it doesn't overflow if the * limit is lower now. */ - next_channel %= migrate_multifd_channels(); - for (i = next_channel;; i = (i + 1) % migrate_multifd_channels()) { + next_channel %= thread_count; + for (i = next_channel;; i = (i + 1) % thread_count) { if (multifd_send_should_exit()) { return false; } @@ -XXX,XX +XXX,XX @@ bool multifd_send(MultiFDSendData **send_data) * sender thread can clear it. */ if (qatomic_read(&p->pending_job) == false) { - next_channel = (i + 1) % migrate_multifd_channels(); + next_channel = (i + 1) % thread_count; break; } } @@ -XXX,XX +XXX,XX @@ bool multifd_recv(void) int i; static int next_recv_channel; MultiFDRecvParams *p = NULL; + int thread_count = migrate_multifd_channels(); MultiFDRecvData *data = multifd_recv_state->data; /* @@ -XXX,XX +XXX,XX @@ bool multifd_recv(void) * using more channels, so ensure it doesn't overflow if the * limit is lower now. */ - next_recv_channel %= migrate_multifd_channels(); - for (i = next_recv_channel;; i = (i + 1) % migrate_multifd_channels()) { + next_recv_channel %= thread_count; + for (i = next_recv_channel;; i = (i + 1) % thread_count) { if (multifd_recv_should_exit()) { return false; } @@ -XXX,XX +XXX,XX @@ bool multifd_recv(void) p = &multifd_recv_state->params[i]; if (qatomic_read(&p->pending_job) == false) { - next_recv_channel = (i + 1) % migrate_multifd_channels(); + next_recv_channel = (i + 1) % thread_count; break; } } -- 2.53.0
From: Bin Guo <guobin@linux.alibaba.com> multifd_send_sync_main() is called once per RAM synchronization round during live migration. It iterates over all multifd channels twice (signal loop + wait loop), calling migrate_multifd_channels() independently in each loop header. Cache migrate_multifd_channels() in a local thread_count variable at function entry, matching the pattern already used in multifd_send_setup() and multifd_recv_setup(). This eliminates 2 redundant config lookups per sync call. Signed-off-by: Bin Guo <guobin@linux.alibaba.com> Reviewed-by: Fabiano Rosas <farosas@suse.de> Link: https://lore.kernel.org/r/20260518110112.21395-9-guobin@linux.alibaba.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/multifd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/migration/multifd.c b/migration/multifd.c index XXXXXXX..XXXXXXX 100644 --- a/migration/multifd.c +++ b/migration/multifd.c @@ -XXX,XX +XXX,XX @@ static int multifd_zero_copy_flush(QIOChannel *c) int multifd_send_sync_main(MultiFDSyncReq req) { int i; + int thread_count; bool flush_zero_copy; assert(req != MULTIFD_SYNC_NONE); + thread_count = migrate_multifd_channels(); flush_zero_copy = migrate_zero_copy_send(); - for (i = 0; i < migrate_multifd_channels(); i++) { + for (i = 0; i < thread_count; i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; if (multifd_send_should_exit()) { @@ -XXX,XX +XXX,XX @@ int multifd_send_sync_main(MultiFDSyncReq req) qatomic_set(&p->pending_sync, req); qemu_sem_post(&p->sem); } - for (i = 0; i < migrate_multifd_channels(); i++) { + for (i = 0; i < thread_count; i++) { MultiFDSendParams *p = &multifd_send_state->params[i]; if (multifd_send_should_exit()) { -- 2.53.0
From: hongmianquan <hongmianquan@bytedance.com> Use a GHashTable to store cpr fds to reduce the time consumption of `cpr_find_fd` in scenarios with a large number of fds. The time complexity for `cpr_find_fd` is reduced from O(N) to O(1). Keep cpr fds lookups in a GHashTable during normal runtime while preserving the existing QLIST migration ABI. Build a temporary QLIST from the hash table in pre_save and rebuild the hash table from the loaded QLIST in post_load. To demonstrate the performance improvement, we tested the total time consumed by `cpr_find_fd` (called N times for N fds) under our real-world business scenarios with different numbers of file descriptors. The results are measured in nanoseconds: | Number of FDs | Total time with QLIST (ns) | Total time with GHashTable (ns) | |---------------|----------------------------|---------------------------------| | 540 | 936,753 | 393,358 | | 2,870 | 24,102,342 | 2,212,113 | | 7,530 | 152,715,916 | 5,474,310 | As shown in the data, the lookup time grows exponentially with the QLIST as the number of fds increases. With the GHashTable, the time consumption remains linear (O(1) per lookup), significantly reducing the downtime during the CPR process. Signed-off-by: hongmianquan <hongmianquan@bytedance.com> Link: https://lore.kernel.org/r/20260519134315.27997-1-hongmianquan@bytedance.com Signed-off-by: Peter Xu <peterx@redhat.com> --- migration/cpr.c | 116 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 18 deletions(-) diff --git a/migration/cpr.c b/migration/cpr.c index XXXXXXX..XXXXXXX 100644 --- a/migration/cpr.c +++ b/migration/cpr.c @@ -XXX,XX +XXX,XX @@ /* cpr state container for all information to be saved. */ CprState cpr_state; +static GHashTable *cpr_fds_hash; /****************************************************************************/ @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_cpr_fd = { } }; +static guint cpr_fd_hash(gconstpointer v) +{ + const CprFd *elem = v; + + return g_str_hash(elem->name) ^ elem->id; +} + +static gboolean cpr_fd_equal(gconstpointer a, gconstpointer b) +{ + const CprFd *elem_a = a; + const CprFd *elem_b = b; + + return !strcmp(elem_a->name, elem_b->name) && elem_a->id == elem_b->id; +} + +static void cpr_fd_destroy(gpointer data) +{ + CprFd *elem = data; + + g_free(elem->name); + g_free(elem); +} + +static GHashTable *get_cpr_fds_hash(void) +{ + if (!cpr_fds_hash) { + cpr_fds_hash = g_hash_table_new_full(cpr_fd_hash, cpr_fd_equal, + cpr_fd_destroy, NULL); + } + + return cpr_fds_hash; +} + +static void cpr_fd_hash_insert(CprFd *elem) +{ + /* Use the same CprFd as key and value. */ + g_hash_table_insert(get_cpr_fds_hash(), elem, elem); +} + +static int cpr_fd_pre_save(void *opaque) +{ + CprState *state = (CprState *)opaque; + GHashTableIter iter; + CprFd *elem; + + QLIST_INIT(&state->fds); + + g_hash_table_iter_init(&iter, get_cpr_fds_hash()); + while (g_hash_table_iter_next(&iter, (gpointer *)&elem, NULL)) { + QLIST_INSERT_HEAD(&state->fds, elem, next); + } + + return 0; +} + +static int cpr_fd_post_load(void *opaque, int version_id) +{ + CprState *state = (CprState *)opaque; + CprFd *elem; + + while ((elem = QLIST_FIRST(&state->fds))) { + QLIST_REMOVE(elem, next); + + /* + * Preserve legacy QLIST lookup semantics if duplicate keys exist in + * the incoming stream: the first matching entry wins. + */ + if (g_hash_table_contains(get_cpr_fds_hash(), elem)) { + cpr_fd_destroy(elem); + continue; + } + + cpr_fd_hash_insert(elem); + } + + return 0; +} + void cpr_save_fd(const char *name, int id, int fd) { CprFd *elem = g_new0(CprFd, 1); @@ -XXX,XX +XXX,XX @@ void cpr_save_fd(const char *name, int id, int fd) elem->namelen = strlen(name) + 1; elem->id = id; elem->fd = fd; - QLIST_INSERT_HEAD(&cpr_state.fds, elem, next); + cpr_fd_hash_insert(elem); } -static CprFd *find_fd(CprFdList *head, const char *name, int id) +static CprFd *find_fd(const char *name, int id) { - CprFd *elem; + CprFd key = { + .name = (char *)name, + .id = id, + }; - QLIST_FOREACH(elem, head, next) { - if (!strcmp(elem->name, name) && elem->id == id) { - return elem; - } - } - return NULL; + return g_hash_table_lookup(get_cpr_fds_hash(), &key); } void cpr_delete_fd(const char *name, int id) { - CprFd *elem = find_fd(&cpr_state.fds, name, id); + CprFd key = { + .name = (char *)name, + .id = id, + }; - if (elem) { - QLIST_REMOVE(elem, next); - g_free(elem->name); - g_free(elem); - } + g_hash_table_remove(get_cpr_fds_hash(), &key); trace_cpr_delete_fd(name, id); } int cpr_find_fd(const char *name, int id) { - CprFd *elem = find_fd(&cpr_state.fds, name, id); + CprFd *elem = find_fd(name, id); int fd = elem ? elem->fd : -1; trace_cpr_find_fd(name, id, fd); @@ -XXX,XX +XXX,XX @@ int cpr_find_fd(const char *name, int id) void cpr_resave_fd(const char *name, int id, int fd) { - CprFd *elem = find_fd(&cpr_state.fds, name, id); + CprFd *elem = find_fd(name, id); int old_fd = elem ? elem->fd : -1; if (old_fd < 0) { @@ -XXX,XX +XXX,XX @@ int cpr_open_fd(const char *path, int flags, const char *name, int id, bool cpr_walk_fd(cpr_walk_fd_cb cb) { + GHashTableIter iter; CprFd *elem; - QLIST_FOREACH(elem, &cpr_state.fds, next) { + g_hash_table_iter_init(&iter, get_cpr_fds_hash()); + while (g_hash_table_iter_next(&iter, (gpointer *)&elem, NULL)) { g_assert(elem->fd >= 0); if (!cb(elem->fd)) { return false; @@ -XXX,XX +XXX,XX @@ static const VMStateDescription vmstate_cpr_state = { .name = CPR_STATE, .version_id = 1, .minimum_version_id = 1, + .pre_save = cpr_fd_pre_save, + .post_load = cpr_fd_post_load, .fields = (VMStateField[]) { VMSTATE_QLIST_V(fds, CprState, 1, vmstate_cpr_fd, CprFd, next), VMSTATE_END_OF_LIST() -- 2.53.0
From: Hyman Huang <yong.huang@bitdeer.com> I left SmartX two weeks ago. Update my email to stay reachable. Signed-off-by: Hyman Huang <infra.ai.cloud@bitdeer.com> Link: https://lore.kernel.org/r/b3bd81c3d9f425bb750a76d7bad7ad0284e55123.1779178180.git.infra.ai.cloud@bitdeer.com [peterx: fix address, s/biitdeer/bitdeer/] Signed-off-by: Peter Xu <peterx@redhat.com> --- MAINTAINERS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index XXXXXXX..XXXXXXX 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -XXX,XX +XXX,XX @@ F: migration/rdma* F: scripts/rdma-migration-helper.sh Migration dirty limit and dirty page rate -M: Hyman Huang <yong.huang@smartx.com> +M: Hyman Huang <infra.ai.cloud@bitdeer.com> S: Maintained F: system/dirtylimit.c F: include/system/dirtylimit.h @@ -XXX,XX +XXX,XX @@ F: include/system/dirtyrate.h F: docs/devel/migration/dirty-limit.rst Detached LUKS header -M: Hyman Huang <yong.huang@smartx.com> +M: Hyman Huang <infra.ai.cloud@bitdeer.com> S: Maintained F: tests/qemu-iotests/tests/luks-detached-header F: docs/devel/luks-detached-header.rst -- 2.53.0