test-replication.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. /*
  2. * Block replication tests
  3. *
  4. * Copyright (c) 2016 FUJITSU LIMITED
  5. * Author: Changlong Xie <xiecl.fnst@cn.fujitsu.com>
  6. *
  7. * This work is licensed under the terms of the GNU GPL, version 2 or
  8. * later. See the COPYING file in the top-level directory.
  9. */
  10. #include "qemu/osdep.h"
  11. #include "qapi/error.h"
  12. #include "qapi/qmp/qdict.h"
  13. #include "qemu/option.h"
  14. #include "qemu/main-loop.h"
  15. #include "replication.h"
  16. #include "block/block_int.h"
  17. #include "block/qdict.h"
  18. #include "sysemu/block-backend.h"
  19. #define IMG_SIZE (64 * 1024 * 1024)
  20. /* primary */
  21. #define P_ID "primary-id"
  22. static char p_local_disk[] = "/tmp/p_local_disk.XXXXXX";
  23. /* secondary */
  24. #define S_ID "secondary-id"
  25. #define S_LOCAL_DISK_ID "secondary-local-disk-id"
  26. static char s_local_disk[] = "/tmp/s_local_disk.XXXXXX";
  27. static char s_active_disk[] = "/tmp/s_active_disk.XXXXXX";
  28. static char s_hidden_disk[] = "/tmp/s_hidden_disk.XXXXXX";
  29. /* FIXME: steal from blockdev.c */
  30. QemuOptsList qemu_drive_opts = {
  31. .name = "drive",
  32. .head = QTAILQ_HEAD_INITIALIZER(qemu_drive_opts.head),
  33. .desc = {
  34. { /* end of list */ }
  35. },
  36. };
  37. #define NOT_DONE 0x7fffffff
  38. static void blk_rw_done(void *opaque, int ret)
  39. {
  40. *(int *)opaque = ret;
  41. }
  42. static void test_blk_read(BlockBackend *blk, long pattern,
  43. int64_t pattern_offset, int64_t pattern_count,
  44. int64_t offset, int64_t count,
  45. bool expect_failed)
  46. {
  47. void *pattern_buf = NULL;
  48. QEMUIOVector qiov;
  49. void *cmp_buf = NULL;
  50. int async_ret = NOT_DONE;
  51. if (pattern) {
  52. cmp_buf = g_malloc(pattern_count);
  53. memset(cmp_buf, pattern, pattern_count);
  54. }
  55. pattern_buf = g_malloc(count);
  56. if (pattern) {
  57. memset(pattern_buf, pattern, count);
  58. } else {
  59. memset(pattern_buf, 0x00, count);
  60. }
  61. qemu_iovec_init(&qiov, 1);
  62. qemu_iovec_add(&qiov, pattern_buf, count);
  63. blk_aio_preadv(blk, offset, &qiov, 0, blk_rw_done, &async_ret);
  64. while (async_ret == NOT_DONE) {
  65. main_loop_wait(false);
  66. }
  67. if (expect_failed) {
  68. g_assert(async_ret != 0);
  69. } else {
  70. g_assert(async_ret == 0);
  71. if (pattern) {
  72. g_assert(memcmp(pattern_buf + pattern_offset,
  73. cmp_buf, pattern_count) <= 0);
  74. }
  75. }
  76. g_free(pattern_buf);
  77. g_free(cmp_buf);
  78. qemu_iovec_destroy(&qiov);
  79. }
  80. static void test_blk_write(BlockBackend *blk, long pattern, int64_t offset,
  81. int64_t count, bool expect_failed)
  82. {
  83. void *pattern_buf = NULL;
  84. QEMUIOVector qiov;
  85. int async_ret = NOT_DONE;
  86. pattern_buf = g_malloc(count);
  87. if (pattern) {
  88. memset(pattern_buf, pattern, count);
  89. } else {
  90. memset(pattern_buf, 0x00, count);
  91. }
  92. qemu_iovec_init(&qiov, 1);
  93. qemu_iovec_add(&qiov, pattern_buf, count);
  94. blk_aio_pwritev(blk, offset, &qiov, 0, blk_rw_done, &async_ret);
  95. while (async_ret == NOT_DONE) {
  96. main_loop_wait(false);
  97. }
  98. if (expect_failed) {
  99. g_assert(async_ret != 0);
  100. } else {
  101. g_assert(async_ret == 0);
  102. }
  103. g_free(pattern_buf);
  104. qemu_iovec_destroy(&qiov);
  105. }
  106. /*
  107. * Create a uniquely-named empty temporary file.
  108. */
  109. static void make_temp(char *template)
  110. {
  111. int fd;
  112. fd = mkstemp(template);
  113. g_assert(fd >= 0);
  114. close(fd);
  115. }
  116. static void prepare_imgs(void)
  117. {
  118. Error *local_err = NULL;
  119. make_temp(p_local_disk);
  120. make_temp(s_local_disk);
  121. make_temp(s_active_disk);
  122. make_temp(s_hidden_disk);
  123. /* Primary */
  124. bdrv_img_create(p_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
  125. BDRV_O_RDWR, true, &local_err);
  126. g_assert(!local_err);
  127. /* Secondary */
  128. bdrv_img_create(s_local_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
  129. BDRV_O_RDWR, true, &local_err);
  130. g_assert(!local_err);
  131. bdrv_img_create(s_active_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
  132. BDRV_O_RDWR, true, &local_err);
  133. g_assert(!local_err);
  134. bdrv_img_create(s_hidden_disk, "qcow2", NULL, NULL, NULL, IMG_SIZE,
  135. BDRV_O_RDWR, true, &local_err);
  136. g_assert(!local_err);
  137. }
  138. static void cleanup_imgs(void)
  139. {
  140. /* Primary */
  141. unlink(p_local_disk);
  142. /* Secondary */
  143. unlink(s_local_disk);
  144. unlink(s_active_disk);
  145. unlink(s_hidden_disk);
  146. }
  147. static BlockBackend *start_primary(void)
  148. {
  149. BlockBackend *blk;
  150. QemuOpts *opts;
  151. QDict *qdict;
  152. Error *local_err = NULL;
  153. char *cmdline;
  154. cmdline = g_strdup_printf("driver=replication,mode=primary,node-name=xxx,"
  155. "file.driver=qcow2,file.file.filename=%s,"
  156. "file.file.locking=off"
  157. , p_local_disk);
  158. opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
  159. g_free(cmdline);
  160. qdict = qemu_opts_to_qdict(opts, NULL);
  161. qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
  162. qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
  163. blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
  164. g_assert(blk);
  165. g_assert(!local_err);
  166. monitor_add_blk(blk, P_ID, &local_err);
  167. g_assert(!local_err);
  168. qemu_opts_del(opts);
  169. return blk;
  170. }
  171. static void teardown_primary(void)
  172. {
  173. BlockBackend *blk;
  174. AioContext *ctx;
  175. /* remove P_ID */
  176. blk = blk_by_name(P_ID);
  177. assert(blk);
  178. ctx = blk_get_aio_context(blk);
  179. aio_context_acquire(ctx);
  180. monitor_remove_blk(blk);
  181. blk_unref(blk);
  182. aio_context_release(ctx);
  183. }
  184. static void test_primary_read(void)
  185. {
  186. BlockBackend *blk;
  187. blk = start_primary();
  188. /* read from 0 to IMG_SIZE */
  189. test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true);
  190. teardown_primary();
  191. }
  192. static void test_primary_write(void)
  193. {
  194. BlockBackend *blk;
  195. blk = start_primary();
  196. /* write from 0 to IMG_SIZE */
  197. test_blk_write(blk, 0, 0, IMG_SIZE, true);
  198. teardown_primary();
  199. }
  200. static void test_primary_start(void)
  201. {
  202. BlockBackend *blk = NULL;
  203. Error *local_err = NULL;
  204. blk = start_primary();
  205. replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
  206. g_assert(!local_err);
  207. /* read from 0 to IMG_SIZE */
  208. test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true);
  209. /* write 0x22 from 0 to IMG_SIZE */
  210. test_blk_write(blk, 0x22, 0, IMG_SIZE, false);
  211. teardown_primary();
  212. }
  213. static void test_primary_stop(void)
  214. {
  215. Error *local_err = NULL;
  216. bool failover = true;
  217. start_primary();
  218. replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
  219. g_assert(!local_err);
  220. replication_stop_all(failover, &local_err);
  221. g_assert(!local_err);
  222. teardown_primary();
  223. }
  224. static void test_primary_do_checkpoint(void)
  225. {
  226. Error *local_err = NULL;
  227. start_primary();
  228. replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
  229. g_assert(!local_err);
  230. replication_do_checkpoint_all(&local_err);
  231. g_assert(!local_err);
  232. teardown_primary();
  233. }
  234. static void test_primary_get_error_all(void)
  235. {
  236. Error *local_err = NULL;
  237. start_primary();
  238. replication_start_all(REPLICATION_MODE_PRIMARY, &local_err);
  239. g_assert(!local_err);
  240. replication_get_error_all(&local_err);
  241. g_assert(!local_err);
  242. teardown_primary();
  243. }
  244. static BlockBackend *start_secondary(void)
  245. {
  246. QemuOpts *opts;
  247. QDict *qdict;
  248. BlockBackend *blk;
  249. char *cmdline;
  250. Error *local_err = NULL;
  251. /* add s_local_disk and forge S_LOCAL_DISK_ID */
  252. cmdline = g_strdup_printf("file.filename=%s,driver=qcow2,"
  253. "file.locking=off",
  254. s_local_disk);
  255. opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
  256. g_free(cmdline);
  257. qdict = qemu_opts_to_qdict(opts, NULL);
  258. qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
  259. qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
  260. blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
  261. assert(blk);
  262. monitor_add_blk(blk, S_LOCAL_DISK_ID, &local_err);
  263. g_assert(!local_err);
  264. /* format s_local_disk with pattern "0x11" */
  265. test_blk_write(blk, 0x11, 0, IMG_SIZE, false);
  266. qemu_opts_del(opts);
  267. /* add S_(ACTIVE/HIDDEN)_DISK and forge S_ID */
  268. cmdline = g_strdup_printf("driver=replication,mode=secondary,top-id=%s,"
  269. "file.driver=qcow2,file.file.filename=%s,"
  270. "file.file.locking=off,"
  271. "file.backing.driver=qcow2,"
  272. "file.backing.file.filename=%s,"
  273. "file.backing.file.locking=off,"
  274. "file.backing.backing=%s"
  275. , S_ID, s_active_disk, s_hidden_disk
  276. , S_LOCAL_DISK_ID);
  277. opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
  278. g_free(cmdline);
  279. qdict = qemu_opts_to_qdict(opts, NULL);
  280. qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
  281. qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
  282. blk = blk_new_open(NULL, NULL, qdict, BDRV_O_RDWR, &local_err);
  283. assert(blk);
  284. monitor_add_blk(blk, S_ID, &local_err);
  285. g_assert(!local_err);
  286. qemu_opts_del(opts);
  287. return blk;
  288. }
  289. static void teardown_secondary(void)
  290. {
  291. /* only need to destroy two BBs */
  292. BlockBackend *blk;
  293. AioContext *ctx;
  294. /* remove S_LOCAL_DISK_ID */
  295. blk = blk_by_name(S_LOCAL_DISK_ID);
  296. assert(blk);
  297. ctx = blk_get_aio_context(blk);
  298. aio_context_acquire(ctx);
  299. monitor_remove_blk(blk);
  300. blk_unref(blk);
  301. aio_context_release(ctx);
  302. /* remove S_ID */
  303. blk = blk_by_name(S_ID);
  304. assert(blk);
  305. ctx = blk_get_aio_context(blk);
  306. aio_context_acquire(ctx);
  307. monitor_remove_blk(blk);
  308. blk_unref(blk);
  309. aio_context_release(ctx);
  310. }
  311. static void test_secondary_read(void)
  312. {
  313. BlockBackend *blk;
  314. blk = start_secondary();
  315. /* read from 0 to IMG_SIZE */
  316. test_blk_read(blk, 0, 0, IMG_SIZE, 0, IMG_SIZE, true);
  317. teardown_secondary();
  318. }
  319. static void test_secondary_write(void)
  320. {
  321. BlockBackend *blk;
  322. blk = start_secondary();
  323. /* write from 0 to IMG_SIZE */
  324. test_blk_write(blk, 0, 0, IMG_SIZE, true);
  325. teardown_secondary();
  326. }
  327. static void test_secondary_start(void)
  328. {
  329. BlockBackend *top_blk, *local_blk;
  330. Error *local_err = NULL;
  331. bool failover = true;
  332. top_blk = start_secondary();
  333. replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
  334. g_assert(!local_err);
  335. /* read from s_local_disk (0, IMG_SIZE) */
  336. test_blk_read(top_blk, 0x11, 0, IMG_SIZE, 0, IMG_SIZE, false);
  337. /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
  338. local_blk = blk_by_name(S_LOCAL_DISK_ID);
  339. test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false);
  340. /* replication will backup s_local_disk to s_hidden_disk */
  341. test_blk_read(top_blk, 0x11, IMG_SIZE / 2,
  342. IMG_SIZE / 2, 0, IMG_SIZE, false);
  343. /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */
  344. test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false);
  345. /* read from s_active_disk (0, IMG_SIZE/2) */
  346. test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2,
  347. 0, IMG_SIZE / 2, false);
  348. /* unblock top_bs */
  349. replication_stop_all(failover, &local_err);
  350. g_assert(!local_err);
  351. teardown_secondary();
  352. }
  353. static void test_secondary_stop(void)
  354. {
  355. BlockBackend *top_blk, *local_blk;
  356. Error *local_err = NULL;
  357. bool failover = true;
  358. top_blk = start_secondary();
  359. replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
  360. g_assert(!local_err);
  361. /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
  362. local_blk = blk_by_name(S_LOCAL_DISK_ID);
  363. test_blk_write(local_blk, 0x22, IMG_SIZE / 2, IMG_SIZE / 2, false);
  364. /* replication will backup s_local_disk to s_hidden_disk */
  365. test_blk_read(top_blk, 0x11, IMG_SIZE / 2,
  366. IMG_SIZE / 2, 0, IMG_SIZE, false);
  367. /* write 0x33 to s_active_disk (0, IMG_SIZE / 2) */
  368. test_blk_write(top_blk, 0x33, 0, IMG_SIZE / 2, false);
  369. /* do active commit */
  370. replication_stop_all(failover, &local_err);
  371. g_assert(!local_err);
  372. /* read from s_local_disk (0, IMG_SIZE / 2) */
  373. test_blk_read(top_blk, 0x33, 0, IMG_SIZE / 2,
  374. 0, IMG_SIZE / 2, false);
  375. /* read from s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
  376. test_blk_read(top_blk, 0x22, IMG_SIZE / 2,
  377. IMG_SIZE / 2, 0, IMG_SIZE, false);
  378. teardown_secondary();
  379. }
  380. static void test_secondary_do_checkpoint(void)
  381. {
  382. BlockBackend *top_blk, *local_blk;
  383. Error *local_err = NULL;
  384. bool failover = true;
  385. top_blk = start_secondary();
  386. replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
  387. g_assert(!local_err);
  388. /* write 0x22 to s_local_disk (IMG_SIZE / 2, IMG_SIZE) */
  389. local_blk = blk_by_name(S_LOCAL_DISK_ID);
  390. test_blk_write(local_blk, 0x22, IMG_SIZE / 2,
  391. IMG_SIZE / 2, false);
  392. /* replication will backup s_local_disk to s_hidden_disk */
  393. test_blk_read(top_blk, 0x11, IMG_SIZE / 2,
  394. IMG_SIZE / 2, 0, IMG_SIZE, false);
  395. replication_do_checkpoint_all(&local_err);
  396. g_assert(!local_err);
  397. /* after checkpoint, read pattern 0x22 from s_local_disk */
  398. test_blk_read(top_blk, 0x22, IMG_SIZE / 2,
  399. IMG_SIZE / 2, 0, IMG_SIZE, false);
  400. /* unblock top_bs */
  401. replication_stop_all(failover, &local_err);
  402. g_assert(!local_err);
  403. teardown_secondary();
  404. }
  405. static void test_secondary_get_error_all(void)
  406. {
  407. Error *local_err = NULL;
  408. bool failover = true;
  409. start_secondary();
  410. replication_start_all(REPLICATION_MODE_SECONDARY, &local_err);
  411. g_assert(!local_err);
  412. replication_get_error_all(&local_err);
  413. g_assert(!local_err);
  414. /* unblock top_bs */
  415. replication_stop_all(failover, &local_err);
  416. g_assert(!local_err);
  417. teardown_secondary();
  418. }
  419. static void sigabrt_handler(int signo)
  420. {
  421. cleanup_imgs();
  422. }
  423. static void setup_sigabrt_handler(void)
  424. {
  425. struct sigaction sigact;
  426. sigact = (struct sigaction) {
  427. .sa_handler = sigabrt_handler,
  428. .sa_flags = SA_RESETHAND,
  429. };
  430. sigemptyset(&sigact.sa_mask);
  431. sigaction(SIGABRT, &sigact, NULL);
  432. }
  433. int main(int argc, char **argv)
  434. {
  435. int ret;
  436. qemu_init_main_loop(&error_fatal);
  437. bdrv_init();
  438. g_test_init(&argc, &argv, NULL);
  439. setup_sigabrt_handler();
  440. prepare_imgs();
  441. /* Primary */
  442. g_test_add_func("/replication/primary/read", test_primary_read);
  443. g_test_add_func("/replication/primary/write", test_primary_write);
  444. g_test_add_func("/replication/primary/start", test_primary_start);
  445. g_test_add_func("/replication/primary/stop", test_primary_stop);
  446. g_test_add_func("/replication/primary/do_checkpoint",
  447. test_primary_do_checkpoint);
  448. g_test_add_func("/replication/primary/get_error_all",
  449. test_primary_get_error_all);
  450. /* Secondary */
  451. g_test_add_func("/replication/secondary/read", test_secondary_read);
  452. g_test_add_func("/replication/secondary/write", test_secondary_write);
  453. g_test_add_func("/replication/secondary/start", test_secondary_start);
  454. g_test_add_func("/replication/secondary/stop", test_secondary_stop);
  455. g_test_add_func("/replication/secondary/do_checkpoint",
  456. test_secondary_do_checkpoint);
  457. g_test_add_func("/replication/secondary/get_error_all",
  458. test_secondary_get_error_all);
  459. ret = g_test_run();
  460. cleanup_imgs();
  461. return ret;
  462. }